File: fusion-sequence.mlir

package info (click to toggle)
llvm-toolchain-13 1%3A13.0.1-11
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,418,840 kB
  • sloc: cpp: 5,290,826; ansic: 996,570; asm: 544,593; python: 188,212; objc: 72,027; lisp: 30,291; f90: 25,395; sh: 24,898; javascript: 9,780; pascal: 9,398; perl: 7,484; ml: 5,432; awk: 3,523; makefile: 2,913; xml: 953; cs: 573; fortran: 539
file content (260 lines) | stat: -rw-r--r-- 13,764 bytes parent folder | download | duplicates (3)
1
2
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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
// RUN: mlir-opt -pass-pipeline="func(test-linalg-tile-and-fuse{tile-sizes=16,32,64}),resolve-shaped-type-result-dims,canonicalize,cse" -split-input-file %s | FileCheck %s

module {
  func @three_op_fusion(%arg0: memref<?x?xf32>, %arg1: memref<?x?xf32>,
                        %arg2: memref<?xf32>, %arg3 : memref<?x?xf32>) {
    %cst = constant 0.000000e+00 : f32
    %c0 = constant 0 : index
    %c1 = constant 1 : index
    %d0 = memref.dim %arg0, %c0 : memref<?x?xf32>
    %d1 = memref.dim %arg1, %c1 : memref<?x?xf32>
    %0 = memref.alloc(%d0, %d1) : memref<?x?xf32>
    linalg.fill(%cst, %0) : f32, memref<?x?xf32>
    linalg.matmul ins(%arg0, %arg1 : memref<?x?xf32>, memref<?x?xf32>)
      outs(%0 : memref<?x?xf32>)
    linalg.generic
      {indexing_maps = [affine_map<(d0, d1) -> (d0, d1)>,
                        affine_map<(d0, d1) -> (d1)>,
                        affine_map<(d0, d1) -> (d0, d1)>],
       iterator_types = ["parallel", "parallel"]}
      ins(%0, %arg2 : memref<?x?xf32>, memref<?xf32>)
      outs(%arg3 : memref<?x?xf32>) {
      ^bb0(%arg4 : f32, %arg5 : f32, %arg6 : f32) :
        %5 = addf %arg4, %arg5 : f32
        linalg.yield %5 : f32
      }
    return
  }
}

//   CHECK-DAG: #[[MAP2:.+]] = affine_map<(d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)>
//   CHECK-DAG: #[[MAP3:.+]] = affine_map<(d0)[s0] -> (d0 + s0)>
//       CHECK: func @three_op_fusion
//  CHECK-SAME:   %[[ARG0:[a-zA-Z0-9_]+]]: memref<?x?xf32>
//  CHECK-SAME:   %[[ARG1:[a-zA-Z0-9_]+]]: memref<?x?xf32>
//  CHECK-SAME:   %[[ARG2:[a-zA-Z0-9_]+]]: memref<?xf32>
//  CHECK-SAME:   %[[ARG3:[a-zA-Z0-9_]+]]: memref<?x?xf32>
//       CHECK:   %[[TEMP:.+]] = memref.alloc(%{{.*}}, %{{.*}}) : memref<?x?xf32>
//       CHECK:   scf.parallel (%[[IV0:.+]], %[[IV1:.+]]) = {{.*}} {
//       CHECK:     %[[SV_TEMP_1:.+]] = memref.subview %[[TEMP]][%[[IV0]], %[[IV1]]]
//   CHECK-DAG:     %[[SV_ARG2:.+]] = memref.subview %[[ARG2]][%[[IV1]]]
//   CHECK-DAG:     %[[SV_ARG3:.+]] = memref.subview %[[ARG3]][%[[IV0]], %[[IV1]]]
//   CHECK-DAG:     %[[SV_ARG0:.+]] = memref.subview %[[ARG0]][%[[IV0]], 0]
//   CHECK-DAG:     %[[SV_ARG1:.+]] = memref.subview %[[ARG1]][0, %[[IV1]]]
//       CHECK:     %[[SV_TEMP_2:.+]] = memref.subview %[[TEMP]][%[[IV0]], %[[IV1]]]
//       CHECK:     linalg.fill(%{{.+}}, %[[SV_TEMP_2]])
//       CHECK:     linalg.matmul
//  CHECK-SAME:       ins(%[[SV_ARG0]], %[[SV_ARG1]]
//  CHECK-SAME:         : memref<?x?xf32, #[[MAP2]]>, memref<?x?xf32, #[[MAP2]]>)
//  CHECK-SAME:       outs(%[[SV_TEMP_2]] : memref<?x?xf32, #[[MAP2]]>)
//       CHECK:     linalg.generic
//  CHECK-SAME:       ins(%[[SV_TEMP_1]], %[[SV_ARG2]]
//  CHECK-SAME:         : memref<?x?xf32, #[[MAP2]]>, memref<?xf32, #[[MAP3]]>)
//  CHECK-SAME:       outs(%[[SV_ARG3]] : memref<?x?xf32, #[[MAP2]]>)
//       CHECK:     scf.yield
//       CHECK:   }

