1 | // RUN: %clang_cc1 -triple spir-unknown-unknown -emit-llvm %s -o - | opt -instnamer -S | 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)) |
8 | void non_convfun(void) { |
9 | volatile int* p; |
10 | *p = 0; |
11 | } |
12 | |
13 | void convfun(void) __attribute__((convergent)); |
14 | void nodupfun(void) __attribute__((noduplicate)); |
15 | |
16 | // External functions should be assumed convergent. |
17 | void f(void); |
18 | void 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 %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 | |
48 | void 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 %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: %[[tobool_pr:.+]] = phi i1 [ true, %[[if_then]] ], [ false, %{{.+}} ] |
73 | // CHECK: tail call spir_func void @convfun() #[[attr4:.+]] |
74 | // CHECK: br i1 %[[tobool_pr]], label %[[if_then2:.+]], label %[[if_end3:.+]] |
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 | |
81 | void 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 | |
107 | void 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 | |
122 | void 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 |
131 | kernel void assume_convergent_asm() |
132 | { |
133 | __asm__ volatile("s_barrier"); |
134 | } |
135 | |
136 | // CHECK: attributes #0 = { 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 = { {{[^}]*}}convergent noduplicate{{[^}]*}} } |
143 | |