1// RUN: %clang_cc1 -triple spir-unknown-unknown -emit-llvm %s -o - | opt -instnamer -S | FileCheck %s
2
3void convfun(void) __attribute__((convergent));
4void non_convfun(void);
5void nodupfun(void) __attribute__((noduplicate));
6
7void f(void);
8void g(void);
9
10// Test two if's are merged and non_convfun duplicated.
11// The LLVM IR is equivalent to:
12//    if (a) {
13//      f();
14//      non_convfun();
15//      g();
16//    } else {
17//      non_convfun();
18//    }
19//
20// CHECK: define spir_func void @test_merge_if(i32 %[[a:.+]])
21// CHECK: %[[tobool:.+]] = icmp eq i32 %[[a]], 0
22// CHECK: br i1 %[[tobool]], label %[[if_end3_critedge:.+]], label %[[if_then:.+]]
23// CHECK: [[if_then]]:
24// CHECK: tail call spir_func void @f()
25// CHECK: tail call spir_func void @non_convfun()
26// CHECK: tail call spir_func void @g()
27// CHECK: br label %[[if_end3:.+]]
28// CHECK: [[if_end3_critedge]]:
29// CHECK: tail call spir_func void @non_convfun()
30// CHECK: br label %[[if_end3]]
31// CHECK: [[if_end3]]:
32// CHECK-LABEL: ret void
33
34void test_merge_if(int a) {
35  if (a) {
36    f();
37  }
38  non_convfun();
39  if (a) {
40    g();
41  }
42}
43
44// CHECK-DAG: declare spir_func void @f()
45// CHECK-DAG: declare spir_func void @non_convfun()
46// CHECK-DAG: declare spir_func void @g()
47
48// Test two if's are not merged.
49// CHECK: define spir_func void @test_no_merge_if(i32 %[[a:.+]])
50// CHECK:  %[[tobool:.+]] = icmp eq i32 %[[a]], 0
51// CHECK: br i1 %[[tobool]], label %[[if_end:.+]], label %[[if_then:.+]]
52// CHECK: [[if_then]]:
53// CHECK: tail call spir_func void @f()
54// CHECK-NOT: call spir_func void @convfun()
55// CHECK-NOT: call spir_func void @g()
56// CHECK: br label %[[if_end]]
57// CHECK: [[if_end]]:
58// CHECK:  %[[tobool_pr:.+]] = phi i1 [ true, %[[if_then]] ], [ false, %{{.+}} ]
59// CHECK:  tail call spir_func void @convfun() #[[attr5:.+]]
60// CHECK:  br i1 %[[tobool_pr]], label %[[if_then2:.+]], label %[[if_end3:.+]]
61// CHECK: [[if_then2]]:
62// CHECK: tail call spir_func void @g()
63// CHECK:  br label %[[if_end3:.+]]
64// CHECK: [[if_end3]]:
65// CHECK-LABEL:  ret void
66
67void test_no_merge_if(int a) {
68  if (a) {
69    f();
70  }
71  convfun();
72  if(a) {
73    g();
74  }
75}
76
77// CHECK: declare spir_func void @convfun(){{[^#]*}} #[[attr2:[0-9]+]]
78
79// Test loop is unrolled for convergent function.
80// CHECK-LABEL: define spir_func void @test_unroll()
81// CHECK:  tail call spir_func void @convfun() #[[attr5:[0-9]+]]
82// CHECK:  tail call spir_func void @convfun() #[[attr5]]
83// CHECK:  tail call spir_func void @convfun() #[[attr5]]
84// CHECK:  tail call spir_func void @convfun() #[[attr5]]
85// CHECK:  tail call spir_func void @convfun() #[[attr5]]
86// CHECK:  tail call spir_func void @convfun() #[[attr5]]
87// CHECK:  tail call spir_func void @convfun() #[[attr5]]
88// CHECK:  tail call spir_func void @convfun() #[[attr5]]
89// CHECK:  tail call spir_func void @convfun() #[[attr5]]
90// CHECK:  tail call spir_func void @convfun() #[[attr5]]
91// CHECK-LABEL:  ret void
92
93void test_unroll() {
94  for (int i = 0; i < 10; i++)
95    convfun();
96}
97
98// Test loop is not unrolled for noduplicate function.
99// CHECK-LABEL: define spir_func void @test_not_unroll()
100// CHECK:  br label %[[for_body:.+]]
101// CHECK: [[for_cond_cleanup:.+]]:
102// CHECK:  ret void
103// CHECK: [[for_body]]:
104// CHECK:  tail call spir_func void @nodupfun() #[[attr6:[0-9]+]]
105// CHECK-NOT: call spir_func void @nodupfun()
106// CHECK:  br i1 %{{.+}}, label %[[for_body]], label %[[for_cond_cleanup]]
107
108void test_not_unroll() {
109  for (int i = 0; i < 10; i++)
110    nodupfun();
111}
112
113// CHECK: declare spir_func void @nodupfun(){{[^#]*}} #[[attr3:[0-9]+]]
114
115// CHECK-DAG: attributes #[[attr2]] = { {{[^}]*}}convergent{{[^}]*}} }
116// CHECK-DAG: attributes #[[attr3]] = { {{[^}]*}}noduplicate{{[^}]*}} }
117// CHECK-DAG: attributes #[[attr5]] = { {{[^}]*}}convergent{{[^}]*}} }
118// CHECK-DAG: attributes #[[attr6]] = { {{[^}]*}}noduplicate{{[^}]*}} }
119