// -----

module {
  func @sequence_of_matmul(%arg0: memref<?x?xf32>, %arg1: memref<?x?xf32>,
                           %arg2: memref<?x?xf32>, %arg3: memref<?x?xf32>,
                           %arg4: memref<?x?xf32>) {
    %cst = constant 0.000000e+00 : f32
    %c0 = constant 0 : index
    %c1 = constant 1 : index
    %m = memref.dim %arg0, %c0 : memref<?x?xf32>
    %n1 = memref.dim %arg1, %c1 : memref<?x?xf32>
    %n2 = memref.dim %arg2, %c1 : memref<?x?xf32>
    %n3 = memref.dim %arg3, %c1 : memref<?x?xf32>
    %0 = memref.alloc(%m, %n1) : memref<?x?xf32>
    %1 = memref.alloc(%m, %n2) : memref<?x?xf32>
    linalg.fill(%cst, %0) : f32, memref<?x?xf32>
    linalg.matmul ins(%arg0, %arg1 : memref<?x?xf32>, memref<?x?xf32>)
      outs(%0 : memref<?x?xf32>)
    linalg.fill(%cst, %1) : f32, memref<?x?xf32>
    linalg.matmul ins(%0, %arg2 : memref<?x?xf32>, memref<?x?xf32>)
      outs(%1 : memref<?x?xf32>)
    linalg.fill(%cst, %arg4) : f32, memref<?x?xf32>
    linalg.matmul ins(%1, %arg3 : memref<?x?xf32>, memref<?x?xf32>)
      outs(%arg4 : memref<?x?xf32>)
    return
  }
}

//   CHECK-DAG: #[[MAP0:.+]] = affine_map<(d0)[s0] -> (16, -d0 + s0)>
//   CHECK-DAG: #[[MAP1:.+]] = affine_map<(d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)>
//   CHECK-DAG: #[[MAP2:.+]] = affine_map<(d0)[s0, s1] -> (-d0 + s0, 16, -d0 + s1)>
//   CHECK-DAG: #[[MAP3:.+]] = affine_map<(d0)[s0] -> (-d0 + s0, 16)>


