MatrixBuilder.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. //===- llvm/MatrixBuilder.h - Builder to lower matrix ops -------*- 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. // This file defines the MatrixBuilder class, which is used as a convenient way
  10. // to lower matrix operations to LLVM IR.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #ifndef LLVM_IR_MATRIXBUILDER_H
  14. #define LLVM_IR_MATRIXBUILDER_H
  15. #include "llvm/IR/Constant.h"
  16. #include "llvm/IR/Constants.h"
  17. #include "llvm/IR/IRBuilder.h"
  18. #include "llvm/IR/InstrTypes.h"
  19. #include "llvm/IR/Instruction.h"
  20. #include "llvm/IR/IntrinsicInst.h"
  21. #include "llvm/IR/Type.h"
  22. #include "llvm/IR/Value.h"
  23. #include "llvm/Support/Alignment.h"
  24. namespace llvm {
  25. class Function;
  26. class Twine;
  27. class Module;
  28. template <class IRBuilderTy> class MatrixBuilder {
  29. IRBuilderTy &B;
  30. Module *getModule() { return B.GetInsertBlock()->getParent()->getParent(); }
  31. std::pair<Value *, Value *> splatScalarOperandIfNeeded(Value *LHS,
  32. Value *RHS) {
  33. assert((LHS->getType()->isVectorTy() || RHS->getType()->isVectorTy()) &&
  34. "One of the operands must be a matrix (embedded in a vector)");
  35. if (LHS->getType()->isVectorTy() && !RHS->getType()->isVectorTy()) {
  36. assert(!isa<ScalableVectorType>(LHS->getType()) &&
  37. "LHS Assumed to be fixed width");
  38. RHS = B.CreateVectorSplat(
  39. cast<VectorType>(LHS->getType())->getElementCount(), RHS,
  40. "scalar.splat");
  41. } else if (!LHS->getType()->isVectorTy() && RHS->getType()->isVectorTy()) {
  42. assert(!isa<ScalableVectorType>(RHS->getType()) &&
  43. "RHS Assumed to be fixed width");
  44. LHS = B.CreateVectorSplat(
  45. cast<VectorType>(RHS->getType())->getElementCount(), LHS,
  46. "scalar.splat");
  47. }
  48. return {LHS, RHS};
  49. }
  50. public:
  51. MatrixBuilder(IRBuilderTy &Builder) : B(Builder) {}
  52. /// Create a column major, strided matrix load.
  53. /// \p DataPtr - Start address of the matrix read
  54. /// \p Rows - Number of rows in matrix (must be a constant)
  55. /// \p Columns - Number of columns in matrix (must be a constant)
  56. /// \p Stride - Space between columns
  57. CallInst *CreateColumnMajorLoad(Value *DataPtr, Align Alignment,
  58. Value *Stride, bool IsVolatile, unsigned Rows,
  59. unsigned Columns, const Twine &Name = "") {
  60. // Deal with the pointer
  61. PointerType *PtrTy = cast<PointerType>(DataPtr->getType());
  62. Type *EltTy = PtrTy->getElementType();
  63. auto *RetType = FixedVectorType::get(EltTy, Rows * Columns);
  64. Value *Ops[] = {DataPtr, Stride, B.getInt1(IsVolatile), B.getInt32(Rows),
  65. B.getInt32(Columns)};
  66. Type *OverloadedTypes[] = {RetType};
  67. Function *TheFn = Intrinsic::getDeclaration(
  68. getModule(), Intrinsic::matrix_column_major_load, OverloadedTypes);
  69. CallInst *Call = B.CreateCall(TheFn->getFunctionType(), TheFn, Ops, Name);
  70. Attribute AlignAttr =
  71. Attribute::getWithAlignment(Call->getContext(), Alignment);
  72. Call->addAttribute(1, AlignAttr);
  73. return Call;
  74. }
  75. /// Create a column major, strided matrix store.
  76. /// \p Matrix - Matrix to store
  77. /// \p Ptr - Pointer to write back to
  78. /// \p Stride - Space between columns
  79. CallInst *CreateColumnMajorStore(Value *Matrix, Value *Ptr, Align Alignment,
  80. Value *Stride, bool IsVolatile,
  81. unsigned Rows, unsigned Columns,
  82. const Twine &Name = "") {
  83. Value *Ops[] = {Matrix, Ptr,
  84. Stride, B.getInt1(IsVolatile),
  85. B.getInt32(Rows), B.getInt32(Columns)};
  86. Type *OverloadedTypes[] = {Matrix->getType()};
  87. Function *TheFn = Intrinsic::getDeclaration(
  88. getModule(), Intrinsic::matrix_column_major_store, OverloadedTypes);
  89. CallInst *Call = B.CreateCall(TheFn->getFunctionType(), TheFn, Ops, Name);
  90. Attribute AlignAttr =
  91. Attribute::getWithAlignment(Call->getContext(), Alignment);
  92. Call->addAttribute(2, AlignAttr);
  93. return Call;
  94. }
  95. /// Create a llvm.matrix.transpose call, transposing \p Matrix with \p Rows
  96. /// rows and \p Columns columns.
  97. CallInst *CreateMatrixTranspose(Value *Matrix, unsigned Rows,
  98. unsigned Columns, const Twine &Name = "") {
  99. auto *OpType = cast<VectorType>(Matrix->getType());
  100. auto *ReturnType =
  101. FixedVectorType::get(OpType->getElementType(), Rows * Columns);
  102. Type *OverloadedTypes[] = {ReturnType};
  103. Value *Ops[] = {Matrix, B.getInt32(Rows), B.getInt32(Columns)};
  104. Function *TheFn = Intrinsic::getDeclaration(
  105. getModule(), Intrinsic::matrix_transpose, OverloadedTypes);
  106. return B.CreateCall(TheFn->getFunctionType(), TheFn, Ops, Name);
  107. }
  108. /// Create a llvm.matrix.multiply call, multiplying matrixes \p LHS and \p
  109. /// RHS.
  110. CallInst *CreateMatrixMultiply(Value *LHS, Value *RHS, unsigned LHSRows,
  111. unsigned LHSColumns, unsigned RHSColumns,
  112. const Twine &Name = "") {
  113. auto *LHSType = cast<VectorType>(LHS->getType());
  114. auto *RHSType = cast<VectorType>(RHS->getType());
  115. auto *ReturnType =
  116. FixedVectorType::get(LHSType->getElementType(), LHSRows * RHSColumns);
  117. Value *Ops[] = {LHS, RHS, B.getInt32(LHSRows), B.getInt32(LHSColumns),
  118. B.getInt32(RHSColumns)};
  119. Type *OverloadedTypes[] = {ReturnType, LHSType, RHSType};
  120. Function *TheFn = Intrinsic::getDeclaration(
  121. getModule(), Intrinsic::matrix_multiply, OverloadedTypes);
  122. return B.CreateCall(TheFn->getFunctionType(), TheFn, Ops, Name);
  123. }
  124. /// Insert a single element \p NewVal into \p Matrix at indices (\p RowIdx, \p
  125. /// ColumnIdx).
  126. Value *CreateMatrixInsert(Value *Matrix, Value *NewVal, Value *RowIdx,
  127. Value *ColumnIdx, unsigned NumRows) {
  128. return B.CreateInsertElement(
  129. Matrix, NewVal,
  130. B.CreateAdd(B.CreateMul(ColumnIdx, ConstantInt::get(
  131. ColumnIdx->getType(), NumRows)),
  132. RowIdx));
  133. }
  134. /// Add matrixes \p LHS and \p RHS. Support both integer and floating point
  135. /// matrixes.
  136. Value *CreateAdd(Value *LHS, Value *RHS) {
  137. assert(LHS->getType()->isVectorTy() || RHS->getType()->isVectorTy());
  138. if (LHS->getType()->isVectorTy() && !RHS->getType()->isVectorTy()) {
  139. assert(!isa<ScalableVectorType>(LHS->getType()) &&
  140. "LHS Assumed to be fixed width");
  141. RHS = B.CreateVectorSplat(
  142. cast<VectorType>(LHS->getType())->getElementCount(), RHS,
  143. "scalar.splat");
  144. } else if (!LHS->getType()->isVectorTy() && RHS->getType()->isVectorTy()) {
  145. assert(!isa<ScalableVectorType>(RHS->getType()) &&
  146. "RHS Assumed to be fixed width");
  147. LHS = B.CreateVectorSplat(
  148. cast<VectorType>(RHS->getType())->getElementCount(), LHS,
  149. "scalar.splat");
  150. }
  151. return cast<VectorType>(LHS->getType())
  152. ->getElementType()
  153. ->isFloatingPointTy()
  154. ? B.CreateFAdd(LHS, RHS)
  155. : B.CreateAdd(LHS, RHS);
  156. }
  157. /// Subtract matrixes \p LHS and \p RHS. Support both integer and floating
  158. /// point matrixes.
  159. Value *CreateSub(Value *LHS, Value *RHS) {
  160. assert(LHS->getType()->isVectorTy() || RHS->getType()->isVectorTy());
  161. if (LHS->getType()->isVectorTy() && !RHS->getType()->isVectorTy()) {
  162. assert(!isa<ScalableVectorType>(LHS->getType()) &&
  163. "LHS Assumed to be fixed width");
  164. RHS = B.CreateVectorSplat(
  165. cast<VectorType>(LHS->getType())->getElementCount(), RHS,
  166. "scalar.splat");
  167. } else if (!LHS->getType()->isVectorTy() && RHS->getType()->isVectorTy()) {
  168. assert(!isa<ScalableVectorType>(RHS->getType()) &&
  169. "RHS Assumed to be fixed width");
  170. LHS = B.CreateVectorSplat(
  171. cast<VectorType>(RHS->getType())->getElementCount(), LHS,
  172. "scalar.splat");
  173. }
  174. return cast<VectorType>(LHS->getType())
  175. ->getElementType()
  176. ->isFloatingPointTy()
  177. ? B.CreateFSub(LHS, RHS)
  178. : B.CreateSub(LHS, RHS);
  179. }
  180. /// Multiply matrix \p LHS with scalar \p RHS or scalar \p LHS with matrix \p
  181. /// RHS.
  182. Value *CreateScalarMultiply(Value *LHS, Value *RHS) {
  183. std::tie(LHS, RHS) = splatScalarOperandIfNeeded(LHS, RHS);
  184. if (LHS->getType()->getScalarType()->isFloatingPointTy())
  185. return B.CreateFMul(LHS, RHS);
  186. return B.CreateMul(LHS, RHS);
  187. }
  188. /// Divide matrix \p LHS by scalar \p RHS. If the operands are integers, \p
  189. /// IsUnsigned indicates whether UDiv or SDiv should be used.
  190. Value *CreateScalarDiv(Value *LHS, Value *RHS, bool IsUnsigned) {
  191. assert(LHS->getType()->isVectorTy() && !RHS->getType()->isVectorTy());
  192. assert(!isa<ScalableVectorType>(LHS->getType()) &&
  193. "LHS Assumed to be fixed width");
  194. RHS =
  195. B.CreateVectorSplat(cast<VectorType>(LHS->getType())->getElementCount(),
  196. RHS, "scalar.splat");
  197. return cast<VectorType>(LHS->getType())
  198. ->getElementType()
  199. ->isFloatingPointTy()
  200. ? B.CreateFDiv(LHS, RHS)
  201. : (IsUnsigned ? B.CreateUDiv(LHS, RHS) : B.CreateSDiv(LHS, RHS));
  202. }
  203. /// Extracts the element at (\p RowIdx, \p ColumnIdx) from \p Matrix.
  204. Value *CreateExtractElement(Value *Matrix, Value *RowIdx, Value *ColumnIdx,
  205. unsigned NumRows, Twine const &Name = "") {
  206. unsigned MaxWidth = std::max(RowIdx->getType()->getScalarSizeInBits(),
  207. ColumnIdx->getType()->getScalarSizeInBits());
  208. Type *IntTy = IntegerType::get(RowIdx->getType()->getContext(), MaxWidth);
  209. RowIdx = B.CreateZExt(RowIdx, IntTy);
  210. ColumnIdx = B.CreateZExt(ColumnIdx, IntTy);
  211. Value *NumRowsV = B.getIntN(MaxWidth, NumRows);
  212. return B.CreateExtractElement(
  213. Matrix, B.CreateAdd(B.CreateMul(ColumnIdx, NumRowsV), RowIdx),
  214. "matext");
  215. }
  216. };
  217. } // end namespace llvm
  218. #endif // LLVM_IR_MATRIXBUILDER_H