-
Notifications
You must be signed in to change notification settings - Fork 852
Allow native vectors for LLVM operations #7155
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 13 commits
68a284b
556f6e6
654bf8a
248fe80
f1de617
47d42f0
d480caa
c2ee61b
a3a39b8
6f7f9ec
1596d99
411b921
8dc2a3e
46829dd
9002bee
ba831c0
7292edb
96ac2e2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -76,13 +76,17 @@ Type *TryLowerMatTy(Type *Ty) { | |
| } | ||
|
|
||
| class MatrixBitcastLowerPass : public FunctionPass { | ||
| bool SupportsVectors = false; | ||
|
|
||
| public: | ||
| static char ID; // Pass identification, replacement for typeid | ||
| explicit MatrixBitcastLowerPass() : FunctionPass(ID) {} | ||
|
|
||
| StringRef getPassName() const override { return "Matrix Bitcast lower"; } | ||
| bool runOnFunction(Function &F) override { | ||
| DxilModule &DM = F.getParent()->GetOrCreateDxilModule(); | ||
| SupportsVectors = DM.GetShaderModel()->IsSM69Plus(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you want to avoid full DxilModule dependency, I think it would be reasonable to have something that can look up the DXIL version in the module without loading full metadata, whether or not it's HLM or DM.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like this idea. I know I mentioned it somewhere before. I'd prefer it not block this change though. |
||
|
|
||
| bool bUpdated = false; | ||
| std::unordered_set<BitCastInst *> matCastSet; | ||
| for (auto blkIt = F.begin(); blkIt != F.end(); ++blkIt) { | ||
|
|
@@ -100,7 +104,6 @@ class MatrixBitcastLowerPass : public FunctionPass { | |
| } | ||
| } | ||
|
|
||
| DxilModule &DM = F.getParent()->GetOrCreateDxilModule(); | ||
| // Remove bitcast which has CallInst user. | ||
| if (DM.GetShaderModel()->IsLib()) { | ||
| for (auto it = matCastSet.begin(); it != matCastSet.end();) { | ||
|
|
@@ -113,13 +116,13 @@ class MatrixBitcastLowerPass : public FunctionPass { | |
|
|
||
| // Lower matrix first. | ||
| for (BitCastInst *BCI : matCastSet) { | ||
| lowerMatrix(BCI, BCI->getOperand(0)); | ||
| lowerMatrix(DM, BCI, BCI->getOperand(0)); | ||
| } | ||
| return bUpdated; | ||
| } | ||
|
|
||
| private: | ||
| void lowerMatrix(Instruction *M, Value *A); | ||
| void lowerMatrix(DxilModule &DM, Instruction *M, Value *A); | ||
| bool hasCallUser(Instruction *M); | ||
| }; | ||
|
|
||
|
|
@@ -180,44 +183,56 @@ Value *CreateEltGEP(Value *A, unsigned i, Value *zeroIdx, | |
| } | ||
| } // namespace | ||
|
|
||
| void MatrixBitcastLowerPass::lowerMatrix(Instruction *M, Value *A) { | ||
| void MatrixBitcastLowerPass::lowerMatrix(DxilModule &DM, Instruction *M, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not seeing any use of
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, it's a relic from when I was getting the version from it. |
||
| Value *A) { | ||
| for (auto it = M->user_begin(); it != M->user_end();) { | ||
| User *U = *(it++); | ||
| if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(U)) { | ||
| Type *EltTy = GEP->getType()->getPointerElementType(); | ||
| if (HLMatrixType::isa(EltTy)) { | ||
| if (HLMatrixType MatTy = HLMatrixType::dyn_cast(EltTy)) { | ||
| // Change gep matrixArray, 0, index | ||
| // into | ||
| // gep oneDimArray, 0, index * matSize | ||
| IRBuilder<> Builder(GEP); | ||
| SmallVector<Value *, 2> idxList(GEP->idx_begin(), GEP->idx_end()); | ||
| DXASSERT(idxList.size() == 2, | ||
| "else not one dim matrix array index to matrix"); | ||
|
|
||
| HLMatrixType MatTy = HLMatrixType::cast(EltTy); | ||
| Value *matSize = Builder.getInt32(MatTy.getNumElements()); | ||
| idxList.back() = Builder.CreateMul(idxList.back(), matSize); | ||
| unsigned NumElts = MatTy.getNumElements(); | ||
| if (!SupportsVectors || NumElts == 1) { | ||
| Value *MatSize = Builder.getInt32(NumElts); | ||
| idxList.back() = Builder.CreateMul(idxList.back(), MatSize); | ||
| } | ||
| Value *NewGEP = Builder.CreateGEP(A, idxList); | ||
| lowerMatrix(GEP, NewGEP); | ||
| lowerMatrix(DM, GEP, NewGEP); | ||
| DXASSERT(GEP->user_empty(), "else lower matrix fail"); | ||
| GEP->eraseFromParent(); | ||
| } else { | ||
| DXASSERT(0, "invalid GEP for matrix"); | ||
| } | ||
| } else if (BitCastInst *BCI = dyn_cast<BitCastInst>(U)) { | ||
| lowerMatrix(BCI, A); | ||
| lowerMatrix(DM, BCI, A); | ||
| DXASSERT(BCI->user_empty(), "else lower matrix fail"); | ||
| BCI->eraseFromParent(); | ||
| } else if (LoadInst *LI = dyn_cast<LoadInst>(U)) { | ||
| if (VectorType *Ty = dyn_cast<VectorType>(LI->getType())) { | ||
| IRBuilder<> Builder(LI); | ||
| Value *zeroIdx = Builder.getInt32(0); | ||
| unsigned vecSize = Ty->getNumElements(); | ||
| Value *NewVec = UndefValue::get(LI->getType()); | ||
| for (unsigned i = 0; i < vecSize; i++) { | ||
| Value *GEP = CreateEltGEP(A, i, zeroIdx, Builder); | ||
| Value *Elt = Builder.CreateLoad(GEP); | ||
| NewVec = Builder.CreateInsertElement(NewVec, Elt, i); | ||
| Value *NewVec = nullptr; | ||
| unsigned VecSize = Ty->getVectorNumElements(); | ||
| if (SupportsVectors && VecSize > 1) { | ||
| // Create a replacement load using the vector pointer. | ||
| Instruction *NewLd = LI->clone(); | ||
| unsigned VecIdx = NewLd->getNumOperands() - 1; | ||
| NewLd->setOperand(VecIdx, A); | ||
| Builder.Insert(NewLd); | ||
| NewVec = NewLd; | ||
| } else { | ||
| Value *zeroIdx = Builder.getInt32(0); | ||
| NewVec = UndefValue::get(LI->getType()); | ||
| for (unsigned i = 0; i < VecSize; i++) { | ||
| Value *GEP = CreateEltGEP(A, i, zeroIdx, Builder); | ||
| Value *Elt = Builder.CreateLoad(GEP); | ||
| NewVec = Builder.CreateInsertElement(NewVec, Elt, i); | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I noticed that below this point, there's: } else if (StoreInst *ST = dyn_cast<StoreInst>(U)) {where it still scalarizes the store for the vector. Did you mean to leave that scalarization in?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I omitted store support in error. Clearly we need some testing for it as it never caused any issues. |
||
| } | ||
| LI->replaceAllUsesWith(NewVec); | ||
| LI->eraseFromParent(); | ||
|
|
@@ -228,12 +243,20 @@ void MatrixBitcastLowerPass::lowerMatrix(Instruction *M, Value *A) { | |
| Value *V = ST->getValueOperand(); | ||
| if (VectorType *Ty = dyn_cast<VectorType>(V->getType())) { | ||
| IRBuilder<> Builder(LI); | ||
| Value *zeroIdx = Builder.getInt32(0); | ||
| unsigned vecSize = Ty->getNumElements(); | ||
| for (unsigned i = 0; i < vecSize; i++) { | ||
| Value *GEP = CreateEltGEP(A, i, zeroIdx, Builder); | ||
| Value *Elt = Builder.CreateExtractElement(V, i); | ||
| Builder.CreateStore(Elt, GEP); | ||
| if (SupportsVectors && Ty->getVectorNumElements() > 1) { | ||
| // Create a replacement store using the vector pointer. | ||
| Instruction *NewSt = ST->clone(); | ||
| unsigned VecIdx = NewSt->getNumOperands() - 1; | ||
| NewSt->setOperand(VecIdx, A); | ||
| Builder.Insert(NewSt); | ||
| } else { | ||
| Value *zeroIdx = Builder.getInt32(0); | ||
| unsigned vecSize = Ty->getNumElements(); | ||
| for (unsigned i = 0; i < vecSize; i++) { | ||
| Value *GEP = CreateEltGEP(A, i, zeroIdx, Builder); | ||
| Value *Elt = Builder.CreateExtractElement(V, i); | ||
| Builder.CreateStore(Elt, GEP); | ||
| } | ||
| } | ||
| ST->eraseFromParent(); | ||
| } else { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ | |
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "dxc/DXIL/DxilConstants.h" | ||
| #include "dxc/DXIL/DxilModule.h" | ||
| #include "dxc/DXIL/DxilOperations.h" | ||
| #include "dxc/DXIL/DxilUtil.h" | ||
| #include "dxc/HLSL/HLModule.h" | ||
|
|
@@ -180,10 +181,12 @@ bool LowerTypePass::runOnModule(Module &M) { | |
| namespace { | ||
| class DynamicIndexingVectorToArray : public LowerTypePass { | ||
| bool ReplaceAllVectors; | ||
| bool SupportsVectors; | ||
|
|
||
| public: | ||
| explicit DynamicIndexingVectorToArray(bool ReplaceAll = false) | ||
| : LowerTypePass(ID), ReplaceAllVectors(ReplaceAll) {} | ||
| : LowerTypePass(ID), ReplaceAllVectors(ReplaceAll), | ||
| SupportsVectors(false) {} | ||
| static char ID; // Pass identification, replacement for typeid | ||
| void applyOptions(PassOptions O) override; | ||
| void dumpConfig(raw_ostream &OS) override; | ||
|
|
@@ -194,6 +197,7 @@ class DynamicIndexingVectorToArray : public LowerTypePass { | |
| Type *lowerType(Type *Ty) override; | ||
| Constant *lowerInitVal(Constant *InitVal, Type *NewTy) override; | ||
| StringRef getGlobalPrefix() override { return ".v"; } | ||
| void initialize(Module &M) override; | ||
|
|
||
| private: | ||
| bool HasVectorDynamicIndexing(Value *V); | ||
|
|
@@ -207,6 +211,21 @@ class DynamicIndexingVectorToArray : public LowerTypePass { | |
| void ReplaceAddrSpaceCast(ConstantExpr *CE, Value *A, IRBuilder<> &Builder); | ||
| }; | ||
|
|
||
| void DynamicIndexingVectorToArray::initialize(Module &M) { | ||
| // Can be invoked in a few places: | ||
| // - From standard compile before dxilgen. | ||
| // - When linking, where dxmodule is available. | ||
| // - In isolated dxopt, where the module will need to be created. | ||
| // Since HL module can't be created when linking, check for that first. | ||
| // Otherwise, either retrieve or generate the HL module. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this say "Since dxmodule can't be created when linking..."?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, we actually can create a dxil module when linking. Maybe I'll replace it with getorcreatedxilmodule just in case. We can't create an hlmodule while linking
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see why it's confusing now though. the "it" was supposed to be a dxil module, but that is not at all clear from the wording. |
||
| if (M.HasDxilModule()) { | ||
| SupportsVectors = M.GetDxilModule().GetShaderModel()->IsSM69Plus(); | ||
| } else { | ||
| HLModule &HLM = M.GetOrCreateHLModule(); | ||
| SupportsVectors = HLM.GetShaderModel()->IsSM69Plus(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I mentioned earlier, it might be better to get the DXIL version from metadata without relying on full HLModule/DxilModule metadata loading. Maybe we can add a But the fixes to the HLModule loading are appreciated! |
||
| } | ||
| } | ||
|
|
||
| void DynamicIndexingVectorToArray::applyOptions(PassOptions O) { | ||
| GetPassOptionBool(O, "ReplaceAllVectors", &ReplaceAllVectors, | ||
| ReplaceAllVectors); | ||
|
|
@@ -306,9 +325,21 @@ void DynamicIndexingVectorToArray::ReplaceStaticIndexingOnVector(Value *V) { | |
| } | ||
|
|
||
| bool DynamicIndexingVectorToArray::needToLower(Value *V) { | ||
| bool MustReplaceVector = ReplaceAllVectors; | ||
| Type *Ty = V->getType()->getPointerElementType(); | ||
| if (dyn_cast<VectorType>(Ty)) { | ||
| if (isa<GlobalVariable>(V) || ReplaceAllVectors) { | ||
|
|
||
| if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) { | ||
| // Array must be replaced even without dynamic indexing to remove vector | ||
| // type in dxil. | ||
| MustReplaceVector = true; | ||
| Ty = dxilutil::GetArrayEltTy(AT); | ||
| } | ||
|
|
||
| if (isa<VectorType>(Ty)) { | ||
| // Only needed for 2+ vectors where native vectors unsupported. | ||
| if (SupportsVectors && Ty->getVectorNumElements() > 1) | ||
| return false; | ||
| if (isa<GlobalVariable>(V) || MustReplaceVector) { | ||
| return true; | ||
| } | ||
| // Don't lower local vector which only static indexing. | ||
|
|
@@ -319,12 +350,6 @@ bool DynamicIndexingVectorToArray::needToLower(Value *V) { | |
| ReplaceStaticIndexingOnVector(V); | ||
| return false; | ||
| } | ||
| } else if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) { | ||
| // Array must be replaced even without dynamic indexing to remove vector | ||
| // type in dxil. | ||
| // TODO: optimize static array index in later pass. | ||
| Type *EltTy = dxilutil::GetArrayEltTy(AT); | ||
| return isa<VectorType>(EltTy); | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A little suprised to see
ExtractElement`InsertElement\ShuffleVector` weren't already defined since I expected at least the first two as required for scalarization which DXIL already supports.If these are new for vectorization, should
isAllowed()be checkingIsSM69Plus()instead of always returning true?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Scalarization took place before DXIL was generated. The output has no native vectors in non-lib shaders and so had no need for these functions. Intermediate steps might have these, but were disallowed for validation of final output. For similar reasons as their inclusion in intermediate steps, library shaders would allow these ops as they preserved native vectors in function interfaces. The check for library shader allowed ops accounts for this in validation.
DirectXShaderCompiler/lib/DxilValidation/DxilValidation.cpp
Line 2652 in b646ad3
The inclusion here adds them to the list of instructions that are approved for general validation by
IsLLVMInstructionAllowed, a generated function that merelyreturns whether the opcode is in the list of approved LLVM instructions for a non-lib. It is generated into DxilValidationImpl.inc and called here:
DirectXShaderCompiler/lib/DxilValidation/DxilValidation.cpp
Line 2694 in b646ad3
Similar to this function, this member is meant to return just true or false if it is allowed at all. I should add a 6.9 check to validation though.