15#include "llvm/IR/IntrinsicsSPIRV.h"
37 if (
MI.getOpcode() != TargetOpcode::G_INTRINSIC ||
44 if (SubInstr->
getOpcode() != TargetOpcode::G_FSUB)
52 Register SubDestReg =
MI.getOperand(2).getReg();
56 Register ResultReg =
MI.getOperand(0).getReg();
59 Builder.buildIntrinsic(Intrinsic::spv_distance, ResultReg)
103 if (DotInstr->
getOpcode() != TargetOpcode::G_INTRINSIC ||
109 !
MRI.getType(DotOperand1).isScalar() ||
110 !
MRI.getType(DotOperand2).isScalar())
119 auto AreNegatedConstantsOrSplats = [&](
Register TrueReg,
Register FalseReg) {
120 std::optional<FPValueAndVReg> TrueVal, FalseVal;
124 APFloat TrueValNegated = TrueVal->Value;
131 std::optional<FPValueAndVReg> MulConstant;
134 if (TrueInstr->
getOpcode() == TargetOpcode::G_BUILD_VECTOR &&
135 FalseInstr->
getOpcode() == TargetOpcode::G_BUILD_VECTOR &&
153 if (!MulConstant || !MulConstant->Value.isExactlyValue(-1.0))
155 }
else if (!AreNegatedConstantsOrSplats(TrueReg, FalseReg))
172 if (DotInstr->
getOpcode() == TargetOpcode::G_FMUL) {
180 Register FalseReg =
MI.getOperand(3).getReg();
182 if (TrueInstr->
getOpcode() == TargetOpcode::G_FNEG ||
183 TrueInstr->
getOpcode() == TargetOpcode::G_FMUL)
187 Register ResultReg =
MI.getOperand(0).getReg();
189 Builder.buildIntrinsic(Intrinsic::spv_faceforward, ResultReg)
192 .addUse(DotOperand2);
196 auto RemoveAllUses = [&](
Register Reg) {
198 for (
auto &
UseMI :
MRI.use_instructions(Reg))
202 for (
auto *MIToErase : UsesToErase)
203 MIToErase->eraseFromParent();
206 RemoveAllUses(CondReg);
209 RemoveAllUses(DotReg);
212 RemoveAllUses(FalseReg);
218 return MI.getOpcode() == TargetOpcode::G_INTRINSIC &&
230 if (Rows == 1 && Cols == 1) {
231 Builder.buildCopy(ResReg, InReg);
232 MI.eraseFromParent();
237 for (
uint32_t K = 0; K < Rows * Cols; ++K) {
240 Mask.push_back(
C * Rows + R);
243 Builder.buildShuffleVector(ResReg, InReg, InReg, Mask);
244 MI.eraseFromParent();
248 return MI.getOpcode() == TargetOpcode::G_INTRINSIC &&
253SPIRVCombinerHelper::extractColumns(
Register MatrixReg,
uint32_t NumberOfCols,
257 if (NumberOfCols == 1)
262 for (
uint32_t J = 0; J < NumberOfCols; ++J)
263 Cols.
push_back(
MRI.createGenericVirtualRegister(ColTy));
264 Builder.buildUnmerge(Cols, MatrixReg);
272SPIRVCombinerHelper::extractRows(
Register MatrixReg, uint32_t NumRows,
282 for (uint32_t
I = 0;
I < NumRows; ++
I)
283 Rows.
push_back(
MRI.createGenericVirtualRegister(VecTy));
284 Builder.buildUnmerge(Rows, MatrixReg);
296 for (uint32_t
I = 0;
I < NumRows; ++
I) {
297 SmallVector<int, 4>
Mask;
298 for (uint32_t k = 0;
k < NumCols; ++
k)
299 Mask.push_back(k * NumRows +
I);
300 Rows.
push_back(
Builder.buildShuffleVector(VecTy, MatrixReg, MatrixReg, Mask)
312 bool IsVectorOp = SpvVecType->
getOpcode() == SPIRV::OpTypeVector;
314 bool IsFloatOp = SpvScalarType->
getOpcode() == SPIRV::OpTypeFloat;
320 Intrinsic::SPVIntrinsics DotIntrinsic =
321 (IsFloatOp ? Intrinsic::spv_fdot : Intrinsic::spv_udot);
322 DotRes =
Builder.buildIntrinsic(DotIntrinsic, {ScalarTy})
328 DotRes =
Builder.buildFMul(VecTy, RowA, ColB).getReg(0);
330 DotRes =
Builder.buildMul(VecTy, RowA, ColB).getReg(0);
341 SmallVector<Register, 16> ResultScalars;
342 for (uint32_t J = 0; J < ColsB.
size(); ++J) {
343 for (uint32_t
I = 0;
I < RowsA.
size(); ++
I) {
345 computeDotProduct(RowsA[
I], ColsB[J], SpvVecType, GR));
348 return ResultScalars;
352SPIRVCombinerHelper::getDotProductVectorType(
Register ResReg, uint32_t K,
355 Type *ScalarResType =
nullptr;
356 for (
auto &
UseMI :
MRI.use_instructions(ResReg)) {
357 if (
UseMI.getOpcode() != TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS)
374 SPIRV::AccessQualifier::None,
false);
381 uint32_t NumRowsA =
MI.getOperand(4).getImm();
382 uint32_t NumColsA =
MI.getOperand(5).getImm();
383 uint32_t NumColsB =
MI.getOperand(6).getImm();
390 SPIRVType *SpvVecType = getDotProductVectorType(ResReg, NumColsA, GR);
392 extractColumns(BReg, NumColsB, SpvVecType, GR);
394 extractRows(AReg, NumRowsA, NumColsA, SpvVecType, GR);
396 computeDotProducts(RowsA, ColsB, SpvVecType, GR);
398 Builder.buildBuildVector(ResReg, ResultScalars);
399 MI.eraseFromParent();
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
Contains matchers for matching SSA Machine Instructions.
Promote Memory to Register
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ FCMP_OLT
0 1 0 0 True if ordered and less than
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
@ FCMP_ULT
1 1 0 0 True if unordered or less than
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
MachineRegisterInfo & MRI
MachineDominatorTree * MDT
GISelChangeObserver & Observer
MachineIRBuilder & Builder
ConstantFP - Floating Point Values [float, double].
bool isZero() const
Return true if the value is positive or negative zero.
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
Abstract class that contains various methods for clients to notify about changes.
constexpr LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
Helper class to build MachineInstr.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
unsigned getNumOperands() const
Retuns the total number of operands.
LLVM_ABI void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
const MachineOperand & getOperand(unsigned i) const
Register getReg() const
getReg - Returns the register number.
Wrapper class representing virtual and physical registers.
void applyMatrixMultiply(MachineInstr &MI) const
bool matchSelectToFaceForward(MachineInstr &MI) const
This match is part of a combine that rewrites select(fcmp(dot(I, Ng), 0), N, -N) to faceforward(N,...
void applyMatrixTranspose(MachineInstr &MI) const
bool matchMatrixTranspose(MachineInstr &MI) const
CombinerHelper(GISelChangeObserver &Observer, MachineIRBuilder &B, bool IsPreLegalize, GISelValueTracking *VT=nullptr, MachineDominatorTree *MDT=nullptr, const LegalizerInfo *LI=nullptr)
void applySPIRVFaceForward(MachineInstr &MI) const
SPIRVCombinerHelper(GISelChangeObserver &Observer, MachineIRBuilder &B, bool IsPreLegalize, GISelValueTracking *VT, MachineDominatorTree *MDT, const LegalizerInfo *LI, const SPIRVSubtarget &STI)
bool matchMatrixMultiply(MachineInstr &MI) const
const SPIRVSubtarget & STI
void applySPIRVDistance(MachineInstr &MI) const
bool matchLengthToDistance(MachineInstr &MI) const
This match is part of a combine that rewrites length(X - Y) to distance(X, Y) (f32 (g_intrinsic lengt...
SPIRVType * getOrCreateSPIRVType(const Type *Type, MachineInstr &I, SPIRV::AccessQualifier::AccessQualifier AQ, bool EmitIR)
void invalidateMachineInstr(MachineInstr *MI)
SPIRVType * getScalarOrVectorComponentType(Register VReg) const
LLT getRegType(SPIRVType *SpvType) const
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
bool isVectorTy() const
True if this is an instance of VectorType.
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
bool isIntegerTy() const
True if this is an instance of IntegerType.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ C
The default llvm calling convention, compatible with C.
operand_type_match m_Reg()
operand_type_match m_Pred()
TernaryOp_match< Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_SELECT > m_GISelect(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2)
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
SpecificRegisterMatch m_SpecificReg(Register RequestedReg)
Matches a register only if it is equal to RequestedReg.
UnaryOp_match< SrcTy, TargetOpcode::G_FNEG > m_GFNeg(const SrcTy &Src)
GFCstAndRegMatch m_GFCst(std::optional< FPValueAndVReg > &FPValReg)
GFCstOrSplatGFCstMatch m_GFCstOrSplat(std::optional< FPValueAndVReg > &FPValReg)
BinaryOp_match< LHS, RHS, TargetOpcode::G_FMUL, true > m_GFMul(const LHS &L, const RHS &R)
CompareOp_match< Pred, LHS, RHS, TargetOpcode::G_FCMP > m_GFCmp(const Pred &P, const LHS &L, const RHS &R)
This is an optimization pass for GlobalISel generic memory operations.
void setRegClassType(Register Reg, SPIRVType *SpvType, SPIRVGlobalRegistry *GR, MachineRegisterInfo *MRI, const MachineFunction &MF, bool Force)
const MachineInstr SPIRVType
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Type * getMDOperandAsType(const MDNode *N, unsigned I)
bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID)
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.