| 12
 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
 
 | // RUN: mlir-opt %s | mlir-opt | FileCheck %s --check-prefix=CHECK-ROUND
// RUN: mlir-opt %s --lower-sparse-ops-to-foreach="enable-runtime-library=true enable-convert=false" \
// RUN: --lower-sparse-foreach-to-scf --cse --canonicalize  | FileCheck %s
// RUN: mlir-opt %s --lower-sparse-ops-to-foreach="enable-runtime-library=false enable-convert=false" \
// RUN: --lower-sparse-foreach-to-scf --cse --canonicalize  | FileCheck %s
#SparseVector = #sparse_tensor.encoding<{ map = (d0) -> (d0 : compressed) }>
#SparseMatrix = #sparse_tensor.encoding<{ map = (d0, d1) -> (d0 : compressed, d1 : compressed) }>
//
// roundtrip:
//
// CHECK-ROUND-LABEL: func.func @sparse_expand(
// CHECK-ROUND-SAME:  %[[A:.*]]: tensor<100xf64, #sparse{{[0-9]*}}>) -> tensor<10x10xf64, #sparse{{[0-9]*}}>
//      CHECK-ROUND:  %[[E:.*]] = tensor.expand_shape %[[A]] {{\[\[}}0, 1]] : tensor<100xf64, #sparse{{[0-9]*}}> into tensor<10x10xf64, #sparse{{[0-9]*}}>
//      CHECK-ROUND:  return %[[E]] : tensor<10x10xf64, #sparse{{[0-9]*}}>
//
// CHECK-LABEL:   func.func @sparse_expand(
// CHECK-SAME:    %[[S:.*0]]:
// CHECK-DAG:     %[[C10:.*]] = arith.constant 10 : index
// CHECK-DAG:     %[[C0:.*]] = arith.constant 0 : index
// CHECK-DAG:     %[[C1:.*]] = arith.constant 1 : index
// CHECK:         %[[B:.*]] = bufferization.alloc_tensor()
// CHECK:         %[[P0:.*]] = sparse_tensor.positions %[[S]] {level = 0 : index}
// CHECK:         %[[I0:.*]] = sparse_tensor.coordinates %[[S]] {level = 0 : index}
// CHECK:         %[[V:.*]] = sparse_tensor.values %[[S]]
// CHECK:         %[[S0:.*]] = memref.load %[[P0]]{{\[}}%[[C0]]] : memref<?xindex>
// CHECK:         %[[E0:.*]] = memref.load %[[P0]]{{\[}}%[[C1]]] : memref<?xindex>
// CHECK:         %[[RET:.*]] = scf.for %[[I:.*]] = %[[S0]] to %[[E0]] step %[[C1]] iter_args(%[[R:.*]] = %[[B]])
// CHECK:           %[[SI:.*]] = memref.load %[[I0]]{{\[}}%[[I]]] : memref<?xindex>
// CHECK:           %[[SV:.*]] = memref.load %[[V]]{{\[}}%[[I]]] : memref<?xf64>
// CHECK:           %[[DI0:.*]] = arith.divui %[[SI]], %[[C10]] : index
// CHECK:           %[[DI1:.*]] = arith.remui %[[SI]], %[[C10]] : index
// CHECK:           %[[NT:.*]] = sparse_tensor.insert %[[SV]] into %[[R]]{{\[}}%[[DI0]], %[[DI1]]]
// CHECK:           scf.yield %[[NT:.*]]
// CHECK:         }
// CHECK:         %[[NT1:.*]] = sparse_tensor.load %[[RET]] hasInserts
// CHECK-NOT:     sparse_tensor.convert
// CHECK:         return %[[NT1]] : tensor<10x10xf64, #sparse{{[0-9]*}}>
//
func.func @sparse_expand(%arg0: tensor<100xf64, #SparseVector>) -> tensor<10x10xf64, #SparseMatrix> {
  %0 = tensor.expand_shape %arg0 [[0, 1]] :
    tensor<100xf64, #SparseVector> into tensor<10x10xf64, #SparseMatrix>
  return %0 : tensor<10x10xf64, #SparseMatrix>
}
//
// roundtrip:
//
// CHECK-ROUND-LABEL: func.func @sparse_collapse(
// CHECK-ROUND-SAME:  %[[A:.*]]: tensor<10x10xf64, #sparse{{[0-9]*}}>) -> tensor<100xf64, #sparse{{[0-9]*}}>
//      CHECK-ROUND:  %[[C:.*]] = tensor.collapse_shape %[[A]] {{\[\[}}0, 1]] : tensor<10x10xf64, #sparse{{[0-9]*}}> into tensor<100xf64, #sparse{{[0-9]*}}>
//      CHECK-ROUND:  return %[[C]] : tensor<100xf64, #sparse{{[0-9]*}}>
//
// CHECK-LABEL:   func.func @sparse_collapse(
// CHECK-SAME:    %[[S:.*0]]:
// CHECK-DAG:     %[[C10:.*]] = arith.constant 10 : index
// CHECK-DAG:     %[[C0:.*]] = arith.constant 0 : index
// CHECK-DAG:     %[[C1:.*]] = arith.constant 1 : index
// CHECK:         %[[B:.*]] = bufferization.alloc_tensor()
// CHECK:         %[[P0:.*]] = sparse_tensor.positions %[[S]] {level = 0 : index}
// CHECK:         %[[I0:.*]] = sparse_tensor.coordinates %[[S]] {level = 0 : index}
// CHECK:         %[[P1:.*]] = sparse_tensor.positions %[[S]] {level = 1 : index}
// CHECK:         %[[I1:.*]] = sparse_tensor.coordinates %[[S]] {level = 1 : index}
// CHECK:         %[[V:.*]] = sparse_tensor.values %[[S]]
// CHECK:         %[[S0:.*]] = memref.load %[[P0]]{{\[}}%[[C0]]] : memref<?xindex>
// CHECK:         %[[E0:.*]] = memref.load %[[P0]]{{\[}}%[[C1]]] : memref<?xindex>
// CHECK:         %[[RET:.*]] = scf.for %[[I:.*]] = %[[S0]] to %[[E0]] step %[[C1]] iter_args(%[[A0:.*]] = %[[B]])
// CHECK:           %[[SI0:.*]] = memref.load %[[I0]]{{\[}}%[[I]]] : memref<?xindex>
// CHECK-DAG:       %[[S1:.*]] = memref.load %[[P1]]{{\[}}%[[I]]] : memref<?xindex>
// CHECK-DAG:       %[[PE1:.*]] = arith.addi %[[I]], %[[C1]] : index
// CHECK:           %[[E1:.*]] = memref.load %[[P1]]{{\[}}%[[PE1]]] : memref<?xindex>
// CHECK:           %[[RET_1:.*]] = scf.for %[[J:.*]] = %[[S1]] to %[[E1]] step %[[C1]] iter_args(%[[A1:.*]] = %[[A0]])
// CHECK:             %[[SI1:.*]] = memref.load %[[I1]]{{\[}}%[[J]]] : memref<?xindex>
// CHECK:             %[[SV:.*]] = memref.load %[[V]]{{\[}}%[[J]]] : memref<?xf64>
// CHECK:             %[[T:.*]] = arith.muli %[[SI0]], %[[C10]] : index
// CHECK:             %[[DI:.*]] = arith.addi %[[T]], %[[SI1]] : index
// CHECK:             %[[R1:.*]] = sparse_tensor.insert %[[SV]] into %[[A1]]{{\[}}%[[DI]]]
// CHECK              scf.yield %[[R1]]
// CHECK            }
// CHECK            scf.yield %[[RET_1]]
// CHECK:         }
// CHECK:        %[[NT1:.*]] = sparse_tensor.load %[[RET]] hasInserts
// CHECK-NOT:    sparse_tensor.convert
// CHECK:        return %[[NT1]] : tensor<100xf64, #sparse{{[0-9]*}}>
//
func.func @sparse_collapse(%arg0: tensor<10x10xf64, #SparseMatrix>) -> tensor<100xf64, #SparseVector> {
  %0 = tensor.collapse_shape %arg0 [[0, 1]] :
    tensor<10x10xf64, #SparseMatrix> into tensor<100xf64, #SparseVector>
  return %0 : tensor<100xf64, #SparseVector>
}
//
// roundtrip:
//
// CHECK-ROUND-LABEL: func.func @dynamic_sparse_expand(
// CHECK-ROUND-SAME:  %[[A:.*]]: tensor<?xf64, #sparse{{[0-9]*}}>) -> tensor<?x10xf64, #sparse{{[0-9]*}}>
//      CHECK-ROUND:  %[[E:.*]] = tensor.expand_shape %[[A]] {{\[\[}}0, 1]] : tensor<?xf64, #sparse{{[0-9]*}}> into tensor<?x10xf64, #sparse{{[0-9]*}}>
//      CHECK-ROUND:  return %[[E]] : tensor<?x10xf64, #sparse{{[0-9]*}}>
//
// CHECK-LABEL:   func.func @dynamic_sparse_expand(
// CHECK-SAME:    %[[S:.*0]]:
// CHECK-DAG:     %[[C10:.*]] = arith.constant 10 : index
// CHECK-DAG:     %[[C0:.*]] = arith.constant 0 : index
// CHECK-DAG:     %[[C1:.*]] = arith.constant 1 : index
// CHECK:         %[[SD:.*]] = sparse_tensor.lvl %[[S]], %[[C0]]
// CHECK:         %[[DD0:.*]] = arith.divui %[[SD]], %[[C10]] : index
// CHECK:         %[[B:.*]] = bufferization.alloc_tensor(%[[DD0]])
// CHECK:         %[[P0:.*]] = sparse_tensor.positions %[[S]] {level = 0 : index}
// CHECK:         %[[I0:.*]] = sparse_tensor.coordinates %[[S]] {level = 0 : index}
// CHECK:         %[[V:.*]] = sparse_tensor.values %[[S]]
// CHECK:         %[[S0:.*]] = memref.load %[[P0]]{{\[}}%[[C0]]] : memref<?xindex>
// CHECK:         %[[E0:.*]] = memref.load %[[P0]]{{\[}}%[[C1]]] : memref<?xindex>
// CHECK:         %[[RET:.*]] = scf.for %[[I:.*]] = %[[S0]] to %[[E0]] step %[[C1]] iter_args(%[[R:.*]] = %[[B]])
// CHECK:           %[[SI:.*]] = memref.load %[[I0]]{{\[}}%[[I]]] : memref<?xindex>
// CHECK:           %[[SV:.*]] = memref.load %[[V]]{{\[}}%[[I]]] : memref<?xf64>
// CHECK:           %[[T1:.*]] = arith.muli %[[DD0]], %[[C10]] : index
// CHECK:           %[[T2:.*]] = arith.divui %[[T1]], %[[DD0]] : index
// CHECK:           %[[DI0:.*]] = arith.divui %[[SI]], %[[T2]] : index
// CHECK:           %[[T3:.*]] = arith.remui %[[SI]], %[[T2]] : index
// CHECK:           %[[T4:.*]] = arith.divui %[[T2]], %[[C10]] : index
// CHECK:           %[[DI1:.*]] = arith.divui %[[T3]], %[[T4]] : index
// CHECK:           %[[NT:.*]] = sparse_tensor.insert %[[SV]] into %[[R]]{{\[}}%[[DI0]], %[[DI1]]]
// CHECK:           scf.yield %[[NT]]
// CHECK:         }
// CHECK:         %[[NT1:.*]] = sparse_tensor.load %[[RET]] hasInserts
// CHECK-NOT:     sparse_tensor.convert
// CHECK:         return %[[NT1]] : tensor<?x10xf64, #sparse{{[0-9]*}}>
//
func.func @dynamic_sparse_expand(%arg0: tensor<?xf64, #SparseVector>) -> tensor<?x10xf64, #SparseMatrix> {
  %0 = tensor.expand_shape %arg0 [[0, 1]] :
    tensor<?xf64, #SparseVector> into tensor<?x10xf64, #SparseMatrix>
  return %0 : tensor<?x10xf64, #SparseMatrix>
}
//
// roundtrip:
//
// CHECK-ROUND-LABEL: func.func @dynamic_sparse_collapse(
// CHECK-ROUND-SAME:  %[[A:.*]]: tensor<10x?xf64, #sparse{{[0-9]*}}>) -> tensor<?xf64, #sparse{{[0-9]*}}>
//      CHECK-ROUND:  %[[C:.*]] = tensor.collapse_shape %[[A]] {{\[\[}}0, 1]] : tensor<10x?xf64, #sparse{{[0-9]*}}> into tensor<?xf64, #sparse{{[0-9]*}}>
//      CHECK-ROUND:  return %[[C]] : tensor<?xf64, #sparse{{[0-9]*}}>
//
// CHECK-LABEL:   func.func @dynamic_sparse_collapse(
// CHECK-SAME:    %[[S:.*0]]:
// CHECK-DAG:     %[[C10:.*]] = arith.constant 10 : index
// CHECK-DAG:     %[[C0:.*]] = arith.constant 0 : index
// CHECK-DAG:     %[[C1:.*]] = arith.constant 1 : index
// CHECK:         %[[SD1:.*]] = sparse_tensor.lvl %[[S]], %[[C1]]
// CHECK:         %[[DD0:.*]] = arith.muli %[[SD1]], %[[C10]] : index
// CHECK:         %[[B:.*]] = bufferization.alloc_tensor(%[[DD0]])
// CHECK:         %[[P0:.*]] = sparse_tensor.positions %[[S]] {level = 0 : index}
// CHECK:         %[[I0:.*]] = sparse_tensor.coordinates %[[S]] {level = 0 : index}
// CHECK:         %[[P1:.*]] = sparse_tensor.positions %[[S]] {level = 1 : index}
// CHECK:         %[[I1:.*]] = sparse_tensor.coordinates %[[S]] {level = 1 : index}
// CHECK:         %[[V:.*]] = sparse_tensor.values %[[S]]
// CHECK:         %[[S0:.*]] = memref.load %[[P0]]{{\[}}%[[C0]]] : memref<?xindex>
// CHECK:         %[[E0:.*]] = memref.load %[[P0]]{{\[}}%[[C1]]] : memref<?xindex>
// CHECK:         %[[RET:.*]] = scf.for %[[I:.*]] = %[[S0]] to %[[E0]] step %[[C1]] iter_args(%[[R0:.*]] = %[[B]])
// CHECK:           %[[SI0:.*]] = memref.load %[[I0]]{{\[}}%[[I]]] : memref<?xindex>
// CHECK-DAG:       %[[S1:.*]] = memref.load %[[P1]]{{\[}}%[[I]]] : memref<?xindex>
// CHECK-DAG:       %[[PE1:.*]] = arith.addi %[[I]], %[[C1]] : index
// CHECK:           %[[E1:.*]] = memref.load %[[P1]]{{\[}}%[[PE1]]] : memref<?xindex>
// CHECK:           %[[RET_1:.*]] = scf.for %[[J:.*]] = %[[S1]] to %[[E1]] step %[[C1]] iter_args(%[[R1:.*]] = %[[R0]])
// CHECK:             %[[SI1:.*]] = memref.load %[[I1]]{{\[}}%[[J]]] : memref<?xindex>
// CHECK:             %[[SV:.*]] = memref.load %[[V]]{{\[}}%[[J]]] : memref<?xf64>
// CHECK:             %[[T1:.*]] = arith.divui %[[DD0]], %[[C10]] : index
// CHECK:             %[[T2:.*]] = arith.muli %[[SI0]], %[[T1]] : index
// CHECK:             %[[T3:.*]] = arith.divui %[[T1]], %[[SD1]] : index
// CHECK:             %[[T4:.*]] = arith.muli %[[SI1]], %[[T3]] : index
// CHECK:             %[[DI:.*]] = arith.addi %[[T2]], %[[T4]] : index
// CHECK:             %[[NT:.*]] = sparse_tensor.insert %[[SV]] into %[[R1]]{{\[}}%[[DI]]]
// CHECK              scf.yield %[[NT]]
// CHECK            }
// CHECK            scf.yield %[[RET_1]]
// CHECK:        }
// CHECK:        %[[NT1:.*]] = sparse_tensor.load %[[RET]] hasInserts
// CHECK-NOT:    sparse_tensor.convert
// CHECK:        return %[[NT1]] : tensor<?xf64, #sparse{{[0-9]*}}>
//
func.func @dynamic_sparse_collapse(%arg0: tensor<10x?xf64, #SparseMatrix>) -> tensor<?xf64, #SparseVector> {
  %0 = tensor.collapse_shape %arg0 [[0, 1]] :
    tensor<10x?xf64, #SparseMatrix> into tensor<?xf64, #SparseVector>
  return %0 : tensor<?xf64, #SparseVector>
}
 |