//       CHECK: func @sequence_of_matmul
//  CHECK-SAME:   %[[ARG0:[a-zA-Z0-9_]+]]: memref<?x?xf32>
//  CHECK-SAME:   %[[ARG1:[a-zA-Z0-9_]+]]: memref<?x?xf32>
//  CHECK-SAME:   %[[ARG2:[a-zA-Z0-9_]+]]: memref<?x?xf32>
//  CHECK-SAME:   %[[ARG3:[a-zA-Z0-9_]+]]: memref<?x?xf32>
//  CHECK-SAME:   %[[ARG4:[a-zA-Z0-9_]+]]: memref<?x?xf32>
//   CHECK-DAG:   %[[C0:.+]] = constant 0 : index
//   CHECK-DAG:   %[[C1:.+]] = constant 1 : index
//   CHECK-DAG:   %[[C16:.+]] = constant 16 : index
//   CHECK-DAG:   %[[M:.+]] = memref.dim %[[ARG0]], %[[C0]]
//   CHECK-DAG:   %[[N1:.+]] = memref.dim %[[ARG1]], %[[C1]]
//   CHECK-DAG:   %[[N2:.+]] = memref.dim %[[ARG2]], %[[C1]]
//       CHECK:   %[[ALLOC1:.+]] = memref.alloc(%[[M]], %[[N1]])
//       CHECK:   %[[ALLOC2:.+]] = memref.alloc(%[[M]], %[[N2]])
//       CHECK:   scf.parallel (%[[IV0:.+]]) = (%[[C0]]) to (%[[M]])
//  CHECK-SAME:     step (%[[C16]]) {
//       CHECK:     %[[TILE_M:.+]] = affine.min #[[MAP0]](%[[IV0]])[%[[M]]]
//       CHECK:     %[[SV_ALLOC3:.+]] = memref.subview %[[ALLOC2]][%[[IV0]], 0]
//  CHECK-SAME:       [%[[TILE_M]], %[[N2]]]
//       CHECK:     %[[M_2:.+]] = memref.dim %[[ARG4]], %[[C0]]
//       CHECK:     %[[TILE_M_2:.+]] = affine.min #[[MAP0]](%[[IV0]])[%[[M_2]]]
//       CHECK:     %[[N3:.+]] = memref.dim %[[ARG4]], %[[C1]]
//       CHECK:     %[[SV_ARG4:.+]] = memref.subview %[[ARG4]][%[[IV0]], 0]
//  CHECK-SAME:       [%[[TILE_M_2]], %[[N3]]]
//       CHECK:     %[[TILE_M_3:.+]] = affine.min #[[MAP2]](%[[IV0]])[%[[M_2]], %[[M]]]
//       CHECK:     %[[SV_ARG4_2:.+]] = memref.subview %[[ARG4]][%[[IV0]], 0]
//  CHECK-SAME:       [%[[TILE_M_3]], %[[N3]]]
//       CHECK:     %[[TILE_M_4:.+]] = affine.min #[[MAP3]](%[[IV0]])[%[[M]]]
//       CHECK:     %[[SV_ALLOC1:.+]] = memref.subview %[[ALLOC1]][%[[IV0]], 0]
//  CHECK-SAME:       [%[[TILE_M_4]], %[[N1]]]
//       CHECK:     %[[SV_ALLOC2:.+]] = memref.subview %[[ALLOC2]][%[[IV0]], 0]
//  CHECK-SAME:       [%[[TILE_M_4]], %[[N2]]]
//       CHECK:     %[[TILE_M_5:.+]] = affine.min #[[MAP2]](%[[IV0]])[%[[M]], %[[M]]]
//       CHECK:     %[[N0:.+]] = memref.dim %[[ARG0]], %[[C1]]
//       CHECK:     %[[SV_ARG0:.+]] = memref.subview %[[ARG0]][%[[IV0]], 0]
//  CHECK-SAME:       [%[[TILE_M_5]], %[[N0]]]
//       CHECK:     linalg.fill(%{{.+}}, %[[SV_ALLOC1]])
//       CHECK:     linalg.matmul ins(%[[SV_ARG0]], %[[ARG1]]
//  CHECK-SAME:        : memref<?x?xf32, #[[MAP1]]>, memref<?x?xf32>)
//  CHECK-SAME:        outs(%[[SV_ALLOC1]] : memref<?x?xf32, #[[MAP1]]>)
//       CHECK:     linalg.fill(%{{.+}}, %[[SV_ALLOC2]])
//       CHECK:     linalg.matmul ins(%[[SV_ALLOC1]], %[[ARG2]]
//  CHECK-SAME:        : memref<?x?xf32, #[[MAP1]]>, memref<?x?xf32>)
//  CHECK-SAME:        outs(%[[SV_ALLOC2]] : memref<?x?xf32, #[[MAP1]]>)
//       CHECK:     linalg.fill(%{{.+}}, %[[SV_ARG4_2]])
//       CHECK:     linalg.matmul ins(%[[SV_ALLOC3]], %[[ARG3]]
//  CHECK-SAME:        : memref<?x?xf32, #[[MAP1]]>, memref<?x?xf32>)
//  CHECK-SAME:        outs(%[[SV_ARG4]] : memref<?x?xf32, #[[MAP1]]>)
//       CHECK:     scf.yield
//       CHECK:   }


// -----

