1; RUN: llc -stop-after=amdgpu-isel -mtriple=amdgcn-- -mcpu=gfx900 -verify-machineinstrs -o - %s | FileCheck --check-prefixes=CHECK,ISEL %s 2; RUN: llc -stop-after=dead-mi-elimination -mtriple=amdgcn-- -mcpu=gfx900 -verify-machineinstrs -o - %s | FileCheck --check-prefixes=CHECK,DEADMI %s 3; RUN: llc -global-isel -stop-after=irtranslator -mtriple=amdgcn-- -mcpu=gfx900 -verify-machineinstrs -o - %s | FileCheck %s --check-prefixes=CHECK,GISEL 4 5; CHECK-LABEL: name: basic_call 6; CHECK: [[TOKEN:%[0-9]+]]{{[^ ]*}} = CONVERGENCECTRL_ENTRY 7; ISEL: {{.*}} SI_CALL_ISEL {{.*}}, @foo, csr_amdgpu, {{.*}}, implicit [[TOKEN]] 8; DEADMI: {{.*}} SI_CALL {{.*}}, @foo, csr_amdgpu, {{.*}}, implicit [[TOKEN]] 9; GISEL: {{.*}} G_SI_CALL {{.*}}, @foo, csr_amdgpu, {{.*}}, implicit [[TOKEN]] 10define i32 @basic_call(i32 %src) #0 { 11 %t = call token @llvm.experimental.convergence.entry() 12 %r = call i32 @foo(i32 %src) [ "convergencectrl"(token %t) ] 13 ret i32 %r 14} 15 16; CHECK-LABEL: name: basic_intrinsic 17; CHECK: [[TOKEN:%[0-9]+]]{{[^ ]*}} = CONVERGENCECTRL_ANCHOR 18; ISEL: CONVERGENCECTRL_GLUE [[TOKEN]] 19; DEADMI-NOT: CONVERGENCECTRL_GLUE 20; ISEL: {{.*}} = V_READFIRSTLANE_B32 {{.*}}, implicit [[TOKEN]] 21; GISEL: {{.*}} = G_INTRINSIC_CONVERGENT intrinsic(@llvm.amdgcn.readfirstlane){{.*}}, implicit [[TOKEN]] 22define i32 @basic_intrinsic(i32 %src) #0 { 23 %t = call token @llvm.experimental.convergence.anchor() 24 %r = call i32 @llvm.amdgcn.readfirstlane(i32 %src) [ "convergencectrl"(token %t) ] 25 ret i32 %r 26} 27 28; There's nothing to check here. The test is just meant to catch any crashes 29; when a convergent call has no token. 30define i32 @uncontrolled_call(i32 %src) #0 { 31 %r = call i32 @foo(i32 %src) 32 ret i32 %r 33} 34 35; CHECK-LABEL: name: basic_branch 36; CHECK: bb.[[#]].entry: 37; CHECK: [[TOKEN:%[0-9]+]]{{[^ ]*}} = CONVERGENCECTRL_ANCHOR 38; CHECK: bb.[[#]].then: 39; ISEL: CONVERGENCECTRL_GLUE [[TOKEN]] 40; DEADMI-NOT: CONVERGENCECTRL_GLUE 41; ISEL: {{.*}} = V_READFIRSTLANE_B32 {{.*}}, implicit [[TOKEN]] 42; GISEL: {{.*}} = G_INTRINSIC_CONVERGENT intrinsic(@llvm.amdgcn.readfirstlane){{.*}}, implicit [[TOKEN]] 43define i32 @basic_branch(i32 %src, i1 %cond) #0 { 44entry: 45 %t = call token @llvm.experimental.convergence.anchor() 46 %x = add i32 %src, 1 47 br i1 %cond, label %then, label %else 48 49then: 50 %r = call i32 @llvm.amdgcn.readfirstlane(i32 %x) [ "convergencectrl"(token %t) ] 51 br label %else 52 53else: 54 %p = phi i32 [%r, %then], [%x, %entry] 55 ret i32 %p 56} 57 58; CHECK-LABEL: name: basic_loop 59; CHECK: [[TOKEN:%[0-9]+]]{{[^ ]*}} = CONVERGENCECTRL_ANCHOR 60; CHECK: bb.[[#]].loop: 61; CHECK: [[LOOP:%[0-9]+]]{{[^ ]*}} = CONVERGENCECTRL_LOOP [[TOKEN]] 62; ISEL: CONVERGENCECTRL_GLUE [[LOOP]] 63; DEADMI-NOT: CONVERGENCECTRL_GLUE 64; ISEL: {{.*}} = V_READFIRSTLANE_B32 {{.*}}, implicit [[LOOP]] 65; GISEL: {{.*}} = G_INTRINSIC_CONVERGENT intrinsic(@llvm.amdgcn.readfirstlane){{.*}}, implicit [[LOOP]] 66define i32 @basic_loop(i32 %src, i1 %cond) #0 { 67 %t1 = call token @llvm.experimental.convergence.anchor() 68 br label %loop 69 70loop: 71 %t2 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %t1) ] 72 %r = call i32 @llvm.amdgcn.readfirstlane(i32 %src) [ "convergencectrl"(token %t2) ] 73 br i1 %cond, label %loop, label %end 74 75end: 76 ret i32 %r 77} 78 79; CHECK-LABEL: name: nested 80; CHECK: [[ENTRY:%[0-9]+]]{{[^ ]*}} = CONVERGENCECTRL_ENTRY 81; CHECK: [[ANCHOR:%[0-9]+]]{{[^ ]*}} = CONVERGENCECTRL_ANCHOR 82; ISEL: {{.*}} = V_READFIRSTLANE_B32 {{.*}}, implicit [[ANCHOR]] 83; GISEL: {{.*}} = G_INTRINSIC_CONVERGENT intrinsic(@llvm.amdgcn.readfirstlane){{.*}}, implicit [[ANCHOR]] 84; ISEL: {{.*}} = V_READFIRSTLANE_B32 {{.*}}, implicit [[ENTRY]] 85; GISEL: {{.*}} = G_INTRINSIC_CONVERGENT intrinsic(@llvm.amdgcn.readfirstlane){{.*}}, implicit [[ENTRY]] 86define i32 @nested(i32 %src) #0 { 87 %t1 = call token @llvm.experimental.convergence.entry() 88 %t2 = call token @llvm.experimental.convergence.anchor() 89 %r2 = call i32 @llvm.amdgcn.readfirstlane(i32 %src) [ "convergencectrl"(token %t2) ] 90 %r1 = call i32 @llvm.amdgcn.readfirstlane(i32 %src) [ "convergencectrl"(token %t1) ] 91 %sum = add i32 %r1, %r2 92 ret i32 %sum 93} 94 95; CHECK-LABEL: name: tail_call_void_func_void 96; CHECK: [[TOKEN:%[0-9]+]]{{[^ ]*}} = CONVERGENCECTRL_ENTRY 97; CHECK: {{.*}} SI_TCRETURN {{.*}}, @external_void_func_void, 0, csr_amdgpu, {{.*}}implicit [[TOKEN]] 98define void @tail_call_void_func_void() #0 { 99 %t1 = call token @llvm.experimental.convergence.entry() 100 tail call void @external_void_func_void() [ "convergencectrl"(token %t1) ] 101 ret void 102} 103 104declare hidden void @external_void_func_void() #0 105declare i32 @foo(i32 %x) #0 106 107declare i32 @llvm.amdgcn.readfirstlane(i32) #0 108 109declare token @llvm.experimental.convergence.entry() 110declare token @llvm.experimental.convergence.anchor() 111declare token @llvm.experimental.convergence.loop() 112 113attributes #0 = { nounwind readnone convergent } 114attributes #1 = { nounwind } 115