1// RUN: mlir-opt -allow-unregistered-dialect %s | FileCheck %s 2// Verify the printed output can be parsed. 3// RUN: mlir-opt -allow-unregistered-dialect %s | mlir-opt -allow-unregistered-dialect | FileCheck %s 4// Verify the generic form can be parsed. 5// RUN: mlir-opt -allow-unregistered-dialect -mlir-print-op-generic %s | mlir-opt -allow-unregistered-dialect | FileCheck %s 6 7// CHECK: #map0 = affine_map<(d0) -> (d0 + 1)> 8 9// CHECK: #map1 = affine_map<()[s0] -> (s0 + 1)> 10 11// CHECK-DAG: #[[$BASE_MAP0:map[0-9]+]] = affine_map<(d0, d1, d2) -> (d0 * 64 + d1 * 4 + d2)> 12// CHECK-DAG: #[[$BASE_MAP3:map[0-9]+]] = affine_map<(d0, d1, d2)[s0, s1, s2, s3] -> (d0 * s1 + s0 + d1 * s2 + d2 * s3)> 13 14// CHECK-LABEL: func @func_with_ops 15// CHECK-SAME: %[[ARG:.*]]: f32 16func.func @func_with_ops(f32) { 17^bb0(%a : f32): 18 // CHECK: %[[T:.*]] = "getTensor"() : () -> tensor<4x4x?xf32> 19 %t = "getTensor"() : () -> tensor<4x4x?xf32> 20 21 // CHECK: %[[C2:.*]] = arith.constant 2 : index 22 // CHECK-NEXT: %{{.*}} = tensor.dim %[[T]], %[[C2]] : tensor<4x4x?xf32> 23 %c2 = arith.constant 2 : index 24 %t2 = "tensor.dim"(%t, %c2) : (tensor<4x4x?xf32>, index) -> index 25 26 // CHECK: %{{.*}} = arith.addf %[[ARG]], %[[ARG]] : f32 27 %x = "arith.addf"(%a, %a) : (f32,f32) -> (f32) 28 29 // CHECK: return 30 return 31} 32 33// CHECK-LABEL: func @standard_instrs(%arg0: tensor<4x4x?xf32>, %arg1: f32, %arg2: i32, %arg3: index, %arg4: i64, %arg5: f16) { 34func.func @standard_instrs(tensor<4x4x?xf32>, f32, i32, index, i64, f16) { 35^bb42(%t: tensor<4x4x?xf32>, %f: f32, %i: i32, %idx : index, %j: i64, %half: f16): 36 // CHECK: %[[C2:.*]] = arith.constant 2 : index 37 // CHECK: %[[A2:.*]] = tensor.dim %arg0, %[[C2]] : tensor<4x4x?xf32> 38 %c2 = arith.constant 2 : index 39 %a2 = tensor.dim %t, %c2 : tensor<4x4x?xf32> 40 41 // CHECK: %f = constant @func_with_ops : (f32) -> () 42 %10 = constant @func_with_ops : (f32) -> () 43 44 // CHECK: %f_0 = constant @affine_apply : () -> () 45 %11 = constant @affine_apply : () -> () 46 47 // CHECK: %[[I2:.*]] = arith.addi 48 %i2 = arith.addi %i, %i: i32 49 // CHECK: %[[I3:.*]] = arith.addi 50 %i3 = arith.addi %i2, %i : i32 51 // CHECK: %[[I4:.*]] = arith.addi 52 %i4 = arith.addi %i2, %i3 : i32 53 // CHECK: %[[F3:.*]] = arith.addf 54 %f3 = arith.addf %f, %f : f32 55 // CHECK: %[[F4:.*]] = arith.addf 56 %f4 = arith.addf %f, %f3 : f32 57 58 %true = arith.constant true 59 %tci32 = arith.constant dense<0> : tensor<42xi32> 60 %vci32 = arith.constant dense<0> : vector<42xi32> 61 %tci1 = arith.constant dense<1> : tensor<42xi1> 62 %vci1 = arith.constant dense<1> : vector<42xi1> 63 64 // CHECK: %{{.*}} = arith.select %{{.*}}, %arg3, %arg3 : index 65 %21 = arith.select %true, %idx, %idx : index 66 67 // CHECK: %{{.*}} = arith.select %{{.*}}, %{{.*}}, %{{.*}} : tensor<42xi1>, tensor<42xi32> 68 %22 = arith.select %tci1, %tci32, %tci32 : tensor<42 x i1>, tensor<42 x i32> 69 70 // CHECK: %{{.*}} = arith.select %{{.*}}, %{{.*}}, %{{.*}} : vector<42xi1>, vector<42xi32> 71 %23 = arith.select %vci1, %vci32, %vci32 : vector<42 x i1>, vector<42 x i32> 72 73 // CHECK: %{{.*}} = arith.select %{{.*}}, %arg3, %arg3 : index 74 %24 = "arith.select"(%true, %idx, %idx) : (i1, index, index) -> index 75 76 // CHECK: %{{.*}} = arith.select %{{.*}}, %{{.*}}, %{{.*}} : tensor<42xi32> 77 %25 = arith.select %true, %tci32, %tci32 : tensor<42 x i32> 78 79 %64 = arith.constant dense<0.> : vector<4 x f32> 80 %tcf32 = arith.constant dense<0.> : tensor<42 x f32> 81 %vcf32 = arith.constant dense<0.> : vector<4 x f32> 82 83 // CHECK: %{{.*}} = arith.cmpf ogt, %{{.*}}, %{{.*}} : f32 84 %65 = arith.cmpf ogt, %f3, %f4 : f32 85 86 // Predicate 0 means ordered equality comparison. 87 // CHECK: %{{.*}} = arith.cmpf oeq, %{{.*}}, %{{.*}} : f32 88 %66 = "arith.cmpf"(%f3, %f4) {predicate = 1} : (f32, f32) -> i1 89 90 // CHECK: %{{.*}} = arith.cmpf olt, %{{.*}}, %{{.*}}: vector<4xf32> 91 %67 = arith.cmpf olt, %vcf32, %vcf32 : vector<4 x f32> 92 93 // CHECK: %{{.*}} = arith.cmpf oeq, %{{.*}}, %{{.*}}: vector<4xf32> 94 %68 = "arith.cmpf"(%vcf32, %vcf32) {predicate = 1} : (vector<4 x f32>, vector<4 x f32>) -> vector<4 x i1> 95 96 // CHECK: %{{.*}} = arith.cmpf oeq, %{{.*}}, %{{.*}}: tensor<42xf32> 97 %69 = arith.cmpf oeq, %tcf32, %tcf32 : tensor<42 x f32> 98 99 // CHECK: %{{.*}} = arith.cmpf oeq, %{{.*}}, %{{.*}}: vector<4xf32> 100 %70 = arith.cmpf oeq, %vcf32, %vcf32 : vector<4 x f32> 101 102 // CHECK: arith.constant true 103 %74 = arith.constant true 104 105 // CHECK: arith.constant false 106 %75 = arith.constant false 107 108 // CHECK: %{{.*}} = math.abs %arg1 : f32 109 %100 = "math.abs"(%f) : (f32) -> f32 110 111 // CHECK: %{{.*}} = math.abs %arg1 : f32 112 %101 = math.abs %f : f32 113 114 // CHECK: %{{.*}} = math.abs %{{.*}}: vector<4xf32> 115 %102 = math.abs %vcf32 : vector<4xf32> 116 117 // CHECK: %{{.*}} = math.abs %arg0 : tensor<4x4x?xf32> 118 %103 = math.abs %t : tensor<4x4x?xf32> 119 120 // CHECK: %{{.*}} = math.ceil %arg1 : f32 121 %104 = "math.ceil"(%f) : (f32) -> f32 122 123 // CHECK: %{{.*}} = math.ceil %arg1 : f32 124 %105 = math.ceil %f : f32 125 126 // CHECK: %{{.*}} = math.ceil %{{.*}}: vector<4xf32> 127 %106 = math.ceil %vcf32 : vector<4xf32> 128 129 // CHECK: %{{.*}} = math.ceil %arg0 : tensor<4x4x?xf32> 130 %107 = math.ceil %t : tensor<4x4x?xf32> 131 132 // CHECK: %{{.*}} = math.copysign %arg1, %arg1 : f32 133 %116 = "math.copysign"(%f, %f) : (f32, f32) -> f32 134 135 // CHECK: %{{.*}} = math.copysign %arg1, %arg1 : f32 136 %117 = math.copysign %f, %f : f32 137 138 // CHECK: %{{.*}} = math.copysign %{{.*}}, %{{.*}}: vector<4xf32> 139 %118 = math.copysign %vcf32, %vcf32 : vector<4xf32> 140 141 // CHECK: %{{.*}} = math.copysign %arg0, %arg0 : tensor<4x4x?xf32> 142 %119 = math.copysign %t, %t : tensor<4x4x?xf32> 143 144 // CHECK: %{{.*}} = math.rsqrt %arg1 : f32 145 %145 = math.rsqrt %f : f32 146 147 // CHECK: math.floor %arg1 : f32 148 %163 = "math.floor"(%f) : (f32) -> f32 149 150 // CHECK: %{{.*}} = math.floor %arg1 : f32 151 %164 = math.floor %f : f32 152 153 // CHECK: %{{.*}} = math.floor %{{.*}}: vector<4xf32> 154 %165 = math.floor %vcf32 : vector<4xf32> 155 156 // CHECK: %{{.*}} = math.floor %arg0 : tensor<4x4x?xf32> 157 %166 = math.floor %t : tensor<4x4x?xf32> 158 159 return 160} 161 162// CHECK-LABEL: func @affine_apply() { 163func.func @affine_apply() { 164 %i = "arith.constant"() {value = 0: index} : () -> index 165 %j = "arith.constant"() {value = 1: index} : () -> index 166 167 // CHECK: affine.apply #map0(%c0) 168 %a = "affine.apply" (%i) { map = affine_map<(d0) -> (d0 + 1)> } : 169 (index) -> (index) 170 171 // CHECK: affine.apply #map1()[%c0] 172 %b = affine.apply affine_map<()[x] -> (x+1)>()[%i] 173 174 return 175} 176 177// CHECK-LABEL: func @load_store_prefetch 178func.func @load_store_prefetch(memref<4x4xi32>, index) { 179^bb0(%0: memref<4x4xi32>, %1: index): 180 // CHECK: %0 = memref.load %arg0[%arg1, %arg1] : memref<4x4xi32> 181 %2 = "memref.load"(%0, %1, %1) : (memref<4x4xi32>, index, index)->i32 182 183 // CHECK: %{{.*}} = memref.load %arg0[%arg1, %arg1] : memref<4x4xi32> 184 %3 = memref.load %0[%1, %1] : memref<4x4xi32> 185 186 // CHECK: memref.prefetch %arg0[%arg1, %arg1], write, locality<1>, data : memref<4x4xi32> 187 memref.prefetch %0[%1, %1], write, locality<1>, data : memref<4x4xi32> 188 189 // CHECK: memref.prefetch %arg0[%arg1, %arg1], read, locality<3>, instr : memref<4x4xi32> 190 memref.prefetch %0[%1, %1], read, locality<3>, instr : memref<4x4xi32> 191 192 return 193} 194 195// Test with zero-dimensional operands using no index in load/store. 196// CHECK-LABEL: func @zero_dim_no_idx 197func.func @zero_dim_no_idx(%arg0 : memref<i32>, %arg1 : memref<i32>, %arg2 : memref<i32>) { 198 %0 = memref.load %arg0[] : memref<i32> 199 memref.store %0, %arg1[] : memref<i32> 200 return 201 // CHECK: %0 = memref.load %{{.*}}[] : memref<i32> 202 // CHECK: memref.store %{{.*}}, %{{.*}}[] : memref<i32> 203} 204 205// CHECK-LABEL: func @return_op(%arg0: i32) -> i32 { 206func.func @return_op(%a : i32) -> i32 { 207 // CHECK: return %arg0 : i32 208 "func.return" (%a) : (i32)->() 209} 210 211// CHECK-LABEL: func @calls(%arg0: i32) { 212func.func @calls(%arg0: i32) { 213 // CHECK: %0 = call @return_op(%arg0) : (i32) -> i32 214 %x = call @return_op(%arg0) : (i32) -> i32 215 // CHECK: %1 = call @return_op(%0) : (i32) -> i32 216 %y = call @return_op(%x) : (i32) -> i32 217 // CHECK: %2 = call @return_op(%0) : (i32) -> i32 218 %z = "func.call"(%x) {callee = @return_op} : (i32) -> i32 219 220 // CHECK: %f = constant @affine_apply : () -> () 221 %f = constant @affine_apply : () -> () 222 223 // CHECK: call_indirect %f() : () -> () 224 call_indirect %f() : () -> () 225 226 // CHECK: %f_0 = constant @return_op : (i32) -> i32 227 %f_0 = constant @return_op : (i32) -> i32 228 229 // CHECK: %3 = call_indirect %f_0(%arg0) : (i32) -> i32 230 %2 = call_indirect %f_0(%arg0) : (i32) -> i32 231 232 // CHECK: %4 = call_indirect %f_0(%arg0) : (i32) -> i32 233 %3 = "func.call_indirect"(%f_0, %arg0) : ((i32) -> i32, i32) -> i32 234 235 return 236} 237 238// CHECK-LABEL: func @memref_cast(%arg0 239func.func @memref_cast(%arg0: memref<4xf32>, %arg1 : memref<?xf32>, %arg2 : memref<64x16x4xf32, offset: 0, strides: [64, 4, 1]>) { 240 // CHECK: %0 = memref.cast %arg0 : memref<4xf32> to memref<?xf32> 241 %0 = memref.cast %arg0 : memref<4xf32> to memref<?xf32> 242 243 // CHECK: %1 = memref.cast %arg1 : memref<?xf32> to memref<4xf32> 244 %1 = memref.cast %arg1 : memref<?xf32> to memref<4xf32> 245 246 // CHECK: {{%.*}} = memref.cast %arg2 : memref<64x16x4xf32, #[[$BASE_MAP0]]> to memref<64x16x4xf32, #[[$BASE_MAP3]]> 247 %2 = memref.cast %arg2 : memref<64x16x4xf32, offset: 0, strides: [64, 4, 1]> to memref<64x16x4xf32, offset: ?, strides: [?, ?, ?]> 248 249 // CHECK: {{%.*}} = memref.cast {{%.*}} : memref<64x16x4xf32, #[[$BASE_MAP3]]> to memref<64x16x4xf32, #[[$BASE_MAP0]]> 250 %3 = memref.cast %2 : memref<64x16x4xf32, offset: ?, strides: [?, ?, ?]> to memref<64x16x4xf32, offset: 0, strides: [64, 4, 1]> 251 252 // CHECK: memref.cast %{{.*}} : memref<4xf32> to memref<*xf32> 253 %4 = memref.cast %1 : memref<4xf32> to memref<*xf32> 254 255 // CHECK: memref.cast %{{.*}} : memref<*xf32> to memref<4xf32> 256 %5 = memref.cast %4 : memref<*xf32> to memref<4xf32> 257 return 258} 259 260// Check that unranked memrefs with non-default memory space roundtrip 261// properly. 262// CHECK-LABEL: @unranked_memref_roundtrip(memref<*xf32, 4>) 263func.func private @unranked_memref_roundtrip(memref<*xf32, 4>) 264 265// CHECK-LABEL: func @memref_view(%arg0 266func.func @memref_view(%arg0 : index, %arg1 : index, %arg2 : index) { 267 %0 = memref.alloc() : memref<2048xi8> 268 // Test two dynamic sizes and dynamic offset. 269 // CHECK: %{{.*}} = memref.view %0[%arg2][%arg0, %arg1] : memref<2048xi8> to memref<?x?xf32> 270 %1 = memref.view %0[%arg2][%arg0, %arg1] : memref<2048xi8> to memref<?x?xf32> 271 272 // Test one dynamic size and dynamic offset. 273 // CHECK: %{{.*}} = memref.view %0[%arg2][%arg1] : memref<2048xi8> to memref<4x?xf32> 274 %3 = memref.view %0[%arg2][%arg1] : memref<2048xi8> to memref<4x?xf32> 275 276 // Test static sizes and static offset. 277 // CHECK: %{{.*}} = memref.view %0[{{.*}}][] : memref<2048xi8> to memref<64x4xf32> 278 %c0 = arith.constant 0: index 279 %5 = memref.view %0[%c0][] : memref<2048xi8> to memref<64x4xf32> 280 return 281} 282 283// CHECK-LABEL: func @test_dimop 284// CHECK-SAME: %[[ARG:.*]]: tensor<4x4x?xf32> 285func.func @test_dimop(%arg0: tensor<4x4x?xf32>) { 286 // CHECK: %[[C2:.*]] = arith.constant 2 : index 287 // CHECK: %{{.*}} = tensor.dim %[[ARG]], %[[C2]] : tensor<4x4x?xf32> 288 %c2 = arith.constant 2 : index 289 %0 = tensor.dim %arg0, %c2 : tensor<4x4x?xf32> 290 // use dim as an index to ensure type correctness 291 %1 = affine.apply affine_map<(d0) -> (d0)>(%0) 292 return 293} 294 295// CHECK-LABEL: func @tensor_load_store 296func.func @tensor_load_store(%0 : memref<4x4xi32>, %1 : tensor<4x4xi32>) { 297 // CHECK-SAME: (%[[MEMREF:.*]]: memref<4x4xi32>, 298 // CHECK-SAME: %[[TENSOR:.*]]: tensor<4x4xi32>) 299 // CHECK: memref.tensor_store %[[TENSOR]], %[[MEMREF]] : memref<4x4xi32> 300 memref.tensor_store %1, %0 : memref<4x4xi32> 301 return 302} 303 304// CHECK-LABEL: func @unranked_tensor_load_store 305func.func @unranked_tensor_load_store(%0 : memref<*xi32>, %1 : tensor<*xi32>) { 306 // CHECK-SAME: (%[[MEMREF:.*]]: memref<*xi32>, 307 // CHECK-SAME: %[[TENSOR:.*]]: tensor<*xi32>) 308 // CHECK: memref.tensor_store %[[TENSOR]], %[[MEMREF]] : memref<*xi32> 309 memref.tensor_store %1, %0 : memref<*xi32> 310 return 311} 312 313// CHECK-LABEL: func @assume_alignment 314// CHECK-SAME: %[[MEMREF:.*]]: memref<4x4xf16> 315func.func @assume_alignment(%0: memref<4x4xf16>) { 316 // CHECK: memref.assume_alignment %[[MEMREF]], 16 : memref<4x4xf16> 317 memref.assume_alignment %0, 16 : memref<4x4xf16> 318 return 319} 320