1 //===- LowerMatrixIntrinsics.cpp -  Lower matrix intrinsics -----*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Lower matrix intrinsics to vector operations.
10 //
11 // TODO:
12 //  * Implement multiply & add fusion
13 //  * Implement shape propagation
14 //  * Implement optimizations to reduce or eliminateshufflevector uses by using
15 //    shape information.
16 //  * Add remark, summarizing the available matrix optimization opportunities.
17 //
18 //===----------------------------------------------------------------------===//
19 
20 #include "llvm/Transforms/Scalar/LowerMatrixIntrinsics.h"
21 #include "llvm/ADT/GraphTraits.h"
22 #include "llvm/ADT/PostOrderIterator.h"
23 #include "llvm/ADT/SmallVector.h"
24 #include "llvm/Analysis/TargetTransformInfo.h"
25 #include "llvm/Analysis/VectorUtils.h"
26 #include "llvm/IR/CFG.h"
27 #include "llvm/IR/DataLayout.h"
28 #include "llvm/IR/Function.h"
29 #include "llvm/IR/IRBuilder.h"
30 #include "llvm/IR/Instructions.h"
31 #include "llvm/IR/IntrinsicInst.h"
32 #include "llvm/IR/PatternMatch.h"
33 #include "llvm/InitializePasses.h"
34 #include "llvm/Pass.h"
35 #include "llvm/Support/Debug.h"
36 #include "llvm/Transforms/Scalar.h"
37 
38 using namespace llvm;
39 using namespace PatternMatch;
40 
41 #define DEBUG_TYPE "lower-matrix-intrinsics"
42 
43 static cl::opt<bool> EnableShapePropagation("matrix-propagate-shape",
44                                             cl::init(true));
45 
46 static cl::opt<bool> AllowContractEnabled(
47     "matrix-allow-contract", cl::init(false), cl::Hidden,
48     cl::desc("Allow the use of FMAs if available and profitable. This may "
49              "result in different results, due to less rounding error."));
50 
51 namespace {
52 
53 // Given an element poitner \p BasePtr to the start of a (sub) matrix, compute
54 // the start address of column \p Col with type (\p EltType x \p NumRows)
55 // assuming \p Stride elements between start two consecutive columns.
56 // \p Stride must be >= \p NumRows.
57 //
58 // Consider a 4x4 matrix like below
59 //
60 //      0       1      2      3
61 // 0   v_0_0  v_0_1  v_0_2  v_0_3
62 // 1   v_1_0  v_1_1  v_1_2  v_1_3
63 // 2   v_2_0  v_2_1  v_2_2  v_2_3
64 // 3   v_3_0  v_3_1  v_3_2  v_3_3
65 
66 // To compute the column addresses for a 2x3 sub-matrix at row 1 and column 1,
67 // we need a pointer to the first element of the submatrix as base pointer.
68 // Then we can use computeColumnAddr to compute the addresses for the columns
69 // of the sub-matrix.
70 //
71 // Column 0: computeColumnAddr(Base, 0 (column), 4 (stride), 2 (num rows), ..)
72 //           -> just returns Base
73 // Column 1: computeColumnAddr(Base, 1 (column), 4 (stride), 2 (num rows), ..)
74 //           -> returns Base + (1 * 4)
75 // Column 2: computeColumnAddr(Base, 2 (column), 4 (stride), 2 (num rows), ..)
76 //           -> returns Base + (2 * 4)
77 //
78 // The graphic below illustrates the number of elements in a column (marked
79 // with |) and the number of skipped elements (marked with }).
80 //
81 //         v_0_0  v_0_1 {v_0_2 {v_0_3
82 //                Base   Col 1  Col 2
83 //                  |     |      |
84 //         v_1_0 |v_1_1 |v_1_2 |v_1_3
85 //         v_2_0 |v_2_1 |v_2_2 |v_2_3
86 //         v_3_0 {v_3_1 {v_3_2  v_3_3
87 //
88 Value *computeColumnAddr(Value *BasePtr, Value *Col, Value *Stride,
89                          unsigned NumRows, Type *EltType,
90                          IRBuilder<> &Builder) {
91 
92   assert((!isa<ConstantInt>(Stride) ||
93           cast<ConstantInt>(Stride)->getZExtValue() >= NumRows) &&
94          "Stride must be >= the number of rows.");
95   unsigned AS = cast<PointerType>(BasePtr->getType())->getAddressSpace();
96 
97   // Compute the start of the column with index Col as Col * Stride.
98   Value *ColumnStart = Builder.CreateMul(Col, Stride);
99 
100   // Get pointer to the start of the selected column. Skip GEP creation,
101   // if we select column 0.
102   if (isa<ConstantInt>(ColumnStart) && cast<ConstantInt>(ColumnStart)->isZero())
103     ColumnStart = BasePtr;
104   else
105     ColumnStart = Builder.CreateGEP(EltType, BasePtr, ColumnStart);
106 
107   // Cast elementwise column start pointer to a pointer to a column
108   // (EltType x NumRows)*.
109   Type *ColumnType = VectorType::get(EltType, NumRows);
110   Type *ColumnPtrType = PointerType::get(ColumnType, AS);
111   return Builder.CreatePointerCast(ColumnStart, ColumnPtrType);
112 }
113 
114 /// LowerMatrixIntrinsics contains the methods used to lower matrix intrinsics.
115 ///
116 /// Currently, the lowering for each matrix intrinsic is done as follows:
117 /// 1. Propagate the shape information from intrinsics to connected
118 /// instructions.
119 /// 2. Lower instructions with shape information.
120 ///  2.1. Get column vectors for each argument. If we already lowered the
121 ///       definition of an argument, use the produced column vectors directly.
122 ///       If not, split the operand vector containing an embedded matrix into
123 ///       a set of column vectors,
124 ///  2.2. Lower the instruction in terms of columnwise operations, which yields
125 ///       a set of column vectors containing result matrix. Note that we lower
126 ///       all instructions that have shape information. Besides the intrinsics,
127 ///       this includes stores for example.
128 ///  2.3. Update uses of the lowered instruction. If we have shape information
129 ///       for a user, there is nothing to do, as we will look up the result
130 ///       column matrix when lowering the user. For other uses, we embed the
131 ///       result matrix in a flat vector and update the use.
132 ///  2.4. Cache the result column matrix for the instruction we lowered
133 /// 3. After we lowered all instructions in a function, remove the now
134 ///    obsolete instructions.
135 ///
136 class LowerMatrixIntrinsics {
137   Function &Func;
138   const DataLayout &DL;
139   const TargetTransformInfo &TTI;
140 
141   /// Wrapper class representing a matrix as a set of column vectors.
142   /// All column vectors must have the same vector type.
143   class ColumnMatrixTy {
144     SmallVector<Value *, 16> Columns;
145 
146   public:
147     ColumnMatrixTy() : Columns() {}
148     ColumnMatrixTy(ArrayRef<Value *> Cols)
149         : Columns(Cols.begin(), Cols.end()) {}
150 
151     Value *getColumn(unsigned i) const { return Columns[i]; }
152 
153     void setColumn(unsigned i, Value *V) { Columns[i] = V; }
154 
155     size_t getNumColumns() const { return Columns.size(); }
156     size_t getNumRows() const {
157       assert(Columns.size() > 0 && "Cannot call getNumRows without columns");
158       return cast<VectorType>(Columns[0]->getType())->getNumElements();
159     }
160 
161     const SmallVectorImpl<Value *> &getColumnVectors() const { return Columns; }
162 
163     SmallVectorImpl<Value *> &getColumnVectors() { return Columns; }
164 
165     void addColumn(Value *V) { Columns.push_back(V); }
166 
167     iterator_range<SmallVector<Value *, 8>::iterator> columns() {
168       return make_range(Columns.begin(), Columns.end());
169     }
170 
171     /// Embed the columns of the matrix into a flat vector by concatenating
172     /// them.
173     Value *embedInVector(IRBuilder<> &Builder) const {
174       return Columns.size() == 1 ? Columns[0]
175                                  : concatenateVectors(Builder, Columns);
176     }
177   };
178 
179   struct ShapeInfo {
180     unsigned NumRows;
181     unsigned NumColumns;
182 
183     ShapeInfo(unsigned NumRows = 0, unsigned NumColumns = 0)
184         : NumRows(NumRows), NumColumns(NumColumns) {}
185 
186     ShapeInfo(Value *NumRows, Value *NumColumns)
187         : NumRows(cast<ConstantInt>(NumRows)->getZExtValue()),
188           NumColumns(cast<ConstantInt>(NumColumns)->getZExtValue()) {}
189 
190     bool operator==(const ShapeInfo &other) {
191       return NumRows == other.NumRows && NumColumns == other.NumColumns;
192     }
193     bool operator!=(const ShapeInfo &other) { return !(*this == other); }
194 
195     /// Returns true if shape-information is defined, meaning both dimensions
196     /// are != 0.
197     operator bool() const {
198       assert(NumRows == 0 || NumColumns != 0);
199       return NumRows != 0;
200     }
201   };
202 
203   /// Maps instructions to their shape information. The shape information
204   /// describes the shape to be used while lowering. This matches the shape of
205   /// the result value of the instruction, with the only exceptions being store
206   /// instructions and the matrix_columnwise_store intrinsics. For those, the
207   /// shape information indicates that those instructions should be lowered
208   /// using shape information as well.
209   DenseMap<Value *, ShapeInfo> ShapeMap;
210 
211   /// List of instructions to remove. While lowering, we are not replacing all
212   /// users of a lowered instruction, if shape information is available and
213   /// those need to be removed after we finished lowering.
214   SmallVector<Instruction *, 16> ToRemove;
215 
216   /// Map from instructions to their produced column matrix.
217   DenseMap<Value *, ColumnMatrixTy> Inst2ColumnMatrix;
218 
219 public:
220   LowerMatrixIntrinsics(Function &F, TargetTransformInfo &TTI)
221       : Func(F), DL(F.getParent()->getDataLayout()), TTI(TTI) {}
222 
223   /// Return the set of column vectors that a matrix value is lowered to.
224   ///
225   /// If we lowered \p MatrixVal, just return the cache result column matrix.
226   /// Otherwie split the flat vector \p MatrixVal containing a matrix with
227   /// shape \p SI into column vectors.
228   ColumnMatrixTy getMatrix(Value *MatrixVal, const ShapeInfo &SI,
229                            IRBuilder<> Builder) {
230     VectorType *VType = dyn_cast<VectorType>(MatrixVal->getType());
231     assert(VType && "MatrixVal must be a vector type");
232     assert(VType->getNumElements() == SI.NumRows * SI.NumColumns &&
233            "The vector size must match the number of matrix elements");
234 
235     // Check if we lowered MatrixVal using shape information. In that case,
236     // return the existing column matrix, if it matches the requested shape
237     // information. If there is a mis-match, embed the result in a flat
238     // vector and split it later.
239     auto Found = Inst2ColumnMatrix.find(MatrixVal);
240     if (Found != Inst2ColumnMatrix.end()) {
241       ColumnMatrixTy &M = Found->second;
242       // Return the found matrix, if its shape matches the requested shape
243       // information
244       if (SI.NumRows == M.getNumRows() && SI.NumColumns == M.getNumColumns())
245         return M;
246 
247       MatrixVal = M.embedInVector(Builder);
248     }
249 
250     // Otherwise split MatrixVal.
251     SmallVector<Value *, 16> SplitVecs;
252     Value *Undef = UndefValue::get(VType);
253     for (unsigned MaskStart = 0; MaskStart < VType->getNumElements();
254          MaskStart += SI.NumRows) {
255       Constant *Mask = createSequentialMask(Builder, MaskStart, SI.NumRows, 0);
256       Value *V = Builder.CreateShuffleVector(MatrixVal, Undef, Mask, "split");
257       SplitVecs.push_back(V);
258     }
259 
260     return {SplitVecs};
261   }
262 
263   /// If \p V already has a known shape return false.  Otherwise set the shape
264   /// for instructions that support it.
265   bool setShapeInfo(Value *V, ShapeInfo Shape) {
266     assert(Shape && "Shape not set");
267     if (isa<UndefValue>(V) || !supportsShapeInfo(V))
268       return false;
269 
270     auto SIter = ShapeMap.find(V);
271     if (SIter != ShapeMap.end()) {
272       LLVM_DEBUG(dbgs() << "  not overriding existing shape: "
273                         << SIter->second.NumRows << " "
274                         << SIter->second.NumColumns << " for " << *V << "\n");
275       return false;
276     }
277 
278     ShapeMap.insert({V, Shape});
279     LLVM_DEBUG(dbgs() << "  " << Shape.NumRows << " x " << Shape.NumColumns
280                       << " for " << *V << "\n");
281     return true;
282   }
283 
284   /// Returns true if shape information can be used for \p V. The supported
285   /// instructions must match the instructions that can be lowered by this pass.
286   bool supportsShapeInfo(Value *V) {
287     Instruction *Inst = dyn_cast<Instruction>(V);
288     if (!Inst)
289       return false;
290 
291     IntrinsicInst *II = dyn_cast<IntrinsicInst>(Inst);
292     if (II)
293       switch (II->getIntrinsicID()) {
294       case Intrinsic::matrix_multiply:
295       case Intrinsic::matrix_transpose:
296       case Intrinsic::matrix_columnwise_load:
297       case Intrinsic::matrix_columnwise_store:
298         return true;
299       default:
300         return false;
301       }
302     return isa<StoreInst>(Inst);
303   }
304 
305   /// Propagate the shape information of instructions to their users.
306   void propagateShapeForward() {
307     // The work list contains instructions for which we can compute the shape,
308     // either based on the information provided by matrix intrinsics or known
309     // shapes of operands.
310     SmallVector<Instruction *, 8> WorkList;
311 
312     // Initialize the work list with ops carrying shape information. Initially
313     // only the shape of matrix intrinsics is known.
314     for (BasicBlock &BB : Func)
315       for (Instruction &Inst : BB) {
316         IntrinsicInst *II = dyn_cast<IntrinsicInst>(&Inst);
317         if (!II)
318           continue;
319 
320         switch (II->getIntrinsicID()) {
321         case Intrinsic::matrix_multiply:
322         case Intrinsic::matrix_transpose:
323         case Intrinsic::matrix_columnwise_load:
324         case Intrinsic::matrix_columnwise_store:
325           WorkList.push_back(&Inst);
326           break;
327         default:
328           break;
329         }
330       }
331 
332     // Pop an element for which we guaranteed to have at least one of the
333     // operand shapes.  Add the shape for this and then add users to the work
334     // list.
335     LLVM_DEBUG(dbgs() << "Forward-propagate shapes:\n");
336     while (!WorkList.empty()) {
337       Instruction *Inst = WorkList.back();
338       WorkList.pop_back();
339 
340       // New entry, set the value and insert operands
341       bool Propagate = false;
342 
343       Value *MatrixA;
344       Value *MatrixB;
345       Value *M;
346       Value *N;
347       Value *K;
348       if (match(Inst, m_Intrinsic<Intrinsic::matrix_multiply>(
349                           m_Value(MatrixA), m_Value(MatrixB), m_Value(M),
350                           m_Value(N), m_Value(K)))) {
351         Propagate = setShapeInfo(Inst, {M, K});
352       } else if (match(Inst, m_Intrinsic<Intrinsic::matrix_transpose>(
353                                  m_Value(MatrixA), m_Value(M), m_Value(N)))) {
354         // Flip dimensions.
355         Propagate = setShapeInfo(Inst, {N, M});
356       } else if (match(Inst, m_Intrinsic<Intrinsic::matrix_columnwise_store>(
357                                  m_Value(MatrixA), m_Value(), m_Value(),
358                                  m_Value(M), m_Value(N)))) {
359         Propagate = setShapeInfo(Inst, {N, M});
360       } else if (match(Inst,
361                        m_Intrinsic<Intrinsic::matrix_columnwise_load>(
362                            m_Value(), m_Value(), m_Value(M), m_Value(N)))) {
363         Propagate = setShapeInfo(Inst, {M, N});
364       } else if (match(Inst, m_Store(m_Value(MatrixA), m_Value()))) {
365         auto OpShape = ShapeMap.find(MatrixA);
366         if (OpShape != ShapeMap.end())
367           setShapeInfo(Inst, OpShape->second);
368         continue;
369       }
370 
371       if (Propagate)
372         for (auto *User : Inst->users())
373           if (ShapeMap.count(User) == 0)
374             WorkList.push_back(cast<Instruction>(User));
375     }
376   }
377 
378   bool Visit() {
379     if (EnableShapePropagation)
380       propagateShapeForward();
381 
382     ReversePostOrderTraversal<Function *> RPOT(&Func);
383     bool Changed = false;
384     for (auto *BB : RPOT) {
385       for (Instruction &Inst : make_early_inc_range(*BB)) {
386         IRBuilder<> Builder(&Inst);
387 
388         if (CallInst *CInst = dyn_cast<CallInst>(&Inst))
389           Changed |= VisitCallInst(CInst);
390 
391         Value *Op1;
392         Value *Op2;
393         if (match(&Inst, m_Store(m_Value(Op1), m_Value(Op2))))
394           Changed |= VisitStore(&Inst, Op1, Op2, Builder);
395       }
396     }
397 
398     for (Instruction *Inst : reverse(ToRemove))
399       Inst->eraseFromParent();
400 
401     return Changed;
402   }
403 
404   LoadInst *createColumnLoad(Value *ColumnPtr, Type *EltType,
405                              IRBuilder<> Builder) {
406     unsigned Align = DL.getABITypeAlignment(EltType);
407     return Builder.CreateAlignedLoad(ColumnPtr, Align);
408   }
409 
410   StoreInst *createColumnStore(Value *ColumnValue, Value *ColumnPtr,
411                                Type *EltType, IRBuilder<> Builder) {
412     unsigned Align = DL.getABITypeAlignment(EltType);
413     return Builder.CreateAlignedStore(ColumnValue, ColumnPtr, Align);
414   }
415 
416 
417   /// Turns \p BasePtr into an elementwise pointer to \p EltType.
418   Value *createElementPtr(Value *BasePtr, Type *EltType, IRBuilder<> &Builder) {
419     unsigned AS = cast<PointerType>(BasePtr->getType())->getAddressSpace();
420     Type *EltPtrType = PointerType::get(EltType, AS);
421     return Builder.CreatePointerCast(BasePtr, EltPtrType);
422   }
423 
424   /// Replace intrinsic calls
425   bool VisitCallInst(CallInst *Inst) {
426     if (!Inst->getCalledFunction() || !Inst->getCalledFunction()->isIntrinsic())
427       return false;
428 
429     switch (Inst->getCalledFunction()->getIntrinsicID()) {
430     case Intrinsic::matrix_multiply:
431       LowerMultiply(Inst);
432       break;
433     case Intrinsic::matrix_transpose:
434       LowerTranspose(Inst);
435       break;
436     case Intrinsic::matrix_columnwise_load:
437       LowerColumnwiseLoad(Inst);
438       break;
439     case Intrinsic::matrix_columnwise_store:
440       LowerColumnwiseStore(Inst);
441       break;
442     default:
443       return false;
444     }
445     return true;
446   }
447 
448   /// Lowers llvm.matrix.columnwise.load.
449   ///
450   /// The intrinsic loads a matrix from memory using a stride between columns.
451   void LowerColumnwiseLoad(CallInst *Inst) {
452     IRBuilder<> Builder(Inst);
453     Value *Ptr = Inst->getArgOperand(0);
454     Value *Stride = Inst->getArgOperand(1);
455     auto VType = cast<VectorType>(Inst->getType());
456     Value *EltPtr = createElementPtr(Ptr, VType->getElementType(), Builder);
457     ShapeInfo Shape(Inst->getArgOperand(2), Inst->getArgOperand(3));
458 
459     ColumnMatrixTy Result;
460     // Distance between start of one column and the start of the next
461     for (unsigned C = 0, E = Shape.NumColumns; C < E; ++C) {
462       Value *GEP =
463           computeColumnAddr(EltPtr, Builder.getInt32(C), Stride, Shape.NumRows,
464                             VType->getElementType(), Builder);
465       Value *Column = createColumnLoad(GEP, VType->getElementType(), Builder);
466       Result.addColumn(Column);
467     }
468 
469     finalizeLowering(Inst, Result, Builder);
470   }
471 
472   void LowerStore(Instruction *Inst, Value *Matrix, Value *Ptr, Value *Stride,
473                   ShapeInfo Shape) {
474     IRBuilder<> Builder(Inst);
475     auto VType = cast<VectorType>(Matrix->getType());
476     Value *EltPtr = createElementPtr(Ptr, VType->getElementType(), Builder);
477     auto LM = getMatrix(Matrix, Shape, Builder);
478     for (auto C : enumerate(LM.columns())) {
479       Value *GEP =
480           computeColumnAddr(EltPtr, Builder.getInt32(C.index()), Stride,
481                             Shape.NumRows, VType->getElementType(), Builder);
482       createColumnStore(C.value(), GEP, VType->getElementType(), Builder);
483     }
484 
485     ToRemove.push_back(Inst);
486   }
487 
488   /// Lowers llvm.matrix.columnwise.store.
489   ///
490   /// The intrinsic store a matrix back memory using a stride between columns.
491   void LowerColumnwiseStore(CallInst *Inst) {
492     Value *Matrix = Inst->getArgOperand(0);
493     Value *Ptr = Inst->getArgOperand(1);
494     Value *Stride = Inst->getArgOperand(2);
495     LowerStore(Inst, Matrix, Ptr, Stride,
496                {Inst->getArgOperand(3), Inst->getArgOperand(4)});
497   }
498 
499   /// Extract a column vector of \p NumElts starting at index (\p I, \p J) from
500   /// the matrix \p LM represented as a vector of column vectors.
501   Value *extractVector(const ColumnMatrixTy &LM, unsigned I, unsigned J,
502                        unsigned NumElts, IRBuilder<> Builder) {
503     Value *Col = LM.getColumn(J);
504     Value *Undef = UndefValue::get(Col->getType());
505     Constant *Mask = createSequentialMask(Builder, I, NumElts, 0);
506     return Builder.CreateShuffleVector(Col, Undef, Mask, "block");
507   }
508 
509   // Set elements I..I+NumElts-1 to Block
510   Value *insertVector(Value *Col, unsigned I, Value *Block,
511                       IRBuilder<> Builder) {
512 
513     // First, bring Block to the same size as Col
514     unsigned BlockNumElts =
515         cast<VectorType>(Block->getType())->getNumElements();
516     unsigned NumElts = cast<VectorType>(Col->getType())->getNumElements();
517     assert(NumElts >= BlockNumElts && "Too few elements for current block");
518 
519     Value *ExtendMask =
520         createSequentialMask(Builder, 0, BlockNumElts, NumElts - BlockNumElts);
521     Value *Undef = UndefValue::get(Block->getType());
522     Block = Builder.CreateShuffleVector(Block, Undef, ExtendMask);
523 
524     // If Col is 7 long and I is 2 and BlockNumElts is 2 the mask is: 0, 1, 7,
525     // 8, 4, 5, 6
526     SmallVector<Constant *, 16> Mask;
527     unsigned i;
528     for (i = 0; i < I; i++)
529       Mask.push_back(Builder.getInt32(i));
530 
531     unsigned VecNumElts = cast<VectorType>(Col->getType())->getNumElements();
532     for (; i < I + BlockNumElts; i++)
533       Mask.push_back(Builder.getInt32(i - I + VecNumElts));
534 
535     for (; i < VecNumElts; i++)
536       Mask.push_back(Builder.getInt32(i));
537 
538     Value *MaskVal = ConstantVector::get(Mask);
539 
540     return Builder.CreateShuffleVector(Col, Block, MaskVal);
541   }
542 
543   Value *createMulAdd(Value *Sum, Value *A, Value *B, bool UseFPOp,
544                       IRBuilder<> &Builder, bool AllowContraction) {
545 
546     if (!Sum)
547       return UseFPOp ? Builder.CreateFMul(A, B) : Builder.CreateMul(A, B);
548 
549     if (UseFPOp) {
550       if (AllowContraction) {
551         // Use fmuladd for floating point operations and let the backend decide
552         // if that's profitable.
553         Value *FMulAdd = Intrinsic::getDeclaration(
554             Func.getParent(), Intrinsic::fmuladd, A->getType());
555         return Builder.CreateCall(FMulAdd, {A, B, Sum});
556       }
557       Value *Mul = Builder.CreateFMul(A, B);
558       return Builder.CreateFAdd(Sum, Mul);
559     }
560 
561     Value *Mul = Builder.CreateMul(A, B);
562     return Builder.CreateAdd(Sum, Mul);
563   }
564 
565   /// Cache \p Matrix as result of \p Inst and update the uses of \p Inst. For
566   /// users with shape information, there's nothing to do: the will use the
567   /// cached value when they are lowered. For other users, \p Matrix is
568   /// flattened and the uses are updated to use it. Also marks \p Inst for
569   /// deletion.
570   void finalizeLowering(Instruction *Inst, ColumnMatrixTy Matrix,
571                         IRBuilder<> &Builder) {
572     Inst2ColumnMatrix.insert(std::make_pair(Inst, Matrix));
573 
574     ToRemove.push_back(Inst);
575     Value *Flattened = nullptr;
576     for (auto I = Inst->use_begin(), E = Inst->use_end(); I != E;) {
577       Use &U = *I++;
578       if (ShapeMap.find(U.getUser()) == ShapeMap.end()) {
579         if (!Flattened)
580           Flattened = Matrix.embedInVector(Builder);
581         U.set(Flattened);
582       }
583     }
584   }
585 
586   /// Lowers llvm.matrix.multiply.
587   void LowerMultiply(CallInst *MatMul) {
588     IRBuilder<> Builder(MatMul);
589     auto *EltType = cast<VectorType>(MatMul->getType())->getElementType();
590     ShapeInfo LShape(MatMul->getArgOperand(2), MatMul->getArgOperand(3));
591     ShapeInfo RShape(MatMul->getArgOperand(3), MatMul->getArgOperand(4));
592 
593     const ColumnMatrixTy &Lhs =
594         getMatrix(MatMul->getArgOperand(0), LShape, Builder);
595     const ColumnMatrixTy &Rhs =
596         getMatrix(MatMul->getArgOperand(1), RShape, Builder);
597 
598     const unsigned R = LShape.NumRows;
599     const unsigned M = LShape.NumColumns;
600     const unsigned C = RShape.NumColumns;
601     assert(M == RShape.NumRows);
602 
603     // Initialize the output
604     ColumnMatrixTy Result;
605     for (unsigned J = 0; J < C; ++J)
606       Result.addColumn(UndefValue::get(VectorType::get(EltType, R)));
607 
608     const unsigned VF = std::max(TTI.getRegisterBitWidth(true) /
609                                      EltType->getPrimitiveSizeInBits(),
610                                  uint64_t(1));
611 
612     bool AllowContract = AllowContractEnabled || (isa<FPMathOperator>(MatMul) &&
613                                                   MatMul->hasAllowContract());
614     // Multiply columns from the first operand with scalars from the second
615     // operand.  Then move along the K axes and accumulate the columns.  With
616     // this the adds can be vectorized without reassociation.
617     for (unsigned J = 0; J < C; ++J) {
618       unsigned BlockSize = VF;
619       for (unsigned I = 0; I < R; I += BlockSize) {
620         // Gradually lower the vectorization factor to cover the remainder.
621         while (I + BlockSize > R)
622           BlockSize /= 2;
623 
624         Value *Sum = nullptr;
625         for (unsigned K = 0; K < M; ++K) {
626           Value *L = extractVector(Lhs, I, K, BlockSize, Builder);
627           Value *RH = Builder.CreateExtractElement(Rhs.getColumn(J), K);
628           Value *Splat = Builder.CreateVectorSplat(BlockSize, RH, "splat");
629           Sum = createMulAdd(Sum, L, Splat, EltType->isFloatingPointTy(),
630                              Builder, AllowContract);
631         }
632         Result.setColumn(J, insertVector(Result.getColumn(J), I, Sum, Builder));
633       }
634     }
635     finalizeLowering(MatMul, Result, Builder);
636   }
637 
638   /// Lowers llvm.matrix.transpose.
639   void LowerTranspose(CallInst *Inst) {
640     ColumnMatrixTy Result;
641     IRBuilder<> Builder(Inst);
642     Value *InputVal = Inst->getArgOperand(0);
643     VectorType *VectorTy = cast<VectorType>(InputVal->getType());
644     ShapeInfo ArgShape(Inst->getArgOperand(1), Inst->getArgOperand(2));
645     ColumnMatrixTy InputMatrix = getMatrix(InputVal, ArgShape, Builder);
646 
647     for (unsigned Row = 0; Row < ArgShape.NumRows; ++Row) {
648       // Build a single column vector for this row. First initialize it.
649       Value *ResultColumn = UndefValue::get(
650           VectorType::get(VectorTy->getElementType(), ArgShape.NumColumns));
651 
652       // Go through the elements of this row and insert it into the resulting
653       // column vector.
654       for (auto C : enumerate(InputMatrix.columns())) {
655         Value *Elt = Builder.CreateExtractElement(C.value(), Row);
656         // We insert at index Column since that is the row index after the
657         // transpose.
658         ResultColumn =
659             Builder.CreateInsertElement(ResultColumn, Elt, C.index());
660       }
661       Result.addColumn(ResultColumn);
662     }
663 
664     finalizeLowering(Inst, Result, Builder);
665   }
666 
667   bool VisitStore(Instruction *Inst, Value *StoredVal, Value *Ptr,
668                   IRBuilder<> &Builder) {
669     auto I = ShapeMap.find(StoredVal);
670     if (I == ShapeMap.end())
671       return false;
672 
673     LowerStore(Inst, StoredVal, Ptr, Builder.getInt32(I->second.NumRows), I->second);
674     return true;
675   }
676 };
677 } // namespace
678 
679 PreservedAnalyses LowerMatrixIntrinsicsPass::run(Function &F,
680                                                  FunctionAnalysisManager &AM) {
681   auto &TTI = AM.getResult<TargetIRAnalysis>(F);
682   LowerMatrixIntrinsics LMT(F, TTI);
683   if (LMT.Visit()) {
684     PreservedAnalyses PA;
685     PA.preserveSet<CFGAnalyses>();
686     return PA;
687   }
688   return PreservedAnalyses::all();
689 }
690 
691 namespace {
692 
693 class LowerMatrixIntrinsicsLegacyPass : public FunctionPass {
694 public:
695   static char ID;
696 
697   LowerMatrixIntrinsicsLegacyPass() : FunctionPass(ID) {
698     initializeLowerMatrixIntrinsicsLegacyPassPass(
699         *PassRegistry::getPassRegistry());
700   }
701 
702   bool runOnFunction(Function &F) override {
703     auto *TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
704     LowerMatrixIntrinsics LMT(F, *TTI);
705     bool C = LMT.Visit();
706     return C;
707   }
708 
709   void getAnalysisUsage(AnalysisUsage &AU) const override {
710     AU.addRequired<TargetTransformInfoWrapperPass>();
711     AU.setPreservesCFG();
712   }
713 };
714 } // namespace
715 
716 static const char pass_name[] = "Lower the matrix intrinsics";
717 char LowerMatrixIntrinsicsLegacyPass::ID = 0;
718 INITIALIZE_PASS_BEGIN(LowerMatrixIntrinsicsLegacyPass, DEBUG_TYPE, pass_name,
719                       false, false)
720 INITIALIZE_PASS_END(LowerMatrixIntrinsicsLegacyPass, DEBUG_TYPE, pass_name,
721                     false, false)
722 
723 Pass *llvm::createLowerMatrixIntrinsicsPass() {
724   return new LowerMatrixIntrinsicsLegacyPass();
725 }
726