| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132 |
- ///////////////////////////////////////////////////////////////////////////////
- // //
- // DxilGenerationPass.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. //
- // //
- // DxilGenerationPass implementation. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
- #include "dxc/HLSL/DxilGenerationPass.h"
- #include "dxc/HLSL/DxilOperations.h"
- #include "dxc/HLSL/DxilModule.h"
- #include "dxc/HLSL/HLModule.h"
- #include "dxc/HLSL/HLOperations.h"
- #include "dxc/HLSL/HLMatrixLowerHelper.h"
- #include "dxc/HlslIntrinsicOp.h"
- #include "dxc/Support/Global.h"
- #include "dxc/HLSL/DxilTypeSystem.h"
- #include "dxc/HLSL/HLOperationLower.h"
- #include "HLSignatureLower.h"
- #include "dxc/HLSL/DxilUtil.h"
- #include "dxc/Support/exception.h"
- #include "llvm/IR/GetElementPtrTypeIterator.h"
- #include "llvm/IR/IRBuilder.h"
- #include "llvm/IR/Instructions.h"
- #include "llvm/IR/InstIterator.h"
- #include "llvm/IR/IntrinsicInst.h"
- #include "llvm/IR/Module.h"
- #include "llvm/IR/DebugInfo.h"
- #include "llvm/IR/PassManager.h"
- #include "llvm/ADT/BitVector.h"
- #include "llvm/Pass.h"
- #include "llvm/Transforms/Utils/SSAUpdater.h"
- #include "llvm/Analysis/AssumptionCache.h"
- #include "llvm/Transforms/Utils/PromoteMemToReg.h"
- #include <memory>
- #include <unordered_set>
- #include <iterator>
- using namespace llvm;
- using namespace hlsl;
- // TODO: use hlsl namespace for the most of this file.
- namespace {
- // Collect unused phi of resources and remove them.
- class ResourceRemover : public LoadAndStorePromoter {
- AllocaInst *AI;
- mutable std::unordered_set<PHINode *> unusedPhis;
- public:
- ResourceRemover(ArrayRef<Instruction *> Insts, SSAUpdater &S)
- : LoadAndStorePromoter(Insts, S), AI(nullptr) {}
- void run(AllocaInst *AI, const SmallVectorImpl<Instruction *> &Insts) {
- // Remember which alloca we're promoting (for isInstInList).
- this->AI = AI;
- LoadAndStorePromoter::run(Insts);
- for (PHINode *P : unusedPhis) {
- P->eraseFromParent();
- }
- }
- bool
- isInstInList(Instruction *I,
- const SmallVectorImpl<Instruction *> &Insts) const override {
- if (LoadInst *LI = dyn_cast<LoadInst>(I))
- return LI->getOperand(0) == AI;
- return cast<StoreInst>(I)->getPointerOperand() == AI;
- }
- void replaceLoadWithValue(LoadInst *LI, Value *V) const override {
- if (PHINode *PHI = dyn_cast<PHINode>(V)) {
- if (PHI->user_empty())
- unusedPhis.insert(PHI);
- }
- LI->replaceAllUsesWith(UndefValue::get(LI->getType()));
- }
- };
- void InitResourceBase(const DxilResourceBase *pSource, DxilResourceBase *pDest) {
- DXASSERT_NOMSG(pSource->GetClass() == pDest->GetClass());
- pDest->SetKind(pSource->GetKind());
- pDest->SetID(pSource->GetID());
- pDest->SetSpaceID(pSource->GetSpaceID());
- pDest->SetLowerBound(pSource->GetLowerBound());
- pDest->SetRangeSize(pSource->GetRangeSize());
- pDest->SetGlobalSymbol(pSource->GetGlobalSymbol());
- pDest->SetGlobalName(pSource->GetGlobalName());
- pDest->SetHandle(pSource->GetHandle());
- }
- void InitResource(const DxilResource *pSource, DxilResource *pDest) {
- pDest->SetCompType(pSource->GetCompType());
- pDest->SetSampleCount(pSource->GetSampleCount());
- pDest->SetElementStride(pSource->GetElementStride());
- pDest->SetGloballyCoherent(pSource->IsGloballyCoherent());
- pDest->SetHasCounter(pSource->HasCounter());
- pDest->SetRW(pSource->IsRW());
- pDest->SetROV(pSource->IsROV());
- InitResourceBase(pSource, pDest);
- }
- void InitDxilModuleFromHLModule(HLModule &H, DxilModule &M, DxilEntrySignature *pSig, bool HasDebugInfo) {
- std::unique_ptr<DxilEntrySignature> pSigPtr(pSig);
- // Subsystems.
- unsigned ValMajor, ValMinor;
- H.GetValidatorVersion(ValMajor, ValMinor);
- M.SetValidatorVersion(ValMajor, ValMinor);
- M.SetShaderModel(H.GetShaderModel());
- // Entry function.
- Function *EntryFn = H.GetEntryFunction();
- DxilFunctionProps *FnProps = H.HasDxilFunctionProps(EntryFn) ? &H.GetDxilFunctionProps(EntryFn) : nullptr;
- M.SetEntryFunction(EntryFn);
- M.SetEntryFunctionName(H.GetEntryFunctionName());
-
- std::vector<GlobalVariable* > &LLVMUsed = M.GetLLVMUsed();
- // Resources
- for (auto && C : H.GetCBuffers()) {
- auto b = make_unique<DxilCBuffer>();
- InitResourceBase(C.get(), b.get());
- b->SetSize(C->GetSize());
- if (HasDebugInfo)
- LLVMUsed.emplace_back(cast<GlobalVariable>(b->GetGlobalSymbol()));
- b->SetGlobalSymbol(UndefValue::get(b->GetGlobalSymbol()->getType()));
- M.AddCBuffer(std::move(b));
- }
- for (auto && C : H.GetUAVs()) {
- auto b = make_unique<DxilResource>();
- InitResource(C.get(), b.get());
- if (HasDebugInfo)
- LLVMUsed.emplace_back(cast<GlobalVariable>(b->GetGlobalSymbol()));
- b->SetGlobalSymbol(UndefValue::get(b->GetGlobalSymbol()->getType()));
- M.AddUAV(std::move(b));
- }
- for (auto && C : H.GetSRVs()) {
- auto b = make_unique<DxilResource>();
- InitResource(C.get(), b.get());
- if (HasDebugInfo)
- LLVMUsed.emplace_back(cast<GlobalVariable>(b->GetGlobalSymbol()));
- b->SetGlobalSymbol(UndefValue::get(b->GetGlobalSymbol()->getType()));
- M.AddSRV(std::move(b));
- }
- for (auto && C : H.GetSamplers()) {
- auto b = make_unique<DxilSampler>();
- InitResourceBase(C.get(), b.get());
- b->SetSamplerKind(C->GetSamplerKind());
- if (HasDebugInfo)
- LLVMUsed.emplace_back(cast<GlobalVariable>(b->GetGlobalSymbol()));
- b->SetGlobalSymbol(UndefValue::get(b->GetGlobalSymbol()->getType()));
- M.AddSampler(std::move(b));
- }
- // Signatures.
- M.ResetEntrySignature(pSigPtr.release());
- M.ResetRootSignature(H.ReleaseRootSignature());
- // Shader properties.
- //bool m_bDisableOptimizations;
- M.m_ShaderFlags.SetDisableOptimizations(H.GetHLOptions().bDisableOptimizations);
- //bool m_bDisableMathRefactoring;
- //bool m_bEnableDoublePrecision;
- //bool m_bEnableDoubleExtensions;
- //M.CollectShaderFlags();
- //bool m_bForceEarlyDepthStencil;
- //bool m_bEnableRawAndStructuredBuffers;
- //bool m_bEnableMSAD;
- //M.m_ShaderFlags.SetAllResourcesBound(H.GetHLOptions().bAllResourcesBound);
- M.m_ShaderFlags.SetUseNativeLowPrecision(!H.GetHLOptions().bUseMinPrecision);
- if (FnProps)
- M.SetShaderProperties(FnProps);
- // Move function props.
- if (M.GetShaderModel()->IsLib())
- M.ResetFunctionPropsMap(H.ReleaseFunctionPropsMap());
- // DXIL type system.
- M.ResetTypeSystem(H.ReleaseTypeSystem());
- // Dxil OP.
- M.ResetOP(H.ReleaseOP());
- // Keep llvm used.
- M.EmitLLVMUsed();
- M.m_ShaderFlags.SetAllResourcesBound(H.GetHLOptions().bAllResourcesBound);
- // Update Validator Version
- M.UpgradeToMinValidatorVersion();
- }
- class DxilGenerationPass : public ModulePass {
- HLModule *m_pHLModule;
- bool m_HasDbgInfo;
- HLSLExtensionsCodegenHelper *m_extensionsCodegenHelper;
- public:
- static char ID; // Pass identification, replacement for typeid
- explicit DxilGenerationPass(bool NoOpt = false)
- : ModulePass(ID), m_pHLModule(nullptr), NotOptimized(NoOpt), m_extensionsCodegenHelper(nullptr) {}
- const char *getPassName() const override { return "DXIL Generator"; }
- void SetExtensionsHelper(HLSLExtensionsCodegenHelper *helper) {
- m_extensionsCodegenHelper = helper;
- }
- bool runOnModule(Module &M) override {
- m_pHLModule = &M.GetOrCreateHLModule();
- const ShaderModel *SM = m_pHLModule->GetShaderModel();
- // Load up debug information, to cross-reference values and the instructions
- // used to load them.
- m_HasDbgInfo = getDebugMetadataVersionFromModule(M) != 0;
- std::unique_ptr<DxilEntrySignature> pSig =
- llvm::make_unique<DxilEntrySignature>(SM->GetKind(), M.GetHLModule().GetHLOptions().bUseMinPrecision);
- // EntrySig for shader functions.
- std::unordered_map<llvm::Function *, std::unique_ptr<DxilEntrySignature>>
- DxilEntrySignatureMap;
- if (!SM->IsLib()) {
- HLSignatureLower sigLower(m_pHLModule->GetEntryFunction(), *m_pHLModule,
- *pSig);
- sigLower.Run();
- } else {
- for (auto It = M.begin(); It != M.end();) {
- Function &F = *(It++);
- // Lower signature for each entry function.
- if (m_pHLModule->HasDxilFunctionProps(&F)) {
- DxilFunctionProps &props = m_pHLModule->GetDxilFunctionProps(&F);
- std::unique_ptr<DxilEntrySignature> pSig =
- llvm::make_unique<DxilEntrySignature>(props.shaderKind, m_pHLModule->GetHLOptions().bUseMinPrecision);
- HLSignatureLower sigLower(&F, *m_pHLModule, *pSig);
- sigLower.Run();
- DxilEntrySignatureMap[&F] = std::move(pSig);
- }
- }
- }
- std::unordered_set<LoadInst *> UpdateCounterSet;
- std::unordered_set<Value *> NonUniformSet;
- GenerateDxilOperations(M, UpdateCounterSet, NonUniformSet);
- std::unordered_map<Instruction *, Value *> handleMap;
- GenerateDxilCBufferHandles(NonUniformSet);
- GenerateParamDxilResourceHandles(handleMap);
- GenerateDxilResourceHandles(UpdateCounterSet, NonUniformSet);
- AddCreateHandleForPhiNodeAndSelect(m_pHLModule->GetOP());
- // For module which not promote mem2reg.
- // Remove local resource alloca/load/store/phi.
- for (auto It = M.begin(); It != M.end();) {
- Function &F = *(It++);
- if (!F.isDeclaration()) {
- RemoveLocalDxilResourceAllocas(&F);
- if (hlsl::GetHLOpcodeGroupByName(&F) == HLOpcodeGroup::HLCreateHandle) {
- if (F.user_empty()) {
- F.eraseFromParent();
- } else {
- M.getContext().emitError("Fail to lower createHandle.");
- }
- }
- }
- }
- // Translate precise on allocas into function call to keep the information after mem2reg.
- // The function calls will be removed after propagate precise attribute.
- TranslatePreciseAttribute();
- // Change struct type to legacy layout for cbuf and struct buf for min precision data types.
- if (M.GetHLModule().GetHLOptions().bUseMinPrecision)
- UpdateStructTypeForLegacyLayout();
- // High-level metadata should now be turned into low-level metadata.
- const bool SkipInit = true;
- hlsl::DxilModule &DxilMod = M.GetOrCreateDxilModule(SkipInit);
- InitDxilModuleFromHLModule(*m_pHLModule, DxilMod, pSig.release(),
- m_HasDbgInfo);
- if (SM->IsLib())
- DxilMod.ResetEntrySignatureMap(std::move(DxilEntrySignatureMap));
- HLModule::ClearHLMetadata(M);
- M.ResetHLModule();
- // We now have a DXIL representation - record this.
- SetPauseResumePasses(M, "hlsl-dxilemit", "hlsl-dxilload");
- // Remove debug code when not debug info.
- if (!m_HasDbgInfo)
- DxilMod.StripDebugRelatedCode();
- return true;
- }
- private:
- void RemoveLocalDxilResourceAllocas(Function *F);
- void
- TranslateDxilResourceUses(DxilResourceBase &res,
- std::unordered_set<LoadInst *> &UpdateCounterSet,
- std::unordered_set<Value *> &NonUniformSet);
- void
- GenerateDxilResourceHandles(std::unordered_set<LoadInst *> &UpdateCounterSet,
- std::unordered_set<Value *> &NonUniformSet);
- void AddCreateHandleForPhiNodeAndSelect(OP *hlslOP);
- void TranslateParamDxilResourceHandles(Function *F, std::unordered_map<Instruction *, Value *> &handleMap);
- void GenerateParamDxilResourceHandles(
- std::unordered_map<Instruction *, Value *> &handleMap);
- // Generate DXIL cbuffer handles.
- void
- GenerateDxilCBufferHandles(std::unordered_set<Value *> &NonUniformSet);
- // change built-in funtion into DXIL operations
- void GenerateDxilOperations(Module &M,
- std::unordered_set<LoadInst *> &UpdateCounterSet,
- std::unordered_set<Value *> &NonUniformSet);
- // Change struct type to legacy layout for cbuf and struct buf.
- void UpdateStructTypeForLegacyLayout();
- // Translate precise attribute into HL function call.
- void TranslatePreciseAttribute();
- // Input module is not optimized.
- bool NotOptimized;
- };
- }
- static Value *MergeImmResClass(Value *resClass) {
- if (ConstantInt *Imm = dyn_cast<ConstantInt>(resClass)) {
- return resClass;
- } else {
- PHINode *phi = cast<PHINode>(resClass);
- Value *immResClass = MergeImmResClass(phi->getIncomingValue(0));
- unsigned numOperands = phi->getNumOperands();
- for (unsigned i=0;i<numOperands;i++)
- phi->setIncomingValue(i, immResClass);
- return immResClass;
- }
- }
- static const StringRef kResourceMapErrorMsg = "local resource not guaranteed to map to unique global resource.";
- static void EmitResMappingError(Instruction *Res) {
- const DebugLoc &DL = Res->getDebugLoc();
- if (DL.get()) {
- Res->getContext().emitError("line:" + std::to_string(DL.getLine()) +
- " col:" + std::to_string(DL.getCol()) + " " +
- Twine(kResourceMapErrorMsg));
- } else {
- Res->getContext().emitError(Twine(kResourceMapErrorMsg) + " With /Zi to show more information.");
- }
- }
- static Value *SelectOnOperand(Value *Cond, CallInst *CIT, CallInst *CIF,
- unsigned idx, IRBuilder<> &Builder) {
- Value *OpT = CIT->getArgOperand(idx);
- Value *OpF = CIF->getArgOperand(idx);
- Value *OpSel = OpT;
- if (OpT != OpF) {
- OpSel = Builder.CreateSelect(Cond, OpT, OpF);
- }
- return OpSel;
- }
- static void ReplaceResourceUserWithHandle(LoadInst *Res, Value *handle) {
- for (auto resUser = Res->user_begin(); resUser != Res->user_end();) {
- CallInst *CI = dyn_cast<CallInst>(*(resUser++));
- DXASSERT(GetHLOpcodeGroupByName(CI->getCalledFunction()) ==
- HLOpcodeGroup::HLCreateHandle,
- "must be createHandle");
- CI->replaceAllUsesWith(handle);
- CI->eraseFromParent();
- }
- Res->eraseFromParent();
- }
- static bool IsResourceType(Type *Ty) {
- bool isResource = HLModule::IsHLSLObjectType(Ty);
- if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
- Type *EltTy = AT->getElementType();
- while (isa<ArrayType>(EltTy)) {
- EltTy = EltTy->getArrayElementType();
- }
- isResource = HLModule::IsHLSLObjectType(EltTy);
- // TODO: support local resource array.
- DXASSERT(!isResource, "local resource array");
- }
- return isResource;
- }
- void DxilGenerationPass::RemoveLocalDxilResourceAllocas(Function *F) {
- BasicBlock &BB = F->getEntryBlock(); // Get the entry node for the function
- std::unordered_set<AllocaInst *> localResources;
- 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())) {
- localResources.insert(AI);
- }
- }
- SSAUpdater SSA;
- SmallVector<Instruction *, 4> Insts;
- for (AllocaInst *AI : localResources) {
- // Build list of instructions to promote.
- for (User *U : AI->users())
- Insts.emplace_back(cast<Instruction>(U));
- ResourceRemover(Insts, SSA).run(AI, Insts);
- Insts.clear();
- }
- }
- void DxilGenerationPass::TranslateParamDxilResourceHandles(Function *F, std::unordered_map<Instruction *, Value *> &handleMap) {
- Type *handleTy = m_pHLModule->GetOP()->GetHandleType();
- IRBuilder<> Builder(F->getEntryBlock().getFirstInsertionPt());
- for (Argument &arg : F->args()) {
- Type *Ty = arg.getType();
- if (isa<PointerType>(Ty))
- Ty = Ty->getPointerElementType();
- SmallVector<unsigned,4> arraySizeList;
- while (isa<ArrayType>(Ty)) {
- arraySizeList.push_back(Ty->getArrayNumElements());
- Ty = Ty->getArrayElementType();
- }
- DXIL::ResourceClass RC = m_pHLModule->GetResourceClass(Ty);
- if (RC != DXIL::ResourceClass::Invalid) {
- Type *curTy = handleTy;
- for (auto it = arraySizeList.rbegin(), E = arraySizeList.rend(); it != E;
- it++) {
- curTy = ArrayType::get(curTy, *it);
- }
- curTy = PointerType::get(curTy, 0);
- CallInst *castToHandle = cast<CallInst>(HLModule::EmitHLOperationCall(
- Builder, HLOpcodeGroup::HLCast, 0, curTy,
- {UndefValue::get(arg.getType())}, *F->getParent()));
- for (User *U : arg.users()) {
- Instruction *I = cast<Instruction>(U);
- IRBuilder<> userBuilder(I);
- if (LoadInst *ldInst = dyn_cast<LoadInst>(U)) {
- Value *handleLd = userBuilder.CreateLoad(castToHandle);
- handleMap[ldInst] = handleLd;
- } else if (StoreInst *stInst = dyn_cast<StoreInst>(U)) {
- Value *res = stInst->getValueOperand();
- Value *handle = HLModule::EmitHLOperationCall(
- userBuilder, HLOpcodeGroup::HLCast, 0, handleTy, {res},
- *F->getParent());
- userBuilder.CreateStore(handle, castToHandle);
- } else if (CallInst *CI = dyn_cast<CallInst>(U)) {
- // Don't flatten argument here.
- continue;
- } else {
- DXASSERT(
- dyn_cast<GEPOperator>(U) != nullptr,
- "else AddOpcodeParamForIntrinsic in CodeGen did not patch uses "
- "to only have ld/st refer to temp object");
- GEPOperator *GEP = cast<GEPOperator>(U);
- std::vector<Value *> idxList(GEP->idx_begin(), GEP->idx_end());
- Value *handleGEP = userBuilder.CreateGEP(castToHandle, idxList);
- for (auto GEPU : GEP->users()) {
- Instruction *GEPI = cast<Instruction>(GEPU);
- IRBuilder<> gepUserBuilder(GEPI);
- if (LoadInst *ldInst = dyn_cast<LoadInst>(GEPU)) {
- handleMap[ldInst] = gepUserBuilder.CreateLoad(handleGEP);
- } else {
- StoreInst *stInst = cast<StoreInst>(GEPU);
- Value *res = stInst->getValueOperand();
- Value *handle = HLModule::EmitHLOperationCall(
- gepUserBuilder, HLOpcodeGroup::HLCast, 0, handleTy, {res},
- *F->getParent());
- gepUserBuilder.CreateStore(handle, handleGEP);
- }
- }
- }
- }
- castToHandle->setArgOperand(0, &arg);
- }
- }
- }
- void DxilGenerationPass::GenerateParamDxilResourceHandles(
- std::unordered_map<Instruction *, Value *> &handleMap) {
- Module &M = *m_pHLModule->GetModule();
- for (Function &F : M.functions()) {
- if (!F.isDeclaration())
- TranslateParamDxilResourceHandles(&F, handleMap);
- }
- }
- void DxilGenerationPass::TranslateDxilResourceUses(
- DxilResourceBase &res, std::unordered_set<LoadInst *> &UpdateCounterSet,
- std::unordered_set<Value *> &NonUniformSet) {
- OP *hlslOP = m_pHLModule->GetOP();
- Function *createHandle = hlslOP->GetOpFunc(
- OP::OpCode::CreateHandle, llvm::Type::getVoidTy(m_pHLModule->GetCtx()));
- Value *opArg = hlslOP->GetU32Const((unsigned)OP::OpCode::CreateHandle);
- bool isViewResource = res.GetClass() == DXIL::ResourceClass::SRV || res.GetClass() == DXIL::ResourceClass::UAV;
- bool isROV = isViewResource && static_cast<DxilResource &>(res).IsROV();
- std::string handleName = (res.GetGlobalName() + Twine("_") + Twine(res.GetResClassName())).str();
- if (isViewResource)
- handleName += (Twine("_") + Twine(res.GetResDimName())).str();
- if (isROV)
- handleName += "_ROV";
- Value *resClassArg = hlslOP->GetU8Const(
- static_cast<std::underlying_type<DxilResourceBase::Class>::type>(
- res.GetClass()));
- Value *resIDArg = hlslOP->GetU32Const(res.GetID());
- // resLowerBound will be added after allocation in DxilCondenseResources.
- Value *resLowerBound = hlslOP->GetU32Const(0);
- // TODO: Set Non-uniform resource bit based on whether index comes from IOP_NonUniformResourceIndex.
- Value *isUniformRes = hlslOP->GetI1Const(0);
- Value *GV = res.GetGlobalSymbol();
- Module *pM = m_pHLModule->GetModule();
- // TODO: add debug info to create handle.
- DIVariable *DIV = nullptr;
- DILocation *DL = nullptr;
- if (m_HasDbgInfo) {
- DebugInfoFinder &Finder = m_pHLModule->GetOrCreateDebugInfoFinder();
- DIV =
- HLModule::FindGlobalVariableDebugInfo(cast<GlobalVariable>(GV), Finder);
- if (DIV)
- // TODO: how to get col?
- DL =
- DILocation::get(pM->getContext(), DIV->getLine(), 1, DIV->getScope());
- }
- bool isResArray = res.GetRangeSize() > 1;
- std::unordered_map<Function *, Instruction *> handleMapOnFunction;
- Value *createHandleArgs[] = {opArg, resClassArg, resIDArg, resLowerBound,
- isUniformRes};
- for (iplist<Function>::iterator F : pM->getFunctionList()) {
- if (!F->isDeclaration()) {
- if (!isResArray) {
- IRBuilder<> Builder(F->getEntryBlock().getFirstInsertionPt());
- if (m_HasDbgInfo) {
- // TODO: set debug info.
- //Builder.SetCurrentDebugLocation(DL);
- }
- handleMapOnFunction[F] = Builder.CreateCall(createHandle, createHandleArgs, handleName);
- }
- }
- }
- for (auto U = GV->user_begin(), E = GV->user_end(); U != E; ) {
- User *user = *(U++);
- // Skip unused user.
- if (user->user_empty())
- continue;
- if (LoadInst *ldInst = dyn_cast<LoadInst>(user)) {
- if (UpdateCounterSet.count(ldInst)) {
- DxilResource *resource = llvm::dyn_cast<DxilResource>(&res);
- DXASSERT_NOMSG(resource);
- DXASSERT_NOMSG(resource->GetClass() == DXIL::ResourceClass::UAV);
- resource->SetHasCounter(true);
- }
- Function *userF = ldInst->getParent()->getParent();
- DXASSERT(handleMapOnFunction.count(userF), "must exist");
- Value *handle = handleMapOnFunction[userF];
- ReplaceResourceUserWithHandle(ldInst, handle);
- } else {
- DXASSERT(dyn_cast<GEPOperator>(user) != nullptr,
- "else AddOpcodeParamForIntrinsic in CodeGen did not patch uses "
- "to only have ld/st refer to temp object");
- GEPOperator *GEP = cast<GEPOperator>(user);
- Value *idx = nullptr;
- if (GEP->getNumIndices() == 2) {
- // one dim array of resource
- idx = (GEP->idx_begin() + 1)->get();
- } else {
- gep_type_iterator GEPIt = gep_type_begin(GEP), E = gep_type_end(GEP);
- // Must be instruction for multi dim array.
- std::unique_ptr<IRBuilder<> > Builder;
- if (GetElementPtrInst *GEPInst = dyn_cast<GetElementPtrInst>(GEP)) {
- Builder = std::make_unique<IRBuilder<> >(GEPInst);
- } else {
- Builder = std::make_unique<IRBuilder<> >(GV->getContext());
- }
- for (; GEPIt != E; ++GEPIt) {
- if (GEPIt->isArrayTy()) {
- unsigned arraySize = GEPIt->getArrayNumElements();
- Value * tmpIdx = GEPIt.getOperand();
- if (idx == nullptr)
- idx = tmpIdx;
- else {
- idx = Builder->CreateMul(idx, Builder->getInt32(arraySize));
- idx = Builder->CreateAdd(idx, tmpIdx);
- }
- }
- }
- }
- createHandleArgs[DXIL::OperandIndex::kCreateHandleResIndexOpIdx] = idx;
- if (!NonUniformSet.count(idx))
- createHandleArgs[DXIL::OperandIndex::kCreateHandleIsUniformOpIdx] =
- isUniformRes;
- else
- createHandleArgs[DXIL::OperandIndex::kCreateHandleIsUniformOpIdx] =
- hlslOP->GetI1Const(1);
- Value *handle = nullptr;
- if (GetElementPtrInst *GEPInst = dyn_cast<GetElementPtrInst>(GEP)) {
- IRBuilder<> Builder = IRBuilder<>(GEPInst);
- handle = Builder.CreateCall(createHandle, createHandleArgs, handleName);
- }
- for (auto GEPU = GEP->user_begin(), GEPE = GEP->user_end(); GEPU != GEPE; ) {
- // Must be load inst.
- LoadInst *ldInst = cast<LoadInst>(*(GEPU++));
- if (UpdateCounterSet.count(ldInst)) {
- DxilResource *resource = dyn_cast<DxilResource>(&res);
- DXASSERT_NOMSG(resource);
- DXASSERT_NOMSG(resource->GetClass() == DXIL::ResourceClass::UAV);
- resource->SetHasCounter(true);
- }
- if (handle) {
- ReplaceResourceUserWithHandle(ldInst, handle);
- }
- else {
- IRBuilder<> Builder = IRBuilder<>(ldInst);
- Value *localHandle = Builder.CreateCall(createHandle, createHandleArgs, handleName);
- ReplaceResourceUserWithHandle(ldInst, localHandle);
- }
- }
- }
- }
- // Erase unused handle.
- for (auto It : handleMapOnFunction) {
- Instruction *I = It.second;
- if (I->user_empty())
- I->eraseFromParent();
- }
- }
- void DxilGenerationPass::GenerateDxilResourceHandles(
- std::unordered_set<LoadInst *> &UpdateCounterSet,
- std::unordered_set<Value *> &NonUniformSet) {
- // Create sampler handle first, may be used by SRV operations.
- for (size_t i = 0; i < m_pHLModule->GetSamplers().size(); i++) {
- DxilSampler &S = m_pHLModule->GetSampler(i);
- TranslateDxilResourceUses(S, UpdateCounterSet, NonUniformSet);
- }
- for (size_t i = 0; i < m_pHLModule->GetSRVs().size(); i++) {
- HLResource &SRV = m_pHLModule->GetSRV(i);
- TranslateDxilResourceUses(SRV, UpdateCounterSet, NonUniformSet);
- }
- for (size_t i = 0; i < m_pHLModule->GetUAVs().size(); i++) {
- HLResource &UAV = m_pHLModule->GetUAV(i);
- TranslateDxilResourceUses(UAV, UpdateCounterSet, NonUniformSet);
- }
- }
- static void
- AddResourceToSet(Instruction *Res, std::unordered_set<Instruction *> &resSet) {
- unsigned startOpIdx = 0;
- // Skip Cond for Select.
- if (isa<SelectInst>(Res))
- startOpIdx = 1;
- else if (!isa<PHINode>(Res))
- // Only check phi and select here.
- return;
- // Already add.
- if (resSet.count(Res))
- return;
- resSet.insert(Res);
- // Scan operand to add resource node which only used by phi/select.
- unsigned numOperands = Res->getNumOperands();
- for (unsigned i = startOpIdx; i < numOperands; i++) {
- Value *V = Res->getOperand(i);
- if (Instruction *I = dyn_cast<Instruction>(V)) {
- AddResourceToSet(I, resSet);
- }
- }
- }
- // Transform
- //
- // %g_texture_texture_2d1 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 0, i32 0, i1 false)
- // %g_texture_texture_2d = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 0, i32 2, i1 false)
- // %13 = select i1 %cmp, %dx.types.Handle %g_texture_texture_2d1, %dx.types.Handle %g_texture_texture_2d
- // Into
- // %11 = select i1 %cmp, i32 0, i32 2
- // %12 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 0, i32 %11, i1 false)
- //
- static bool MergeHandleOpWithSameValue(Instruction *HandleOp,
- unsigned startOpIdx,
- unsigned numOperands) {
- Value *op0 = nullptr;
- for (unsigned i = startOpIdx; i < numOperands; i++) {
- Value *op = HandleOp->getOperand(i);
- if (i == startOpIdx) {
- op0 = op;
- } else {
- if (op0 != op)
- op0 = nullptr;
- }
- }
- if (op0) {
- HandleOp->replaceAllUsesWith(op0);
- return true;
- }
- return false;
- }
- static void
- UpdateHandleOperands(Instruction *Res,
- std::unordered_map<Instruction *, CallInst *> &handleMap,
- std::unordered_set<Instruction *> &nonUniformOps) {
- unsigned numOperands = Res->getNumOperands();
- unsigned startOpIdx = 0;
- // Skip Cond for Select.
- if (SelectInst *Sel = dyn_cast<SelectInst>(Res))
- startOpIdx = 1;
- CallInst *Handle = handleMap[Res];
- Instruction *resClass = cast<Instruction>(
- Handle->getArgOperand(DXIL::OperandIndex::kCreateHandleResClassOpIdx));
- Instruction *resID = cast<Instruction>(
- Handle->getArgOperand(DXIL::OperandIndex::kCreateHandleResIDOpIdx));
- Instruction *resAddr = cast<Instruction>(
- Handle->getArgOperand(DXIL::OperandIndex::kCreateHandleResIndexOpIdx));
- for (unsigned i = startOpIdx; i < numOperands; i++) {
- if (!isa<Instruction>(Res->getOperand(i))) {
- EmitResMappingError(Res);
- continue;
- }
- Instruction *ResOp = cast<Instruction>(Res->getOperand(i));
- CallInst *HandleOp = dyn_cast<CallInst>(ResOp);
- if (!HandleOp) {
- if (handleMap.count(ResOp)) {
- EmitResMappingError(Res);
- continue;
- }
- HandleOp = handleMap[ResOp];
- }
- Value *resClassOp =
- HandleOp->getArgOperand(DXIL::OperandIndex::kCreateHandleResClassOpIdx);
- Value *resIDOp =
- HandleOp->getArgOperand(DXIL::OperandIndex::kCreateHandleResIDOpIdx);
- Value *resAddrOp =
- HandleOp->getArgOperand(DXIL::OperandIndex::kCreateHandleResIndexOpIdx);
- resClass->setOperand(i, resClassOp);
- resID->setOperand(i, resIDOp);
- resAddr->setOperand(i, resAddrOp);
- }
- if (!MergeHandleOpWithSameValue(resClass, startOpIdx, numOperands))
- nonUniformOps.insert(resClass);
- if (!MergeHandleOpWithSameValue(resID, startOpIdx, numOperands))
- nonUniformOps.insert(resID);
- MergeHandleOpWithSameValue(resAddr, startOpIdx, numOperands);
- }
- void DxilGenerationPass::AddCreateHandleForPhiNodeAndSelect(OP *hlslOP) {
- Function *createHandle = hlslOP->GetOpFunc(
- OP::OpCode::CreateHandle, llvm::Type::getVoidTy(hlslOP->GetCtx()));
- std::unordered_set<PHINode *> objPhiList;
- std::unordered_set<SelectInst *> objSelectList;
- std::unordered_set<Instruction *> resSelectSet;
- for (User *U : createHandle->users()) {
- for (User *HandleU : U->users()) {
- Instruction *I = cast<Instruction>(HandleU);
- if (!isa<CallInst>(I))
- AddResourceToSet(I, resSelectSet);
- }
- }
- // Generate Handle inst for Res inst.
- FunctionType *FT = createHandle->getFunctionType();
- Value *opArg = hlslOP->GetU32Const((unsigned)OP::OpCode::CreateHandle);
- Type *resClassTy =
- FT->getParamType(DXIL::OperandIndex::kCreateHandleResClassOpIdx);
- Type *resIDTy = FT->getParamType(DXIL::OperandIndex::kCreateHandleResIDOpIdx);
- Type *resAddrTy =
- FT->getParamType(DXIL::OperandIndex::kCreateHandleResIndexOpIdx);
- Value *UndefResClass = UndefValue::get(resClassTy);
- Value *UndefResID = UndefValue::get(resIDTy);
- Value *UndefResAddr = UndefValue::get(resAddrTy);
- // phi/select node resource is not uniform
- Value *nonUniformRes = hlslOP->GetI1Const(1);
- std::unordered_map<Instruction *, CallInst *> handleMap;
- for (Instruction *Res : resSelectSet) {
- 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();
- Value *resClassSel =
- Builder.CreateSelect(Cond, UndefResClass, UndefResClass);
- Value *resIDSel = Builder.CreateSelect(Cond, UndefResID, UndefResID);
- Value *resAddrSel =
- Builder.CreateSelect(Cond, UndefResAddr, UndefResAddr);
- CallInst *HandleSel =
- Builder.CreateCall(createHandle, {opArg, resClassSel, resIDSel,
- resAddrSel, nonUniformRes});
- handleMap[Res] = HandleSel;
- Res->replaceAllUsesWith(HandleSel);
- } else {
- PHINode *Phi = cast<PHINode>(Res); // res class must be same.
- PHINode *resClassPhi = Builder.CreatePHI(resClassTy, numOperands);
- PHINode *resIDPhi = Builder.CreatePHI(resIDTy, numOperands);
- PHINode *resAddrPhi = Builder.CreatePHI(resAddrTy, numOperands);
- for (unsigned i = 0; i < numOperands; i++) {
- BasicBlock *BB = Phi->getIncomingBlock(i);
- resClassPhi->addIncoming(UndefResClass, BB);
- resIDPhi->addIncoming(UndefResID, BB);
- resAddrPhi->addIncoming(UndefResAddr, BB);
- }
- IRBuilder<> HandleBuilder(Phi->getParent()->getFirstNonPHI());
- CallInst *HandlePhi =
- HandleBuilder.CreateCall(createHandle, {opArg, resClassPhi, resIDPhi,
- resAddrPhi, nonUniformRes});
- handleMap[Res] = HandlePhi;
- Res->replaceAllUsesWith(HandlePhi);
- }
- }
- // Update operand for Handle phi/select.
- // If ResClass or ResID is phi/select, save to nonUniformOps.
- std::unordered_set<Instruction *> nonUniformOps;
- for (Instruction *Res : resSelectSet) {
- UpdateHandleOperands(Res, handleMap, nonUniformOps);
- }
- bool bIsLib = m_pHLModule->GetShaderModel()->IsLib();
- // ResClass and ResID must be uniform.
- // Try to merge res class, res id into imm.
- while (1) {
- bool bUpdated = false;
- for (auto It = nonUniformOps.begin(); It != nonUniformOps.end();) {
- Instruction *I = *(It++);
- unsigned numOperands = I->getNumOperands();
- unsigned startOpIdx = 0;
- // Skip Cond for Select.
- if (SelectInst *Sel = dyn_cast<SelectInst>(I))
- startOpIdx = 1;
- if (MergeHandleOpWithSameValue(I, startOpIdx, numOperands)) {
- nonUniformOps.erase(I);
- bUpdated = true;
- }
- }
- if (!bUpdated) {
- if (!nonUniformOps.empty() && !bIsLib) {
- for (Instruction *I : nonUniformOps) {
- // Non uniform res class or res id.
- EmitResMappingError(I);
- }
- return;
- }
- break;
- }
- }
- // Remove useless select/phi.
- for (Instruction *Res : resSelectSet) {
- Res->eraseFromParent();
- }
- }
- void DxilGenerationPass::GenerateDxilCBufferHandles(
- std::unordered_set<Value *> &NonUniformSet) {
- // For CBuffer, handle are mapped to HLCreateHandle.
- OP *hlslOP = m_pHLModule->GetOP();
- Function *createHandle = hlslOP->GetOpFunc(
- OP::OpCode::CreateHandle, llvm::Type::getVoidTy(m_pHLModule->GetCtx()));
- Value *opArg = hlslOP->GetU32Const((unsigned)OP::OpCode::CreateHandle);
- Value *resClassArg = hlslOP->GetU8Const(
- static_cast<std::underlying_type<DxilResourceBase::Class>::type>(
- DXIL::ResourceClass::CBuffer));
- for (size_t i = 0; i < m_pHLModule->GetCBuffers().size(); i++) {
- DxilCBuffer &CB = m_pHLModule->GetCBuffer(i);
- GlobalVariable *GV = cast<GlobalVariable>(CB.GetGlobalSymbol());
- // Remove GEP created in HLObjectOperationLowerHelper::UniformCbPtr.
- GV->removeDeadConstantUsers();
- std::string handleName = std::string(GV->getName()) + "_buffer";
- Value *args[] = {opArg, resClassArg, nullptr, nullptr,
- hlslOP->GetI1Const(0)};
- DIVariable *DIV = nullptr;
- DILocation *DL = nullptr;
- if (m_HasDbgInfo) {
- DebugInfoFinder &Finder = m_pHLModule->GetOrCreateDebugInfoFinder();
- DIV = HLModule::FindGlobalVariableDebugInfo(GV, Finder);
- if (DIV)
- // TODO: how to get col?
- DL = DILocation::get(createHandle->getContext(), DIV->getLine(), 1,
- DIV->getScope());
- }
- Value *resIDArg = hlslOP->GetU32Const(CB.GetID());
- args[DXIL::OperandIndex::kCreateHandleResIDOpIdx] = resIDArg;
- // resLowerBound will be added after allocation in DxilCondenseResources.
- Value *resLowerBound = hlslOP->GetU32Const(0);
- if (CB.GetRangeSize() == 1) {
- args[DXIL::OperandIndex::kCreateHandleResIndexOpIdx] = resLowerBound;
- for (auto U = GV->user_begin(); U != GV->user_end(); ) {
- // Must HLCreateHandle.
- CallInst *CI = cast<CallInst>(*(U++));
- // Put createHandle to entry block.
- auto InsertPt =
- CI->getParent()->getParent()->getEntryBlock().getFirstInsertionPt();
- IRBuilder<> Builder(InsertPt);
- CallInst *handle = Builder.CreateCall(createHandle, args, handleName);
- if (m_HasDbgInfo) {
- // TODO: add debug info.
- //handle->setDebugLoc(DL);
- }
- CI->replaceAllUsesWith(handle);
- CI->eraseFromParent();
- }
- } else {
- for (auto U = GV->user_begin(); U != GV->user_end(); ) {
- // Must HLCreateHandle.
- CallInst *CI = cast<CallInst>(*(U++));
- IRBuilder<> Builder(CI);
- Value *CBIndex = CI->getArgOperand(HLOperandIndex::kCreateHandleIndexOpIdx);
- args[DXIL::OperandIndex::kCreateHandleResIndexOpIdx] =
- CBIndex;
- if (isa<ConstantInt>(CBIndex)) {
- // Put createHandle to entry block for const index.
- auto InsertPt = CI->getParent()
- ->getParent()
- ->getEntryBlock()
- .getFirstInsertionPt();
- Builder.SetInsertPoint(InsertPt);
- }
- if (!NonUniformSet.count(CBIndex))
- args[DXIL::OperandIndex::kCreateHandleIsUniformOpIdx] =
- hlslOP->GetI1Const(0);
- else
- args[DXIL::OperandIndex::kCreateHandleIsUniformOpIdx] =
- hlslOP->GetI1Const(1);
- CallInst *handle = Builder.CreateCall(createHandle, args, handleName);
- CI->replaceAllUsesWith(handle);
- CI->eraseFromParent();
- }
- }
- }
- }
- void DxilGenerationPass::GenerateDxilOperations(
- Module &M, std::unordered_set<LoadInst *> &UpdateCounterSet,
- std::unordered_set<Value *> &NonUniformSet) {
- // remove all functions except entry function
- Function *entry = m_pHLModule->GetEntryFunction();
- const ShaderModel *pSM = m_pHLModule->GetShaderModel();
- Function *patchConstantFunc = nullptr;
- if (pSM->IsHS()) {
- DxilFunctionProps &funcProps = m_pHLModule->GetDxilFunctionProps(entry);
- patchConstantFunc = funcProps.ShaderProps.HS.patchConstantFunc;
- }
- if (!pSM->IsLib()) {
- for (auto F = M.begin(); F != M.end();) {
- Function *func = F++;
- if (func->isDeclaration())
- continue;
- if (func == entry)
- continue;
- if (func == patchConstantFunc)
- continue;
- if (func->user_empty())
- func->eraseFromParent();
- }
- }
- TranslateBuiltinOperations(*m_pHLModule, m_extensionsCodegenHelper,
- UpdateCounterSet, NonUniformSet);
- // Remove unused HL Operation functions.
- std::vector<Function *> deadList;
- for (iplist<Function>::iterator F : M.getFunctionList()) {
- hlsl::HLOpcodeGroup group = hlsl::GetHLOpcodeGroupByName(F);
- if (group != HLOpcodeGroup::NotHL || F->isIntrinsic())
- if (F->user_empty())
- deadList.emplace_back(F);
- }
- for (Function *F : deadList)
- F->eraseFromParent();
- }
- static void TranslatePreciseAttributeOnFunction(Function &F, Module &M) {
- BasicBlock &BB = F.getEntryBlock(); // Get the entry node for the function
- // Find allocas that has precise attribute, by looking at all instructions in
- // the entry node
- for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E;) {
- Instruction *Inst = (I++);
- if (AllocaInst *AI = dyn_cast<AllocaInst>(Inst)) {
- if (HLModule::HasPreciseAttributeWithMetadata(AI)) {
- HLModule::MarkPreciseAttributeOnPtrWithFunctionCall(AI, M);
- }
- } else {
- DXASSERT(!HLModule::HasPreciseAttributeWithMetadata(Inst), "Only alloca can has precise metadata.");
- }
- }
- FastMathFlags FMF;
- FMF.setUnsafeAlgebra();
- // Set fast math for all FPMathOperators.
- // Already set FastMath in options. But that only enable things like fadd.
- // Every inst which type is float can be cast to FPMathOperator.
- for (Function::iterator BBI = F.begin(), BBE = F.end(); BBI != BBE; ++BBI) {
- BasicBlock *BB = BBI;
- for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) {
- if (FPMathOperator *FPMath = dyn_cast<FPMathOperator>(I)) {
- // Set precise fast math on those instructions that support it.
- if (DxilModule::PreservesFastMathFlags(I))
- I->copyFastMathFlags(FMF);
- }
- }
- }
- }
- void DxilGenerationPass::TranslatePreciseAttribute() {
- bool bIEEEStrict = m_pHLModule->GetHLOptions().bIEEEStrict;
- // If IEEE strict, everying is precise, don't need to mark it.
- if (bIEEEStrict)
- return;
- Module &M = *m_pHLModule->GetModule();
- // TODO: If not inline every function, for function has call site with precise
- // argument and call site without precise argument, need to clone the function
- // to propagate the precise for the precise call site.
- // This should be done at CGMSHLSLRuntime::FinishCodeGen.
- Function *EntryFn = m_pHLModule->GetEntryFunction();
- if (!m_pHLModule->GetShaderModel()->IsLib()) {
- TranslatePreciseAttributeOnFunction(*EntryFn, M);
- }
- if (m_pHLModule->GetShaderModel()->IsHS()) {
- DxilFunctionProps &EntryQual = m_pHLModule->GetDxilFunctionProps(EntryFn);
- Function *patchConstantFunc = EntryQual.ShaderProps.HS.patchConstantFunc;
- TranslatePreciseAttributeOnFunction(*patchConstantFunc, M);
- }
- }
- char DxilGenerationPass::ID = 0;
- ModulePass *llvm::createDxilGenerationPass(bool NotOptimized, hlsl::HLSLExtensionsCodegenHelper *extensionsHelper) {
- DxilGenerationPass *dxilPass = new DxilGenerationPass(NotOptimized);
- dxilPass->SetExtensionsHelper(extensionsHelper);
- return dxilPass;
- }
- INITIALIZE_PASS(DxilGenerationPass, "dxilgen", "HLSL DXIL Generation", false, false)
- ///////////////////////////////////////////////////////////////////////////////
- namespace {
- StructType *UpdateStructTypeForLegacyLayout(StructType *ST, bool IsCBuf,
- DxilTypeSystem &TypeSys, Module &M);
- Type *UpdateFieldTypeForLegacyLayout(Type *Ty, bool IsCBuf, DxilFieldAnnotation &annotation,
- DxilTypeSystem &TypeSys, Module &M) {
- DXASSERT(!Ty->isPointerTy(), "struct field should not be a pointer");
- if (Ty->isArrayTy()) {
- Type *EltTy = Ty->getArrayElementType();
- Type *UpdatedTy = UpdateFieldTypeForLegacyLayout(EltTy, IsCBuf, annotation, TypeSys, M);
- if (EltTy == UpdatedTy)
- return Ty;
- else
- return ArrayType::get(UpdatedTy, Ty->getArrayNumElements());
- } else if (HLMatrixLower::IsMatrixType(Ty)) {
- DXASSERT(annotation.HasMatrixAnnotation(), "must a matrix");
- unsigned rows, cols;
- Type *EltTy = HLMatrixLower::GetMatrixInfo(Ty, cols, rows);
- // Get cols and rows from annotation.
- const DxilMatrixAnnotation &matrix = annotation.GetMatrixAnnotation();
- if (matrix.Orientation == MatrixOrientation::RowMajor) {
- rows = matrix.Rows;
- cols = matrix.Cols;
- } else {
- DXASSERT(matrix.Orientation == MatrixOrientation::ColumnMajor, "");
- cols = matrix.Rows;
- rows = matrix.Cols;
- }
- // CBuffer matrix must 4 * 4 bytes align.
- if (IsCBuf)
- cols = 4;
- EltTy = UpdateFieldTypeForLegacyLayout(EltTy, IsCBuf, annotation, TypeSys, M);
- Type *rowTy = VectorType::get(EltTy, cols);
- return ArrayType::get(rowTy, rows);
- } else if (StructType *ST = dyn_cast<StructType>(Ty)) {
- return UpdateStructTypeForLegacyLayout(ST, IsCBuf, TypeSys, M);
- } else if (Ty->isVectorTy()) {
- Type *EltTy = Ty->getVectorElementType();
- Type *UpdatedTy = UpdateFieldTypeForLegacyLayout(EltTy, IsCBuf, annotation, TypeSys, M);
- if (EltTy == UpdatedTy)
- return Ty;
- else
- return VectorType::get(UpdatedTy, Ty->getVectorNumElements());
- } else {
- Type *i32Ty = Type::getInt32Ty(Ty->getContext());
- // Basic types.
- if (Ty->isHalfTy()) {
- return Type::getFloatTy(Ty->getContext());
- } else if (IntegerType *ITy = dyn_cast<IntegerType>(Ty)) {
- if (ITy->getBitWidth() < 32)
- return i32Ty;
- else
- return Ty;
- } else
- return Ty;
- }
- }
- StructType *UpdateStructTypeForLegacyLayout(StructType *ST, bool IsCBuf,
- DxilTypeSystem &TypeSys, Module &M) {
- bool bUpdated = false;
- unsigned fieldsCount = ST->getNumElements();
- std::vector<Type *> fieldTypes(fieldsCount);
- DxilStructAnnotation *SA = TypeSys.GetStructAnnotation(ST);
- DXASSERT(SA, "must have annotation for struct type");
- for (unsigned i = 0; i < fieldsCount; i++) {
- Type *EltTy = ST->getElementType(i);
- Type *UpdatedTy =
- UpdateFieldTypeForLegacyLayout(EltTy, IsCBuf, SA->GetFieldAnnotation(i), TypeSys, M);
- fieldTypes[i] = UpdatedTy;
- if (EltTy != UpdatedTy)
- bUpdated = true;
- }
- if (!bUpdated) {
- return ST;
- } else {
- std::string legacyName = "dx.alignment.legacy." + ST->getName().str();
- if (StructType *legacyST = M.getTypeByName(legacyName))
- return legacyST;
- StructType *NewST = StructType::create(ST->getContext(), fieldTypes, legacyName);
- DxilStructAnnotation *NewSA = TypeSys.AddStructAnnotation(NewST);
- // Clone annotation.
- *NewSA = *SA;
- return NewST;
- }
- }
- void UpdateStructTypeForLegacyLayout(DxilResourceBase &Res, DxilTypeSystem &TypeSys, Module &M) {
- GlobalVariable *GV = cast<GlobalVariable>(Res.GetGlobalSymbol());
- Type *Ty = GV->getType()->getPointerElementType();
- bool IsResourceArray = Res.GetRangeSize() != 1;
- if (IsResourceArray) {
- // Support Array of struct buffer.
- if (Ty->isArrayTy())
- Ty = Ty->getArrayElementType();
- }
- StructType *ST = cast<StructType>(Ty);
- if (ST->isOpaque()) {
- DXASSERT(Res.GetClass() == DxilResourceBase::Class::CBuffer,
- "Only cbuffer can have opaque struct.");
- return;
- }
- Type *UpdatedST = UpdateStructTypeForLegacyLayout(ST, IsResourceArray, TypeSys, M);
- if (ST != UpdatedST) {
- Type *Ty = GV->getType()->getPointerElementType();
- if (IsResourceArray) {
- // Support Array of struct buffer.
- if (Ty->isArrayTy()) {
- UpdatedST = ArrayType::get(UpdatedST, Ty->getArrayNumElements());
- }
- }
- GlobalVariable *NewGV = cast<GlobalVariable>(M.getOrInsertGlobal(GV->getName().str() + "_legacy", UpdatedST));
- Res.SetGlobalSymbol(NewGV);
- // Delete old GV.
- for (auto UserIt = GV->user_begin(); UserIt != GV->user_end(); ) {
- Value *User = *(UserIt++);
- if (Instruction *I = dyn_cast<Instruction>(User)) {
- if (!User->user_empty())
- I->replaceAllUsesWith(UndefValue::get(I->getType()));
- I->eraseFromParent();
- } else {
- ConstantExpr *CE = cast<ConstantExpr>(User);
- if (!CE->user_empty())
- CE->replaceAllUsesWith(UndefValue::get(CE->getType()));
- }
- }
- GV->removeDeadConstantUsers();
- GV->eraseFromParent();
- }
- }
- void UpdateStructTypeForLegacyLayoutOnHLM(HLModule &HLM) {
- DxilTypeSystem &TypeSys = HLM.GetTypeSystem();
- Module &M = *HLM.GetModule();
- for (auto &CBuf : HLM.GetCBuffers()) {
- UpdateStructTypeForLegacyLayout(*CBuf.get(), TypeSys, M);
- }
- for (auto &UAV : HLM.GetUAVs()) {
- if (UAV->GetKind() == DxilResourceBase::Kind::StructuredBuffer)
- UpdateStructTypeForLegacyLayout(*UAV.get(), TypeSys, M);
- }
- for (auto &SRV : HLM.GetSRVs()) {
- if (SRV->GetKind() == DxilResourceBase::Kind::StructuredBuffer)
- UpdateStructTypeForLegacyLayout(*SRV.get(), TypeSys, M);
- }
- }
- }
- void DxilGenerationPass::UpdateStructTypeForLegacyLayout() {
- UpdateStructTypeForLegacyLayoutOnHLM(*m_pHLModule);
- }
- ///////////////////////////////////////////////////////////////////////////////
- namespace {
- class HLEmitMetadata : public ModulePass {
- public:
- static char ID; // Pass identification, replacement for typeid
- explicit HLEmitMetadata() : ModulePass(ID) {}
- const char *getPassName() const override { return "HLSL High-Level Metadata Emit"; }
- bool runOnModule(Module &M) override {
- if (M.HasHLModule()) {
- HLModule::ClearHLMetadata(M);
- M.GetHLModule().EmitHLMetadata();
- return true;
- }
- return false;
- }
- };
- }
- char HLEmitMetadata::ID = 0;
- ModulePass *llvm::createHLEmitMetadataPass() {
- return new HLEmitMetadata();
- }
- INITIALIZE_PASS(HLEmitMetadata, "hlsl-hlemit", "HLSL High-Level Metadata Emit", false, false)
- ///////////////////////////////////////////////////////////////////////////////
- namespace {
- class HLEnsureMetadata : public ModulePass {
- public:
- static char ID; // Pass identification, replacement for typeid
- explicit HLEnsureMetadata() : ModulePass(ID) {}
- const char *getPassName() const override { return "HLSL High-Level Metadata Ensure"; }
- bool runOnModule(Module &M) override {
- if (!M.HasHLModule()) {
- M.GetOrCreateHLModule();
- return true;
- }
- return false;
- }
- };
- }
- char HLEnsureMetadata::ID = 0;
- ModulePass *llvm::createHLEnsureMetadataPass() {
- return new HLEnsureMetadata();
- }
- INITIALIZE_PASS(HLEnsureMetadata, "hlsl-hlensure", "HLSL High-Level Metadata Ensure", false, false)
- ///////////////////////////////////////////////////////////////////////////////
- // Precise propagate.
- namespace {
- class DxilPrecisePropagatePass : public ModulePass {
- HLModule *m_pHLModule;
- public:
- static char ID; // Pass identification, replacement for typeid
- explicit DxilPrecisePropagatePass() : ModulePass(ID), m_pHLModule(nullptr) {}
- const char *getPassName() const override { return "DXIL Precise Propagate"; }
- bool runOnModule(Module &M) override {
- DxilModule &dxilModule = M.GetOrCreateDxilModule();
- DxilTypeSystem &typeSys = dxilModule.GetTypeSystem();
- std::unordered_set<Instruction*> processedSet;
- std::vector<Function*> deadList;
- for (Function &F : M.functions()) {
- if (HLModule::HasPreciseAttribute(&F)) {
- PropagatePreciseOnFunctionUser(F, typeSys, processedSet);
- deadList.emplace_back(&F);
- }
- }
- for (Function *F : deadList)
- F->eraseFromParent();
- return true;
- }
- private:
- void PropagatePreciseOnFunctionUser(
- Function &F, DxilTypeSystem &typeSys,
- std::unordered_set<Instruction *> &processedSet);
- };
- char DxilPrecisePropagatePass::ID = 0;
- }
- static void PropagatePreciseAttribute(Instruction *I, DxilTypeSystem &typeSys,
- std::unordered_set<Instruction *> &processedSet);
- static void PropagatePreciseAttributeOnOperand(
- Value *V, DxilTypeSystem &typeSys, LLVMContext &Context,
- std::unordered_set<Instruction *> &processedSet) {
- Instruction *I = dyn_cast<Instruction>(V);
- // Skip none inst.
- if (!I)
- return;
- FPMathOperator *FPMath = dyn_cast<FPMathOperator>(I);
- // Skip none FPMath
- if (!FPMath)
- return;
- // Skip inst already marked.
- if (processedSet.count(I) > 0)
- return;
- // TODO: skip precise on integer type, sample instruction...
- processedSet.insert(I);
- // Set precise fast math on those instructions that support it.
- if (DxilModule::PreservesFastMathFlags(I))
- DxilModule::SetPreciseFastMathFlags(I);
- // Fast math not work on call, use metadata.
- if (CallInst *CI = dyn_cast<CallInst>(I))
- HLModule::MarkPreciseAttributeWithMetadata(CI);
- PropagatePreciseAttribute(I, typeSys, processedSet);
- }
- static void PropagatePreciseAttributeOnPointer(
- Value *Ptr, DxilTypeSystem &typeSys, LLVMContext &Context,
- std::unordered_set<Instruction *> &processedSet) {
- // Find all store and propagate on the val operand of store.
- // For CallInst, if Ptr is used as out parameter, mark it.
- for (User *U : Ptr->users()) {
- Instruction *user = cast<Instruction>(U);
- if (StoreInst *stInst = dyn_cast<StoreInst>(user)) {
- Value *val = stInst->getValueOperand();
- PropagatePreciseAttributeOnOperand(val, typeSys, Context, processedSet);
- } else if (CallInst *CI = dyn_cast<CallInst>(user)) {
- bool bReadOnly = true;
- Function *F = CI->getCalledFunction();
- const DxilFunctionAnnotation *funcAnnotation =
- typeSys.GetFunctionAnnotation(F);
- for (unsigned i = 0; i < CI->getNumArgOperands(); ++i) {
- if (Ptr != CI->getArgOperand(i))
- continue;
- const DxilParameterAnnotation ¶mAnnotation =
- funcAnnotation->GetParameterAnnotation(i);
- // OutputPatch and OutputStream will be checked after scalar repl.
- // Here only check out/inout
- if (paramAnnotation.GetParamInputQual() == DxilParamInputQual::Out ||
- paramAnnotation.GetParamInputQual() == DxilParamInputQual::Inout) {
- bReadOnly = false;
- break;
- }
- }
- if (!bReadOnly)
- PropagatePreciseAttributeOnOperand(CI, typeSys, Context, processedSet);
- }
- }
- }
- static void
- PropagatePreciseAttribute(Instruction *I, DxilTypeSystem &typeSys,
- std::unordered_set<Instruction *> &processedSet) {
- LLVMContext &Context = I->getContext();
- if (AllocaInst *AI = dyn_cast<AllocaInst>(I)) {
- PropagatePreciseAttributeOnPointer(AI, typeSys, Context, processedSet);
- } else if (CallInst *CI = dyn_cast<CallInst>(I)) {
- // Propagate every argument.
- // TODO: only propagate precise argument.
- for (Value *src : I->operands())
- PropagatePreciseAttributeOnOperand(src, typeSys, Context, processedSet);
- } else if (FPMathOperator *FPMath = dyn_cast<FPMathOperator>(I)) {
- // TODO: only propagate precise argument.
- for (Value *src : I->operands())
- PropagatePreciseAttributeOnOperand(src, typeSys, Context, processedSet);
- } else if (LoadInst *ldInst = dyn_cast<LoadInst>(I)) {
- Value *Ptr = ldInst->getPointerOperand();
- PropagatePreciseAttributeOnPointer(Ptr, typeSys, Context, processedSet);
- } else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(I))
- PropagatePreciseAttributeOnPointer(GEP, typeSys, Context, processedSet);
- // TODO: support more case which need
- }
- void DxilPrecisePropagatePass::PropagatePreciseOnFunctionUser(
- Function &F, DxilTypeSystem &typeSys,
- std::unordered_set<Instruction *> &processedSet) {
- LLVMContext &Context = F.getContext();
- for (auto U = F.user_begin(), E = F.user_end(); U != E;) {
- CallInst *CI = cast<CallInst>(*(U++));
- Value *V = CI->getArgOperand(0);
- PropagatePreciseAttributeOnOperand(V, typeSys, Context, processedSet);
- CI->eraseFromParent();
- }
- }
- ModulePass *llvm::createDxilPrecisePropagatePass() {
- return new DxilPrecisePropagatePass();
- }
- INITIALIZE_PASS(DxilPrecisePropagatePass, "hlsl-dxil-precise", "DXIL precise attribute propagate", false, false)
- ///////////////////////////////////////////////////////////////////////////////
- namespace {
- class HLDeadFunctionElimination : public ModulePass {
- public:
- static char ID; // Pass identification, replacement for typeid
- explicit HLDeadFunctionElimination () : ModulePass(ID) {}
- const char *getPassName() const override { return "Remove all unused function except entry from HLModule"; }
- bool runOnModule(Module &M) override {
- if (M.HasHLModule()) {
- HLModule &HLM = M.GetHLModule();
- bool IsLib = HLM.GetShaderModel()->IsLib();
- // Remove unused functions except entry and patch constant func.
- // For library profile, only remove unused external functions.
- Function *EntryFunc = HLM.GetEntryFunction();
- Function *PatchConstantFunc = HLM.GetPatchConstantFunction();
- return dxilutil::RemoveUnusedFunctions(M, EntryFunc, PatchConstantFunc,
- IsLib);
- }
- return false;
- }
- };
- }
- char HLDeadFunctionElimination::ID = 0;
- ModulePass *llvm::createHLDeadFunctionEliminationPass() {
- return new HLDeadFunctionElimination();
- }
- INITIALIZE_PASS(HLDeadFunctionElimination, "hl-dfe", "Remove all unused function except entry from HLModule", false, false)
- ///////////////////////////////////////////////////////////////////////////////
- // Legalize resource use.
- // Map local or static global resource to global resource.
- // Require inline for static global resource.
- namespace {
- class DxilLegalizeStaticResourceUsePass : public ModulePass {
- public:
- static char ID; // Pass identification, replacement for typeid
- explicit DxilLegalizeStaticResourceUsePass()
- : ModulePass(ID) {}
- const char *getPassName() const override {
- return "DXIL Legalize Static Resource Use";
- }
- bool runOnModule(Module &M) override {
- HLModule &HLM = M.GetOrCreateHLModule();
- OP *hlslOP = HLM.GetOP();
- Type *HandleTy = hlslOP->GetHandleType();
- // Promote static global variables.
- PromoteStaticGlobalResources(M);
- // Lower handle cast.
- for (Function &F : M.functions()) {
- if (!F.isDeclaration())
- continue;
- HLOpcodeGroup group = hlsl::GetHLOpcodeGroupByName(&F);
- if (group != HLOpcodeGroup::HLCast)
- continue;
- Type *Ty = F.getFunctionType()->getReturnType();
- if (Ty->isPointerTy())
- Ty = Ty->getPointerElementType();
- if (HLModule::IsHLSLObjectType(Ty)) {
- TransformHandleCast(F);
- }
- }
- 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)) {
- if (Instruction *UI = dyn_cast<Instruction>(U))
- EmitResMappingError(UI);
- else
- M.getContext().emitError(kResourceMapErrorMsg);
- }
- }
- }
- return true;
- }
- private:
- void PromoteStaticGlobalResources(Module &M);
- void TransformHandleCast(Function &F);
- };
- char DxilLegalizeStaticResourceUsePass::ID = 0;
- class DxilLegalizeResourceUsePass : public FunctionPass {
- HLModule *m_pHLModule;
- void getAnalysisUsage(AnalysisUsage &AU) const override;
- public:
- static char ID; // Pass identification, replacement for typeid
- explicit DxilLegalizeResourceUsePass()
- : FunctionPass(ID), m_pHLModule(nullptr) {}
- const char *getPassName() const override {
- return "DXIL Legalize Resource Use";
- }
- bool runOnFunction(Function &F) override {
- // Promote local resource first.
- PromoteLocalResource(F);
- return true;
- }
- private:
- void PromoteLocalResource(Function &F);
- };
- char DxilLegalizeResourceUsePass::ID = 0;
- }
- void DxilLegalizeResourceUsePass::getAnalysisUsage(AnalysisUsage &AU) const {
- AU.addRequired<AssumptionCacheTracker>();
- AU.addRequired<DominatorTreeWrapperPass>();
- AU.setPreservesAll();
- }
- void DxilLegalizeResourceUsePass::PromoteLocalResource(Function &F) {
- std::vector<AllocaInst *> Allocas;
- DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
- AssumptionCache &AC =
- getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
- HLModule &HLM = F.getParent()->GetOrCreateHLModule();
- OP *hlslOP = HLM.GetOP();
- Type *HandleTy = hlslOP->GetHandleType();
- bool IsLib = HLM.GetShaderModel()->IsLib();
- BasicBlock &BB = F.getEntryBlock();
- unsigned allocaSize = 0;
- while (1) {
- Allocas.clear();
- // Find allocas that are safe to promote, by looking at all instructions in
- // 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 (HandleTy == dxilutil::GetArrayEltTy(AI->getAllocatedType())) {
- // Skip for unpromotable for lib.
- if (!isAllocaPromotable(AI) && IsLib)
- continue;
- if (!isAllocaPromotable(AI)) {
- static const StringRef kNonPromotableLocalResourceErrorMsg =
- "non-promotable local resource found.";
- F.getContext().emitError(kNonPromotableLocalResourceErrorMsg);
- throw hlsl::Exception(DXC_E_ABORT_COMPILATION_ERROR,
- kNonPromotableLocalResourceErrorMsg);
- continue;
- }
- Allocas.push_back(AI);
- }
- }
- if (Allocas.empty())
- break;
- // No update.
- // Report error and break.
- if (allocaSize == Allocas.size()) {
- F.getContext().emitError(kResourceMapErrorMsg);
- break;
- }
- allocaSize = Allocas.size();
- PromoteMemToReg(Allocas, *DT, nullptr, &AC);
- }
- return;
- }
- FunctionPass *llvm::createDxilLegalizeResourceUsePass() {
- return new DxilLegalizeResourceUsePass();
- }
- INITIALIZE_PASS_BEGIN(DxilLegalizeResourceUsePass,
- "hlsl-dxil-legalize-resource-use",
- "DXIL legalize resource use", false, true)
- INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
- INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
- INITIALIZE_PASS_END(DxilLegalizeResourceUsePass,
- "hlsl-dxil-legalize-resource-use",
- "DXIL legalize resource use", false, true)
- 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 &&
- HandleTy == dxilutil::GetArrayEltTy(GV.getType())) {
- staticResources.insert(&GV);
- }
- }
- SSAUpdater SSA;
- SmallVector<Instruction *, 4> Insts;
- // Make sure every resource load has mapped to global variable.
- while (!staticResources.empty()) {
- bool bUpdated = false;
- for (auto it = staticResources.begin(); it != staticResources.end();) {
- GlobalVariable *GV = *(it++);
- // Build list of instructions to promote.
- for (User *U : GV->users()) {
- Instruction *I = cast<Instruction>(U);
- Insts.emplace_back(I);
- }
- LoadAndStorePromoter(Insts, SSA).run(Insts);
- if (GV->user_empty()) {
- bUpdated = true;
- staticResources.erase(GV);
- }
- Insts.clear();
- }
- if (!bUpdated) {
- M.getContext().emitError(kResourceMapErrorMsg);
- break;
- }
- }
- }
- static void ReplaceResUseWithHandle(Instruction *Res, Value *Handle) {
- Type *HandleTy = Handle->getType();
- for (auto ResU = Res->user_begin(); ResU != Res->user_end();) {
- Instruction *I = cast<Instruction>(*(ResU++));
- if (isa<LoadInst>(I)) {
- ReplaceResUseWithHandle(I, Handle);
- } else if (isa<CallInst>(I)) {
- if (I->getType() == HandleTy)
- I->replaceAllUsesWith(Handle);
- else
- DXASSERT(0, "must createHandle here");
- } else {
- DXASSERT(0, "should only used by load and createHandle");
- }
- if (I->user_empty()) {
- I->eraseFromParent();
- }
- }
- }
- void DxilLegalizeStaticResourceUsePass::TransformHandleCast(Function &F) {
- for (auto U = F.user_begin(); U != F.user_end(); ) {
- CallInst *CI = cast<CallInst>(*(U++));
- Value *Handle = CI->getArgOperand(HLOperandIndex::kUnaryOpSrc0Idx);
- ReplaceResUseWithHandle(CI, Handle);
- if (CI->user_empty())
- CI->eraseFromParent();
- }
- }
- ModulePass *llvm::createDxilLegalizeStaticResourceUsePass() {
- return new DxilLegalizeStaticResourceUsePass();
- }
- 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)
- ///////////////////////////////////////////////////////////////////////////////
- // Translate RawBufferLoad/RawBufferStore
- // This pass is to make sure that we generate correct buffer load for DXIL
- // For DXIL < 1.2, rawBufferLoad will be translated to BufferLoad instruction
- // without mask.
- // For DXIL >= 1.2, if min precision is enabled, currently generation pass is
- // producing i16/f16 return type for min precisions. For rawBuffer, we will
- // change this so that min precisions are returning its actual scalar type (i32/f32)
- // and will be truncated to their corresponding types after loading / before storing.
- namespace {
- class DxilTranslateRawBuffer : public ModulePass {
- public:
- static char ID;
- explicit DxilTranslateRawBuffer() : ModulePass(ID) {}
- bool runOnModule(Module &M) {
- unsigned major, minor;
- M.GetDxilModule().GetDxilVersion(major, minor);
- DxilModule::ShaderFlags flag = M.GetDxilModule().m_ShaderFlags;
- if (major == 1 && minor < 2) {
- for (auto F = M.functions().begin(), E = M.functions().end(); F != E;) {
- Function *func = &*(F++);
- if (func->hasName()) {
- if (func->getName().startswith("dx.op.rawBufferLoad")) {
- ReplaceRawBufferLoad(func, M);
- func->eraseFromParent();
- } else if (func->getName().startswith("dx.op.rawBufferStore")) {
- ReplaceRawBufferStore(func, M);
- func->eraseFromParent();
- }
- }
- }
- } else if (!flag.GetUseNativeLowPrecision()) {
- for (auto F = M.functions().begin(), E = M.functions().end(); F != E;) {
- Function *func = &*(F++);
- if (func->hasName()) {
- if (func->getName().startswith("dx.op.rawBufferLoad")) {
- ReplaceMinPrecisionRawBufferLoad(func, M);
- } else if (func->getName().startswith("dx.op.rawBufferStore")) {
- ReplaceMinPrecisionRawBufferStore(func, M);
- }
- }
- }
- }
- return true;
- }
- private:
- // Replace RawBufferLoad/Store to BufferLoad/Store for DXIL < 1.2
- void ReplaceRawBufferLoad(Function *F, Module &M);
- void ReplaceRawBufferStore(Function *F, Module &M);
- // Replace RawBufferLoad/Store of min-precision types to have its actual storage size
- void ReplaceMinPrecisionRawBufferLoad(Function *F, Module &M);
- void ReplaceMinPrecisionRawBufferStore(Function *F, Module &M);
- void ReplaceMinPrecisionRawBufferLoadByType(Function *F, Type *FromTy,
- Type *ToTy, OP *Op,
- const DataLayout &DL);
- };
- } // namespace
- void DxilTranslateRawBuffer::ReplaceRawBufferLoad(Function *F,
- Module &M) {
- OP *op = M.GetDxilModule().GetOP();
- Type *RTy = F->getReturnType();
- if (StructType *STy = dyn_cast<StructType>(RTy)) {
- Type *ETy = STy->getElementType(0);
- Function *newFunction = op->GetOpFunc(hlsl::DXIL::OpCode::BufferLoad, ETy);
- for (auto U = F->user_begin(), E = F->user_end(); U != E;) {
- User *user = *(U++);
- if (CallInst *CI = dyn_cast<CallInst>(user)) {
- IRBuilder<> Builder(CI);
- SmallVector<Value *, 4> args;
- args.emplace_back(op->GetI32Const((unsigned)DXIL::OpCode::BufferLoad));
- for (unsigned i = 1; i < 4; ++i) {
- args.emplace_back(CI->getArgOperand(i));
- }
- CallInst *newCall = Builder.CreateCall(newFunction, args);
- CI->replaceAllUsesWith(newCall);
- CI->eraseFromParent();
- } else {
- DXASSERT(false, "function can only be used with call instructions.");
- }
- }
- } else {
- DXASSERT(false, "RawBufferLoad should return struct type.");
- }
- }
- void DxilTranslateRawBuffer::ReplaceRawBufferStore(Function *F,
- Module &M) {
- OP *op = M.GetDxilModule().GetOP();
- DXASSERT(F->getReturnType()->isVoidTy(), "rawBufferStore should return a void type.");
- Type *ETy = F->getFunctionType()->getParamType(4); // value
- Function *newFunction = op->GetOpFunc(hlsl::DXIL::OpCode::BufferStore, ETy);
- for (auto U = F->user_begin(), E = F->user_end(); U != E;) {
- User *user = *(U++);
- if (CallInst *CI = dyn_cast<CallInst>(user)) {
- IRBuilder<> Builder(CI);
- SmallVector<Value *, 4> args;
- args.emplace_back(op->GetI32Const((unsigned)DXIL::OpCode::BufferStore));
- for (unsigned i = 1; i < 9; ++i) {
- args.emplace_back(CI->getArgOperand(i));
- }
- Builder.CreateCall(newFunction, args);
- CI->eraseFromParent();
- }
- else {
- DXASSERT(false, "function can only be used with call instructions.");
- }
- }
- }
- void DxilTranslateRawBuffer::ReplaceMinPrecisionRawBufferLoad(Function *F,
- Module &M) {
- OP *Op = M.GetDxilModule().GetOP();
- Type *RetTy = F->getReturnType();
- if (StructType *STy = dyn_cast<StructType>(RetTy)) {
- Type *EltTy = STy->getElementType(0);
- if (EltTy->isHalfTy()) {
- ReplaceMinPrecisionRawBufferLoadByType(F, Type::getHalfTy(M.getContext()),
- Type::getFloatTy(M.getContext()),
- Op, M.getDataLayout());
- } else if (EltTy == Type::getInt16Ty(M.getContext())) {
- ReplaceMinPrecisionRawBufferLoadByType(
- F, Type::getInt16Ty(M.getContext()), Type::getInt32Ty(M.getContext()),
- Op, M.getDataLayout());
- }
- } else {
- DXASSERT(false, "RawBufferLoad should return struct type.");
- }
- }
- void DxilTranslateRawBuffer::ReplaceMinPrecisionRawBufferStore(Function *F,
- Module &M) {
- DXASSERT(F->getReturnType()->isVoidTy(), "rawBufferStore should return a void type.");
- Type *ETy = F->getFunctionType()->getParamType(4); // value
- Type *NewETy;
- if (ETy->isHalfTy()) {
- NewETy = Type::getFloatTy(M.getContext());
- }
- else if (ETy == Type::getInt16Ty(M.getContext())) {
- NewETy = Type::getInt32Ty(M.getContext());
- }
- else {
- return; // not a min precision type
- }
- Function *newFunction = M.GetDxilModule().GetOP()->GetOpFunc(
- DXIL::OpCode::RawBufferStore, NewETy);
- // for each function
- // add argument 4-7 to its upconverted values
- // replace function call
- for (auto FuncUser = F->user_begin(), FuncEnd = F->user_end(); FuncUser != FuncEnd;) {
- CallInst *CI = dyn_cast<CallInst>(*(FuncUser++));
- DXASSERT(CI, "function user must be a call instruction.");
- IRBuilder<> CIBuilder(CI);
- SmallVector<Value *, 9> Args;
- for (unsigned i = 0; i < 4; ++i) {
- Args.emplace_back(CI->getArgOperand(i));
- }
- // values to store should be converted to its higher precision types
- if (ETy->isHalfTy()) {
- for (unsigned i = 4; i < 8; ++i) {
- Value *NewV = CIBuilder.CreateFPExt(CI->getArgOperand(i),
- Type::getFloatTy(M.getContext()));
- Args.emplace_back(NewV);
- }
- }
- else if (ETy == Type::getInt16Ty(M.getContext())) {
- // This case only applies to typed buffer since Store operation of byte
- // address buffer for min precision is handled by implicit conversion on
- // intrinsic call. Since we are extending integer, we have to know if we
- // should sign ext or zero ext. We can do this by iterating checking the
- // size of the element at struct type and comp type at type annotation
- CallInst *handleCI = dyn_cast<CallInst>(CI->getArgOperand(1));
- DXASSERT(handleCI, "otherwise handle was not an argument to buffer store.");
- ConstantInt *resClass = dyn_cast<ConstantInt>(handleCI->getArgOperand(1));
- DXASSERT_LOCALVAR(resClass, resClass && resClass->getSExtValue() ==
- (unsigned)DXIL::ResourceClass::UAV,
- "otherwise buffer store called on non uav kind.");
- ConstantInt *rangeID = dyn_cast<ConstantInt>(handleCI->getArgOperand(2)); // range id or idx?
- DXASSERT(rangeID, "wrong createHandle call.");
- DxilResource dxilRes = M.GetDxilModule().GetUAV(rangeID->getSExtValue());
- StructType *STy = dyn_cast<StructType>(dxilRes.GetRetType());
- DxilStructAnnotation *SAnnot = M.GetDxilModule().GetTypeSystem().GetStructAnnotation(STy);
- ConstantInt *offsetInt = dyn_cast<ConstantInt>(CI->getArgOperand(3));
- unsigned offset = offsetInt->getSExtValue();
- unsigned currentOffset = 0;
- for (DxilStructTypeIterator iter = begin(STy, SAnnot), ItEnd = end(STy, SAnnot); iter != ItEnd; ++iter) {
- std::pair<Type *, DxilFieldAnnotation*> pair = *iter;
- currentOffset += M.getDataLayout().getTypeAllocSize(pair.first);
- if (currentOffset > offset) {
- if (pair.second->GetCompType().IsUIntTy()) {
- for (unsigned i = 4; i < 8; ++i) {
- Value *NewV = CIBuilder.CreateZExt(CI->getArgOperand(i), Type::getInt32Ty(M.getContext()));
- Args.emplace_back(NewV);
- }
- break;
- }
- else if (pair.second->GetCompType().IsIntTy()) {
- for (unsigned i = 4; i < 8; ++i) {
- Value *NewV = CIBuilder.CreateSExt(CI->getArgOperand(i), Type::getInt32Ty(M.getContext()));
- Args.emplace_back(NewV);
- }
- break;
- }
- else {
- DXASSERT(false, "Invalid comp type");
- }
- }
- }
- }
- // mask
- Args.emplace_back(CI->getArgOperand(8));
- // alignment
- Args.emplace_back(M.GetDxilModule().GetOP()->GetI32Const(
- M.getDataLayout().getTypeAllocSize(NewETy)));
- CIBuilder.CreateCall(newFunction, Args);
- CI->eraseFromParent();
- }
- }
- void DxilTranslateRawBuffer::ReplaceMinPrecisionRawBufferLoadByType(
- Function *F, Type *FromTy, Type *ToTy, OP *Op, const DataLayout &DL) {
- Function *newFunction = Op->GetOpFunc(DXIL::OpCode::RawBufferLoad, ToTy);
- for (auto FUser = F->user_begin(), FEnd = F->user_end(); FUser != FEnd;) {
- User *UserCI = *(FUser++);
- if (CallInst *CI = dyn_cast<CallInst>(UserCI)) {
- IRBuilder<> CIBuilder(CI);
- SmallVector<Value *, 5> newFuncArgs;
- // opcode, handle, index, elementOffset, mask
- // Compiler is generating correct element offset even for min precision types
- // So no need to recalculate here
- for (unsigned i = 0; i < 5; ++i) {
- newFuncArgs.emplace_back(CI->getArgOperand(i));
- }
- // new alignment for new type
- newFuncArgs.emplace_back(Op->GetI32Const(DL.getTypeAllocSize(ToTy)));
- CallInst *newCI = CIBuilder.CreateCall(newFunction, newFuncArgs);
- for (auto CIUser = CI->user_begin(), CIEnd = CI->user_end();
- CIUser != CIEnd;) {
- User *UserEV = *(CIUser++);
- if (ExtractValueInst *EV = dyn_cast<ExtractValueInst>(UserEV)) {
- IRBuilder<> EVBuilder(EV);
- ArrayRef<unsigned> Indices = EV->getIndices();
- DXASSERT(Indices.size() == 1, "Otherwise we have wrong extract value.");
- Value *newEV = EVBuilder.CreateExtractValue(newCI, Indices);
- Value *newTruncV;
- if (4 == Indices[0]) { // Don't truncate status
- newTruncV = newEV;
- }
- else if (FromTy->isHalfTy()) {
- newTruncV = EVBuilder.CreateFPTrunc(newEV, FromTy);
- } else if (FromTy->isIntegerTy()) {
- newTruncV = EVBuilder.CreateTrunc(newEV, FromTy);
- } else {
- DXASSERT(false, "unexpected type conversion");
- }
- EV->replaceAllUsesWith(newTruncV);
- EV->eraseFromParent();
- }
- }
- CI->eraseFromParent();
- }
- }
- F->eraseFromParent();
- }
- char DxilTranslateRawBuffer::ID = 0;
- ModulePass *llvm::createDxilTranslateRawBuffer() {
- return new DxilTranslateRawBuffer();
- }
- INITIALIZE_PASS(DxilTranslateRawBuffer, "hlsl-translate-dxil-raw-buffer",
- "Translate raw buffer load", false, false)
|