|
@@ -256,7 +256,6 @@ public:
|
|
|
// Load up debug information, to cross-reference values and the instructions
|
|
|
// used to load them.
|
|
|
m_HasDbgInfo = getDebugMetadataVersionFromModule(M) != 0;
|
|
|
- LegalizeEvalOperations(M);
|
|
|
if (!SM->IsCS()) {
|
|
|
CreateDxilSignatures();
|
|
|
|
|
@@ -381,10 +380,6 @@ private:
|
|
|
// For validation
|
|
|
std::unordered_map<unsigned, std::unordered_set<unsigned> > m_InputSemanticsUsed,
|
|
|
m_OutputSemanticsUsed[4], m_PatchConstantSemanticsUsed, m_OtherSemanticsUsed;
|
|
|
-
|
|
|
- // For EvaluateAttribute operations.
|
|
|
- void LegalizeEvalOperations(Module &M);
|
|
|
- void FindAllocasForEvalOperations(Value *f, std::unordered_set<AllocaInst*> &allocas);
|
|
|
};
|
|
|
|
|
|
class SimplifyInst : public FunctionPass {
|
|
@@ -2708,81 +2703,6 @@ void DxilGenerationPass::UpdateStructTypeForLegacyLayout() {
|
|
|
UpdateStructTypeForLegacyLayoutOnHLM(*m_pHLModule);
|
|
|
}
|
|
|
|
|
|
-// Find allocas for EvaluateAttribute operations
|
|
|
-void DxilGenerationPass::FindAllocasForEvalOperations(
|
|
|
- Value *val, std::unordered_set<AllocaInst *> &allocas) {
|
|
|
- Value *CurVal = val;
|
|
|
- while (!isa<AllocaInst>(CurVal)) {
|
|
|
- if (CallInst *CI = dyn_cast<CallInst>(CurVal)) {
|
|
|
- CurVal = CI->getOperand(HLOperandIndex::kUnaryOpSrc0Idx);
|
|
|
- } else if (InsertElementInst *IE = dyn_cast<InsertElementInst>(CurVal)) {
|
|
|
- Value *arg0 =
|
|
|
- IE->getOperand(0); // Could be another insertelement or undef
|
|
|
- Value *arg1 = IE->getOperand(1);
|
|
|
- FindAllocasForEvalOperations(arg0, allocas);
|
|
|
- CurVal = arg1;
|
|
|
- } else if (ShuffleVectorInst *SV = dyn_cast<ShuffleVectorInst>(CurVal)) {
|
|
|
- Value *arg0 = SV->getOperand(0);
|
|
|
- Value *arg1 = SV->getOperand(1);
|
|
|
- FindAllocasForEvalOperations(
|
|
|
- arg0, allocas); // Shuffle vector could come from different allocas
|
|
|
- CurVal = arg1;
|
|
|
- } else if (ExtractElementInst *EE = dyn_cast<ExtractElementInst>(CurVal)) {
|
|
|
- CurVal = EE->getOperand(0);
|
|
|
- } else if (LoadInst *LI = dyn_cast<LoadInst>(CurVal)) {
|
|
|
- CurVal = LI->getOperand(0);
|
|
|
- } else {
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- if (AllocaInst *AI = dyn_cast<AllocaInst>(CurVal)) {
|
|
|
- allocas.insert(AI);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// This is needed in order to translate EvaluateAttribute operations that traces
|
|
|
-// back to LoadInput operations during translation stage. Promoting load/store
|
|
|
-// instructions beforehand will allow us to easily trace back to loadInput from
|
|
|
-// function call.
|
|
|
-void DxilGenerationPass::LegalizeEvalOperations(Module &M) {
|
|
|
- for (Function &F : M.getFunctionList()) {
|
|
|
- hlsl::HLOpcodeGroup group = hlsl::GetHLOpcodeGroup(&F);
|
|
|
- if (group != HLOpcodeGroup::NotHL) {
|
|
|
- std::vector<CallInst *> EvalFunctionCalls;
|
|
|
- // Find all EvaluateAttribute calls
|
|
|
- for (User *U : F.users()) {
|
|
|
- if (CallInst *CI = dyn_cast<CallInst>(U)) {
|
|
|
- IntrinsicOp evalOp = static_cast<IntrinsicOp>(hlsl::GetHLOpcode(CI));
|
|
|
- if (evalOp == IntrinsicOp::IOP_EvaluateAttributeAtSample ||
|
|
|
- evalOp == IntrinsicOp::IOP_EvaluateAttributeCentroid ||
|
|
|
- evalOp == IntrinsicOp::IOP_EvaluateAttributeSnapped) {
|
|
|
- EvalFunctionCalls.push_back(CI);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- if (EvalFunctionCalls.empty()) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- // Start from the call instruction, find all allocas that this call uses.
|
|
|
- std::unordered_set<AllocaInst *> allocas;
|
|
|
- for (CallInst *CI : EvalFunctionCalls) {
|
|
|
- FindAllocasForEvalOperations(CI, allocas);
|
|
|
- }
|
|
|
- SSAUpdater SSA;
|
|
|
- SmallVector<Instruction *, 4> Insts;
|
|
|
- for (AllocaInst *AI : allocas) {
|
|
|
- for (User *user : AI->users()) {
|
|
|
- if (isa<LoadInst>(user) || isa<StoreInst>(user)) {
|
|
|
- Insts.emplace_back(cast<Instruction>(user));
|
|
|
- }
|
|
|
- }
|
|
|
- LoadAndStorePromoter(Insts, SSA).run(Insts);
|
|
|
- Insts.clear();
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
namespace {
|
|
@@ -3248,6 +3168,9 @@ public:
|
|
|
}
|
|
|
|
|
|
bool runOnModule(Module &M) override {
|
|
|
+ HLModule &HLM = M.GetOrCreateHLModule();
|
|
|
+ OP *hlslOP = HLM.GetOP();
|
|
|
+ Type *HandleTy = hlslOP->GetHandleType();
|
|
|
// Promote static global variables.
|
|
|
PromoteStaticGlobalResources(M);
|
|
|
|
|
@@ -3266,15 +3189,20 @@ public:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Transform PHINode/SelectInst on resource into PHINode/SelectInst on
|
|
|
- // Handle. This will make sure resource only have ld/st/gep use.
|
|
|
- TransformResourcePHINodeToHandlePHINode(M);
|
|
|
+ Value *UndefHandle = UndefValue::get(HandleTy);
|
|
|
+ if (!UndefHandle->user_empty()) {
|
|
|
+ for (User *U : UndefHandle->users()) {
|
|
|
+ // Report error if undef handle used for function call.
|
|
|
+ if (isa<CallInst>(U)) {
|
|
|
+ M.getContext().emitError(kResourceMapErrorMsg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
private:
|
|
|
void PromoteStaticGlobalResources(Module &M);
|
|
|
- void TransformResourcePHINodeToHandlePHINode(Module &M);
|
|
|
void TransformHandleCast(Function &F);
|
|
|
};
|
|
|
|
|
@@ -3318,6 +3246,9 @@ void DxilLegalizeResourceUsePass::PromoteLocalResource(Function &F) {
|
|
|
DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
|
|
|
AssumptionCache &AC =
|
|
|
getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
|
|
|
+ HLModule &HLM = F.getParent()->GetOrCreateHLModule();
|
|
|
+ OP *hlslOP = HLM.GetOP();
|
|
|
+ Type *HandleTy = hlslOP->GetHandleType();
|
|
|
|
|
|
BasicBlock &BB = F.getEntryBlock();
|
|
|
unsigned allocaSize = 0;
|
|
@@ -3328,7 +3259,7 @@ void DxilLegalizeResourceUsePass::PromoteLocalResource(Function &F) {
|
|
|
// the entry node
|
|
|
for (BasicBlock::iterator I = BB.begin(), E = --BB.end(); I != E; ++I)
|
|
|
if (AllocaInst *AI = dyn_cast<AllocaInst>(I)) { // Is it an alloca?
|
|
|
- if (IsResourceType(AI->getAllocatedType()))
|
|
|
+ if (HandleTy == HLModule::GetArrayEltTy(AI->getAllocatedType()))
|
|
|
Allocas.push_back(AI);
|
|
|
}
|
|
|
if (Allocas.empty())
|
|
@@ -3363,10 +3294,13 @@ INITIALIZE_PASS_END(DxilLegalizeResourceUsePass,
|
|
|
|
|
|
void DxilLegalizeStaticResourceUsePass::PromoteStaticGlobalResources(
|
|
|
Module &M) {
|
|
|
+ HLModule &HLM = M.GetOrCreateHLModule();
|
|
|
+ Type *HandleTy = HLM.GetOP()->GetHandleType();
|
|
|
+
|
|
|
std::set<GlobalVariable *> staticResources;
|
|
|
for (auto &GV : M.globals()) {
|
|
|
if (GV.getLinkage() == GlobalValue::LinkageTypes::InternalLinkage &&
|
|
|
- IsResourceType(GV.getType()->getElementType())) {
|
|
|
+ HandleTy == HLModule::GetArrayEltTy(GV.getType())) {
|
|
|
staticResources.insert(&GV);
|
|
|
}
|
|
|
}
|
|
@@ -3398,122 +3332,6 @@ void DxilLegalizeStaticResourceUsePass::PromoteStaticGlobalResources(
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void DxilLegalizeStaticResourceUsePass::TransformResourcePHINodeToHandlePHINode(
|
|
|
- Module &M) {
|
|
|
- HLModule &HLM = M.GetOrCreateHLModule();
|
|
|
- OP *hlslOP = HLM.GetOP();
|
|
|
- Type *HandleTy = hlslOP->GetHandleType();
|
|
|
-
|
|
|
- std::unordered_set<Instruction *> resSet;
|
|
|
- // Find all hl create handle which use a phi/select.
|
|
|
- for (Function &TempF : M.functions()) {
|
|
|
- if (GetHLOpcodeGroupByName(&TempF) == HLOpcodeGroup::HLCreateHandle) {
|
|
|
- for (User *U : TempF.users()) {
|
|
|
- CallInst *CI = cast<CallInst>(U);
|
|
|
- Value *ResOp =
|
|
|
- CI->getArgOperand(HLOperandIndex::kCreateHandleResourceOpIdx);
|
|
|
- if (Instruction *Res = dyn_cast<Instruction>(ResOp))
|
|
|
- AddResourceToSet(Res, resSet);
|
|
|
- else if (isa<UndefValue>(ResOp)) {
|
|
|
- CI->getContext().emitError(CI, kResourceMapErrorMsg);
|
|
|
- continue;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- Value *UndefHandle = UndefValue::get(HandleTy);
|
|
|
-
|
|
|
- // Generate Handle inst for Res inst.
|
|
|
- std::unordered_map<Instruction *, Value *> resHandleMap;
|
|
|
- for (Instruction *Res : resSet) {
|
|
|
- unsigned numOperands = Res->getNumOperands();
|
|
|
- IRBuilder<> Builder(Res);
|
|
|
-
|
|
|
- unsigned startOpIdx = 0;
|
|
|
- // Skip Cond for Select.
|
|
|
- if (SelectInst *Sel = dyn_cast<SelectInst>(Res)) {
|
|
|
- startOpIdx = 1;
|
|
|
- Value *Cond = Sel->getCondition();
|
|
|
- // Use undef handle to create, will be updated in next loop.
|
|
|
- Value *Handle = Builder.CreateSelect(Cond, UndefHandle, UndefHandle);
|
|
|
- resHandleMap[Res] = Handle;
|
|
|
- } else {
|
|
|
- PHINode *Phi = cast<PHINode>(Res);
|
|
|
- PHINode *HandlePhi = Builder.CreatePHI(HandleTy, numOperands);
|
|
|
- // Use undef handle to create, will be updated in next loop.
|
|
|
- for (unsigned i = 0; i < numOperands; i++) {
|
|
|
- BasicBlock *BB = Phi->getIncomingBlock(i);
|
|
|
- HandlePhi->addIncoming(UndefHandle, BB);
|
|
|
- }
|
|
|
- resHandleMap[Res] = HandlePhi;
|
|
|
- }
|
|
|
-
|
|
|
- // Generate createHandle for LdInst opreands.
|
|
|
- for (unsigned i = startOpIdx; i < numOperands; i++) {
|
|
|
- if (LoadInst *LI = dyn_cast<LoadInst>(Res->getOperand(i))) {
|
|
|
- if (resHandleMap.count(LI))
|
|
|
- continue;
|
|
|
- IRBuilder<> LocalBuilder(LI);
|
|
|
-
|
|
|
- Instruction *Handle =
|
|
|
- HLM.EmitHLOperationCall(LocalBuilder, HLOpcodeGroup::HLCreateHandle,
|
|
|
- /*opcode*/ 0, HandleTy, {LI}, M);
|
|
|
- // No new HL createHandle will be created.
|
|
|
- // So don't need MarkResourceAttribute here.
|
|
|
- resHandleMap[LI] = Handle;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Update operand for Handle phi/select.
|
|
|
- for (Instruction *Res : resSet) {
|
|
|
- unsigned numOperands = Res->getNumOperands();
|
|
|
-
|
|
|
- unsigned startOpIdx = 0;
|
|
|
- // Skip Cond for Select.
|
|
|
- if (SelectInst *Sel = dyn_cast<SelectInst>(Res))
|
|
|
- startOpIdx = 1;
|
|
|
-
|
|
|
- Instruction *Handle = cast<Instruction>(resHandleMap[Res]);
|
|
|
-
|
|
|
- for (unsigned i = startOpIdx; i < numOperands; i++) {
|
|
|
- if (!isa<Instruction>(Res->getOperand(i))) {
|
|
|
- Res->getContext().emitError(Res, kResourceMapErrorMsg);
|
|
|
- continue;
|
|
|
- }
|
|
|
- Instruction *ResOp = cast<Instruction>(Res->getOperand(i));
|
|
|
- if (resHandleMap.count(ResOp) == 0) {
|
|
|
- Res->getContext().emitError(Res, kResourceMapErrorMsg);
|
|
|
- continue;
|
|
|
- }
|
|
|
- Instruction *HandleOp = cast<Instruction>(resHandleMap[ResOp]);
|
|
|
- Handle->setOperand(i, HandleOp);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Replace use of handle with new created handle.
|
|
|
- for (Instruction *Res : resSet) {
|
|
|
- Value *Handle = resHandleMap[Res];
|
|
|
- for (auto U = Res->user_begin(); U != Res->user_end();) {
|
|
|
- User *ResU = *(U++);
|
|
|
- if (isa<CallInst>(ResU) && ResU->getType() == HandleTy) {
|
|
|
- ResU->replaceAllUsesWith(Handle);
|
|
|
- cast<Instruction>(ResU)->eraseFromParent();
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Remove the unused phi/select on resource.
|
|
|
- for (Instruction *Res : resSet) {
|
|
|
- Res->dropAllReferences();
|
|
|
- }
|
|
|
-
|
|
|
- for (Instruction *Res : resSet) {
|
|
|
- Res->eraseFromParent();
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
static void ReplaceResUseWithHandle(Instruction *Res, Value *Handle) {
|
|
|
Type *HandleTy = Handle->getType();
|
|
|
for (auto ResU = Res->user_begin(); ResU != Res->user_end();) {
|
|
@@ -3551,3 +3369,111 @@ ModulePass *llvm::createDxilLegalizeStaticResourceUsePass() {
|
|
|
INITIALIZE_PASS(DxilLegalizeStaticResourceUsePass,
|
|
|
"hlsl-dxil-legalize-static-resource-use",
|
|
|
"DXIL legalize static resource use", false, false)
|
|
|
+
|
|
|
+///////////////////////////////////////////////////////////////////////////////
|
|
|
+// Legalize EvalOperations.
|
|
|
+// Make sure src of EvalOperations are from function parameter.
|
|
|
+// This is needed in order to translate EvaluateAttribute operations that traces
|
|
|
+// back to LoadInput operations during translation stage. Promoting load/store
|
|
|
+// instructions beforehand will allow us to easily trace back to loadInput from
|
|
|
+// function call.
|
|
|
+namespace {
|
|
|
+
|
|
|
+class DxilLegalizeEvalOperations : public ModulePass {
|
|
|
+public:
|
|
|
+ static char ID; // Pass identification, replacement for typeid
|
|
|
+ explicit DxilLegalizeEvalOperations() : ModulePass(ID) {}
|
|
|
+
|
|
|
+ const char *getPassName() const override {
|
|
|
+ return "DXIL Legalize EvalOperations";
|
|
|
+ }
|
|
|
+
|
|
|
+ bool runOnModule(Module &M) override {
|
|
|
+ for (Function &F : M.getFunctionList()) {
|
|
|
+ hlsl::HLOpcodeGroup group = hlsl::GetHLOpcodeGroup(&F);
|
|
|
+ if (group != HLOpcodeGroup::NotHL) {
|
|
|
+ std::vector<CallInst *> EvalFunctionCalls;
|
|
|
+ // Find all EvaluateAttribute calls
|
|
|
+ for (User *U : F.users()) {
|
|
|
+ if (CallInst *CI = dyn_cast<CallInst>(U)) {
|
|
|
+ IntrinsicOp evalOp =
|
|
|
+ static_cast<IntrinsicOp>(hlsl::GetHLOpcode(CI));
|
|
|
+ if (evalOp == IntrinsicOp::IOP_EvaluateAttributeAtSample ||
|
|
|
+ evalOp == IntrinsicOp::IOP_EvaluateAttributeCentroid ||
|
|
|
+ evalOp == IntrinsicOp::IOP_EvaluateAttributeSnapped) {
|
|
|
+ EvalFunctionCalls.push_back(CI);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (EvalFunctionCalls.empty()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // Start from the call instruction, find all allocas that this call
|
|
|
+ // uses.
|
|
|
+ std::unordered_set<AllocaInst *> allocas;
|
|
|
+ for (CallInst *CI : EvalFunctionCalls) {
|
|
|
+ FindAllocasForEvalOperations(CI, allocas);
|
|
|
+ }
|
|
|
+ SSAUpdater SSA;
|
|
|
+ SmallVector<Instruction *, 4> Insts;
|
|
|
+ for (AllocaInst *AI : allocas) {
|
|
|
+ for (User *user : AI->users()) {
|
|
|
+ if (isa<LoadInst>(user) || isa<StoreInst>(user)) {
|
|
|
+ Insts.emplace_back(cast<Instruction>(user));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ LoadAndStorePromoter(Insts, SSA).run(Insts);
|
|
|
+ Insts.clear();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+private:
|
|
|
+ void FindAllocasForEvalOperations(Value *val,
|
|
|
+ std::unordered_set<AllocaInst *> &allocas);
|
|
|
+};
|
|
|
+
|
|
|
+char DxilLegalizeEvalOperations::ID = 0;
|
|
|
+
|
|
|
+// Find allocas for EvaluateAttribute operations
|
|
|
+void DxilLegalizeEvalOperations::FindAllocasForEvalOperations(
|
|
|
+ Value *val, std::unordered_set<AllocaInst *> &allocas) {
|
|
|
+ Value *CurVal = val;
|
|
|
+ while (!isa<AllocaInst>(CurVal)) {
|
|
|
+ if (CallInst *CI = dyn_cast<CallInst>(CurVal)) {
|
|
|
+ CurVal = CI->getOperand(HLOperandIndex::kUnaryOpSrc0Idx);
|
|
|
+ } else if (InsertElementInst *IE = dyn_cast<InsertElementInst>(CurVal)) {
|
|
|
+ Value *arg0 =
|
|
|
+ IE->getOperand(0); // Could be another insertelement or undef
|
|
|
+ Value *arg1 = IE->getOperand(1);
|
|
|
+ FindAllocasForEvalOperations(arg0, allocas);
|
|
|
+ CurVal = arg1;
|
|
|
+ } else if (ShuffleVectorInst *SV = dyn_cast<ShuffleVectorInst>(CurVal)) {
|
|
|
+ Value *arg0 = SV->getOperand(0);
|
|
|
+ Value *arg1 = SV->getOperand(1);
|
|
|
+ FindAllocasForEvalOperations(
|
|
|
+ arg0, allocas); // Shuffle vector could come from different allocas
|
|
|
+ CurVal = arg1;
|
|
|
+ } else if (ExtractElementInst *EE = dyn_cast<ExtractElementInst>(CurVal)) {
|
|
|
+ CurVal = EE->getOperand(0);
|
|
|
+ } else if (LoadInst *LI = dyn_cast<LoadInst>(CurVal)) {
|
|
|
+ CurVal = LI->getOperand(0);
|
|
|
+ } else {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (AllocaInst *AI = dyn_cast<AllocaInst>(CurVal)) {
|
|
|
+ allocas.insert(AI);
|
|
|
+ }
|
|
|
+}
|
|
|
+} // namespace
|
|
|
+
|
|
|
+ModulePass *llvm::createDxilLegalizeEvalOperationsPass() {
|
|
|
+ return new DxilLegalizeEvalOperations();
|
|
|
+}
|
|
|
+
|
|
|
+INITIALIZE_PASS(DxilLegalizeEvalOperations,
|
|
|
+ "hlsl-dxil-legalize-eval-operations",
|
|
|
+ "DXIL legalize eval operations", false, false)
|