/////////////////////////////////////////////////////////////////////////////// // // // DxilLegalizeEvalOperations.cpp // // Copyright (C) Microsoft Corporation. All rights reserved. // // This file is distributed under the University of Illinois Open Source // // License. See LICENSE.TXT for details. // // // /////////////////////////////////////////////////////////////////////////////// #include "dxc/HlslIntrinsicOp.h" #include "dxc/DXIL/DxilModule.h" #include "dxc/HLSL/DxilGenerationPass.h" #include "dxc/HLSL/HLOperations.h" #include "llvm/Pass.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" #include "llvm/Transforms/Utils/SSAUpdater.h" #include #include using namespace llvm; using namespace hlsl; // 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 EvalFunctionCalls; // Find all EvaluateAttribute calls for (User *U : F.users()) { if (CallInst *CI = dyn_cast(U)) { IntrinsicOp evalOp = static_cast(hlsl::GetHLOpcode(CI)); if (evalOp == IntrinsicOp::IOP_EvaluateAttributeAtSample || evalOp == IntrinsicOp::IOP_EvaluateAttributeCentroid || evalOp == IntrinsicOp::IOP_EvaluateAttributeSnapped || evalOp == IntrinsicOp::IOP_GetAttributeAtVertex) { EvalFunctionCalls.push_back(CI); } } } if (EvalFunctionCalls.empty()) { continue; } // Start from the call instruction, find all allocas that this call // uses. std::unordered_set allocas; for (CallInst *CI : EvalFunctionCalls) { FindAllocasForEvalOperations(CI, allocas); } SSAUpdater SSA; SmallVector Insts; for (AllocaInst *AI : allocas) { for (User *user : AI->users()) { if (isa(user) || isa(user)) { Insts.emplace_back(cast(user)); } } LoadAndStorePromoter(Insts, SSA).run(Insts); Insts.clear(); } } } return true; } private: void FindAllocasForEvalOperations(Value *val, std::unordered_set &allocas); }; char DxilLegalizeEvalOperations::ID = 0; // Find allocas for EvaluateAttribute operations void DxilLegalizeEvalOperations::FindAllocasForEvalOperations( Value *val, std::unordered_set &allocas) { Value *CurVal = val; while (!isa(CurVal)) { if (CallInst *CI = dyn_cast(CurVal)) { CurVal = CI->getOperand(HLOperandIndex::kUnaryOpSrc0Idx); } else if (InsertElementInst *IE = dyn_cast(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(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(CurVal)) { CurVal = EE->getOperand(0); } else if (LoadInst *LI = dyn_cast(CurVal)) { CurVal = LI->getOperand(0); } else { break; } } if (AllocaInst *AI = dyn_cast(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)