1// RUN: %clang_cc1 -triple spir-unknown-unknown -emit-llvm %s -o - | FileCheck -enable-var-scope %s 2 3// This is initially assumed convergent, but can be deduced to not require it. 4 5// CHECK-LABEL: define{{.*}} spir_func void @non_convfun() local_unnamed_addr #0 6// CHECK: ret void 7__attribute__((noinline)) 8void non_convfun(void) { 9 volatile int* p; 10 *p = 0; 11} 12 13void convfun(void) __attribute__((convergent)); 14void nodupfun(void) __attribute__((noduplicate)); 15 16// External functions should be assumed convergent. 17void f(void); 18void g(void); 19 20// Test two if's are merged and non_convfun duplicated. 21// The LLVM IR is equivalent to: 22// if (a) { 23// f(); 24// non_convfun(); 25// g(); 26// } else { 27// non_convfun(); 28// } 29// 30// CHECK-LABEL: define{{.*}} spir_func void @test_merge_if(i32 noundef %a) local_unnamed_addr #1 { 31// CHECK: %[[tobool:.+]] = icmp eq i32 %a, 0 32// CHECK: br i1 %[[tobool]], label %[[if_end3_critedge:.+]], label %[[if_then:.+]] 33 34// CHECK: [[if_then]]: 35// CHECK: tail call spir_func void @f() 36// CHECK: tail call spir_func void @non_convfun() 37// CHECK: tail call spir_func void @g() 38 39// CHECK: br label %[[if_end3:.+]] 40 41// CHECK: [[if_end3_critedge]]: 42// CHECK: tail call spir_func void @non_convfun() 43// CHECK: br label %[[if_end3]] 44 45// CHECK: [[if_end3]]: 46// CHECK: ret void 47 48void test_merge_if(int a) { 49 if (a) { 50 f(); 51 } 52 non_convfun(); 53 if (a) { 54 g(); 55 } 56} 57 58// CHECK-DAG: declare spir_func void @f() local_unnamed_addr #2 59// CHECK-DAG: declare spir_func void @g() local_unnamed_addr #2 60 61 62// Test two if's are not merged. 63// CHECK-LABEL: define{{.*}} spir_func void @test_no_merge_if(i32 noundef %a) local_unnamed_addr #1 64// CHECK: %[[tobool:.+]] = icmp eq i32 %a, 0 65// CHECK: br i1 %[[tobool]], label %[[if_end:.+]], label %[[if_then:.+]] 66// CHECK: [[if_then]]: 67// CHECK: tail call spir_func void @f() 68// CHECK-NOT: call spir_func void @convfun() 69// CHECK-NOT: call spir_func void @g() 70// CHECK: br label %[[if_end]] 71// CHECK: [[if_end]]: 72// CHECK-NOT: phi i1 73// CHECK: tail call spir_func void @convfun() #[[attr4:.+]] 74// CHECK: br i1 %[[tobool]], label %[[if_end3:.+]], label %[[if_then2:.+]] 75// CHECK: [[if_then2]]: 76// CHECK: tail call spir_func void @g() 77// CHECK: br label %[[if_end3:.+]] 78// CHECK: [[if_end3]]: 79// CHECK-LABEL: ret void 80 81void test_no_merge_if(int a) { 82 if (a) { 83 f(); 84 } 85 convfun(); 86 if(a) { 87 g(); 88 } 89} 90 91// CHECK: declare spir_func void @convfun(){{[^#]*}} #2 92 93// Test loop is unrolled for convergent function. 94// CHECK-LABEL: define{{.*}} spir_func void @test_unroll() local_unnamed_addr #1 95// CHECK: tail call spir_func void @convfun() #[[attr4:[0-9]+]] 96// CHECK: tail call spir_func void @convfun() #[[attr4]] 97// CHECK: tail call spir_func void @convfun() #[[attr4]] 98// CHECK: tail call spir_func void @convfun() #[[attr4]] 99// CHECK: tail call spir_func void @convfun() #[[attr4]] 100// CHECK: tail call spir_func void @convfun() #[[attr4]] 101// CHECK: tail call spir_func void @convfun() #[[attr4]] 102// CHECK: tail call spir_func void @convfun() #[[attr4]] 103// CHECK: tail call spir_func void @convfun() #[[attr4]] 104// CHECK: tail call spir_func void @convfun() #[[attr4]] 105// CHECK-LABEL: ret void 106 107void test_unroll() { 108 for (int i = 0; i < 10; i++) 109 convfun(); 110} 111 112// Test loop is not unrolled for noduplicate function. 113// CHECK-LABEL: define{{.*}} spir_func void @test_not_unroll() 114// CHECK: br label %[[for_body:.+]] 115// CHECK: [[for_cond_cleanup:.+]]: 116// CHECK: ret void 117// CHECK: [[for_body]]: 118// CHECK: tail call spir_func void @nodupfun() #[[attr5:[0-9]+]] 119// CHECK-NOT: call spir_func void @nodupfun() 120// CHECK: br i1 %{{.+}}, label %[[for_body]], label %[[for_cond_cleanup]] 121 122void test_not_unroll() { 123 for (int i = 0; i < 10; i++) 124 nodupfun(); 125} 126 127// CHECK: declare spir_func void @nodupfun(){{[^#]*}} #[[attr3:[0-9]+]] 128 129// CHECK-LABEL: @assume_convergent_asm 130// CHECK: tail call void asm sideeffect "s_barrier", ""() #5 131kernel void assume_convergent_asm() 132{ 133 __asm__ volatile("s_barrier"); 134} 135 136// CHECK: attributes #0 = { nofree noinline norecurse nounwind " 137// CHECK: attributes #1 = { {{[^}]*}}convergent{{[^}]*}} } 138// CHECK: attributes #2 = { {{[^}]*}}convergent{{[^}]*}} } 139// CHECK: attributes #3 = { {{[^}]*}}convergent noduplicate{{[^}]*}} } 140// CHECK: attributes #4 = { {{[^}]*}}convergent{{[^}]*}} } 141// CHECK: attributes #5 = { {{[^}]*}}convergent{{[^}]*}} } 142// CHECK: attributes #6 = { {{[^}]*}}nounwind{{[^}]*}} } 143// CHECK: attributes #7 = { {{[^}]*}}convergent noduplicate nounwind{{[^}]*}} } 144