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