1 // RUN: mlir-opt %s -canonicalize="test-convergence" | FileCheck %s
3 // CHECK-LABEL: func @create_of_real_and_imag
4 // CHECK-SAME: (%[[CPLX:.*]]: complex<f32>)
5 func.func @create_of_real_and_imag(%cplx: complex<f32>) -> complex<f32> {
6 // CHECK-NEXT: return %[[CPLX]] : complex<f32>
7 %real = complex.re %cplx : complex<f32>
8 %imag = complex.im %cplx : complex<f32>
9 %complex = complex.create %real, %imag : complex<f32>
10 return %complex : complex<f32>
13 // CHECK-LABEL: func @create_of_real_and_imag_different_operand
14 // CHECK-SAME: (%[[CPLX:.*]]: complex<f32>, %[[CPLX2:.*]]: complex<f32>)
15 func.func @create_of_real_and_imag_different_operand(
16 %cplx: complex<f32>, %cplx2 : complex<f32>) -> complex<f32> {
17 // CHECK-NEXT: %[[REAL:.*]] = complex.re %[[CPLX]] : complex<f32>
18 // CHECK-NEXT: %[[IMAG:.*]] = complex.im %[[CPLX2]] : complex<f32>
19 // CHECK-NEXT: %[[COMPLEX:.*]] = complex.create %[[REAL]], %[[IMAG]] : complex<f32>
20 %real = complex.re %cplx : complex<f32>
21 %imag = complex.im %cplx2 : complex<f32>
22 %complex = complex.create %real, %imag : complex<f32>
23 return %complex: complex<f32>
26 // CHECK-LABEL: func @real_of_const(
27 func.func @real_of_const() -> f32 {
28 // CHECK: %[[CST:.*]] = arith.constant 1.000000e+00 : f32
29 // CHECK-NEXT: return %[[CST]] : f32
30 %complex = complex.constant [1.0 : f32, 0.0 : f32] : complex<f32>
31 %1 = complex.re %complex : complex<f32>
35 // CHECK-LABEL: func @real_of_create_op(
36 func.func @real_of_create_op() -> f32 {
37 // CHECK: %[[CST:.*]] = arith.constant 1.000000e+00 : f32
38 // CHECK-NEXT: return %[[CST]] : f32
39 %real = arith.constant 1.0 : f32
40 %imag = arith.constant 0.0 : f32
41 %complex = complex.create %real, %imag : complex<f32>
42 %1 = complex.re %complex : complex<f32>
46 // CHECK-LABEL: func @imag_of_const(
47 func.func @imag_of_const() -> f32 {
48 // CHECK: %[[CST:.*]] = arith.constant 0.000000e+00 : f32
49 // CHECK-NEXT: return %[[CST]] : f32
50 %complex = complex.constant [1.0 : f32, 0.0 : f32] : complex<f32>
51 %1 = complex.im %complex : complex<f32>
55 // CHECK-LABEL: func @imag_of_create_op(
56 func.func @imag_of_create_op() -> f32 {
57 // CHECK: %[[CST:.*]] = arith.constant 0.000000e+00 : f32
58 // CHECK-NEXT: return %[[CST]] : f32
59 %real = arith.constant 1.0 : f32
60 %imag = arith.constant 0.0 : f32
61 %complex = complex.create %real, %imag : complex<f32>
62 %1 = complex.im %complex : complex<f32>
66 // CHECK-LABEL: func @complex_add_sub_lhs
67 func.func @complex_add_sub_lhs() -> complex<f32> {
68 %complex1 = complex.constant [1.0 : f32, 0.0 : f32] : complex<f32>
69 %complex2 = complex.constant [0.0 : f32, 2.0 : f32] : complex<f32>
70 // CHECK: %[[CPLX:.*]] = complex.constant [1.000000e+00 : f32, 0.000000e+00 : f32] : complex<f32>
71 // CHECK-NEXT: return %[[CPLX:.*]] : complex<f32>
72 %sub = complex.sub %complex1, %complex2 : complex<f32>
73 %add = complex.add %sub, %complex2 : complex<f32>
74 return %add : complex<f32>
77 // CHECK-LABEL: func @complex_add_sub_rhs
78 func.func @complex_add_sub_rhs() -> complex<f32> {
79 %complex1 = complex.constant [1.0 : f32, 0.0 : f32] : complex<f32>
80 %complex2 = complex.constant [0.0 : f32, 2.0 : f32] : complex<f32>
81 // CHECK: %[[CPLX:.*]] = complex.constant [1.000000e+00 : f32, 0.000000e+00 : f32] : complex<f32>
82 // CHECK-NEXT: return %[[CPLX:.*]] : complex<f32>
83 %sub = complex.sub %complex1, %complex2 : complex<f32>
84 %add = complex.add %complex2, %sub : complex<f32>
85 return %add : complex<f32>
88 // CHECK-LABEL: func @complex_neg_neg
89 func.func @complex_neg_neg() -> complex<f32> {
90 %complex1 = complex.constant [1.0 : f32, 0.0 : f32] : complex<f32>
91 // CHECK: %[[CPLX:.*]] = complex.constant [1.000000e+00 : f32, 0.000000e+00 : f32] : complex<f32>
92 // CHECK-NEXT: return %[[CPLX:.*]] : complex<f32>
93 %neg1 = complex.neg %complex1 : complex<f32>
94 %neg2 = complex.neg %neg1 : complex<f32>
95 return %neg2 : complex<f32>
98 // CHECK-LABEL: func @complex_log_exp
99 func.func @complex_log_exp() -> complex<f32> {
100 %complex1 = complex.constant [1.0 : f32, 0.0 : f32] : complex<f32>
101 // CHECK: %[[CPLX:.*]] = complex.constant [1.000000e+00 : f32, 0.000000e+00 : f32] : complex<f32>
102 // CHECK-NEXT: return %[[CPLX:.*]] : complex<f32>
103 %exp = complex.exp %complex1 : complex<f32>
104 %log = complex.log %exp : complex<f32>
105 return %log : complex<f32>
108 // CHECK-LABEL: func @complex_exp_log
109 func.func @complex_exp_log() -> complex<f32> {
110 %complex1 = complex.constant [1.0 : f32, 0.0 : f32] : complex<f32>
111 // CHECK: %[[CPLX:.*]] = complex.constant [1.000000e+00 : f32, 0.000000e+00 : f32] : complex<f32>
112 // CHECK-NEXT: return %[[CPLX:.*]] : complex<f32>
113 %log = complex.log %complex1 : complex<f32>
114 %exp = complex.exp %log : complex<f32>
115 return %exp : complex<f32>
118 // CHECK-LABEL: func @complex_conj_conj
119 func.func @complex_conj_conj() -> complex<f32> {
120 %complex1 = complex.constant [1.0 : f32, 0.0 : f32] : complex<f32>
121 // CHECK: %[[CPLX:.*]] = complex.constant [1.000000e+00 : f32, 0.000000e+00 : f32] : complex<f32>
122 // CHECK-NEXT: return %[[CPLX:.*]] : complex<f32>
123 %conj1 = complex.conj %complex1 : complex<f32>
124 %conj2 = complex.conj %conj1 : complex<f32>
125 return %conj2 : complex<f32>
128 // CHECK-LABEL: func @complex_add_zero
129 func.func @complex_add_zero() -> complex<f32> {
130 %complex1 = complex.constant [1.0 : f32, 0.0 : f32] : complex<f32>
131 %complex2 = complex.constant [0.0 : f32, 0.0 : f32] : complex<f32>
132 // CHECK: %[[CPLX:.*]] = complex.constant [1.000000e+00 : f32, 0.000000e+00 : f32] : complex<f32>
133 // CHECK-NEXT: return %[[CPLX:.*]] : complex<f32>
134 %add = complex.add %complex1, %complex2 : complex<f32>
135 return %add : complex<f32>
138 // CHECK-LABEL: func @complex_sub_add_lhs
139 func.func @complex_sub_add_lhs() -> complex<f32> {
140 %complex1 = complex.constant [1.0 : f32, 0.0 : f32] : complex<f32>
141 %complex2 = complex.constant [0.0 : f32, 2.0 : f32] : complex<f32>
142 // CHECK: %[[CPLX:.*]] = complex.constant [1.000000e+00 : f32, 0.000000e+00 : f32] : complex<f32>
143 // CHECK-NEXT: return %[[CPLX:.*]] : complex<f32>
144 %add = complex.add %complex1, %complex2 : complex<f32>
145 %sub = complex.sub %add, %complex2 : complex<f32>
146 return %sub : complex<f32>
149 // CHECK-LABEL: func @complex_sub_zero
150 func.func @complex_sub_zero() -> complex<f32> {
151 %complex1 = complex.constant [1.0 : f32, 0.0 : f32] : complex<f32>
152 %complex2 = complex.constant [0.0 : f32, 0.0 : f32] : complex<f32>
153 // CHECK: %[[CPLX:.*]] = complex.constant [1.000000e+00 : f32, 0.000000e+00 : f32] : complex<f32>
154 // CHECK-NEXT: return %[[CPLX:.*]] : complex<f32>
155 %sub = complex.sub %complex1, %complex2 : complex<f32>
156 return %sub : complex<f32>
159 // CHECK-LABEL: func @re_neg
160 // CHECK-SAME: (%[[ARG0:.*]]: f32, %[[ARG1:.*]]: f32)
161 func.func @re_neg(%arg0: f32, %arg1: f32) -> f32 {
162 %create = complex.create %arg0, %arg1: complex<f32>
163 // CHECK: %[[NEG:.*]] = arith.negf %[[ARG0]]
164 %neg = complex.neg %create : complex<f32>
165 %re = complex.re %neg : complex<f32>
166 // CHECK-NEXT: return %[[NEG]]
170 // CHECK-LABEL: func @im_neg
171 // CHECK-SAME: (%[[ARG0:.*]]: f32, %[[ARG1:.*]]: f32)
172 func.func @im_neg(%arg0: f32, %arg1: f32) -> f32 {
173 %create = complex.create %arg0, %arg1: complex<f32>
174 // CHECK: %[[NEG:.*]] = arith.negf %[[ARG1]]
175 %neg = complex.neg %create : complex<f32>
176 %im = complex.im %neg : complex<f32>
177 // CHECK-NEXT: return %[[NEG]]
181 // CHECK-LABEL: func @mul_one_f16
182 // CHECK-SAME: (%[[ARG0:.*]]: f16, %[[ARG1:.*]]: f16) -> complex<f16>
183 func.func @mul_one_f16(%arg0: f16, %arg1: f16) -> complex<f16> {
184 %create = complex.create %arg0, %arg1: complex<f16>
185 %one = complex.constant [1.0 : f16, 0.0 : f16] : complex<f16>
186 %mul = complex.mul %create, %one : complex<f16>
187 // CHECK: %[[CREATE:.*]] = complex.create %[[ARG0]], %[[ARG1]] : complex<f16>
188 // CHECK-NEXT: return %[[CREATE]]
189 return %mul : complex<f16>
192 // CHECK-LABEL: func @mul_one_f32
193 // CHECK-SAME: (%[[ARG0:.*]]: f32, %[[ARG1:.*]]: f32) -> complex<f32>
194 func.func @mul_one_f32(%arg0: f32, %arg1: f32) -> complex<f32> {
195 %create = complex.create %arg0, %arg1: complex<f32>
196 %one = complex.constant [1.0 : f32, 0.0 : f32] : complex<f32>
197 %mul = complex.mul %create, %one : complex<f32>
198 // CHECK: %[[CREATE:.*]] = complex.create %[[ARG0]], %[[ARG1]] : complex<f32>
199 // CHECK-NEXT: return %[[CREATE]]
200 return %mul : complex<f32>
203 // CHECK-LABEL: func @mul_one_f64
204 // CHECK-SAME: (%[[ARG0:.*]]: f64, %[[ARG1:.*]]: f64) -> complex<f64>
205 func.func @mul_one_f64(%arg0: f64, %arg1: f64) -> complex<f64> {
206 %create = complex.create %arg0, %arg1: complex<f64>
207 %one = complex.constant [1.0 : f64, 0.0 : f64] : complex<f64>
208 %mul = complex.mul %create, %one : complex<f64>
209 // CHECK: %[[CREATE:.*]] = complex.create %[[ARG0]], %[[ARG1]] : complex<f64>
210 // CHECK-NEXT: return %[[CREATE]]
211 return %mul : complex<f64>
214 // CHECK-LABEL: func @mul_one_f80
215 // CHECK-SAME: (%[[ARG0:.*]]: f80, %[[ARG1:.*]]: f80) -> complex<f80>
216 func.func @mul_one_f80(%arg0: f80, %arg1: f80) -> complex<f80> {
217 %create = complex.create %arg0, %arg1: complex<f80>
218 %one = complex.constant [1.0 : f80, 0.0 : f80] : complex<f80>
219 %mul = complex.mul %create, %one : complex<f80>
220 // CHECK: %[[CREATE:.*]] = complex.create %[[ARG0]], %[[ARG1]] : complex<f80>
221 // CHECK-NEXT: return %[[CREATE]]
222 return %mul : complex<f80>
225 // CHECK-LABEL: func @mul_one_f128
226 // CHECK-SAME: (%[[ARG0:.*]]: f128, %[[ARG1:.*]]: f128) -> complex<f128>
227 func.func @mul_one_f128(%arg0: f128, %arg1: f128) -> complex<f128> {
228 %create = complex.create %arg0, %arg1: complex<f128>
229 %one = complex.constant [1.0 : f128, 0.0 : f128] : complex<f128>
230 %mul = complex.mul %create, %one : complex<f128>
231 // CHECK: %[[CREATE:.*]] = complex.create %[[ARG0]], %[[ARG1]] : complex<f128>
232 // CHECK-NEXT: return %[[CREATE]]
233 return %mul : complex<f128>
236 // CHECK-LABEL: func @fold_between_complex
237 // CHECK-SAME: %[[ARG0:.*]]: complex<f32>
238 func.func @fold_between_complex(%arg0 : complex<f32>) -> complex<f32> {
239 %0 = complex.bitcast %arg0 : complex<f32> to i64
240 %1 = complex.bitcast %0 : i64 to complex<f32>
241 // CHECK: return %[[ARG0]] : complex<f32>
242 func.return %1 : complex<f32>
245 // CHECK-LABEL: func @fold_between_i64
246 // CHECK-SAME: %[[ARG0:.*]]: i64
247 func.func @fold_between_i64(%arg0 : i64) -> i64 {
248 %0 = complex.bitcast %arg0 : i64 to complex<f32>
249 %1 = complex.bitcast %0 : complex<f32> to i64
250 // CHECK: return %[[ARG0]] : i64
254 // CHECK-LABEL: func @canon_arith_bitcast
255 // CHECK-SAME: %[[ARG0:.*]]: f64
256 func.func @canon_arith_bitcast(%arg0 : f64) -> i64 {
257 %0 = complex.bitcast %arg0 : f64 to complex<f32>
258 %1 = complex.bitcast %0 : complex<f32> to i64
259 // CHECK: %[[R0:.+]] = arith.bitcast %[[ARG0]]
260 // CHECK: return %[[R0]] : i64
265 // CHECK-LABEL: func @double_bitcast
266 // CHECK-SAME: %[[ARG0:.*]]: f64
267 func.func @double_bitcast(%arg0 : f64) -> complex<f32> {
268 // CHECK: %[[R0:.+]] = complex.bitcast %[[ARG0]]
269 %0 = arith.bitcast %arg0 : f64 to i64
270 %1 = complex.bitcast %0 : i64 to complex<f32>
271 // CHECK: return %[[R0]] : complex<f32>
272 func.return %1 : complex<f32>
275 // CHECK-LABEL: func @double_reverse_bitcast
276 // CHECK-SAME: %[[ARG0:.*]]: complex<f32>
277 func.func @double_reverse_bitcast(%arg0 : complex<f32>) -> f64 {
278 // CHECK: %[[R0:.+]] = complex.bitcast %[[ARG0]]
279 %0 = complex.bitcast %arg0 : complex<f32> to i64
280 %1 = arith.bitcast %0 : i64 to f64
281 // CHECK: return %[[R0]] : f64
286 // CHECK-LABEL: func @div_one_f16
287 // CHECK-SAME: (%[[ARG0:.*]]: f16, %[[ARG1:.*]]: f16) -> complex<f16>
288 func.func @div_one_f16(%arg0: f16, %arg1: f16) -> complex<f16> {
289 %create = complex.create %arg0, %arg1: complex<f16>
290 %one = complex.constant [1.0 : f16, 0.0 : f16] : complex<f16>
291 %div = complex.div %create, %one : complex<f16>
292 // CHECK: %[[CREATE:.*]] = complex.create %[[ARG0]], %[[ARG1]] : complex<f16>
293 // CHECK-NEXT: return %[[CREATE]]
294 return %div : complex<f16>
297 // CHECK-LABEL: func @div_one_f32
298 // CHECK-SAME: (%[[ARG0:.*]]: f32, %[[ARG1:.*]]: f32) -> complex<f32>
299 func.func @div_one_f32(%arg0: f32, %arg1: f32) -> complex<f32> {
300 %create = complex.create %arg0, %arg1: complex<f32>
301 %one = complex.constant [1.0 : f32, 0.0 : f32] : complex<f32>
302 %div = complex.div %create, %one : complex<f32>
303 // CHECK: %[[CREATE:.*]] = complex.create %[[ARG0]], %[[ARG1]] : complex<f32>
304 // CHECK-NEXT: return %[[CREATE]]
305 return %div : complex<f32>
308 // CHECK-LABEL: func @div_one_f64
309 // CHECK-SAME: (%[[ARG0:.*]]: f64, %[[ARG1:.*]]: f64) -> complex<f64>
310 func.func @div_one_f64(%arg0: f64, %arg1: f64) -> complex<f64> {
311 %create = complex.create %arg0, %arg1: complex<f64>
312 %one = complex.constant [1.0 : f64, 0.0 : f64] : complex<f64>
313 %div = complex.div %create, %one : complex<f64>
314 // CHECK: %[[CREATE:.*]] = complex.create %[[ARG0]], %[[ARG1]] : complex<f64>
315 // CHECK-NEXT: return %[[CREATE]]
316 return %div : complex<f64>
319 // CHECK-LABEL: func @div_one_f80
320 // CHECK-SAME: (%[[ARG0:.*]]: f80, %[[ARG1:.*]]: f80) -> complex<f80>
321 func.func @div_one_f80(%arg0: f80, %arg1: f80) -> complex<f80> {
322 %create = complex.create %arg0, %arg1: complex<f80>
323 %one = complex.constant [1.0 : f80, 0.0 : f80] : complex<f80>
324 %div = complex.div %create, %one : complex<f80>
325 // CHECK: %[[CREATE:.*]] = complex.create %[[ARG0]], %[[ARG1]] : complex<f80>
326 // CHECK-NEXT: return %[[CREATE]]
327 return %div : complex<f80>
330 // CHECK-LABEL: func @div_one_f128
331 // CHECK-SAME: (%[[ARG0:.*]]: f128, %[[ARG1:.*]]: f128) -> complex<f128>
332 func.func @div_one_f128(%arg0: f128, %arg1: f128) -> complex<f128> {
333 %create = complex.create %arg0, %arg1: complex<f128>
334 %one = complex.constant [1.0 : f128, 0.0 : f128] : complex<f128>
335 %div = complex.div %create, %one : complex<f128>
336 // CHECK: %[[CREATE:.*]] = complex.create %[[ARG0]], %[[ARG1]] : complex<f128>
337 // CHECK-NEXT: return %[[CREATE]]
338 return %div : complex<f128>