-
Notifications
You must be signed in to change notification settings - Fork 76
/
canonicalize.mlir
379 lines (274 loc) · 19.2 KB
/
canonicalize.mlir
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
// RUN: xdsl-opt --split-input-file -p canonicalize %s | filecheck %s
builtin.module {
%i0, %i1, %i2 = "test.op"() : () -> (!riscv.reg<a0>, !riscv.reg<a1>, !riscv.reg)
%o0 = riscv.mv %i0 : (!riscv.reg<a0>) -> !riscv.reg<a0>
%o1 = riscv.mv %i1 : (!riscv.reg<a1>) -> !riscv.reg<a2>
%o2 = riscv.mv %i2 : (!riscv.reg) -> !riscv.reg
"test.op"(%o0, %o1, %o2) : (!riscv.reg<a0>, !riscv.reg<a2>, !riscv.reg) -> ()
%i3 = riscv.li 100 : !riscv.reg
%i4 = riscv.mv %i3 : (!riscv.reg) -> !riscv.reg
%i5 = riscv.mv %i3 : (!riscv.reg) -> !riscv.reg<j0>
"test.op"(%i3, %i4, %i5) : (!riscv.reg, !riscv.reg, !riscv.reg<j0>) -> ()
%f0, %f1, %f2 = "test.op"() : () -> (!riscv.freg<fa0>, !riscv.freg<fa1>, !riscv.freg)
%fo0 = riscv.fmv.s %f0 : (!riscv.freg<fa0>) -> !riscv.freg<fa0>
%fo1 = riscv.fmv.s %f1 : (!riscv.freg<fa1>) -> !riscv.freg<fa2>
%fo2 = riscv.fmv.s %f2 : (!riscv.freg) -> !riscv.freg
%fo3 = riscv.fmv.d %f0 : (!riscv.freg<fa0>) -> !riscv.freg<fa0>
%fo4 = riscv.fmv.d %f1 : (!riscv.freg<fa1>) -> !riscv.freg<fa2>
%fo5 = riscv.fmv.d %f2 : (!riscv.freg) -> !riscv.freg
"test.op"(%fo0, %fo1, %fo2, %fo3, %fo4, %fo5) : (!riscv.freg<fa0>, !riscv.freg<fa2>, !riscv.freg, !riscv.freg<fa0>, !riscv.freg<fa2>, !riscv.freg) -> ()
%zero = riscv.get_register : !riscv.reg<zero>
%c0 = riscv.li 0 : !riscv.reg
%c1 = riscv.li 1 : !riscv.reg
%c2 = riscv.li 2 : !riscv.reg
%c3 = riscv.li 3 : !riscv.reg
// Don't optimise out unused immediates
"test.op"(%zero, %c0, %c1, %c2, %c3) : (!riscv.reg<zero>, !riscv.reg, !riscv.reg, !riscv.reg, !riscv.reg) -> ()
%load_zero_zero = riscv.li 0 : !riscv.reg<zero>
"test.op"(%load_zero_zero) : (!riscv.reg<zero>) -> ()
%add_immediate_zero_reg = riscv.addi %zero, 1 : (!riscv.reg<zero>) -> !riscv.reg<a0>
"test.op"(%add_immediate_zero_reg) : (!riscv.reg<a0>) -> ()
%multiply_immediates = riscv.mul %c2, %c3 : (!riscv.reg, !riscv.reg) -> !riscv.reg<a0>
"test.op"(%multiply_immediates) : (!riscv.reg<a0>) -> ()
%multiply_immediate_r0 = riscv.mul %c0, %i1 : (!riscv.reg, !riscv.reg<a1>) -> !riscv.reg<a0>
"test.op"(%multiply_immediate_r0) : (!riscv.reg<a0>) -> ()
%multiply_immediate_l0 = riscv.mul %i1, %c0 : (!riscv.reg<a1>, !riscv.reg) -> !riscv.reg<a0>
"test.op"(%multiply_immediate_l0) : (!riscv.reg<a0>) -> ()
%add_lhs_immediate = riscv.add %c2, %i2 : (!riscv.reg, !riscv.reg) -> !riscv.reg<a0>
"test.op"(%add_lhs_immediate) : (!riscv.reg<a0>) -> ()
%add_rhs_immediate = riscv.add %i2, %c2 : (!riscv.reg, !riscv.reg) -> !riscv.reg<a0>
"test.op"(%add_rhs_immediate) : (!riscv.reg<a0>) -> ()
%add_immediates = riscv.add %c2, %c3 : (!riscv.reg, !riscv.reg) -> !riscv.reg<a0>
"test.op"(%add_immediates) : (!riscv.reg<a0>) -> ()
%add_vars = riscv.add %i0, %i1 : (!riscv.reg<a0>, !riscv.reg<a1>) -> !riscv.reg<a0>
"test.op"(%add_vars) : (!riscv.reg<a0>) -> ()
%add_immediate_zero = riscv.addi %i2, 0 : (!riscv.reg) -> !riscv.reg<a0>
"test.op"(%add_immediate_zero) : (!riscv.reg<a0>) -> ()
%add_immediate_constant = riscv.addi %c2, 1 : (!riscv.reg) -> !riscv.reg<a0>
"test.op"(%add_immediate_constant) : (!riscv.reg<a0>) -> ()
// Unchanged
%sub_lhs_immediate = riscv.sub %c2, %i2 : (!riscv.reg, !riscv.reg) -> !riscv.reg<a0>
"test.op"(%sub_lhs_immediate) : (!riscv.reg<a0>) -> ()
// Replace with addi
%sub_rhs_immediate = riscv.sub %i2, %c2 : (!riscv.reg, !riscv.reg) -> !riscv.reg<a0>
"test.op"(%sub_rhs_immediate) : (!riscv.reg<a0>) -> ()
%sub_immediates = riscv.sub %c2, %c3 : (!riscv.reg, !riscv.reg) -> !riscv.reg<a0>
"test.op"(%sub_immediates) : (!riscv.reg<a0>) -> ()
// Unchanged
%sub_vars = riscv.sub %i0, %i1 : (!riscv.reg<a0>, !riscv.reg<a1>) -> !riscv.reg<a0>
"test.op"(%add_vars) : (!riscv.reg<a0>) -> ()
// Optimise out an arithmetic operation
%sub_add_immediate = riscv.sub %add_rhs_immediate, %i2 : (!riscv.reg<a0>, !riscv.reg) -> !riscv.reg<a0>
"test.op"(%sub_add_immediate) : (!riscv.reg<a0>) -> ()
%shift_left_immediate = riscv.slli %c2, 4 : (!riscv.reg) -> !riscv.reg<a0>
"test.op"(%shift_left_immediate) : (!riscv.reg<a0>) -> ()
%load_float_ptr = riscv.addi %i2, 8 : (!riscv.reg) -> !riscv.reg
%load_float_known_offset = riscv.flw %load_float_ptr, 4 : (!riscv.reg) -> !riscv.freg<fa0>
"test.op"(%load_float_known_offset) : (!riscv.freg<fa0>) -> ()
%load_double_ptr = riscv.addi %i2, 8 : (!riscv.reg) -> !riscv.reg
%load_double_known_offset = riscv.fld %load_double_ptr, 4 : (!riscv.reg) -> !riscv.freg<fa0>
"test.op"(%load_double_known_offset) : (!riscv.freg<fa0>) -> ()
%store_float_ptr = riscv.addi %i2, 8 : (!riscv.reg) -> !riscv.reg
riscv.fsw %store_float_ptr, %f2, 4 : (!riscv.reg, !riscv.freg) -> ()
%store_double_ptr = riscv.addi %i2, 8 : (!riscv.reg) -> !riscv.reg
riscv.fsd %store_double_ptr, %f2, 4 : (!riscv.reg, !riscv.freg) -> ()
%add_lhs_rhs = riscv.add %i1, %i1 : (!riscv.reg<a1>, !riscv.reg<a1>) -> !riscv.reg<a0>
"test.op"(%add_lhs_rhs) : (!riscv.reg<a0>) -> ()
%and_bitwise_zero_l0 = riscv.and %c1, %c0 : (!riscv.reg, !riscv.reg) -> !riscv.reg<a0>
"test.op"(%and_bitwise_zero_l0) : (!riscv.reg<a0>) -> ()
%and_bitwise_zero_r0 = riscv.and %c0, %c1 : (!riscv.reg, !riscv.reg) -> !riscv.reg<a0>
"test.op"(%and_bitwise_zero_r0) : (!riscv.reg<a0>) -> ()
%or_bitwise_zero_l0 = riscv.or %c1, %c0 : (!riscv.reg, !riscv.reg) -> !riscv.reg<a0>
"test.op"(%or_bitwise_zero_l0) : (!riscv.reg<a0>) -> ()
%or_bitwise_zero_r0 = riscv.or %c0, %c1 : (!riscv.reg, !riscv.reg) -> !riscv.reg<a0>
"test.op"(%or_bitwise_zero_r0) : (!riscv.reg<a0>) -> ()
%xor_lhs_rhs = riscv.xor %i1, %i1 : (!riscv.reg<a1>, !riscv.reg<a1>) -> !riscv.reg<a0>
"test.op"(%xor_lhs_rhs) : (!riscv.reg<a0>) -> ()
%xor_bitwise_zero_l0 = riscv.xor %c1, %c0 : (!riscv.reg, !riscv.reg) -> !riscv.reg<a0>
"test.op"(%xor_bitwise_zero_l0) : (!riscv.reg<a0>) -> ()
%xor_bitwise_zero_r0 = riscv.xor %c0, %c1 : (!riscv.reg, !riscv.reg) -> !riscv.reg<a0>
"test.op"(%xor_bitwise_zero_r0) : (!riscv.reg<a0>) -> ()
// scfgw immediates
riscv_snitch.scfgw %i1, %c1 : (!riscv.reg<a1>, !riscv.reg) -> ()
}
// CHECK: builtin.module {
// CHECK-NEXT: %{{.*}}, %{{.*}}, %{{.*}} = "test.op"() : () -> (!riscv.reg<a0>, !riscv.reg<a1>, !riscv.reg)
// CHECK-NOT: %{{.*}} = riscv.mv %{{.*}} : (!riscv.reg<a0>) -> !riscv.reg<a0>
// CHECK-NEXT: %{{.*}} = riscv.mv %{{.*}} : (!riscv.reg<a1>) -> !riscv.reg<a2>
// CHECK-NEXT: %{{.*}} = riscv.mv %{{.*}} : (!riscv.reg) -> !riscv.reg
// CHECK-NEXT: "test.op"(%i0, %o1, %o2) : (!riscv.reg<a0>, !riscv.reg<a2>, !riscv.reg) -> ()
// CHECK-NEXT: %i3 = riscv.li 100 : !riscv.reg
// CHECK-NEXT: %i4 = riscv.mv %i3 : (!riscv.reg) -> !riscv.reg
// CHECK-NEXT: %i5 = riscv.mv %i3 : (!riscv.reg) -> !riscv.reg<j0>
// CHECK-NEXT: "test.op"(%i3, %i4, %i5) : (!riscv.reg, !riscv.reg, !riscv.reg<j0>) -> ()
// CHECK-NEXT: %{{.*}}, %{{.*}}, %{{.*}} = "test.op"() : () -> (!riscv.freg<fa0>, !riscv.freg<fa1>, !riscv.freg)
// CHECK-NEXT: %{{.*}} = riscv.fmv.s %{{.*}} : (!riscv.freg<fa1>) -> !riscv.freg<fa2>
// CHECK-NEXT: %{{.*}} = riscv.fmv.s %{{.*}} : (!riscv.freg) -> !riscv.freg
// CHECK-NEXT: %{{.*}} = riscv.fmv.d %{{.*}} : (!riscv.freg<fa1>) -> !riscv.freg<fa2>
// CHECK-NEXT: %{{.*}} = riscv.fmv.d %{{.*}} : (!riscv.freg) -> !riscv.freg
// CHECK-NEXT: "test.op"(%f0, %fo1, %fo2, %f0, %fo4, %fo5) : (!riscv.freg<fa0>, !riscv.freg<fa2>, !riscv.freg, !riscv.freg<fa0>, !riscv.freg<fa2>, !riscv.freg) -> ()
// CHECK-NEXT: %zero = riscv.get_register : !riscv.reg<zero>
// CHECK-NEXT: %c0 = riscv.get_register : !riscv.reg<zero>
// CHECK-NEXT: %c0_1 = riscv.mv %c0 : (!riscv.reg<zero>) -> !riscv.reg
// CHECK-NEXT: %c1 = riscv.li 1 : !riscv.reg
// CHECK-NEXT: %c2 = riscv.li 2 : !riscv.reg
// CHECK-NEXT: %c3 = riscv.li 3 : !riscv.reg
// CHECK-NEXT: "test.op"(%zero, %c0_1, %c1, %c2, %c3) : (!riscv.reg<zero>, !riscv.reg, !riscv.reg, !riscv.reg, !riscv.reg) -> ()
// CHECK-NEXT: %load_zero_zero = riscv.get_register : !riscv.reg<zero>
// CHECK-NEXT: "test.op"(%load_zero_zero) : (!riscv.reg<zero>) -> ()
// CHECK-NEXT: %add_immediate_zero_reg = riscv.li 1 : !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%add_immediate_zero_reg) : (!riscv.reg<a0>) -> ()
// CHECK-NEXT: %multiply_immediates = riscv.li 6 : !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%multiply_immediates) : (!riscv.reg<a0>) -> ()
// CHECK-NEXT: %multiply_immediate_r0 = riscv.mv %c0_1 : (!riscv.reg) -> !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%multiply_immediate_r0) : (!riscv.reg<a0>) -> ()
// CHECK-NEXT: %multiply_immediate_l0 = riscv.mv %c0_1 : (!riscv.reg) -> !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%multiply_immediate_l0) : (!riscv.reg<a0>) -> ()
// CHECK-NEXT: %add_lhs_immediate = riscv.addi %i2, 2 : (!riscv.reg) -> !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%add_lhs_immediate) : (!riscv.reg<a0>) -> ()
// CHECK-NEXT: %add_rhs_immediate = riscv.addi %i2, 2 : (!riscv.reg) -> !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%add_rhs_immediate) : (!riscv.reg<a0>) -> ()
// CHECK-NEXT: %add_immediates = riscv.li 5 : !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%add_immediates) : (!riscv.reg<a0>) -> ()
// CHECK-NEXT: %add_vars = riscv.add %i0, %i1 : (!riscv.reg<a0>, !riscv.reg<a1>) -> !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%add_vars) : (!riscv.reg<a0>) -> ()
// CHECK-NEXT: %add_immediate_zero = riscv.mv %i2 : (!riscv.reg) -> !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%add_immediate_zero) : (!riscv.reg<a0>) -> ()
// CHECK-NEXT: %add_immediate_constant = riscv.li 3 : !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%add_immediate_constant) : (!riscv.reg<a0>) -> ()
// Unchanged
// CHECK-NEXT: %sub_lhs_immediate = riscv.sub %c2, %i2 : (!riscv.reg, !riscv.reg) -> !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%sub_lhs_immediate) : (!riscv.reg<a0>) -> ()
// Replace with addi
// CHECK-NEXT: %sub_rhs_immediate = riscv.addi %i2, -2 : (!riscv.reg) -> !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%sub_rhs_immediate) : (!riscv.reg<a0>) -> ()
// CHECK-NEXT: %sub_immediates = riscv.li -1 : !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%sub_immediates) : (!riscv.reg<a0>) -> ()
// Unchanged
// CHECK-NEXT: %sub_vars = riscv.sub %i0, %i1 : (!riscv.reg<a0>, !riscv.reg<a1>) -> !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%add_vars) : (!riscv.reg<a0>) -> ()
// Optimise out an arithmetic operation
// CHECK-NEXT: %sub_add_immediate = riscv.li 2 : !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%sub_add_immediate) : (!riscv.reg<a0>) -> ()
// CHECK-NEXT: %shift_left_immediate = riscv.li 32 : !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%shift_left_immediate) : (!riscv.reg<a0>) -> ()
// CHECK-NEXT: %load_float_known_offset = riscv.flw %i2, 12 : (!riscv.reg) -> !riscv.freg<fa0>
// CHECK-NEXT: "test.op"(%load_float_known_offset) : (!riscv.freg<fa0>) -> ()
// CHECK-NEXT: %load_double_known_offset = riscv.fld %i2, 12 : (!riscv.reg) -> !riscv.freg<fa0>
// CHECK-NEXT: "test.op"(%load_double_known_offset) : (!riscv.freg<fa0>) -> ()
// CHECK-NEXT: riscv.fsw %i2, %f2, 12 : (!riscv.reg, !riscv.freg) -> ()
// CHECK-NEXT: riscv.fsd %i2, %f2, 12 : (!riscv.reg, !riscv.freg) -> ()
// CHECK-NEXT: %add_lhs_rhs = riscv.li 2 : !riscv.reg
// CHECK-NEXT: %add_lhs_rhs_1 = riscv.mul %i1, %add_lhs_rhs : (!riscv.reg<a1>, !riscv.reg) -> !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%add_lhs_rhs_1) : (!riscv.reg<a0>) -> ()
// CHECK-NEXT: %and_bitwise_zero_l0 = riscv.mv %c0_1 : (!riscv.reg) -> !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%and_bitwise_zero_l0) : (!riscv.reg<a0>) -> ()
// CHECK-NEXT: %and_bitwise_zero_r0 = riscv.mv %c0_1 : (!riscv.reg) -> !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%and_bitwise_zero_r0) : (!riscv.reg<a0>) -> ()
// CHECK-NEXT: %or_bitwise_zero_l0 = riscv.mv %c1 : (!riscv.reg) -> !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%or_bitwise_zero_l0) : (!riscv.reg<a0>) -> ()
// CHECK-NEXT: %or_bitwise_zero_r0 = riscv.mv %c1 : (!riscv.reg) -> !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%or_bitwise_zero_r0) : (!riscv.reg<a0>) -> ()
// CHECK-NEXT: %xor_lhs_rhs = riscv.get_register : !riscv.reg<zero>
// CHECK-NEXT: %xor_lhs_rhs_1 = riscv.mv %xor_lhs_rhs : (!riscv.reg<zero>) -> !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%xor_lhs_rhs_1) : (!riscv.reg<a0>) -> ()
// CHECK-NEXT: %xor_bitwise_zero_l0 = riscv.mv %c1 : (!riscv.reg) -> !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%xor_bitwise_zero_l0) : (!riscv.reg<a0>) -> ()
// CHECK-NEXT: %xor_bitwise_zero_r0 = riscv.mv %c1 : (!riscv.reg) -> !riscv.reg<a0>
// CHECK-NEXT: "test.op"(%xor_bitwise_zero_r0) : (!riscv.reg<a0>) -> ()
// CHECK-NEXT: riscv_snitch.scfgwi %i1, 1 : (!riscv.reg<a1>) -> ()
// CHECK-NEXT: }
// -----
%0, %1 = "test.op"() : () -> (!riscv.freg, !riscv.freg)
// should fuse
%rmul0 = riscv.fmul.d %0, %1 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
%radd0 = riscv.fadd.d %0, %rmul0 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
// same as above, but swapped addends
%rmul0b = riscv.fmul.d %0, %1 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
%radd0b = riscv.fadd.d %rmul0b, %0 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
// same as above but allocated
%rmul0_a = riscv.fmul.d %0, %1 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
%radd0_a = riscv.fadd.d %0, %rmul0_a fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg<ft0>
%rmul0b_a = riscv.fmul.d %0, %1 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
%radd0b_a = riscv.fadd.d %rmul0b_a, %0 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg<ft1>
// both addends are results of multiplcation, if all else is the same we fuse with second operand
%rmul0c0 = riscv.fmul.d %0, %1 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
%rmul0c1 = riscv.fmul.d %0, %1 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
%radd0c = riscv.fadd.d %rmul0c0, %rmul0c1 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
// should not fuse due to missing "contract" fastmath flag
%rmul1 = riscv.fmul.d %0, %1 : (!riscv.freg, !riscv.freg) -> !riscv.freg
%radd1 = riscv.fadd.d %0, %rmul1 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
%rmul1b = riscv.fmul.d %0, %1 : (!riscv.freg, !riscv.freg) -> !riscv.freg
%radd1b = riscv.fadd.d %rmul1b, %0 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
// should not fuse due to missing "contract" fastmath flag
%rmul2 = riscv.fmul.d %0, %1 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
%radd2 = riscv.fadd.d %0, %rmul2 : (!riscv.freg, !riscv.freg) -> !riscv.freg
%rmul2b = riscv.fmul.d %0, %1 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
%radd2b = riscv.fadd.d %rmul2b, %0 : (!riscv.freg, !riscv.freg) -> !riscv.freg
// should not fuse due to missing "contract" fastmath flag
%rmul3 = riscv.fmul.d %0, %1 : (!riscv.freg, !riscv.freg) -> !riscv.freg
%radd3 = riscv.fadd.d %0, %rmul3 : (!riscv.freg, !riscv.freg) -> !riscv.freg
%rmul3b = riscv.fmul.d %0, %1 : (!riscv.freg, !riscv.freg) -> !riscv.freg
%radd3b = riscv.fadd.d %rmul3b, %0 : (!riscv.freg, !riscv.freg) -> !riscv.freg
// should not fuse due to more than one uses
%rmul4 = riscv.fmul.d %0, %1 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
%radd4 = riscv.fadd.d %0, %rmul4 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
%rmul4b = riscv.fmul.d %0, %1 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
%radd4b = riscv.fadd.d %rmul4b, %0 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
// use multiplication result here to stop the fusion
"test.op"(%rmul4) : (!riscv.freg) -> ()
"test.op"(%rmul4b) : (!riscv.freg) -> ()
// use results here to avoid dead code elimination up the SSA chain
"test.op"(%radd0) : (!riscv.freg) -> ()
"test.op"(%radd0b) : (!riscv.freg) -> ()
"test.op"(%radd0_a) : (!riscv.freg<ft0>) -> ()
"test.op"(%radd0b_a) : (!riscv.freg<ft1>) -> ()
"test.op"(%radd0c) : (!riscv.freg) -> ()
"test.op"(%radd1) : (!riscv.freg) -> ()
"test.op"(%radd1b) : (!riscv.freg) -> ()
"test.op"(%radd2) : (!riscv.freg) -> ()
"test.op"(%radd2b) : (!riscv.freg) -> ()
"test.op"(%radd3) : (!riscv.freg) -> ()
"test.op"(%radd3b) : (!riscv.freg) -> ()
"test.op"(%radd4) : (!riscv.freg) -> ()
"test.op"(%radd4b) : (!riscv.freg) -> ()
// CHECK: builtin.module {
// CHECK-NEXT: %0, %1 = "test.op"() : () -> (!riscv.freg, !riscv.freg)
// CHECK-NEXT: %radd0 = riscv.fmadd.d %{{.*}}, %{{.*}}, %{{.*}} : (!riscv.freg, !riscv.freg, !riscv.freg) -> !riscv.freg
// CHECK-NEXT: %radd0b = riscv.fmadd.d %{{.*}}, %{{.*}}, %{{.*}} : (!riscv.freg, !riscv.freg, !riscv.freg) -> !riscv.freg
// CHECK-NEXT: %radd0_a = riscv.fmadd.d %{{.*}}, %{{.*}}, %{{.*}} : (!riscv.freg, !riscv.freg, !riscv.freg) -> !riscv.freg<ft0>
// CHECK-NEXT: %radd0b_a = riscv.fmadd.d %{{.*}}, %{{.*}}, %{{.*}} : (!riscv.freg, !riscv.freg, !riscv.freg) -> !riscv.freg<ft1>
// CHECK-NEXT: %rmul0c0 = riscv.fmul.d %0, %1 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
// CHECK-NEXT: %radd0c = riscv.fmadd.d %{{.*}}, %{{.*}}, %{{.*}} : (!riscv.freg, !riscv.freg, !riscv.freg) -> !riscv.freg
// CHECK-NEXT: %rmul1 = riscv.fmul.d %0, %1 : (!riscv.freg, !riscv.freg) -> !riscv.freg
// CHECK-NEXT: %radd1 = riscv.fadd.d %0, %rmul1 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
// CHECK-NEXT: %rmul1b = riscv.fmul.d %0, %1 : (!riscv.freg, !riscv.freg) -> !riscv.freg
// CHECK-NEXT: %radd1b = riscv.fadd.d %rmul1b, %0 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
// CHECK-NEXT: %rmul2 = riscv.fmul.d %0, %1 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
// CHECK-NEXT: %radd2 = riscv.fadd.d %0, %rmul2 : (!riscv.freg, !riscv.freg) -> !riscv.freg
// CHECK-NEXT: %rmul2b = riscv.fmul.d %0, %1 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
// CHECK-NEXT: %radd2b = riscv.fadd.d %rmul2b, %0 : (!riscv.freg, !riscv.freg) -> !riscv.freg
// CHECK-NEXT: %rmul3 = riscv.fmul.d %0, %1 : (!riscv.freg, !riscv.freg) -> !riscv.freg
// CHECK-NEXT: %radd3 = riscv.fadd.d %0, %rmul3 : (!riscv.freg, !riscv.freg) -> !riscv.freg
// CHECK-NEXT: %rmul3b = riscv.fmul.d %0, %1 : (!riscv.freg, !riscv.freg) -> !riscv.freg
// CHECK-NEXT: %radd3b = riscv.fadd.d %rmul3b, %0 : (!riscv.freg, !riscv.freg) -> !riscv.freg
// CHECK-NEXT: %rmul4 = riscv.fmul.d %0, %1 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
// CHECK-NEXT: %radd4 = riscv.fadd.d %0, %rmul4 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
// CHECK-NEXT: %rmul4b = riscv.fmul.d %0, %1 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
// CHECK-NEXT: %radd4b = riscv.fadd.d %rmul4b, %0 fastmath<fast> : (!riscv.freg, !riscv.freg) -> !riscv.freg
// CHECK-NEXT: "test.op"(%rmul4) : (!riscv.freg) -> ()
// CHECK-NEXT: "test.op"(%rmul4b) : (!riscv.freg) -> ()
// CHECK-NEXT: "test.op"(%radd0) : (!riscv.freg) -> ()
// CHECK-NEXT: "test.op"(%radd0b) : (!riscv.freg) -> ()
// CHECK-NEXT: "test.op"(%radd0_a) : (!riscv.freg<ft0>) -> ()
// CHECK-NEXT: "test.op"(%radd0b_a) : (!riscv.freg<ft1>) -> ()
// CHECK-NEXT: "test.op"(%radd0c) : (!riscv.freg) -> ()
// CHECK-NEXT: "test.op"(%radd1) : (!riscv.freg) -> ()
// CHECK-NEXT: "test.op"(%radd1b) : (!riscv.freg) -> ()
// CHECK-NEXT: "test.op"(%radd2) : (!riscv.freg) -> ()
// CHECK-NEXT: "test.op"(%radd2b) : (!riscv.freg) -> ()
// CHECK-NEXT: "test.op"(%radd3) : (!riscv.freg) -> ()
// CHECK-NEXT: "test.op"(%radd3b) : (!riscv.freg) -> ()
// CHECK-NEXT: "test.op"(%radd4) : (!riscv.freg) -> ()
// CHECK-NEXT: "test.op"(%radd4b) : (!riscv.freg) -> ()
// CHECK-NEXT: }