module {
  func @tensor_op_fusion(%arg0: tensor<?x?xf32>, %arg1: tensor<?x?xf32>,
                         %arg2: tensor<?x?xf32>, %arg3: tensor<?xf32>)
    -> tensor<?x?xf32> {
    %c0 = constant 0 : index
    %c1 = constant 1 : index
    %0 = linalg.matmul ins(%arg0, %arg1 : tensor<?x?xf32>, tensor<?x?xf32>)
      outs(%arg2 : tensor<?x?xf32>) -> tensor<?x?xf32>
    %1 = tensor.dim %0, %c0 : tensor<?x?xf32>
    %2 = tensor.dim %0, %c1 : tensor<?x?xf32>
    %3 = linalg.init_tensor [%1, %2] : tensor<?x?xf32>
    %4 = linalg.generic
      {indexing_maps = [affine_map<(d0, d1) -> (d0, d1)>,
                        affine_map<(d0, d1) -> (d0)>,
                        affine_map<(d0, d1) -> (d0, d1)>],
       iterator_types = ["parallel", "parallel"]}
      ins(%0, %arg3 : tensor<?x?xf32>, tensor<?xf32>)
      outs(%3 : tensor<?x?xf32>) {
      ^bb0(%arg4: f32, %arg5: f32, %arg6: f32):
        %5 = addf %arg4, %arg5 : f32
        linalg.yield %5 : f32
      } -> tensor<?x?xf32>
    return %4 : tensor<?x?xf32>
  }
}
// CHECK-LABEL: func @tensor_op_fusion
//  CHECK-SAME:   %[[ARG0:[a-zA-Z0-9_]+]]: tensor<?x?xf32>
//  CHECK-SAME:   %[[ARG1:[a-zA-Z0-9_]+]]: tensor<?x?xf32>
//  CHECK-SAME:   %[[ARG2:[a-zA-Z0-9_]+]]: tensor<?x?xf32>
//  CHECK-SAME:   %[[ARG3:[a-zA-Z0-9_]+]]: tensor<?xf32>
//       CHECK:   %[[INIT:.+]] = linalg.init_tensor
//       CHECK:   %[[R0:.+]] = scf.for %{{.+}} to %{{.+}} step %{{.+}} iter_args(%[[ARG5:.+]] = %[[INIT]]) -> (tensor<?x?xf32>) {
//       CHECK:     %[[R1:.+]] = scf.for %{{.+}} to %{{.+}} step %{{.+}} iter_args(%[[ARG7:.+]] = %[[ARG5]]) -> (tensor<?x?xf32>) {
//   CHECK-DAG:       %[[STARG3:.+]] = tensor.extract_slice %[[ARG3]]
//   CHECK-DAG:       %[[STARG7:.+]] = tensor.extract_slice %[[ARG7]]
//   CHECK-DAG:       %[[STARG0:.+]] = tensor.extract_slice %[[ARG0]]
//   CHECK-DAG:       %[[STARG1:.+]] = tensor.extract_slice %[[ARG1]]
//   CHECK-DAG:       %[[STARG2:.+]] = tensor.extract_slice %[[ARG2]]
//       CHECK:       %[[T0:.+]] = linalg.matmul
//  CHECK-SAME:         ins(%[[STARG0]], %[[STARG1]] : tensor<?x?xf32>, tensor<?x?xf32>)
//  CHECK-SAME:         outs(%[[STARG2]] : tensor<?x?xf32>) -> tensor<?x?xf32>
//       CHECK:       %[[T1:.+]] = linalg.generic
//  CHECK-SAME:         ins(%[[T0:.+]], %[[STARG3]] : tensor<?x?xf32>, tensor<?xf32>)
//  CHECK-SAME:         outs(%[[STARG7]] : tensor<?x?xf32>)
//       CHECK:       %[[RESULT:.+]] = tensor.insert_slice %[[T1]] into %[[ARG7]]
//       CHECK:       scf.yield %[[RESULT]]
//       CHECK:     }
//       CHECK:     scf.yield %[[R1]]
//       CHECK:   }
//       CHECK:   return %[[R0]]

// -----

module {
  func @tensor_matmul_fusion(%arg0: tensor<?x?xf32>, %arg1: tensor<?x?xf32>,
                             %arg2: tensor<?x?xf32>, %arg3: tensor<?x?xf32>,
           %arg4: tensor<?x?xf32>, %arg5: tensor<?x?xf32>,
           %arg6: tensor<?x?xf32>) -> tensor<?x?xf32> {
    %0 = linalg.matmul ins(%arg0, %arg1 : tensor<?x?xf32>, tensor<?x?xf32>)
      outs(%arg2 : tensor<?x?xf32>) -> tensor<?x?xf32> // [M, N0] * [N0, N1]
    %1 = linalg.matmul ins(%0, %arg3 : tensor<?x?xf32>, tensor<?x?xf32>)
      outs(%arg4 : tensor<?x?xf32>) -> tensor<?x?xf32> // [M, N1] * [N1, N2]
    %2 = linalg.matmul ins(%1, %arg5 : tensor<?x?xf32>, tensor<?x?xf32>)
      outs(%arg6 : tensor<?x?xf32>) -> tensor<?x?xf32> // [M, N2] * [N2, N3]
    return %2 : tensor<?x?xf32>
  }
}

//       CHECK: #[[MAP0:.+]] = affine_map<(d0, d1) -> (16, d0 - d1)>
//       CHECK: #[[MAP1:.+]] = affine_map<(d0)[s0, s1] -> (-d0 + s0, 16, -d0 + s1)>

