15#include "llvm/IR/IntrinsicsSPIRV.h"
47 Register SubDestReg =
MI.getOperand(2).getReg();
51 Register ResultReg =
MI.getOperand(0).getReg();
54 Builder.buildIntrinsic(Intrinsic::spv_distance, ResultReg)
71 Register NumeratorReg =
MI.getOperand(1).getReg();
72 Register DivisorReg =
MI.getOperand(2).getReg();
76 if (ShuffleInstr->
getOpcode() != TargetOpcode::G_SHUFFLE_VECTOR)
79 [](
int M) {
return M == 0; }))
100 Register NumeratorReg =
MI.getOperand(1).getReg();
101 Register ResultReg =
MI.getOperand(0).getReg();
104 Builder.buildIntrinsic(Intrinsic::spv_normalize, ResultReg)
105 .addUse(NumeratorReg);
107 MI.eraseFromParent();
129 Register CondReg, TrueReg, FalseReg;
151 !
MRI.getType(DotOperand1).isScalar() ||
152 !
MRI.getType(DotOperand2).isScalar())
161 auto AreNegatedConstantsOrSplats = [&](
Register TrueReg,
Register FalseReg) {
162 std::optional<FPValueAndVReg> TrueVal, FalseVal;
166 APFloat TrueValNegated = TrueVal->Value;
173 std::optional<FPValueAndVReg> MulConstant;
194 if (!MulConstant || !MulConstant->Value.isMinusOne())
196 }
else if (!AreNegatedConstantsOrSplats(TrueReg, FalseReg))
213 if (DotInstr->
getOpcode() == TargetOpcode::G_FMUL) {
221 Register FalseReg =
MI.getOperand(3).getReg();
223 if (TrueInstr->
getOpcode() == TargetOpcode::G_FNEG ||
224 TrueInstr->
getOpcode() == TargetOpcode::G_FMUL)
227 Register ResultReg =
MI.getOperand(0).getReg();
229 Builder.buildIntrinsic(Intrinsic::spv_faceforward, ResultReg)
232 .addUse(DotOperand2);
234 MI.eraseFromParent();
246 if (Rows == 1 || Cols == 1) {
247 Builder.buildCopy(ResReg, InReg);
248 MI.eraseFromParent();
253 for (
uint32_t K = 0; K < Rows * Cols; ++K) {
256 Mask.push_back(
C * Rows + R);
259 Builder.buildShuffleVector(ResReg, InReg, InReg, Mask);
260 MI.eraseFromParent();
264SPIRVCombinerHelper::extractColumns(
Register MatrixReg,
uint32_t NumberOfCols,
268 if (NumberOfCols == 1)
273 for (
uint32_t J = 0; J < NumberOfCols; ++J)
275 Builder.buildUnmerge(Cols, MatrixReg);
283SPIRVCombinerHelper::extractRows(
Register MatrixReg, uint32_t NumRows,
293 for (uint32_t
I = 0;
I < NumRows; ++
I)
294 Rows.
push_back(
MRI.createGenericVirtualRegister(VecTy));
295 Builder.buildUnmerge(Rows, MatrixReg);
307 for (uint32_t
I = 0;
I < NumRows; ++
I) {
308 SmallVector<int, 4>
Mask;
309 for (uint32_t k = 0;
k < NumCols; ++
k)
310 Mask.push_back(k * NumRows +
I);
311 Rows.
push_back(
Builder.buildShuffleVector(VecTy, MatrixReg, MatrixReg, Mask)
324 bool IsFloatOp = SpvScalarType->
getOpcode() == SPIRV::OpTypeFloat;
330 Intrinsic::SPVIntrinsics DotIntrinsic =
331 (IsFloatOp ? Intrinsic::spv_fdot : Intrinsic::spv_udot);
332 DotRes =
Builder.buildIntrinsic(DotIntrinsic, {ScalarTy})
338 DotRes =
Builder.buildFMul(VecTy, RowA, ColB).getReg(0);
340 DotRes =
Builder.buildMul(VecTy, RowA, ColB).getReg(0);
349 SmallVector<Register, 16> ResultScalars;
350 for (uint32_t J = 0; J < ColsB.
size(); ++J) {
351 for (uint32_t
I = 0;
I < RowsA.
size(); ++
I) {
353 computeDotProduct(RowsA[
I], ColsB[J], SpvVecType, GR));
356 return ResultScalars;
360SPIRVCombinerHelper::getDotProductVectorType(
Register ResReg, uint32_t K,
363 Type *ScalarResType =
nullptr;
364 for (
auto &
UseMI :
MRI.use_instructions(ResReg)) {
365 if (
UseMI.getOpcode() != TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS)
384 SPIRV::AccessQualifier::None,
false);
391 uint32_t NumRowsA =
MI.getOperand(4).getImm();
392 uint32_t NumColsA =
MI.getOperand(5).getImm();
393 uint32_t NumColsB =
MI.getOperand(6).getImm();
400 SPIRVTypeInst SpvVecType = getDotProductVectorType(ResReg, NumColsA, GR);
402 extractColumns(BReg, NumColsB, SpvVecType, GR);
404 extractRows(AReg, NumRowsA, NumColsA, SpvVecType, GR);
406 computeDotProducts(RowsA, ColsB, SpvVecType, GR);
408 if (ResultScalars.
size() == 1)
409 Builder.buildCopy(ResReg, ResultScalars[0]);
411 Builder.buildBuildVector(ResReg, ResultScalars);
412 MI.eraseFromParent();
MachineInstrBuilder & UseMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
static std::pair< Value *, APInt > getMask(Value *WideMask, unsigned Factor, ElementCount LeafValueEC)
Contains matchers for matching SSA Machine Instructions.
Promote Memory to Register
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
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)
Represents a G_BUILD_VECTOR.
Abstract class that contains various methods for clients to notify about changes.
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.
const MachineOperand & getOperand(unsigned i) const
Register getReg() const
getReg - Returns the register number.
const MachineFunction & getMF() const
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
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 matchFDivToNormalize(MachineInstr &MI) const
This match is part of a combine that rewrites X / length(X) to normalize(X) (vXf32 (g_fdiv (vXf32 X) ...
LLVM_ABI 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)
void applySPIRVNormalize(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...
LLT getRegType(SPIRVTypeInst SpvType) const
SPIRVTypeInst getScalarOrVectorComponentType(SPIRVTypeInst Type) const
SPIRVTypeInst getOrCreateSPIRVType(const Type *Type, MachineInstr &I, SPIRV::AccessQualifier::AccessQualifier AQ, bool EmitIR)
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.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
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.
operand_type_match m_Reg()
GInstrBind< GBuildVector > m_GBuildVector(GBuildVector *&Inst)
operand_type_match m_Pred()
SpecificConstantMatch m_ZeroInt()
Convenience matchers for specific integer values.
BinaryOp_match< LHS, RHS, TargetOpcode::G_FSUB, false > m_GFSub(const LHS &L, const RHS &R)
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)
GInstrBind< GIntrinsic > m_GIntrinsic(GIntrinsic *&Inst)
Binds the defining instruction of Reg if it is a GIntrinsic (any of the four G_INTRINSIC* opcodes).
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.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
bool isVectorType(SPIRVTypeInst SPVTy)
void setRegClassType(Register Reg, SPIRVTypeInst SpvType, SPIRVGlobalRegistry *GR, MachineRegisterInfo *MRI, const MachineFunction &MF, bool Force)
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.