1// RUN: mlir-opt -allow-unregistered-dialect %s -pass-pipeline="func(sccp)" -split-input-file | FileCheck %s
2
3/// Check simple forward constant propagation without any control flow.
4
5// CHECK-LABEL: func @no_control_flow
6func @no_control_flow(%arg0: i32) -> i32 {
7  // CHECK: %[[CST:.*]] = constant 1 : i32
8  // CHECK: return %[[CST]] : i32
9
10  %cond = constant true
11  %cst_1 = constant 1 : i32
12  %select = select %cond, %cst_1, %arg0 : i32
13  return %select : i32
14}
15
16/// Check that a constant is properly propagated when only one edge of a branch
17/// is taken.
18
19// CHECK-LABEL: func @simple_control_flow
20func @simple_control_flow(%arg0 : i32) -> i32 {
21  // CHECK: %[[CST:.*]] = constant 1 : i32
22
23  %cond = constant true
24  %1 = constant 1 : i32
25  cond_br %cond, ^bb1, ^bb2(%arg0 : i32)
26
27^bb1:
28  br ^bb2(%1 : i32)
29
30^bb2(%arg : i32):
31  // CHECK: ^bb2(%{{.*}}: i32):
32  // CHECK: return %[[CST]] : i32
33
34  return %arg : i32
35}
36
37/// Check that the arguments go to overdefined if the branch cannot detect when
38/// a specific successor is taken.
39
40// CHECK-LABEL: func @simple_control_flow_overdefined
41func @simple_control_flow_overdefined(%arg0 : i32, %arg1 : i1) -> i32 {
42  %1 = constant 1 : i32
43  cond_br %arg1, ^bb1, ^bb2(%arg0 : i32)
44
45^bb1:
46  br ^bb2(%1 : i32)
47
48^bb2(%arg : i32):
49  // CHECK: ^bb2(%[[ARG:.*]]: i32):
50  // CHECK: return %[[ARG]] : i32
51
52  return %arg : i32
53}
54
55/// Check that the arguments go to overdefined if there are conflicting
56/// constants.
57
58// CHECK-LABEL: func @simple_control_flow_constant_overdefined
59func @simple_control_flow_constant_overdefined(%arg0 : i32, %arg1 : i1) -> i32 {
60  %1 = constant 1 : i32
61  %2 = constant 2 : i32
62  cond_br %arg1, ^bb1, ^bb2(%arg0 : i32)
63
64^bb1:
65  br ^bb2(%2 : i32)
66
67^bb2(%arg : i32):
68  // CHECK: ^bb2(%[[ARG:.*]]: i32):
69  // CHECK: return %[[ARG]] : i32
70
71  return %arg : i32
72}
73
74/// Check that the arguments go to overdefined if the branch is unknown.
75
76// CHECK-LABEL: func @unknown_terminator
77func @unknown_terminator(%arg0 : i32, %arg1 : i1) -> i32 {
78  %1 = constant 1 : i32
79  "foo.cond_br"() [^bb1, ^bb2] : () -> ()
80
81^bb1:
82  br ^bb2(%1 : i32)
83
84^bb2(%arg : i32):
85  // CHECK: ^bb2(%[[ARG:.*]]: i32):
86  // CHECK: return %[[ARG]] : i32
87
88  return %arg : i32
89}
90
91/// Check that arguments are properly merged across loop-like control flow.
92
93func private @ext_cond_fn() -> i1
94
95// CHECK-LABEL: func @simple_loop
96func @simple_loop(%arg0 : i32, %cond1 : i1) -> i32 {
97  // CHECK: %[[CST:.*]] = constant 1 : i32
98
99  %cst_1 = constant 1 : i32
100  cond_br %cond1, ^bb1(%cst_1 : i32), ^bb2(%cst_1 : i32)
101
102^bb1(%iv: i32):
103  // CHECK: ^bb1(%{{.*}}: i32):
104  // CHECK-NEXT: %[[COND:.*]] = call @ext_cond_fn()
105  // CHECK-NEXT: cond_br %[[COND]], ^bb1(%[[CST]] : i32), ^bb2(%[[CST]] : i32)
106
107  %cst_0 = constant 0 : i32
108  %res = addi %iv, %cst_0 : i32
109  %cond2 = call @ext_cond_fn() : () -> i1
110  cond_br %cond2, ^bb1(%res : i32), ^bb2(%res : i32)
111
112^bb2(%arg : i32):
113  // CHECK: ^bb2(%{{.*}}: i32):
114  // CHECK: return %[[CST]] : i32
115
116  return %arg : i32
117}
118
119/// Test that we can properly propagate within inner control, and in situations
120/// where the executable edges within the CFG are sensitive to the current state
121/// of the analysis.
122
123// CHECK-LABEL: func @simple_loop_inner_control_flow
124func @simple_loop_inner_control_flow(%arg0 : i32) -> i32 {
125  // CHECK-DAG: %[[CST:.*]] = constant 1 : i32
126  // CHECK-DAG: %[[TRUE:.*]] = constant true
127
128  %cst_1 = constant 1 : i32
129  br ^bb1(%cst_1 : i32)
130
131^bb1(%iv: i32):
132  %cond2 = call @ext_cond_fn() : () -> i1
133  cond_br %cond2, ^bb5(%iv : i32), ^bb2
134
135^bb2:
136  // CHECK: ^bb2:
137  // CHECK: cond_br %[[TRUE]], ^bb3, ^bb4
138
139  %cst_20 = constant 20 : i32
140  %cond = cmpi "ult", %iv, %cst_20 : i32
141  cond_br %cond, ^bb3, ^bb4
142
143^bb3:
144  // CHECK: ^bb3:
145  // CHECK: br ^bb1(%[[CST]] : i32)
146
147  %cst_1_2 = constant 1 : i32
148  br ^bb1(%cst_1_2 : i32)
149
150^bb4:
151  %iv_inc = addi %iv, %cst_1 : i32
152  br ^bb1(%iv_inc : i32)
153
154^bb5(%result: i32):
155  // CHECK: ^bb5(%{{.*}}: i32):
156  // CHECK: return %[[CST]] : i32
157
158  return %result : i32
159}
160
161/// Check that arguments go to overdefined when loop backedges produce a
162/// conflicting value.
163
164func private @ext_cond_and_value_fn() -> (i1, i32)
165
166// CHECK-LABEL: func @simple_loop_overdefined
167func @simple_loop_overdefined(%arg0 : i32, %cond1 : i1) -> i32 {
168  %cst_1 = constant 1 : i32
169  cond_br %cond1, ^bb1(%cst_1 : i32), ^bb2(%cst_1 : i32)
170
171^bb1(%iv: i32):
172  %cond2, %res = call @ext_cond_and_value_fn() : () -> (i1, i32)
173  cond_br %cond2, ^bb1(%res : i32), ^bb2(%res : i32)
174
175^bb2(%arg : i32):
176  // CHECK: ^bb2(%[[ARG:.*]]: i32):
177  // CHECK: return %[[ARG]] : i32
178
179  return %arg : i32
180}
181