xref: /llvm-project/mlir/test/Dialect/LLVMIR/canonicalize.mlir (revision 5526c8a7425350cff2cd9cafa1bf5f20753e7848)
1// RUN: mlir-opt --pass-pipeline='builtin.module(llvm.func(canonicalize{test-convergence}))' %s -split-input-file | FileCheck %s
2
3// CHECK-LABEL: @fold_icmp_eq
4llvm.func @fold_icmp_eq(%arg0 : i32) -> i1 {
5  // CHECK: %[[C0:.*]] = llvm.mlir.constant(true) : i1
6  %0 = llvm.icmp "eq" %arg0, %arg0 : i32
7  // CHECK: llvm.return %[[C0]]
8  llvm.return %0 : i1
9}
10
11// -----
12
13// CHECK-LABEL: @fold_icmp_ne
14llvm.func @fold_icmp_ne(%arg0 : vector<2xi32>) -> vector<2xi1> {
15  // CHECK: %[[C0:.*]] = llvm.mlir.constant(dense<false> : vector<2xi1>) : vector<2xi1>
16  %0 = llvm.icmp "ne" %arg0, %arg0 : vector<2xi32>
17  // CHECK: llvm.return %[[C0]]
18  llvm.return %0 : vector<2xi1>
19}
20
21// -----
22
23// CHECK-LABEL: @fold_icmp_alloca
24llvm.func @fold_icmp_alloca() -> i1 {
25  // CHECK: %[[C0:.*]] = llvm.mlir.constant(true) : i1
26  %c0 = llvm.mlir.zero : !llvm.ptr
27  %c1 = arith.constant 1 : i64
28  %0 = llvm.alloca %c1 x i32 : (i64) -> !llvm.ptr
29  %1 = llvm.icmp "ne" %c0, %0 : !llvm.ptr
30  // CHECK: llvm.return %[[C0]]
31  llvm.return %1 : i1
32}
33
34// -----
35
36// CHECK-LABEL: fold_extractvalue
37llvm.func @fold_extractvalue() -> i32 {
38  //  CHECK-DAG: %[[C0:.*]] = arith.constant 0 : i32
39  %c0 = arith.constant 0 : i32
40  //  CHECK-DAG: %[[C1:.*]] = arith.constant 1 : i32
41  %c1 = arith.constant 1 : i32
42
43  %0 = llvm.mlir.undef : !llvm.struct<(i32, i32)>
44
45  // CHECK-NOT: insertvalue
46  %1 = llvm.insertvalue %c0, %0[0] : !llvm.struct<(i32, i32)>
47  %2 = llvm.insertvalue %c1, %1[1] : !llvm.struct<(i32, i32)>
48
49  // CHECK-NOT: extractvalue
50  %3 = llvm.extractvalue %2[0] : !llvm.struct<(i32, i32)>
51  %4 = llvm.extractvalue %2[1] : !llvm.struct<(i32, i32)>
52
53  //     CHECK: llvm.add %[[C0]], %[[C1]]
54  %5 = llvm.add %3, %4 : i32
55  llvm.return %5 : i32
56}
57
58// -----
59
60// CHECK-LABEL: no_fold_extractvalue
61llvm.func @no_fold_extractvalue(%arr: !llvm.array<4 x f32>) -> f32 {
62  %f0 = arith.constant 0.0 : f32
63  %0 = llvm.mlir.undef : !llvm.array<4 x !llvm.array<4 x f32>>
64
65  // CHECK: insertvalue
66  // CHECK: insertvalue
67  // CHECK: extractvalue
68  %1 = llvm.insertvalue %f0, %0[0, 0] : !llvm.array<4 x !llvm.array<4 x f32>>
69  %2 = llvm.insertvalue %arr, %1[0] : !llvm.array<4 x !llvm.array<4 x f32>>
70  %3 = llvm.extractvalue %2[0, 0] : !llvm.array<4 x !llvm.array<4 x f32>>
71
72  llvm.return %3 : f32
73}
74
75// -----
76
77// CHECK-LABEL: fold_unrelated_extractvalue
78llvm.func @fold_unrelated_extractvalue(%arr: !llvm.array<4 x f32>) -> f32 {
79  %f0 = arith.constant 0.0 : f32
80  // CHECK-NOT: insertvalue
81  // CHECK: extractvalue
82  %2 = llvm.insertvalue %f0, %arr[0] : !llvm.array<4 x f32>
83  %3 = llvm.extractvalue %2[1] : !llvm.array<4 x f32>
84  llvm.return %3 : f32
85}
86
87// -----
88
89// CHECK-LABEL: fold_bitcast
90// CHECK-SAME: %[[ARG:[[:alnum:]]+]]
91// CHECK-NEXT: llvm.return %[[ARG]]
92llvm.func @fold_bitcast(%x : !llvm.ptr) -> !llvm.ptr {
93  %c = llvm.bitcast %x : !llvm.ptr to !llvm.ptr
94  llvm.return %c : !llvm.ptr
95}
96
97// -----
98
99// CHECK-LABEL: fold_bitcast2
100// CHECK-SAME: %[[ARG:[[:alnum:]]+]]
101// CHECK-NEXT: llvm.return %[[ARG]]
102llvm.func @fold_bitcast2(%x : i32) -> i32 {
103  %c = llvm.bitcast %x : i32 to f32
104  %d = llvm.bitcast %c : f32 to i32
105  llvm.return %d : i32
106}
107
108// -----
109
110// CHECK-LABEL: fold_bitcast_chain
111// CHECK-SAME: %[[ARG:[[:alnum:]]+]]
112llvm.func @fold_bitcast_chain(%x : i32) -> vector<2xi16> {
113  %c = llvm.bitcast %x : i32 to f32
114  %d = llvm.bitcast %c : f32 to vector<2xi16>
115  // CHECK: %[[BITCAST:.*]] = llvm.bitcast %[[ARG]] : i32 to vector<2xi16>
116  // CHECK: llvm.return %[[BITCAST]]
117  llvm.return %d : vector<2xi16>
118}
119
120// -----
121
122// CHECK-LABEL: fold_addrcast
123// CHECK-SAME: %[[ARG:[[:alnum:]]+]]
124// CHECK-NEXT: llvm.return %[[ARG]]
125llvm.func @fold_addrcast(%x : !llvm.ptr) -> !llvm.ptr {
126  %c = llvm.addrspacecast %x : !llvm.ptr to !llvm.ptr
127  llvm.return %c : !llvm.ptr
128}
129
130// -----
131
132// CHECK-LABEL: fold_addrcast2
133// CHECK-SAME: %[[ARG:[[:alnum:]]+]]
134// CHECK-NEXT: llvm.return %[[ARG]]
135llvm.func @fold_addrcast2(%x : !llvm.ptr) -> !llvm.ptr {
136  %c = llvm.addrspacecast %x : !llvm.ptr to !llvm.ptr<5>
137  %d = llvm.addrspacecast %c : !llvm.ptr<5> to !llvm.ptr
138  llvm.return %d : !llvm.ptr
139}
140
141// -----
142
143// CHECK-LABEL: fold_addrcast_chain
144// CHECK-SAME: %[[ARG:[[:alnum:]]+]]
145llvm.func @fold_addrcast_chain(%x : !llvm.ptr) -> !llvm.ptr<2> {
146  %c = llvm.addrspacecast %x : !llvm.ptr to !llvm.ptr<1>
147  %d = llvm.addrspacecast %c : !llvm.ptr<1> to !llvm.ptr<2>
148  // CHECK: %[[ADDRCAST:.*]] = llvm.addrspacecast %[[ARG]] : !llvm.ptr to !llvm.ptr<2>
149  // CHECK: llvm.return %[[ADDRCAST]]
150  llvm.return %d : !llvm.ptr<2>
151}
152
153// -----
154
155// CHECK-LABEL: fold_gep
156// CHECK-SAME: %[[ARG:[[:alnum:]]+]]
157// CHECK-NEXT: llvm.return %[[ARG]]
158llvm.func @fold_gep(%x : !llvm.ptr) -> !llvm.ptr {
159  %c0 = arith.constant 0 : i32
160  %c = llvm.getelementptr %x[%c0] : (!llvm.ptr, i32) -> !llvm.ptr, i8
161  llvm.return %c : !llvm.ptr
162}
163
164// -----
165
166// CHECK-LABEL: fold_gep_neg
167// CHECK-SAME: %[[ARG:[[:alnum:]]+]]
168// CHECK-NEXT: %[[RES:.*]] = llvm.getelementptr inbounds %[[ARG]][0, 1]
169// CHECK-NEXT: llvm.return %[[RES]]
170llvm.func @fold_gep_neg(%x : !llvm.ptr) -> !llvm.ptr {
171  %c0 = arith.constant 0 : i32
172  %0 = llvm.getelementptr inbounds %x[%c0, 1] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<(i32, i32)>
173  llvm.return %0 : !llvm.ptr
174}
175
176// -----
177
178// CHECK-LABEL: fold_gep_canon
179// CHECK-SAME: %[[ARG:[[:alnum:]]+]]
180// CHECK-NEXT: %[[RES:.*]] = llvm.getelementptr %[[ARG]][2]
181// CHECK-NEXT: llvm.return %[[RES]]
182llvm.func @fold_gep_canon(%x : !llvm.ptr) -> !llvm.ptr {
183  %c2 = arith.constant 2 : i32
184  %c = llvm.getelementptr %x[%c2] : (!llvm.ptr, i32) -> !llvm.ptr, i8
185  llvm.return %c : !llvm.ptr
186}
187
188// -----
189
190// Check that LLVM constants participate in cross-dialect constant folding. The
191// resulting constant is created in the arith dialect because the last folded
192// operation belongs to it.
193// CHECK-LABEL: llvm_constant
194llvm.func @llvm_constant() -> i32 {
195  // CHECK-NOT: llvm.mlir.constant
196  %0 = llvm.mlir.constant(40 : i32) : i32
197  %1 = llvm.mlir.constant(42 : i32) : i32
198  // CHECK: %[[RES:.*]] = arith.constant 82 : i32
199  // CHECK-NOT: arith.addi
200  %2 = arith.addi %0, %1 : i32
201  // CHECK: return %[[RES]]
202  llvm.return %2 : i32
203}
204
205// -----
206
207// CHECK-LABEL: load_dce
208// CHECK-NEXT: llvm.return
209llvm.func @load_dce(%x : !llvm.ptr) {
210  %0 = llvm.load %x : !llvm.ptr -> i8
211  llvm.return
212}
213
214// -----
215
216llvm.mlir.global external @fp() : !llvm.ptr
217
218// CHECK-LABEL: addr_dce
219// CHECK-NEXT: llvm.return
220llvm.func @addr_dce(%x : !llvm.ptr) {
221  %0 = llvm.mlir.addressof @fp : !llvm.ptr
222  llvm.return
223}
224
225// -----
226
227// CHECK-LABEL: alloca_dce
228// CHECK-NEXT: llvm.return
229llvm.func @alloca_dce() {
230  %c1_i64 = arith.constant 1 : i64
231  %0 = llvm.alloca %c1_i64 x i32 : (i64) -> !llvm.ptr
232  llvm.return
233}
234
235// -----
236
237// CHECK-LABEL: func @volatile_load
238llvm.func @volatile_load(%x : !llvm.ptr) {
239  // A volatile load may have side-effects such as a write operation to arbitrary memory.
240  // Make sure it is not removed.
241  // CHECK: llvm.load volatile
242  %0 = llvm.load volatile %x : !llvm.ptr -> i8
243  // Same with monotonic atomics and any stricter modes.
244  // CHECK: llvm.load %{{.*}} atomic monotonic
245  %2 = llvm.load %x atomic monotonic { alignment = 1 } : !llvm.ptr -> i8
246  // But not unordered!
247  // CHECK-NOT: llvm.load %{{.*}} atomic unordered
248  %3 = llvm.load %x  atomic unordered { alignment = 1 } : !llvm.ptr -> i8
249  llvm.return
250}
251
252// -----
253
254// CHECK-LABEL: func @inline_asm_side_effects
255llvm.func @inline_asm_side_effects(%x : i32) {
256  // CHECK-NOT: llvm.inline_asm "pure inline asm"
257  llvm.inline_asm "pure inline asm", "r" %x : (i32) -> ()
258  // CHECK: llvm.inline_asm has_side_effects "inline asm with side effects"
259  llvm.inline_asm has_side_effects "inline asm with side effects", "r" %x : (i32) -> ()
260  llvm.return
261}
262