1// RUN: mlir-opt %s --lower-sparse-foreach-to-scf --canonicalize | FileCheck %s 2 3// CHECK-LABEL: func.func @sparse_foreach_constant 4// CHECK-DAG: %[[C1:.*]] = arith.constant 1 : index 5// CHECK-DAG: %[[V1:.*]] = arith.constant 5.000000e+00 : f32 6// CHECK-DAG: %[[C2:.*]] = arith.constant 2 : index 7// CHECK-DAG: %[[V3:.*]] = arith.constant 1.000000e+00 : f32 8// CHECK-DAG: %[[V4:.*]] = arith.constant 6.000000e+00 : f32 9// (1, 1) -> (2, 1) -> (2, 2) 10// CHECK-NEXT: "test.use"(%[[C1]], %[[C1]], %[[V1]]) 11// CHECK-NEXT: "test.use"(%[[C2]], %[[C1]], %[[V3]]) 12// CHECK-NEXT: "test.use"(%[[C1]], %[[C2]], %[[V4]]) 13// (1, 1) -> (1, 2) -> (2, 1) 14// CHECK-NEXT: "test.use"(%[[C1]], %[[C1]], %[[V1]]) 15// CHECK-NEXT: "test.use"(%[[C1]], %[[C2]], %[[V4]]) 16// CHECK-NEXT: "test.use"(%[[C2]], %[[C1]], %[[V3]]) 17func.func @sparse_foreach_constant() -> () { 18 %cst = arith.constant sparse<[[2, 1], [1, 1], [1, 2]], [1.0, 5.0, 6.0]> : tensor<8x7xf32> 19 // Make use the sparse constant are properly sorted based on the requested order. 20 sparse_tensor.foreach in %cst { order = affine_map<(d0, d1) -> (d1, d0)> } : tensor<8x7xf32> do { 21 ^bb0(%arg0: index, %arg1: index, %arg2: f32): 22 "test.use" (%arg0, %arg1, %arg2): (index,index,f32)->() 23 } 24 sparse_tensor.foreach in %cst : tensor<8x7xf32> do { 25 ^bb0(%arg0: index, %arg1: index, %arg2: f32): 26 "test.use" (%arg0, %arg1, %arg2): (index,index,f32)->() 27 } 28 return 29} 30 31#CSR_SLICE = #sparse_tensor.encoding<{ 32 map = (d0 : #sparse_tensor<slice(0, 4, 1)>, d1 : #sparse_tensor<slice(2, 4, 1)>) -> (d0 : compressed, d1 : compressed) 33}> 34 35#CSR_SLICE_DYN = #sparse_tensor.encoding<{ 36 map = (d0 : #sparse_tensor<slice(?, ?, ?)>, d1 : #sparse_tensor<slice(?, ?, ?)>) -> (d0 : compressed, d1 : compressed) 37}> 38 39// TODO: re-enable after lowering coo.next to function call (such that loop structure is more clear). 40 41// C_HECK-LABEL: func.func @foreach_print_slice_dyn( 42// C_HECK-SAME: %[[VAL_0:.*]]: tensor<?x?xf64, 43// C_HECK-DAG: %[[VAL_1:.*]] = arith.constant 0 : index 44// C_HECK-DAG: %[[VAL_2:.*]] = arith.constant 1 : index 45// C_HECK-DAG: %[[VAL_3:.*]] = sparse_tensor.positions %[[VAL_0]] {level = 0 : index} : tensor<?x?xf64, 46// C_HECK-DAG: %[[VAL_4:.*]] = sparse_tensor.coordinates %[[VAL_0]] {level = 0 : index} : tensor<?x?xf64, 47// C_HECK-DAG: %[[VAL_5:.*]] = sparse_tensor.lvl %[[VAL_0]], %[[VAL_1]] : tensor<?x?xf64, 48// C_HECK-DAG: %[[VAL_6:.*]] = sparse_tensor.slice.offset %[[VAL_0]] at 0 : tensor<?x?xf64, 49// C_HECK-DAG: %[[VAL_7:.*]] = sparse_tensor.slice.stride %[[VAL_0]] at 0 : tensor<?x?xf64, 50// C_HECK-DAG: %[[VAL_8:.*]] = sparse_tensor.positions %[[VAL_0]] {level = 1 : index} : tensor<?x?xf64, 51// C_HECK-DAG: %[[VAL_9:.*]] = sparse_tensor.coordinates %[[VAL_0]] {level = 1 : index} : tensor<?x?xf64, 52// C_HECK-DAG: %[[VAL_10:.*]] = sparse_tensor.lvl %[[VAL_0]], %[[VAL_2]] : tensor<?x?xf64, 53// C_HECK-DAG: %[[VAL_11:.*]] = sparse_tensor.slice.offset %[[VAL_0]] at 1 : tensor<?x?xf64, 54// C_HECK-DAG: %[[VAL_12:.*]] = sparse_tensor.slice.stride %[[VAL_0]] at 1 : tensor<?x?xf64, 55// C_HECK-DAG: %[[VAL_13:.*]] = sparse_tensor.values %[[VAL_0]] : tensor<?x?xf64, 56// C_HECK: %[[VAL_14:.*]] = memref.load %[[VAL_3]]{{\[}}%[[VAL_1]]] : memref<?xindex> 57// C_HECK: %[[VAL_15:.*]] = memref.load %[[VAL_3]]{{\[}}%[[VAL_2]]] : memref<?xindex> 58// C_HECK: scf.for %[[VAL_16:.*]] = %[[VAL_14]] to %[[VAL_15]] step %[[VAL_2]] { 59// C_HECK: %[[VAL_17:.*]] = memref.load %[[VAL_4]]{{\[}}%[[VAL_16]]] : memref<?xindex> 60// C_HECK: %[[VAL_18:.*]] = arith.subi %[[VAL_17]], %[[VAL_6]] : index 61// C_HECK: %[[VAL_19:.*]] = arith.remui %[[VAL_18]], %[[VAL_7]] : index 62// C_HECK: %[[VAL_20:.*]] = arith.divui %[[VAL_18]], %[[VAL_7]] : index 63// C_HECK: %[[VAL_21:.*]] = arith.cmpi uge, %[[VAL_17]], %[[VAL_6]] : index 64// C_HECK: %[[VAL_22:.*]] = arith.cmpi ult, %[[VAL_20]], %[[VAL_5]] : index 65// C_HECK: %[[VAL_23:.*]] = arith.cmpi eq, %[[VAL_19]], %[[VAL_1]] : index 66// C_HECK: %[[VAL_24:.*]] = arith.andi %[[VAL_21]], %[[VAL_22]] : i1 67// C_HECK: %[[VAL_25:.*]] = arith.andi %[[VAL_24]], %[[VAL_23]] : i1 68// C_HECK: scf.if %[[VAL_25]] { 69// C_HECK: %[[VAL_26:.*]] = memref.load %[[VAL_8]]{{\[}}%[[VAL_16]]] : memref<?xindex> 70// C_HECK: %[[VAL_27:.*]] = arith.addi %[[VAL_16]], %[[VAL_2]] : index 71// C_HECK: %[[VAL_28:.*]] = memref.load %[[VAL_8]]{{\[}}%[[VAL_27]]] : memref<?xindex> 72// C_HECK: scf.for %[[VAL_29:.*]] = %[[VAL_26]] to %[[VAL_28]] step %[[VAL_2]] { 73// C_HECK: %[[VAL_30:.*]] = memref.load %[[VAL_9]]{{\[}}%[[VAL_29]]] : memref<?xindex> 74// C_HECK: %[[VAL_31:.*]] = arith.subi %[[VAL_30]], %[[VAL_11]] : index 75// C_HECK: %[[VAL_32:.*]] = arith.remui %[[VAL_31]], %[[VAL_12]] : index 76// C_HECK: %[[VAL_33:.*]] = arith.divui %[[VAL_31]], %[[VAL_12]] : index 77// C_HECK: %[[VAL_34:.*]] = arith.cmpi uge, %[[VAL_30]], %[[VAL_11]] : index 78// C_HECK: %[[VAL_35:.*]] = arith.cmpi ult, %[[VAL_33]], %[[VAL_10]] : index 79// C_HECK: %[[VAL_36:.*]] = arith.cmpi eq, %[[VAL_32]], %[[VAL_1]] : index 80// C_HECK: %[[VAL_37:.*]] = arith.andi %[[VAL_34]], %[[VAL_35]] : i1 81// C_HECK: %[[VAL_38:.*]] = arith.andi %[[VAL_37]], %[[VAL_36]] : i1 82// C_HECK: scf.if %[[VAL_38]] { 83// C_HECK: %[[VAL_39:.*]] = memref.load %[[VAL_13]]{{\[}}%[[VAL_29]]] : memref<?xf64> 84// C_HECK: "test.use"(%[[VAL_39]]) : (f64) -> () 85// C_HECK: } 86// C_HECK: } 87// C_HECK: } 88// C_HECK: } 89// C_HECK: return 90// 91func.func @foreach_print_slice_dyn(%A: tensor<?x?xf64, #CSR_SLICE_DYN>) { 92 sparse_tensor.foreach in %A : tensor<?x?xf64, #CSR_SLICE_DYN> do { 93 ^bb0(%1: index, %2: index, %v: f64) : 94 "test.use" (%v) : (f64) -> () 95 } 96 return 97} 98 99// C_HECK-LABEL: func.func @foreach_print_slice( 100// C_HECK-SAME: %[[VAL_0:.*]]: tensor<4x4xf64, 101// C_HECK-DAG: %[[VAL_1:.*]] = arith.constant 4 : index 102// C_HECK-DAG: %[[VAL_2:.*]] = arith.constant 2 : index 103// C_HECK-DAG: %[[VAL_3:.*]] = arith.constant 0 : index 104// C_HECK-DAG: %[[VAL_4:.*]] = arith.constant 1 : index 105// C_HECK-DAG: %[[VAL_5:.*]] = sparse_tensor.positions %[[VAL_0]] {level = 0 : index} : tensor<4x4xf64, 106// C_HECK-DAG: %[[VAL_6:.*]] = sparse_tensor.coordinates %[[VAL_0]] {level = 0 : index} : tensor<4x4xf64, 107// C_HECK-DAG: %[[VAL_7:.*]] = sparse_tensor.positions %[[VAL_0]] {level = 1 : index} : tensor<4x4xf64, 108// C_HECK-DAG: %[[VAL_8:.*]] = sparse_tensor.coordinates %[[VAL_0]] {level = 1 : index} : tensor<4x4xf64, 109// C_HECK-DAG: %[[VAL_9:.*]] = sparse_tensor.values %[[VAL_0]] : tensor<4x4xf64, 110// C_HECK-DAG: %[[VAL_10:.*]] = memref.load %[[VAL_5]]{{\[}}%[[VAL_3]]] : memref<?xindex> 111// C_HECK: %[[VAL_11:.*]] = memref.load %[[VAL_5]]{{\[}}%[[VAL_4]]] : memref<?xindex> 112// C_HECK: scf.for %[[VAL_12:.*]] = %[[VAL_10]] to %[[VAL_11]] step %[[VAL_4]] { 113// C_HECK: %[[VAL_13:.*]] = memref.load %[[VAL_6]]{{\[}}%[[VAL_12]]] : memref<?xindex> 114// C_HECK: %[[VAL_14:.*]] = arith.cmpi ult, %[[VAL_13]], %[[VAL_1]] : index 115// C_HECK: scf.if %[[VAL_14]] { 116// C_HECK: %[[VAL_15:.*]] = memref.load %[[VAL_7]]{{\[}}%[[VAL_12]]] : memref<?xindex> 117// C_HECK: %[[VAL_16:.*]] = arith.addi %[[VAL_12]], %[[VAL_4]] : index 118// C_HECK: %[[VAL_17:.*]] = memref.load %[[VAL_7]]{{\[}}%[[VAL_16]]] : memref<?xindex> 119// C_HECK: scf.for %[[VAL_18:.*]] = %[[VAL_15]] to %[[VAL_17]] step %[[VAL_4]] { 120// C_HECK: %[[VAL_19:.*]] = memref.load %[[VAL_8]]{{\[}}%[[VAL_18]]] : memref<?xindex> 121// C_HECK: %[[VAL_20:.*]] = arith.subi %[[VAL_19]], %[[VAL_2]] : index 122// C_HECK: %[[VAL_21:.*]] = arith.cmpi uge, %[[VAL_19]], %[[VAL_2]] : index 123// C_HECK: %[[VAL_22:.*]] = arith.cmpi ult, %[[VAL_20]], %[[VAL_1]] : index 124// C_HECK: %[[VAL_23:.*]] = arith.andi %[[VAL_21]], %[[VAL_22]] : i1 125// C_HECK: scf.if %[[VAL_23]] { 126// C_HECK: %[[VAL_24:.*]] = memref.load %[[VAL_9]]{{\[}}%[[VAL_18]]] : memref<?xf64> 127// C_HECK: "test.use"(%[[VAL_24]]) : (f64) -> () 128// C_HECK: } 129// C_HECK: } 130// C_HECK: } 131// C_HECK: } 132// C_HECK: return 133// 134func.func @foreach_print_slice(%A: tensor<4x4xf64, #CSR_SLICE>) { 135 sparse_tensor.foreach in %A : tensor<4x4xf64, #CSR_SLICE> do { 136 ^bb0(%1: index, %2: index, %v: f64) : 137 "test.use" (%v) : (f64) -> () 138 } 139 return 140} 141 142#BCOO = #sparse_tensor.encoding<{ 143 map = (d0, d1, d2) -> (d0 : dense, d1 : loose_compressed(nonunique), d2 : singleton) 144}> 145 146// C_HECK-LABEL: func.func @foreach_bcoo( 147// C_HECK-SAME: %[[VAL_0:.*]]: tensor<4x4x4xf64, #sparse{{[0-9]*}}>) { 148// C_HECK-DAG: %[[VAL_1:.*]] = arith.constant 4 : index 149// C_HECK-DAG: %[[VAL_2:.*]] = arith.constant 0 : index 150// C_HECK-DAG: %[[VAL_3:.*]] = arith.constant 1 : index 151// C_HECK-DAG: %[[VAL_4:.*]] = arith.constant 2 : index 152// C_HECK-DAG: %[[VAL_5:.*]] = sparse_tensor.positions %[[VAL_0]] {level = 1 : index} : tensor<4x4x4xf64, #sparse{{[0-9]*}}> to memref<?xindex> 153// C_HECK-DAG: %[[VAL_6:.*]] = sparse_tensor.values %[[VAL_0]] : tensor<4x4x4xf64, #sparse{{[0-9]*}}> to memref<?xf64> 154// C_HECK: scf.for %[[VAL_7:.*]] = %[[VAL_2]] to %[[VAL_1]] step %[[VAL_3]] { 155// C_HECK: %[[VAL_8:.*]] = arith.muli %[[VAL_7]], %[[VAL_4]] : index 156// C_HECK: %[[VAL_9:.*]] = memref.load %[[VAL_5]]{{\[}}%[[VAL_8]]] : memref<?xindex> 157// C_HECK: %[[VAL_10:.*]] = arith.addi %[[VAL_8]], %[[VAL_3]] : index 158// C_HECK: %[[VAL_11:.*]] = memref.load %[[VAL_5]]{{\[}}%[[VAL_10]]] : memref<?xindex> 159// C_HECK: scf.for %[[VAL_12:.*]] = %[[VAL_9]] to %[[VAL_11]] step %[[VAL_3]] { 160// C_HECK: %[[VAL_13:.*]] = memref.load %[[VAL_6]]{{\[}}%[[VAL_12]]] : memref<?xf64> 161// C_HECK: "test.use"(%[[VAL_13]]) : (f64) -> () 162// C_HECK: } {"Emitted from" = "sparse_tensor.foreach"} 163// C_HECK: } {"Emitted from" = "sparse_tensor.foreach"} 164// C_HECK: return 165// C_HECK: } 166func.func @foreach_bcoo(%A: tensor<4x4x4xf64, #BCOO>) { 167 sparse_tensor.foreach in %A : tensor<4x4x4xf64, #BCOO> do { 168 ^bb0(%1: index, %2: index, %3: index, %v: f64) : 169 "test.use" (%v) : (f64) -> () 170 } 171 return 172} 173