//       CHECK: func @tensor_matmul_fusion(
//  CHECK-SAME:   %[[ARG0:[a-zA-Z0-9_]+]]: tensor<?x?xf32>
//  CHECK-SAME:   %[[ARG1:[a-zA-Z0-9_]+]]: tensor<?x?xf32>
//  CHECK-SAME:   %[[ARG2:[a-zA-Z0-9_]+]]: tensor<?x?xf32>
//  CHECK-SAME:   %[[ARG3:[a-zA-Z0-9_]+]]: tensor<?x?xf32>
//  CHECK-SAME:   %[[ARG4:[a-zA-Z0-9_]+]]: tensor<?x?xf32>
//  CHECK-SAME:   %[[ARG5:[a-zA-Z0-9_]+]]: tensor<?x?xf32>
//  CHECK-SAME:   %[[ARG6:[a-zA-Z0-9_]+]]: tensor<?x?xf32>) -> tensor<?x?xf32> {
//   CHECK-DAG:   %[[C0:.+]] = constant 0 : index
//   CHECK-DAG:   %[[C1:.+]] = constant 1 : index
//       CHECK:   %[[M:.+]] = tensor.dim %[[ARG0]], %c0 : tensor<?x?xf32>
//       CHECK:   %[[R0:.+]] = scf.for %[[IV0:[a-zA-Z0-9_]+]] =
//  CHECK-SAME:     iter_args(%[[ARG8:.+]] = %[[ARG6]]) -> (tensor<?x?xf32>) {
//       CHECK:     %[[M_1:.+]] = tensor.dim %[[ARG8]], %[[C0]]
//       CHECK:     %[[TILE_M_1:.+]] = affine.min #[[MAP0]](%[[M_1]], %[[IV0]])
//       CHECK:     %[[N3:.+]] = tensor.dim %[[ARG8]], %[[C1]]
//       CHECK:     %[[STARG6:.+]] = tensor.extract_slice %[[ARG8]][%[[IV0]], 0]
//  CHECK-SAME:       [%[[TILE_M_1]], %[[N3]]]
//       CHECK:     %[[M_2:.+]] = tensor.dim %[[ARG4]], %[[C0]]
//       CHECK:     %[[TILE_M_2:.+]] = affine.min #[[MAP1]](%[[IV0]])[%[[M_2]], %[[M]]]
//       CHECK:     %[[N2:.+]] = tensor.dim %[[ARG4]], %[[C1]]
//       CHECK:     %[[STARG4:.+]] = tensor.extract_slice %[[ARG4]][%[[IV0]], 0]
//  CHECK-SAME:       [%[[TILE_M_2]], %[[N2]]]
//       CHECK:     %[[TILE_M_3:.+]] = affine.min #[[MAP1]](%[[IV0]])[%[[M]], %[[M]]]
//       CHECK:     %[[N0:.+]] = tensor.dim %[[ARG0]], %[[C1]]
//       CHECK:     %[[STARG0:.+]] = tensor.extract_slice %[[ARG0]][%[[IV0]], 0]
//  CHECK-SAME:       [%[[TILE_M_3]], %[[N0]]]
//       CHECK:     %[[M_3:.+]] = tensor.dim %[[ARG2]], %[[C0]]
//       CHECK:     %[[TILE_M_4:.+]] = affine.min #[[MAP1]](%[[IV0]])[%[[M_3]], %[[M]]]
//       CHECK:     %[[N1:.+]] = tensor.dim %[[ARG2]], %[[C1]]
//       CHECK:     %[[STARG2:.+]] = tensor.extract_slice %[[ARG2]][%[[IV0]], 0]
//  CHECK-SAME:       [%[[TILE_M_4]], %[[N1]]]
//       CHECK:     %[[T0:.+]] = linalg.matmul
//  CHECK-SAME:       ins(%[[STARG0]], %[[ARG1]] : tensor<?x?xf32>, tensor<?x?xf32>
//  CHECK-SAME:       ) outs(%[[STARG2]] : tensor<?x?xf32>)
//       CHECK:     %[[T1:.+]] = linalg.matmul
//  CHECK-SAME:       ins(%[[T0]], %arg3 : tensor<?x?xf32>, tensor<?x?xf32>
//  CHECK-SAME:       ) outs(%[[STARG4]] : tensor<?x?xf32>)
//       CHECK:     %[[T2:.+]] = linalg.matmul
//  CHECK-SAME:       ins(%[[T1]], %arg5 : tensor<?x?xf32>, tensor<?x?xf32>
//  CHECK-SAME:       ) outs(%[[STARG6]] : tensor<?x?xf32>)
//       CHECK:     %[[R1:.+]] = tensor.insert_slice %[[T2]]
//  CHECK-SAME:       into %[[ARG8]][%[[IV0]], 0] [%[[TILE_M_1]], %[[N3]]]
//       CHECK:     scf.yield %[[R1]] : tensor<?x?xf32>
//       CHECK:   }