1// RUN: mlir-opt -convert-memref-to-llvm -split-input-file %s | FileCheck %s
2
3// CHECK-LABEL: func @zero_d_alloc()
4func.func @zero_d_alloc() -> memref<f32> {
5// CHECK: %[[one:.*]] = llvm.mlir.constant(1 : index) : i64
6// CHECK: %[[null:.*]] = llvm.mlir.null : !llvm.ptr<f32>
7// CHECK: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[one]]] : (!llvm.ptr<f32>, i64) -> !llvm.ptr<f32>
8// CHECK: %[[size_bytes:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<f32> to i64
9// CHECK: llvm.call @malloc(%[[size_bytes]]) : (i64) -> !llvm.ptr<i8>
10// CHECK: %[[ptr:.*]] = llvm.bitcast %{{.*}} : !llvm.ptr<i8> to !llvm.ptr<f32>
11// CHECK: llvm.mlir.undef : !llvm.struct<(ptr<f32>, ptr<f32>, i64)>
12// CHECK: llvm.insertvalue %[[ptr]], %{{.*}}[0] : !llvm.struct<(ptr<f32>, ptr<f32>, i64)>
13// CHECK: llvm.insertvalue %[[ptr]], %{{.*}}[1] : !llvm.struct<(ptr<f32>, ptr<f32>, i64)>
14// CHECK: %[[c0:.*]] = llvm.mlir.constant(0 : index) : i64
15// CHECK: llvm.insertvalue %[[c0]], %{{.*}}[2] : !llvm.struct<(ptr<f32>, ptr<f32>, i64)>
16// CHECK: unrealized_conversion_cast %{{.*}}
17
18  %0 = memref.alloc() : memref<f32>
19  return %0 : memref<f32>
20}
21
22// -----
23
24// CHECK-LABEL: func @zero_d_dealloc
25func.func @zero_d_dealloc(%arg0: memref<f32>) {
26// CHECK: unrealized_conversion_cast
27// CHECK: %[[ptr:.*]] = llvm.extractvalue %{{.*}}[0] : !llvm.struct<(ptr<f32>, ptr<f32>, i64)>
28// CHECK: %[[bc:.*]] = llvm.bitcast %[[ptr]] : !llvm.ptr<f32> to !llvm.ptr<i8>
29// CHECK: llvm.call @free(%[[bc]]) : (!llvm.ptr<i8>) -> ()
30
31  memref.dealloc %arg0 : memref<f32>
32  return
33}
34
35// -----
36
37// CHECK-LABEL: func @aligned_1d_alloc(
38func.func @aligned_1d_alloc() -> memref<42xf32> {
39// CHECK: %[[sz1:.*]] = llvm.mlir.constant(42 : index) : i64
40// CHECK: %[[st1:.*]] = llvm.mlir.constant(1 : index) : i64
41// CHECK: %[[null:.*]] = llvm.mlir.null : !llvm.ptr<f32>
42// CHECK: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[sz1]]] : (!llvm.ptr<f32>, i64) -> !llvm.ptr<f32>
43// CHECK: %[[size_bytes:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<f32> to i64
44// CHECK: %[[alignment:.*]] = llvm.mlir.constant(8 : index) : i64
45// CHECK: %[[allocsize:.*]] = llvm.add %[[size_bytes]], %[[alignment]] : i64
46// CHECK: %[[allocated:.*]] = llvm.call @malloc(%[[allocsize]]) : (i64) -> !llvm.ptr<i8>
47// CHECK: %[[ptr:.*]] = llvm.bitcast %{{.*}} : !llvm.ptr<i8> to !llvm.ptr<f32>
48// CHECK: %[[allocatedAsInt:.*]] = llvm.ptrtoint %[[ptr]] : !llvm.ptr<f32> to i64
49// CHECK: %[[one_1:.*]] = llvm.mlir.constant(1 : index) : i64
50// CHECK: %[[bump:.*]] = llvm.sub %[[alignment]], %[[one_1]] : i64
51// CHECK: %[[bumped:.*]] = llvm.add %[[allocatedAsInt]], %[[bump]] : i64
52// CHECK: %[[mod:.*]] = llvm.urem %[[bumped]], %[[alignment]] : i64
53// CHECK: %[[aligned:.*]] = llvm.sub %[[bumped]], %[[mod]] : i64
54// CHECK: %[[alignedBitCast:.*]] = llvm.inttoptr %[[aligned]] : i64 to !llvm.ptr<f32>
55// CHECK: llvm.mlir.undef : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<1 x i64>, array<1 x i64>)>
56// CHECK: llvm.insertvalue %[[ptr]], %{{.*}}[0] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<1 x i64>, array<1 x i64>)>
57// CHECK: llvm.insertvalue %[[alignedBitCast]], %{{.*}}[1] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<1 x i64>, array<1 x i64>)>
58// CHECK: %[[c0:.*]] = llvm.mlir.constant(0 : index) : i64
59// CHECK: llvm.insertvalue %[[c0]], %{{.*}}[2] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<1 x i64>, array<1 x i64>)>
60  %0 = memref.alloc() {alignment = 8} : memref<42xf32>
61  return %0 : memref<42xf32>
62}
63
64// -----
65
66// CHECK-LABEL: func @static_alloc()
67func.func @static_alloc() -> memref<32x18xf32> {
68// CHECK: %[[num_elems:.*]] = llvm.mlir.constant(576 : index) : i64
69// CHECK: %[[null:.*]] = llvm.mlir.null : !llvm.ptr<f32>
70// CHECK: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[num_elems]]] : (!llvm.ptr<f32>, i64) -> !llvm.ptr<f32>
71// CHECK: %[[size_bytes:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<f32> to i64
72// CHECK: %[[allocated:.*]] = llvm.call @malloc(%[[size_bytes]]) : (i64) -> !llvm.ptr<i8>
73// CHECK: llvm.bitcast %[[allocated]] : !llvm.ptr<i8> to !llvm.ptr<f32>
74 %0 = memref.alloc() : memref<32x18xf32>
75 return %0 : memref<32x18xf32>
76}
77
78// -----
79
80// CHECK-LABEL: func @static_alloca()
81func.func @static_alloca() -> memref<32x18xf32> {
82// CHECK: %[[sz1:.*]] = llvm.mlir.constant(32 : index) : i64
83// CHECK: %[[sz2:.*]] = llvm.mlir.constant(18 : index) : i64
84// CHECK: %[[st2:.*]] = llvm.mlir.constant(1 : index) : i64
85// CHECK: %[[num_elems:.*]] = llvm.mlir.constant(576 : index) : i64
86// CHECK: %[[null:.*]] = llvm.mlir.null : !llvm.ptr<f32>
87// CHECK: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[num_elems]]] : (!llvm.ptr<f32>, i64) -> !llvm.ptr<f32>
88// CHECK: %[[size_bytes:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<f32> to i64
89// CHECK: %[[allocated:.*]] = llvm.alloca %[[size_bytes]] x f32 : (i64) -> !llvm.ptr<f32>
90 %0 = memref.alloca() : memref<32x18xf32>
91
92 // Test with explicitly specified alignment. llvm.alloca takes care of the
93 // alignment. The same pointer is thus used for allocation and aligned
94 // accesses.
95 // CHECK: %[[alloca_aligned:.*]] = llvm.alloca %{{.*}} x f32 {alignment = 32 : i64} : (i64) -> !llvm.ptr<f32>
96 // CHECK: %[[desc:.*]] = llvm.mlir.undef : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<2 x i64>, array<2 x i64>)>
97 // CHECK: %[[desc1:.*]] = llvm.insertvalue %[[alloca_aligned]], %[[desc]][0] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<2 x i64>, array<2 x i64>)>
98 // CHECK: llvm.insertvalue %[[alloca_aligned]], %[[desc1]][1] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<2 x i64>, array<2 x i64>)>
99 memref.alloca() {alignment = 32} : memref<32x18xf32>
100 return %0 : memref<32x18xf32>
101}
102
103// -----
104
105// CHECK-LABEL: func @static_dealloc
106func.func @static_dealloc(%static: memref<10x8xf32>) {
107// CHECK: %[[ptr:.*]] = llvm.extractvalue %{{.*}}[0] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<2 x i64>, array<2 x i64>)>
108// CHECK: %[[bc:.*]] = llvm.bitcast %[[ptr]] : !llvm.ptr<f32> to !llvm.ptr<i8>
109// CHECK: llvm.call @free(%[[bc]]) : (!llvm.ptr<i8>) -> ()
110  memref.dealloc %static : memref<10x8xf32>
111  return
112}
113
114// -----
115
116// CHECK-LABEL: func @zero_d_load
117func.func @zero_d_load(%arg0: memref<f32>) -> f32 {
118// CHECK: %[[ptr:.*]] = llvm.extractvalue %{{.*}}[1] : !llvm.struct<(ptr<f32>, ptr<f32>, i64)>
119// CHECK: %{{.*}} = llvm.load %[[ptr]] : !llvm.ptr<f32>
120  %0 = memref.load %arg0[] : memref<f32>
121  return %0 : f32
122}
123
124// -----
125
126// CHECK-LABEL: func @static_load
127// CHECK:         %[[MEMREF:.*]]: memref<10x42xf32>,
128// CHECK:         %[[I:.*]]: index,
129// CHECK:         %[[J:.*]]: index)
130func.func @static_load(%static : memref<10x42xf32>, %i : index, %j : index) {
131// CHECK:  %[[II:.*]] = builtin.unrealized_conversion_cast %[[I]]
132// CHECK:  %[[JJ:.*]] = builtin.unrealized_conversion_cast %[[J]]
133// CHECK:  %[[ptr:.*]] = llvm.extractvalue %{{.*}}[1] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<2 x i64>, array<2 x i64>)>
134// CHECK:  %[[st0:.*]] = llvm.mlir.constant(42 : index) : i64
135// CHECK:  %[[offI:.*]] = llvm.mul %[[II]], %[[st0]] : i64
136// CHECK:  %[[off1:.*]] = llvm.add %[[offI]], %[[JJ]] : i64
137// CHECK:  %[[addr:.*]] = llvm.getelementptr %[[ptr]][%[[off1]]] : (!llvm.ptr<f32>, i64) -> !llvm.ptr<f32>
138// CHECK:  llvm.load %[[addr]] : !llvm.ptr<f32>
139  %0 = memref.load %static[%i, %j] : memref<10x42xf32>
140  return
141}
142
143// -----
144
145// CHECK-LABEL: func @zero_d_store
146func.func @zero_d_store(%arg0: memref<f32>, %arg1: f32) {
147// CHECK: %[[ptr:.*]] = llvm.extractvalue %[[ld:.*]][1] : !llvm.struct<(ptr<f32>, ptr<f32>, i64)>
148// CHECK: llvm.store %{{.*}}, %[[ptr]] : !llvm.ptr<f32>
149  memref.store %arg1, %arg0[] : memref<f32>
150  return
151}
152
153// -----
154
155// CHECK-LABEL: func @static_store
156// CHECK:         %[[MEMREF:.*]]: memref<10x42xf32>,
157// CHECK-SAME:    %[[I:.*]]: index, %[[J:.*]]: index,
158func.func @static_store(%static : memref<10x42xf32>, %i : index, %j : index, %val : f32) {
159// CHECK: %[[II:.*]] = builtin.unrealized_conversion_cast %[[I]]
160// CHECK: %[[JJ:.*]] = builtin.unrealized_conversion_cast %[[J]]
161// CHECK: %[[ptr:.*]] = llvm.extractvalue %{{.*}}[1] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<2 x i64>, array<2 x i64>)>
162// CHECK: %[[st0:.*]] = llvm.mlir.constant(42 : index) : i64
163// CHECK: %[[offI:.*]] = llvm.mul %[[II]], %[[st0]] : i64
164// CHECK: %[[off1:.*]] = llvm.add %[[offI]], %[[JJ]] : i64
165// CHECK: %[[addr:.*]] = llvm.getelementptr %[[ptr]][%[[off1]]] : (!llvm.ptr<f32>, i64) -> !llvm.ptr<f32>
166// CHECK: llvm.store %{{.*}}, %[[addr]] : !llvm.ptr<f32>
167
168  memref.store %val, %static[%i, %j] : memref<10x42xf32>
169  return
170}
171
172// -----
173
174// CHECK-LABEL: func @static_memref_dim
175func.func @static_memref_dim(%static : memref<42x32x15x13x27xf32>) {
176// CHECK:  llvm.mlir.constant(42 : index) : i64
177  %c0 = arith.constant 0 : index
178  %0 = memref.dim %static, %c0 : memref<42x32x15x13x27xf32>
179// CHECK:  llvm.mlir.constant(32 : index) : i64
180  %c1 = arith.constant 1 : index
181  %1 = memref.dim %static, %c1 : memref<42x32x15x13x27xf32>
182// CHECK:  llvm.mlir.constant(15 : index) : i64
183  %c2 = arith.constant 2 : index
184  %2 = memref.dim %static, %c2 : memref<42x32x15x13x27xf32>
185// CHECK:  llvm.mlir.constant(13 : index) : i64
186  %c3 = arith.constant 3 : index
187  %3 = memref.dim %static, %c3 : memref<42x32x15x13x27xf32>
188// CHECK:  llvm.mlir.constant(27 : index) : i64
189  %c4 = arith.constant 4 : index
190  %4 = memref.dim %static, %c4 : memref<42x32x15x13x27xf32>
191  return
192}
193
194// -----
195
196// Check that consistent types are emitted in address arithemic in presence of
197// a data layout specification.
198module attributes { dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<index, 32>> } {
199  func.func @address() {
200    %c1 = arith.constant 1 : index
201    %0 = memref.alloc(%c1) : memref<? x vector<2xf32>>
202    // CHECK: %[[CST_S:.*]] = arith.constant 1 : index
203    // CHECK: %[[CST:.*]] = builtin.unrealized_conversion_cast
204    // CHECK: llvm.mlir.null
205    // CHECK: llvm.getelementptr %{{.*}}[[CST]]
206    // CHECK: llvm.ptrtoint %{{.*}} : !llvm.ptr<{{.*}}> to i32
207    // CHECK: llvm.ptrtoint %{{.*}} : !llvm.ptr<{{.*}}> to i32
208    // CHECK: llvm.add %{{.*}} : i32
209    // CHECK: llvm.call @malloc(%{{.*}}) : (i32) -> !llvm.ptr
210    // CHECK: llvm.ptrtoint %{{.*}} : !llvm.ptr<{{.*}}> to i32
211    // CHECK: llvm.sub {{.*}} : i32
212    // CHECK: llvm.add {{.*}} : i32
213    // CHECK: llvm.urem {{.*}} : i32
214    // CHECK: llvm.sub {{.*}} : i32
215    // CHECK: llvm.inttoptr %{{.*}} : i32 to !llvm.ptr
216    return
217  }
218}
219
220// -----
221
222memref.global "private" constant @__constant_3xi64 : memref<3xi64> = dense<[2, 6, 20]>
223
224// CHECK-LABEL: func @memref.reshape
225// CHECK-SAME:    %[[arg0:.*]]: memref<4x5x6xf32>) -> memref<2x6x20xf32>
226func.func @memref.reshape(%arg0: memref<4x5x6xf32>) -> memref<2x6x20xf32> {
227  // CHECK: %[[cast0:.*]] = builtin.unrealized_conversion_cast %arg0 : memref<4x5x6xf32> to !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<3 x i64>, array<3 x i64>)>
228  %0 = memref.get_global @__constant_3xi64 : memref<3xi64>
229
230  // CHECK: %[[undef:.*]] = llvm.mlir.undef : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<3 x i64>, array<3 x i64>)>
231  // CHECK: %[[elem0:.*]] = llvm.extractvalue %[[cast0]][0] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<3 x i64>, array<3 x i64>)>
232  // CHECK: %[[elem1:.*]] = llvm.extractvalue %[[cast0]][1] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<3 x i64>, array<3 x i64>)>
233  // CHECK: %[[insert0:.*]] = llvm.insertvalue %[[elem0]], %[[undef]][0] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<3 x i64>, array<3 x i64>)>
234  // CHECK: %[[insert1:.*]] = llvm.insertvalue %[[elem1]], %[[insert0:.*]][1] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<3 x i64>, array<3 x i64>)>
235  // CHECK: %[[zero:.*]] = llvm.mlir.constant(0 : index) : i64
236  // CHECK: %[[insert2:.*]] = llvm.insertvalue %[[zero]], %[[insert1]][2] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<3 x i64>, array<3 x i64>)>
237  // CHECK: %[[two:.*]] = llvm.mlir.constant(2 : index) : i64
238  // CHECK: %[[insert3:.*]] = llvm.insertvalue %[[two]], %[[insert2]][3, 0] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<3 x i64>, array<3 x i64>)>
239  // CHECK: %[[hundred_and_twenty:.*]] = llvm.mlir.constant(120 : index) : i64
240  // CHECK: %[[insert4:.*]] = llvm.insertvalue %[[hundred_and_twenty]], %[[insert3]][4, 0] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<3 x i64>, array<3 x i64>)>
241  // CHECK: %[[six:.*]] = llvm.mlir.constant(6 : index) : i64
242  // CHECK: %[[insert5:.*]] = llvm.insertvalue %[[six]], %[[insert4]][3, 1] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<3 x i64>, array<3 x i64>)>
243  // CHECK: %[[twenty0:.*]] = llvm.mlir.constant(20 : index) : i64
244  // CHECK: %[[insert6:.*]] = llvm.insertvalue %[[twenty0]], %[[insert5]][4, 1] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<3 x i64>, array<3 x i64>)>
245  // CHECK: %[[twenty1:.*]] = llvm.mlir.constant(20 : index) : i64
246  // CHECK: %[[insert7:.*]] = llvm.insertvalue %[[twenty1]], %[[insert6]][3, 2] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<3 x i64>, array<3 x i64>)>
247  // CHECK: %[[one:.*]] = llvm.mlir.constant(1 : index) : i64
248  // CHECK: %[[insert8:.*]] = llvm.insertvalue %[[one]], %[[insert7]][4, 2] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<3 x i64>, array<3 x i64>)>
249  // CHECK: %[[cast1:.*]] = builtin.unrealized_conversion_cast %[[insert8]] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<3 x i64>, array<3 x i64>)> to memref<2x6x20xf32>
250  %1 = memref.reshape %arg0(%0) : (memref<4x5x6xf32>, memref<3xi64>) -> memref<2x6x20xf32>
251
252  // CHECK: return %[[cast1]] : memref<2x6x20xf32>
253  return %1 : memref<2x6x20xf32>
254}
255