DxilGenerationPass.cpp 63 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // DxilGenerationPass.cpp //
  4. // Copyright (C) Microsoft Corporation. All rights reserved. //
  5. // This file is distributed under the University of Illinois Open Source //
  6. // License. See LICENSE.TXT for details. //
  7. // //
  8. // DxilGenerationPass implementation. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #include "dxc/HLSL/DxilGenerationPass.h"
  12. #include "dxc/HLSL/DxilOperations.h"
  13. #include "dxc/HLSL/DxilModule.h"
  14. #include "dxc/HLSL/HLModule.h"
  15. #include "dxc/HLSL/HLOperations.h"
  16. #include "dxc/HLSL/HLMatrixLowerHelper.h"
  17. #include "dxc/HlslIntrinsicOp.h"
  18. #include "dxc/Support/Global.h"
  19. #include "dxc/HLSL/DxilTypeSystem.h"
  20. #include "dxc/HLSL/HLOperationLower.h"
  21. #include "HLSignatureLower.h"
  22. #include "dxc/HLSL/DxilUtil.h"
  23. #include "llvm/IR/GetElementPtrTypeIterator.h"
  24. #include "llvm/IR/IRBuilder.h"
  25. #include "llvm/IR/Instructions.h"
  26. #include "llvm/IR/InstIterator.h"
  27. #include "llvm/IR/IntrinsicInst.h"
  28. #include "llvm/IR/Module.h"
  29. #include "llvm/IR/DebugInfo.h"
  30. #include "llvm/IR/PassManager.h"
  31. #include "llvm/ADT/BitVector.h"
  32. #include "llvm/Pass.h"
  33. #include "llvm/Transforms/Utils/SSAUpdater.h"
  34. #include "llvm/Analysis/AssumptionCache.h"
  35. #include "llvm/Transforms/Utils/PromoteMemToReg.h"
  36. #include <memory>
  37. #include <unordered_set>
  38. using namespace llvm;
  39. using namespace hlsl;
  40. // TODO: use hlsl namespace for the most of this file.
  41. namespace {
  42. // Collect unused phi of resources and remove them.
  43. class ResourceRemover : public LoadAndStorePromoter {
  44. AllocaInst *AI;
  45. mutable std::unordered_set<PHINode *> unusedPhis;
  46. public:
  47. ResourceRemover(ArrayRef<Instruction *> Insts, SSAUpdater &S)
  48. : LoadAndStorePromoter(Insts, S), AI(nullptr) {}
  49. void run(AllocaInst *AI, const SmallVectorImpl<Instruction *> &Insts) {
  50. // Remember which alloca we're promoting (for isInstInList).
  51. this->AI = AI;
  52. LoadAndStorePromoter::run(Insts);
  53. for (PHINode *P : unusedPhis) {
  54. P->eraseFromParent();
  55. }
  56. }
  57. bool
  58. isInstInList(Instruction *I,
  59. const SmallVectorImpl<Instruction *> &Insts) const override {
  60. if (LoadInst *LI = dyn_cast<LoadInst>(I))
  61. return LI->getOperand(0) == AI;
  62. return cast<StoreInst>(I)->getPointerOperand() == AI;
  63. }
  64. void replaceLoadWithValue(LoadInst *LI, Value *V) const override {
  65. if (PHINode *PHI = dyn_cast<PHINode>(V)) {
  66. if (PHI->user_empty())
  67. unusedPhis.insert(PHI);
  68. }
  69. LI->replaceAllUsesWith(UndefValue::get(LI->getType()));
  70. }
  71. };
  72. void InitResourceBase(const DxilResourceBase *pSource, DxilResourceBase *pDest) {
  73. DXASSERT_NOMSG(pSource->GetClass() == pDest->GetClass());
  74. pDest->SetKind(pSource->GetKind());
  75. pDest->SetID(pSource->GetID());
  76. pDest->SetSpaceID(pSource->GetSpaceID());
  77. pDest->SetLowerBound(pSource->GetLowerBound());
  78. pDest->SetRangeSize(pSource->GetRangeSize());
  79. pDest->SetGlobalSymbol(pSource->GetGlobalSymbol());
  80. pDest->SetGlobalName(pSource->GetGlobalName());
  81. pDest->SetHandle(pSource->GetHandle());
  82. }
  83. void InitResource(const DxilResource *pSource, DxilResource *pDest) {
  84. pDest->SetCompType(pSource->GetCompType());
  85. pDest->SetSampleCount(pSource->GetSampleCount());
  86. pDest->SetElementStride(pSource->GetElementStride());
  87. pDest->SetGloballyCoherent(pSource->IsGloballyCoherent());
  88. pDest->SetHasCounter(pSource->HasCounter());
  89. pDest->SetRW(pSource->IsRW());
  90. pDest->SetROV(pSource->IsROV());
  91. InitResourceBase(pSource, pDest);
  92. }
  93. void InitDxilModuleFromHLModule(HLModule &H, DxilModule &M, DxilEntrySignature *pSig, bool HasDebugInfo) {
  94. std::unique_ptr<DxilEntrySignature> pSigPtr(pSig);
  95. // Subsystems.
  96. unsigned ValMajor, ValMinor;
  97. H.GetValidatorVersion(ValMajor, ValMinor);
  98. M.SetValidatorVersion(ValMajor, ValMinor);
  99. M.SetShaderModel(H.GetShaderModel());
  100. // Entry function.
  101. Function *EntryFn = H.GetEntryFunction();
  102. DxilFunctionProps *FnProps = H.HasDxilFunctionProps(EntryFn) ? &H.GetDxilFunctionProps(EntryFn) : nullptr;
  103. M.SetEntryFunction(EntryFn);
  104. M.SetEntryFunctionName(H.GetEntryFunctionName());
  105. std::vector<GlobalVariable* > &LLVMUsed = M.GetLLVMUsed();
  106. // Resources
  107. for (auto && C : H.GetCBuffers()) {
  108. auto b = make_unique<DxilCBuffer>();
  109. InitResourceBase(C.get(), b.get());
  110. b->SetSize(C->GetSize());
  111. if (HasDebugInfo)
  112. LLVMUsed.emplace_back(cast<GlobalVariable>(b->GetGlobalSymbol()));
  113. b->SetGlobalSymbol(UndefValue::get(b->GetGlobalSymbol()->getType()));
  114. M.AddCBuffer(std::move(b));
  115. }
  116. for (auto && C : H.GetUAVs()) {
  117. auto b = make_unique<DxilResource>();
  118. InitResource(C.get(), b.get());
  119. if (HasDebugInfo)
  120. LLVMUsed.emplace_back(cast<GlobalVariable>(b->GetGlobalSymbol()));
  121. b->SetGlobalSymbol(UndefValue::get(b->GetGlobalSymbol()->getType()));
  122. M.AddUAV(std::move(b));
  123. }
  124. for (auto && C : H.GetSRVs()) {
  125. auto b = make_unique<DxilResource>();
  126. InitResource(C.get(), b.get());
  127. if (HasDebugInfo)
  128. LLVMUsed.emplace_back(cast<GlobalVariable>(b->GetGlobalSymbol()));
  129. b->SetGlobalSymbol(UndefValue::get(b->GetGlobalSymbol()->getType()));
  130. M.AddSRV(std::move(b));
  131. }
  132. for (auto && C : H.GetSamplers()) {
  133. auto b = make_unique<DxilSampler>();
  134. InitResourceBase(C.get(), b.get());
  135. b->SetSamplerKind(C->GetSamplerKind());
  136. if (HasDebugInfo)
  137. LLVMUsed.emplace_back(cast<GlobalVariable>(b->GetGlobalSymbol()));
  138. b->SetGlobalSymbol(UndefValue::get(b->GetGlobalSymbol()->getType()));
  139. M.AddSampler(std::move(b));
  140. }
  141. // Signatures.
  142. M.ResetEntrySignature(pSigPtr.release());
  143. M.ResetRootSignature(H.ReleaseRootSignature());
  144. // Shader properties.
  145. //bool m_bDisableOptimizations;
  146. M.m_ShaderFlags.SetDisableOptimizations(H.GetHLOptions().bDisableOptimizations);
  147. //bool m_bDisableMathRefactoring;
  148. //bool m_bEnableDoublePrecision;
  149. //bool m_bEnableDoubleExtensions;
  150. //M.CollectShaderFlags();
  151. //bool m_bForceEarlyDepthStencil;
  152. //bool m_bEnableRawAndStructuredBuffers;
  153. //bool m_bEnableMSAD;
  154. //M.m_ShaderFlags.SetAllResourcesBound(H.GetHLOptions().bAllResourcesBound);
  155. M.m_ShaderFlags.SetUseNativeLowPrecision(!H.GetHLOptions().bUseMinPrecision);
  156. if (FnProps)
  157. M.SetShaderProperties(FnProps);
  158. // Move function props.
  159. if (M.GetShaderModel()->IsLib())
  160. M.ResetFunctionPropsMap(H.ReleaseFunctionPropsMap());
  161. // DXIL type system.
  162. M.ResetTypeSystem(H.ReleaseTypeSystem());
  163. // Dxil OP.
  164. M.ResetOP(H.ReleaseOP());
  165. // Keep llvm used.
  166. M.EmitLLVMUsed();
  167. M.m_ShaderFlags.SetAllResourcesBound(H.GetHLOptions().bAllResourcesBound);
  168. // Update Validator Version
  169. M.UpgradeToMinValidatorVersion();
  170. }
  171. class DxilGenerationPass : public ModulePass {
  172. HLModule *m_pHLModule;
  173. bool m_HasDbgInfo;
  174. HLSLExtensionsCodegenHelper *m_extensionsCodegenHelper;
  175. public:
  176. static char ID; // Pass identification, replacement for typeid
  177. explicit DxilGenerationPass(bool NoOpt = false)
  178. : ModulePass(ID), m_pHLModule(nullptr), NotOptimized(NoOpt), m_extensionsCodegenHelper(nullptr) {}
  179. const char *getPassName() const override { return "DXIL Generator"; }
  180. void SetExtensionsHelper(HLSLExtensionsCodegenHelper *helper) {
  181. m_extensionsCodegenHelper = helper;
  182. }
  183. bool runOnModule(Module &M) override {
  184. m_pHLModule = &M.GetOrCreateHLModule();
  185. const ShaderModel *SM = m_pHLModule->GetShaderModel();
  186. // Load up debug information, to cross-reference values and the instructions
  187. // used to load them.
  188. m_HasDbgInfo = getDebugMetadataVersionFromModule(M) != 0;
  189. std::unique_ptr<DxilEntrySignature> pSig =
  190. llvm::make_unique<DxilEntrySignature>(SM->GetKind(), M.GetHLModule().GetHLOptions().bUseMinPrecision);
  191. // EntrySig for shader functions.
  192. std::unordered_map<llvm::Function *, std::unique_ptr<DxilEntrySignature>>
  193. DxilEntrySignatureMap;
  194. if (!SM->IsLib()) {
  195. HLSignatureLower sigLower(m_pHLModule->GetEntryFunction(), *m_pHLModule,
  196. *pSig);
  197. sigLower.Run();
  198. } else {
  199. for (auto It = M.begin(); It != M.end();) {
  200. Function &F = *(It++);
  201. // Lower signature for each entry function.
  202. if (m_pHLModule->HasDxilFunctionProps(&F)) {
  203. DxilFunctionProps &props = m_pHLModule->GetDxilFunctionProps(&F);
  204. std::unique_ptr<DxilEntrySignature> pSig =
  205. llvm::make_unique<DxilEntrySignature>(props.shaderKind, m_pHLModule->GetHLOptions().bUseMinPrecision);
  206. HLSignatureLower sigLower(&F, *m_pHLModule, *pSig);
  207. sigLower.Run();
  208. DxilEntrySignatureMap[&F] = std::move(pSig);
  209. }
  210. }
  211. }
  212. std::unordered_set<LoadInst *> UpdateCounterSet;
  213. std::unordered_set<Value *> NonUniformSet;
  214. GenerateDxilOperations(M, UpdateCounterSet, NonUniformSet);
  215. std::unordered_map<Instruction *, Value *> handleMap;
  216. GenerateDxilCBufferHandles(NonUniformSet);
  217. GenerateParamDxilResourceHandles(handleMap);
  218. GenerateDxilResourceHandles(UpdateCounterSet, NonUniformSet);
  219. AddCreateHandleForPhiNodeAndSelect(m_pHLModule->GetOP());
  220. // For module which not promote mem2reg.
  221. // Remove local resource alloca/load/store/phi.
  222. for (auto It = M.begin(); It != M.end();) {
  223. Function &F = *(It++);
  224. if (!F.isDeclaration()) {
  225. RemoveLocalDxilResourceAllocas(&F);
  226. if (hlsl::GetHLOpcodeGroupByName(&F) == HLOpcodeGroup::HLCreateHandle) {
  227. if (F.user_empty()) {
  228. F.eraseFromParent();
  229. } else {
  230. M.getContext().emitError("Fail to lower createHandle.");
  231. }
  232. }
  233. }
  234. }
  235. // Translate precise on allocas into function call to keep the information after mem2reg.
  236. // The function calls will be removed after propagate precise attribute.
  237. TranslatePreciseAttribute();
  238. // Change struct type to legacy layout for cbuf and struct buf.
  239. UpdateStructTypeForLegacyLayout();
  240. // High-level metadata should now be turned into low-level metadata.
  241. const bool SkipInit = true;
  242. hlsl::DxilModule &DxilMod = M.GetOrCreateDxilModule(SkipInit);
  243. InitDxilModuleFromHLModule(*m_pHLModule, DxilMod, pSig.release(),
  244. m_HasDbgInfo);
  245. if (SM->IsLib())
  246. DxilMod.ResetEntrySignatureMap(std::move(DxilEntrySignatureMap));
  247. HLModule::ClearHLMetadata(M);
  248. M.ResetHLModule();
  249. // We now have a DXIL representation - record this.
  250. SetPauseResumePasses(M, "hlsl-dxilemit", "hlsl-dxilload");
  251. // Remove debug code when not debug info.
  252. if (!m_HasDbgInfo)
  253. DxilMod.StripDebugRelatedCode();
  254. return true;
  255. }
  256. private:
  257. void RemoveLocalDxilResourceAllocas(Function *F);
  258. void
  259. TranslateDxilResourceUses(DxilResourceBase &res,
  260. std::unordered_set<LoadInst *> &UpdateCounterSet,
  261. std::unordered_set<Value *> &NonUniformSet);
  262. void
  263. GenerateDxilResourceHandles(std::unordered_set<LoadInst *> &UpdateCounterSet,
  264. std::unordered_set<Value *> &NonUniformSet);
  265. void AddCreateHandleForPhiNodeAndSelect(OP *hlslOP);
  266. void TranslateParamDxilResourceHandles(Function *F, std::unordered_map<Instruction *, Value *> &handleMap);
  267. void GenerateParamDxilResourceHandles(
  268. std::unordered_map<Instruction *, Value *> &handleMap);
  269. // Generate DXIL cbuffer handles.
  270. void
  271. GenerateDxilCBufferHandles(std::unordered_set<Value *> &NonUniformSet);
  272. // change built-in funtion into DXIL operations
  273. void GenerateDxilOperations(Module &M,
  274. std::unordered_set<LoadInst *> &UpdateCounterSet,
  275. std::unordered_set<Value *> &NonUniformSet);
  276. // Change struct type to legacy layout for cbuf and struct buf.
  277. void UpdateStructTypeForLegacyLayout();
  278. // Translate precise attribute into HL function call.
  279. void TranslatePreciseAttribute();
  280. // Input module is not optimized.
  281. bool NotOptimized;
  282. };
  283. }
  284. static Value *MergeImmResClass(Value *resClass) {
  285. if (ConstantInt *Imm = dyn_cast<ConstantInt>(resClass)) {
  286. return resClass;
  287. } else {
  288. PHINode *phi = cast<PHINode>(resClass);
  289. Value *immResClass = MergeImmResClass(phi->getIncomingValue(0));
  290. unsigned numOperands = phi->getNumOperands();
  291. for (unsigned i=0;i<numOperands;i++)
  292. phi->setIncomingValue(i, immResClass);
  293. return immResClass;
  294. }
  295. }
  296. static const StringRef kResourceMapErrorMsg = "local resource not guaranteed to map to unique global resource.";
  297. static Value *SelectOnOperand(Value *Cond, CallInst *CIT, CallInst *CIF,
  298. unsigned idx, IRBuilder<> &Builder) {
  299. Value *OpT = CIT->getArgOperand(idx);
  300. Value *OpF = CIF->getArgOperand(idx);
  301. Value *OpSel = OpT;
  302. if (OpT != OpF) {
  303. OpSel = Builder.CreateSelect(Cond, OpT, OpF);
  304. }
  305. return OpSel;
  306. }
  307. static void ReplaceResourceUserWithHandle(LoadInst *Res, Value *handle) {
  308. for (auto resUser = Res->user_begin(); resUser != Res->user_end();) {
  309. CallInst *CI = dyn_cast<CallInst>(*(resUser++));
  310. DXASSERT(GetHLOpcodeGroupByName(CI->getCalledFunction()) ==
  311. HLOpcodeGroup::HLCreateHandle,
  312. "must be createHandle");
  313. CI->replaceAllUsesWith(handle);
  314. CI->eraseFromParent();
  315. }
  316. Res->eraseFromParent();
  317. }
  318. static bool IsResourceType(Type *Ty) {
  319. bool isResource = HLModule::IsHLSLObjectType(Ty);
  320. if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
  321. Type *EltTy = AT->getElementType();
  322. while (isa<ArrayType>(EltTy)) {
  323. EltTy = EltTy->getArrayElementType();
  324. }
  325. isResource = HLModule::IsHLSLObjectType(EltTy);
  326. // TODO: support local resource array.
  327. DXASSERT(!isResource, "local resource array");
  328. }
  329. return isResource;
  330. }
  331. void DxilGenerationPass::RemoveLocalDxilResourceAllocas(Function *F) {
  332. BasicBlock &BB = F->getEntryBlock(); // Get the entry node for the function
  333. std::unordered_set<AllocaInst *> localResources;
  334. for (BasicBlock::iterator I = BB.begin(), E = --BB.end(); I != E; ++I)
  335. if (AllocaInst *AI = dyn_cast<AllocaInst>(I)) { // Is it an alloca?
  336. if (IsResourceType(AI->getAllocatedType())) {
  337. localResources.insert(AI);
  338. }
  339. }
  340. SSAUpdater SSA;
  341. SmallVector<Instruction *, 4> Insts;
  342. for (AllocaInst *AI : localResources) {
  343. // Build list of instructions to promote.
  344. for (User *U : AI->users())
  345. Insts.emplace_back(cast<Instruction>(U));
  346. ResourceRemover(Insts, SSA).run(AI, Insts);
  347. Insts.clear();
  348. }
  349. }
  350. void DxilGenerationPass::TranslateParamDxilResourceHandles(Function *F, std::unordered_map<Instruction *, Value *> &handleMap) {
  351. Type *handleTy = m_pHLModule->GetOP()->GetHandleType();
  352. IRBuilder<> Builder(F->getEntryBlock().getFirstInsertionPt());
  353. for (Argument &arg : F->args()) {
  354. Type *Ty = arg.getType();
  355. if (isa<PointerType>(Ty))
  356. Ty = Ty->getPointerElementType();
  357. SmallVector<unsigned,4> arraySizeList;
  358. while (isa<ArrayType>(Ty)) {
  359. arraySizeList.push_back(Ty->getArrayNumElements());
  360. Ty = Ty->getArrayElementType();
  361. }
  362. DXIL::ResourceClass RC = m_pHLModule->GetResourceClass(Ty);
  363. if (RC != DXIL::ResourceClass::Invalid) {
  364. Type *curTy = handleTy;
  365. for (auto it = arraySizeList.rbegin(), E = arraySizeList.rend(); it != E;
  366. it++) {
  367. curTy = ArrayType::get(curTy, *it);
  368. }
  369. curTy = PointerType::get(curTy, 0);
  370. CallInst *castToHandle = cast<CallInst>(HLModule::EmitHLOperationCall(
  371. Builder, HLOpcodeGroup::HLCast, 0, curTy,
  372. {UndefValue::get(arg.getType())}, *F->getParent()));
  373. for (User *U : arg.users()) {
  374. Instruction *I = cast<Instruction>(U);
  375. IRBuilder<> userBuilder(I);
  376. if (LoadInst *ldInst = dyn_cast<LoadInst>(U)) {
  377. Value *handleLd = userBuilder.CreateLoad(castToHandle);
  378. handleMap[ldInst] = handleLd;
  379. } else if (StoreInst *stInst = dyn_cast<StoreInst>(U)) {
  380. Value *res = stInst->getValueOperand();
  381. Value *handle = HLModule::EmitHLOperationCall(
  382. userBuilder, HLOpcodeGroup::HLCast, 0, handleTy, {res},
  383. *F->getParent());
  384. userBuilder.CreateStore(handle, castToHandle);
  385. } else if (CallInst *CI = dyn_cast<CallInst>(U)) {
  386. // Don't flatten argument here.
  387. continue;
  388. } else {
  389. DXASSERT(
  390. dyn_cast<GEPOperator>(U) != nullptr,
  391. "else AddOpcodeParamForIntrinsic in CodeGen did not patch uses "
  392. "to only have ld/st refer to temp object");
  393. GEPOperator *GEP = cast<GEPOperator>(U);
  394. std::vector<Value *> idxList(GEP->idx_begin(), GEP->idx_end());
  395. Value *handleGEP = userBuilder.CreateGEP(castToHandle, idxList);
  396. for (auto GEPU : GEP->users()) {
  397. Instruction *GEPI = cast<Instruction>(GEPU);
  398. IRBuilder<> gepUserBuilder(GEPI);
  399. if (LoadInst *ldInst = dyn_cast<LoadInst>(GEPU)) {
  400. handleMap[ldInst] = gepUserBuilder.CreateLoad(handleGEP);
  401. } else {
  402. StoreInst *stInst = cast<StoreInst>(GEPU);
  403. Value *res = stInst->getValueOperand();
  404. Value *handle = HLModule::EmitHLOperationCall(
  405. gepUserBuilder, HLOpcodeGroup::HLCast, 0, handleTy, {res},
  406. *F->getParent());
  407. gepUserBuilder.CreateStore(handle, handleGEP);
  408. }
  409. }
  410. }
  411. }
  412. castToHandle->setArgOperand(0, &arg);
  413. }
  414. }
  415. }
  416. void DxilGenerationPass::GenerateParamDxilResourceHandles(
  417. std::unordered_map<Instruction *, Value *> &handleMap) {
  418. Module &M = *m_pHLModule->GetModule();
  419. for (Function &F : M.functions()) {
  420. if (!F.isDeclaration())
  421. TranslateParamDxilResourceHandles(&F, handleMap);
  422. }
  423. }
  424. void DxilGenerationPass::TranslateDxilResourceUses(
  425. DxilResourceBase &res, std::unordered_set<LoadInst *> &UpdateCounterSet,
  426. std::unordered_set<Value *> &NonUniformSet) {
  427. OP *hlslOP = m_pHLModule->GetOP();
  428. Function *createHandle = hlslOP->GetOpFunc(
  429. OP::OpCode::CreateHandle, llvm::Type::getVoidTy(m_pHLModule->GetCtx()));
  430. Value *opArg = hlslOP->GetU32Const((unsigned)OP::OpCode::CreateHandle);
  431. bool isViewResource = res.GetClass() == DXIL::ResourceClass::SRV || res.GetClass() == DXIL::ResourceClass::UAV;
  432. bool isROV = isViewResource && static_cast<DxilResource &>(res).IsROV();
  433. std::string handleName = (res.GetGlobalName() + Twine("_") + Twine(res.GetResClassName())).str();
  434. if (isViewResource)
  435. handleName += (Twine("_") + Twine(res.GetResDimName())).str();
  436. if (isROV)
  437. handleName += "_ROV";
  438. Value *resClassArg = hlslOP->GetU8Const(
  439. static_cast<std::underlying_type<DxilResourceBase::Class>::type>(
  440. res.GetClass()));
  441. Value *resIDArg = hlslOP->GetU32Const(res.GetID());
  442. // resLowerBound will be added after allocation in DxilCondenseResources.
  443. Value *resLowerBound = hlslOP->GetU32Const(0);
  444. // TODO: Set Non-uniform resource bit based on whether index comes from IOP_NonUniformResourceIndex.
  445. Value *isUniformRes = hlslOP->GetI1Const(0);
  446. Value *GV = res.GetGlobalSymbol();
  447. Module *pM = m_pHLModule->GetModule();
  448. // TODO: add debug info to create handle.
  449. DIVariable *DIV = nullptr;
  450. DILocation *DL = nullptr;
  451. if (m_HasDbgInfo) {
  452. DebugInfoFinder &Finder = m_pHLModule->GetOrCreateDebugInfoFinder();
  453. DIV =
  454. HLModule::FindGlobalVariableDebugInfo(cast<GlobalVariable>(GV), Finder);
  455. if (DIV)
  456. // TODO: how to get col?
  457. DL =
  458. DILocation::get(pM->getContext(), DIV->getLine(), 1, DIV->getScope());
  459. }
  460. bool isResArray = res.GetRangeSize() > 1;
  461. std::unordered_map<Function *, Instruction *> handleMapOnFunction;
  462. Value *createHandleArgs[] = {opArg, resClassArg, resIDArg, resLowerBound,
  463. isUniformRes};
  464. for (iplist<Function>::iterator F : pM->getFunctionList()) {
  465. if (!F->isDeclaration()) {
  466. if (!isResArray) {
  467. IRBuilder<> Builder(F->getEntryBlock().getFirstInsertionPt());
  468. if (m_HasDbgInfo) {
  469. // TODO: set debug info.
  470. //Builder.SetCurrentDebugLocation(DL);
  471. }
  472. handleMapOnFunction[F] = Builder.CreateCall(createHandle, createHandleArgs, handleName);
  473. }
  474. }
  475. }
  476. for (auto U = GV->user_begin(), E = GV->user_end(); U != E; ) {
  477. User *user = *(U++);
  478. // Skip unused user.
  479. if (user->user_empty())
  480. continue;
  481. if (LoadInst *ldInst = dyn_cast<LoadInst>(user)) {
  482. if (UpdateCounterSet.count(ldInst)) {
  483. DxilResource *resource = llvm::dyn_cast<DxilResource>(&res);
  484. DXASSERT_NOMSG(resource);
  485. DXASSERT_NOMSG(resource->GetClass() == DXIL::ResourceClass::UAV);
  486. resource->SetHasCounter(true);
  487. }
  488. Function *userF = ldInst->getParent()->getParent();
  489. DXASSERT(handleMapOnFunction.count(userF), "must exist");
  490. Value *handle = handleMapOnFunction[userF];
  491. ReplaceResourceUserWithHandle(ldInst, handle);
  492. } else {
  493. DXASSERT(dyn_cast<GEPOperator>(user) != nullptr,
  494. "else AddOpcodeParamForIntrinsic in CodeGen did not patch uses "
  495. "to only have ld/st refer to temp object");
  496. GEPOperator *GEP = cast<GEPOperator>(user);
  497. Value *idx = nullptr;
  498. if (GEP->getNumIndices() == 2) {
  499. // one dim array of resource
  500. idx = (GEP->idx_begin() + 1)->get();
  501. } else {
  502. gep_type_iterator GEPIt = gep_type_begin(GEP), E = gep_type_end(GEP);
  503. // Must be instruction for multi dim array.
  504. std::unique_ptr<IRBuilder<> > Builder;
  505. if (GetElementPtrInst *GEPInst = dyn_cast<GetElementPtrInst>(GEP)) {
  506. Builder = std::make_unique<IRBuilder<> >(GEPInst);
  507. } else {
  508. Builder = std::make_unique<IRBuilder<> >(GV->getContext());
  509. }
  510. for (; GEPIt != E; ++GEPIt) {
  511. if (GEPIt->isArrayTy()) {
  512. unsigned arraySize = GEPIt->getArrayNumElements();
  513. Value * tmpIdx = GEPIt.getOperand();
  514. if (idx == nullptr)
  515. idx = tmpIdx;
  516. else {
  517. idx = Builder->CreateMul(idx, Builder->getInt32(arraySize));
  518. idx = Builder->CreateAdd(idx, tmpIdx);
  519. }
  520. }
  521. }
  522. }
  523. createHandleArgs[DXIL::OperandIndex::kCreateHandleResIndexOpIdx] = idx;
  524. if (!NonUniformSet.count(idx))
  525. createHandleArgs[DXIL::OperandIndex::kCreateHandleIsUniformOpIdx] =
  526. isUniformRes;
  527. else
  528. createHandleArgs[DXIL::OperandIndex::kCreateHandleIsUniformOpIdx] =
  529. hlslOP->GetI1Const(1);
  530. Value *handle = nullptr;
  531. if (GetElementPtrInst *GEPInst = dyn_cast<GetElementPtrInst>(GEP)) {
  532. IRBuilder<> Builder = IRBuilder<>(GEPInst);
  533. handle = Builder.CreateCall(createHandle, createHandleArgs, handleName);
  534. }
  535. for (auto GEPU = GEP->user_begin(), GEPE = GEP->user_end(); GEPU != GEPE; ) {
  536. // Must be load inst.
  537. LoadInst *ldInst = cast<LoadInst>(*(GEPU++));
  538. if (UpdateCounterSet.count(ldInst)) {
  539. DxilResource *resource = dyn_cast<DxilResource>(&res);
  540. DXASSERT_NOMSG(resource);
  541. DXASSERT_NOMSG(resource->GetClass() == DXIL::ResourceClass::UAV);
  542. resource->SetHasCounter(true);
  543. }
  544. if (handle) {
  545. ReplaceResourceUserWithHandle(ldInst, handle);
  546. }
  547. else {
  548. IRBuilder<> Builder = IRBuilder<>(ldInst);
  549. Value *localHandle = Builder.CreateCall(createHandle, createHandleArgs, handleName);
  550. ReplaceResourceUserWithHandle(ldInst, localHandle);
  551. }
  552. }
  553. }
  554. }
  555. // Erase unused handle.
  556. for (auto It : handleMapOnFunction) {
  557. Instruction *I = It.second;
  558. if (I->user_empty())
  559. I->eraseFromParent();
  560. }
  561. }
  562. void DxilGenerationPass::GenerateDxilResourceHandles(
  563. std::unordered_set<LoadInst *> &UpdateCounterSet,
  564. std::unordered_set<Value *> &NonUniformSet) {
  565. // Create sampler handle first, may be used by SRV operations.
  566. for (size_t i = 0; i < m_pHLModule->GetSamplers().size(); i++) {
  567. DxilSampler &S = m_pHLModule->GetSampler(i);
  568. TranslateDxilResourceUses(S, UpdateCounterSet, NonUniformSet);
  569. }
  570. for (size_t i = 0; i < m_pHLModule->GetSRVs().size(); i++) {
  571. HLResource &SRV = m_pHLModule->GetSRV(i);
  572. TranslateDxilResourceUses(SRV, UpdateCounterSet, NonUniformSet);
  573. }
  574. for (size_t i = 0; i < m_pHLModule->GetUAVs().size(); i++) {
  575. HLResource &UAV = m_pHLModule->GetUAV(i);
  576. TranslateDxilResourceUses(UAV, UpdateCounterSet, NonUniformSet);
  577. }
  578. }
  579. static void
  580. AddResourceToSet(Instruction *Res, std::unordered_set<Instruction *> &resSet) {
  581. unsigned startOpIdx = 0;
  582. // Skip Cond for Select.
  583. if (isa<SelectInst>(Res))
  584. startOpIdx = 1;
  585. else if (!isa<PHINode>(Res))
  586. // Only check phi and select here.
  587. return;
  588. // Already add.
  589. if (resSet.count(Res))
  590. return;
  591. resSet.insert(Res);
  592. // Scan operand to add resource node which only used by phi/select.
  593. unsigned numOperands = Res->getNumOperands();
  594. for (unsigned i = startOpIdx; i < numOperands; i++) {
  595. Value *V = Res->getOperand(i);
  596. if (Instruction *I = dyn_cast<Instruction>(V)) {
  597. AddResourceToSet(I, resSet);
  598. }
  599. }
  600. }
  601. // Transform
  602. //
  603. // %g_texture_texture_2d1 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 0, i32 0, i1 false)
  604. // %g_texture_texture_2d = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 0, i32 2, i1 false)
  605. // %13 = select i1 %cmp, %dx.types.Handle %g_texture_texture_2d1, %dx.types.Handle %g_texture_texture_2d
  606. // Into
  607. // %11 = select i1 %cmp, i32 0, i32 2
  608. // %12 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 0, i32 %11, i1 false)
  609. //
  610. static bool MergeHandleOpWithSameValue(Instruction *HandleOp,
  611. unsigned startOpIdx,
  612. unsigned numOperands) {
  613. Value *op0 = nullptr;
  614. for (unsigned i = startOpIdx; i < numOperands; i++) {
  615. Value *op = HandleOp->getOperand(i);
  616. if (i == startOpIdx) {
  617. op0 = op;
  618. } else {
  619. if (op0 != op)
  620. op0 = nullptr;
  621. }
  622. }
  623. if (op0) {
  624. HandleOp->replaceAllUsesWith(op0);
  625. return true;
  626. }
  627. return false;
  628. }
  629. static void
  630. UpdateHandleOperands(Instruction *Res,
  631. std::unordered_map<Instruction *, CallInst *> &handleMap,
  632. std::unordered_set<Instruction *> &nonUniformOps) {
  633. unsigned numOperands = Res->getNumOperands();
  634. unsigned startOpIdx = 0;
  635. // Skip Cond for Select.
  636. if (SelectInst *Sel = dyn_cast<SelectInst>(Res))
  637. startOpIdx = 1;
  638. CallInst *Handle = handleMap[Res];
  639. Instruction *resClass = cast<Instruction>(
  640. Handle->getArgOperand(DXIL::OperandIndex::kCreateHandleResClassOpIdx));
  641. Instruction *resID = cast<Instruction>(
  642. Handle->getArgOperand(DXIL::OperandIndex::kCreateHandleResIDOpIdx));
  643. Instruction *resAddr = cast<Instruction>(
  644. Handle->getArgOperand(DXIL::OperandIndex::kCreateHandleResIndexOpIdx));
  645. for (unsigned i = startOpIdx; i < numOperands; i++) {
  646. if (!isa<Instruction>(Res->getOperand(i))) {
  647. Res->getContext().emitError(Res, kResourceMapErrorMsg);
  648. continue;
  649. }
  650. Instruction *ResOp = cast<Instruction>(Res->getOperand(i));
  651. CallInst *HandleOp = dyn_cast<CallInst>(ResOp);
  652. if (!HandleOp) {
  653. if (handleMap.count(ResOp)) {
  654. Res->getContext().emitError(Res, kResourceMapErrorMsg);
  655. continue;
  656. }
  657. HandleOp = handleMap[ResOp];
  658. }
  659. Value *resClassOp =
  660. HandleOp->getArgOperand(DXIL::OperandIndex::kCreateHandleResClassOpIdx);
  661. Value *resIDOp =
  662. HandleOp->getArgOperand(DXIL::OperandIndex::kCreateHandleResIDOpIdx);
  663. Value *resAddrOp =
  664. HandleOp->getArgOperand(DXIL::OperandIndex::kCreateHandleResIndexOpIdx);
  665. resClass->setOperand(i, resClassOp);
  666. resID->setOperand(i, resIDOp);
  667. resAddr->setOperand(i, resAddrOp);
  668. }
  669. if (!MergeHandleOpWithSameValue(resClass, startOpIdx, numOperands))
  670. nonUniformOps.insert(resClass);
  671. if (!MergeHandleOpWithSameValue(resID, startOpIdx, numOperands))
  672. nonUniformOps.insert(resID);
  673. MergeHandleOpWithSameValue(resAddr, startOpIdx, numOperands);
  674. }
  675. void DxilGenerationPass::AddCreateHandleForPhiNodeAndSelect(OP *hlslOP) {
  676. Function *createHandle = hlslOP->GetOpFunc(
  677. OP::OpCode::CreateHandle, llvm::Type::getVoidTy(hlslOP->GetCtx()));
  678. std::unordered_set<PHINode *> objPhiList;
  679. std::unordered_set<SelectInst *> objSelectList;
  680. std::unordered_set<Instruction *> resSelectSet;
  681. for (User *U : createHandle->users()) {
  682. for (User *HandleU : U->users()) {
  683. Instruction *I = cast<Instruction>(HandleU);
  684. if (!isa<CallInst>(I))
  685. AddResourceToSet(I, resSelectSet);
  686. }
  687. }
  688. // Generate Handle inst for Res inst.
  689. FunctionType *FT = createHandle->getFunctionType();
  690. Value *opArg = hlslOP->GetU32Const((unsigned)OP::OpCode::CreateHandle);
  691. Type *resClassTy =
  692. FT->getParamType(DXIL::OperandIndex::kCreateHandleResClassOpIdx);
  693. Type *resIDTy = FT->getParamType(DXIL::OperandIndex::kCreateHandleResIDOpIdx);
  694. Type *resAddrTy =
  695. FT->getParamType(DXIL::OperandIndex::kCreateHandleResIndexOpIdx);
  696. Value *UndefResClass = UndefValue::get(resClassTy);
  697. Value *UndefResID = UndefValue::get(resIDTy);
  698. Value *UndefResAddr = UndefValue::get(resAddrTy);
  699. // phi/select node resource is not uniform
  700. Value *nonUniformRes = hlslOP->GetI1Const(1);
  701. std::unordered_map<Instruction *, CallInst *> handleMap;
  702. for (Instruction *Res : resSelectSet) {
  703. unsigned numOperands = Res->getNumOperands();
  704. IRBuilder<> Builder(Res);
  705. unsigned startOpIdx = 0;
  706. // Skip Cond for Select.
  707. if (SelectInst *Sel = dyn_cast<SelectInst>(Res)) {
  708. startOpIdx = 1;
  709. Value *Cond = Sel->getCondition();
  710. Value *resClassSel =
  711. Builder.CreateSelect(Cond, UndefResClass, UndefResClass);
  712. Value *resIDSel = Builder.CreateSelect(Cond, UndefResID, UndefResID);
  713. Value *resAddrSel =
  714. Builder.CreateSelect(Cond, UndefResAddr, UndefResAddr);
  715. CallInst *HandleSel =
  716. Builder.CreateCall(createHandle, {opArg, resClassSel, resIDSel,
  717. resAddrSel, nonUniformRes});
  718. handleMap[Res] = HandleSel;
  719. Res->replaceAllUsesWith(HandleSel);
  720. } else {
  721. PHINode *Phi = cast<PHINode>(Res); // res class must be same.
  722. PHINode *resClassPhi = Builder.CreatePHI(resClassTy, numOperands);
  723. PHINode *resIDPhi = Builder.CreatePHI(resIDTy, numOperands);
  724. PHINode *resAddrPhi = Builder.CreatePHI(resAddrTy, numOperands);
  725. for (unsigned i = 0; i < numOperands; i++) {
  726. BasicBlock *BB = Phi->getIncomingBlock(i);
  727. resClassPhi->addIncoming(UndefResClass, BB);
  728. resIDPhi->addIncoming(UndefResID, BB);
  729. resAddrPhi->addIncoming(UndefResAddr, BB);
  730. }
  731. IRBuilder<> HandleBuilder(Phi->getParent()->getFirstNonPHI());
  732. CallInst *HandlePhi =
  733. HandleBuilder.CreateCall(createHandle, {opArg, resClassPhi, resIDPhi,
  734. resAddrPhi, nonUniformRes});
  735. handleMap[Res] = HandlePhi;
  736. Res->replaceAllUsesWith(HandlePhi);
  737. }
  738. }
  739. // Update operand for Handle phi/select.
  740. // If ResClass or ResID is phi/select, save to nonUniformOps.
  741. std::unordered_set<Instruction *> nonUniformOps;
  742. for (Instruction *Res : resSelectSet) {
  743. UpdateHandleOperands(Res, handleMap, nonUniformOps);
  744. }
  745. bool bIsLib = m_pHLModule->GetShaderModel()->IsLib();
  746. // ResClass and ResID must be uniform.
  747. // Try to merge res class, res id into imm.
  748. while (1) {
  749. bool bUpdated = false;
  750. for (auto It = nonUniformOps.begin(); It != nonUniformOps.end();) {
  751. Instruction *I = *(It++);
  752. unsigned numOperands = I->getNumOperands();
  753. unsigned startOpIdx = 0;
  754. // Skip Cond for Select.
  755. if (SelectInst *Sel = dyn_cast<SelectInst>(I))
  756. startOpIdx = 1;
  757. if (MergeHandleOpWithSameValue(I, startOpIdx, numOperands)) {
  758. nonUniformOps.erase(I);
  759. bUpdated = true;
  760. }
  761. }
  762. if (!bUpdated) {
  763. if (!nonUniformOps.empty() && !bIsLib) {
  764. for (Instruction *I : nonUniformOps) {
  765. // Non uniform res class or res id.
  766. FT->getContext().emitError(I, kResourceMapErrorMsg);
  767. }
  768. return;
  769. }
  770. break;
  771. }
  772. }
  773. // Remove useless select/phi.
  774. for (Instruction *Res : resSelectSet) {
  775. Res->eraseFromParent();
  776. }
  777. }
  778. void DxilGenerationPass::GenerateDxilCBufferHandles(
  779. std::unordered_set<Value *> &NonUniformSet) {
  780. // For CBuffer, handle are mapped to HLCreateHandle.
  781. OP *hlslOP = m_pHLModule->GetOP();
  782. Function *createHandle = hlslOP->GetOpFunc(
  783. OP::OpCode::CreateHandle, llvm::Type::getVoidTy(m_pHLModule->GetCtx()));
  784. Value *opArg = hlslOP->GetU32Const((unsigned)OP::OpCode::CreateHandle);
  785. Value *resClassArg = hlslOP->GetU8Const(
  786. static_cast<std::underlying_type<DxilResourceBase::Class>::type>(
  787. DXIL::ResourceClass::CBuffer));
  788. for (size_t i = 0; i < m_pHLModule->GetCBuffers().size(); i++) {
  789. DxilCBuffer &CB = m_pHLModule->GetCBuffer(i);
  790. GlobalVariable *GV = cast<GlobalVariable>(CB.GetGlobalSymbol());
  791. // Remove GEP created in HLObjectOperationLowerHelper::UniformCbPtr.
  792. GV->removeDeadConstantUsers();
  793. std::string handleName = std::string(GV->getName()) + "_buffer";
  794. Value *args[] = {opArg, resClassArg, nullptr, nullptr,
  795. hlslOP->GetI1Const(0)};
  796. DIVariable *DIV = nullptr;
  797. DILocation *DL = nullptr;
  798. if (m_HasDbgInfo) {
  799. DebugInfoFinder &Finder = m_pHLModule->GetOrCreateDebugInfoFinder();
  800. DIV = HLModule::FindGlobalVariableDebugInfo(GV, Finder);
  801. if (DIV)
  802. // TODO: how to get col?
  803. DL = DILocation::get(createHandle->getContext(), DIV->getLine(), 1,
  804. DIV->getScope());
  805. }
  806. Value *resIDArg = hlslOP->GetU32Const(CB.GetID());
  807. args[DXIL::OperandIndex::kCreateHandleResIDOpIdx] = resIDArg;
  808. // resLowerBound will be added after allocation in DxilCondenseResources.
  809. Value *resLowerBound = hlslOP->GetU32Const(0);
  810. if (CB.GetRangeSize() == 1) {
  811. args[DXIL::OperandIndex::kCreateHandleResIndexOpIdx] = resLowerBound;
  812. for (auto U = GV->user_begin(); U != GV->user_end(); ) {
  813. // Must HLCreateHandle.
  814. CallInst *CI = cast<CallInst>(*(U++));
  815. // Put createHandle to entry block.
  816. auto InsertPt =
  817. CI->getParent()->getParent()->getEntryBlock().getFirstInsertionPt();
  818. IRBuilder<> Builder(InsertPt);
  819. CallInst *handle = Builder.CreateCall(createHandle, args, handleName);
  820. if (m_HasDbgInfo) {
  821. // TODO: add debug info.
  822. //handle->setDebugLoc(DL);
  823. }
  824. CI->replaceAllUsesWith(handle);
  825. CI->eraseFromParent();
  826. }
  827. } else {
  828. for (auto U = GV->user_begin(); U != GV->user_end(); ) {
  829. // Must HLCreateHandle.
  830. CallInst *CI = cast<CallInst>(*(U++));
  831. IRBuilder<> Builder(CI);
  832. Value *CBIndex = CI->getArgOperand(HLOperandIndex::kCreateHandleIndexOpIdx);
  833. args[DXIL::OperandIndex::kCreateHandleResIndexOpIdx] =
  834. CBIndex;
  835. if (isa<ConstantInt>(CBIndex)) {
  836. // Put createHandle to entry block for const index.
  837. auto InsertPt = CI->getParent()
  838. ->getParent()
  839. ->getEntryBlock()
  840. .getFirstInsertionPt();
  841. Builder.SetInsertPoint(InsertPt);
  842. }
  843. if (!NonUniformSet.count(CBIndex))
  844. args[DXIL::OperandIndex::kCreateHandleIsUniformOpIdx] =
  845. hlslOP->GetI1Const(0);
  846. else
  847. args[DXIL::OperandIndex::kCreateHandleIsUniformOpIdx] =
  848. hlslOP->GetI1Const(1);
  849. CallInst *handle = Builder.CreateCall(createHandle, args, handleName);
  850. CI->replaceAllUsesWith(handle);
  851. CI->eraseFromParent();
  852. }
  853. }
  854. }
  855. }
  856. void DxilGenerationPass::GenerateDxilOperations(
  857. Module &M, std::unordered_set<LoadInst *> &UpdateCounterSet,
  858. std::unordered_set<Value *> &NonUniformSet) {
  859. // remove all functions except entry function
  860. Function *entry = m_pHLModule->GetEntryFunction();
  861. const ShaderModel *pSM = m_pHLModule->GetShaderModel();
  862. Function *patchConstantFunc = nullptr;
  863. if (pSM->IsHS()) {
  864. DxilFunctionProps &funcProps = m_pHLModule->GetDxilFunctionProps(entry);
  865. patchConstantFunc = funcProps.ShaderProps.HS.patchConstantFunc;
  866. }
  867. if (!pSM->IsLib()) {
  868. for (auto F = M.begin(); F != M.end();) {
  869. Function *func = F++;
  870. if (func->isDeclaration())
  871. continue;
  872. if (func == entry)
  873. continue;
  874. if (func == patchConstantFunc)
  875. continue;
  876. if (func->user_empty())
  877. func->eraseFromParent();
  878. }
  879. }
  880. TranslateBuiltinOperations(*m_pHLModule, m_extensionsCodegenHelper,
  881. UpdateCounterSet, NonUniformSet);
  882. // Remove unused HL Operation functions.
  883. std::vector<Function *> deadList;
  884. for (iplist<Function>::iterator F : M.getFunctionList()) {
  885. hlsl::HLOpcodeGroup group = hlsl::GetHLOpcodeGroupByName(F);
  886. if (group != HLOpcodeGroup::NotHL || F->isIntrinsic())
  887. if (F->user_empty())
  888. deadList.emplace_back(F);
  889. }
  890. for (Function *F : deadList)
  891. F->eraseFromParent();
  892. }
  893. static void TranslatePreciseAttributeOnFunction(Function &F, Module &M) {
  894. BasicBlock &BB = F.getEntryBlock(); // Get the entry node for the function
  895. // Find allocas that has precise attribute, by looking at all instructions in
  896. // the entry node
  897. for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E;) {
  898. Instruction *Inst = (I++);
  899. if (AllocaInst *AI = dyn_cast<AllocaInst>(Inst)) {
  900. if (HLModule::HasPreciseAttributeWithMetadata(AI)) {
  901. HLModule::MarkPreciseAttributeOnPtrWithFunctionCall(AI, M);
  902. }
  903. } else {
  904. DXASSERT(!HLModule::HasPreciseAttributeWithMetadata(Inst), "Only alloca can has precise metadata.");
  905. }
  906. }
  907. FastMathFlags FMF;
  908. FMF.setUnsafeAlgebra();
  909. // Set fast math for all FPMathOperators.
  910. // Already set FastMath in options. But that only enable things like fadd.
  911. // Every inst which type is float can be cast to FPMathOperator.
  912. for (Function::iterator BBI = F.begin(), BBE = F.end(); BBI != BBE; ++BBI) {
  913. BasicBlock *BB = BBI;
  914. for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) {
  915. if (FPMathOperator *FPMath = dyn_cast<FPMathOperator>(I)) {
  916. I->copyFastMathFlags(FMF);
  917. }
  918. }
  919. }
  920. }
  921. void DxilGenerationPass::TranslatePreciseAttribute() {
  922. bool bIEEEStrict = m_pHLModule->GetHLOptions().bIEEEStrict;
  923. // If IEEE strict, everying is precise, don't need to mark it.
  924. if (bIEEEStrict)
  925. return;
  926. Module &M = *m_pHLModule->GetModule();
  927. // TODO: If not inline every function, for function has call site with precise
  928. // argument and call site without precise argument, need to clone the function
  929. // to propagate the precise for the precise call site.
  930. // This should be done at CGMSHLSLRuntime::FinishCodeGen.
  931. Function *EntryFn = m_pHLModule->GetEntryFunction();
  932. if (!m_pHLModule->GetShaderModel()->IsLib()) {
  933. TranslatePreciseAttributeOnFunction(*EntryFn, M);
  934. }
  935. if (m_pHLModule->GetShaderModel()->IsHS()) {
  936. DxilFunctionProps &EntryQual = m_pHLModule->GetDxilFunctionProps(EntryFn);
  937. Function *patchConstantFunc = EntryQual.ShaderProps.HS.patchConstantFunc;
  938. TranslatePreciseAttributeOnFunction(*patchConstantFunc, M);
  939. }
  940. }
  941. char DxilGenerationPass::ID = 0;
  942. ModulePass *llvm::createDxilGenerationPass(bool NotOptimized, hlsl::HLSLExtensionsCodegenHelper *extensionsHelper) {
  943. DxilGenerationPass *dxilPass = new DxilGenerationPass(NotOptimized);
  944. dxilPass->SetExtensionsHelper(extensionsHelper);
  945. return dxilPass;
  946. }
  947. INITIALIZE_PASS(DxilGenerationPass, "dxilgen", "HLSL DXIL Generation", false, false)
  948. ///////////////////////////////////////////////////////////////////////////////
  949. namespace {
  950. StructType *UpdateStructTypeForLegacyLayout(StructType *ST, bool IsCBuf,
  951. DxilTypeSystem &TypeSys, Module &M);
  952. Type *UpdateFieldTypeForLegacyLayout(Type *Ty, bool IsCBuf, DxilFieldAnnotation &annotation,
  953. DxilTypeSystem &TypeSys, Module &M) {
  954. DXASSERT(!Ty->isPointerTy(), "struct field should not be a pointer");
  955. if (Ty->isArrayTy()) {
  956. Type *EltTy = Ty->getArrayElementType();
  957. Type *UpdatedTy = UpdateFieldTypeForLegacyLayout(EltTy, IsCBuf, annotation, TypeSys, M);
  958. if (EltTy == UpdatedTy)
  959. return Ty;
  960. else
  961. return ArrayType::get(UpdatedTy, Ty->getArrayNumElements());
  962. } else if (HLMatrixLower::IsMatrixType(Ty)) {
  963. DXASSERT(annotation.HasMatrixAnnotation(), "must a matrix");
  964. unsigned rows, cols;
  965. Type *EltTy = HLMatrixLower::GetMatrixInfo(Ty, cols, rows);
  966. // Get cols and rows from annotation.
  967. const DxilMatrixAnnotation &matrix = annotation.GetMatrixAnnotation();
  968. if (matrix.Orientation == MatrixOrientation::RowMajor) {
  969. rows = matrix.Rows;
  970. cols = matrix.Cols;
  971. } else {
  972. DXASSERT(matrix.Orientation == MatrixOrientation::ColumnMajor, "");
  973. cols = matrix.Rows;
  974. rows = matrix.Cols;
  975. }
  976. // CBuffer matrix must 4 * 4 bytes align.
  977. if (IsCBuf)
  978. cols = 4;
  979. EltTy = UpdateFieldTypeForLegacyLayout(EltTy, IsCBuf, annotation, TypeSys, M);
  980. Type *rowTy = VectorType::get(EltTy, cols);
  981. return ArrayType::get(rowTy, rows);
  982. } else if (StructType *ST = dyn_cast<StructType>(Ty)) {
  983. return UpdateStructTypeForLegacyLayout(ST, IsCBuf, TypeSys, M);
  984. } else if (Ty->isVectorTy()) {
  985. Type *EltTy = Ty->getVectorElementType();
  986. Type *UpdatedTy = UpdateFieldTypeForLegacyLayout(EltTy, IsCBuf, annotation, TypeSys, M);
  987. if (EltTy == UpdatedTy)
  988. return Ty;
  989. else
  990. return VectorType::get(UpdatedTy, Ty->getVectorNumElements());
  991. } else {
  992. Type *i32Ty = Type::getInt32Ty(Ty->getContext());
  993. // Basic types.
  994. if (Ty->isHalfTy()) {
  995. return Type::getFloatTy(Ty->getContext());
  996. } else if (IntegerType *ITy = dyn_cast<IntegerType>(Ty)) {
  997. if (ITy->getBitWidth() <= 32)
  998. return i32Ty;
  999. else
  1000. return Ty;
  1001. } else
  1002. return Ty;
  1003. }
  1004. }
  1005. StructType *UpdateStructTypeForLegacyLayout(StructType *ST, bool IsCBuf,
  1006. DxilTypeSystem &TypeSys, Module &M) {
  1007. bool bUpdated = false;
  1008. unsigned fieldsCount = ST->getNumElements();
  1009. std::vector<Type *> fieldTypes(fieldsCount);
  1010. DxilStructAnnotation *SA = TypeSys.GetStructAnnotation(ST);
  1011. DXASSERT(SA, "must have annotation for struct type");
  1012. for (unsigned i = 0; i < fieldsCount; i++) {
  1013. Type *EltTy = ST->getElementType(i);
  1014. Type *UpdatedTy =
  1015. UpdateFieldTypeForLegacyLayout(EltTy, IsCBuf, SA->GetFieldAnnotation(i), TypeSys, M);
  1016. fieldTypes[i] = UpdatedTy;
  1017. if (EltTy != UpdatedTy)
  1018. bUpdated = true;
  1019. }
  1020. if (!bUpdated) {
  1021. return ST;
  1022. } else {
  1023. std::string legacyName = "dx.alignment.legacy." + ST->getName().str();
  1024. if (StructType *legacyST = M.getTypeByName(legacyName))
  1025. return legacyST;
  1026. StructType *NewST = StructType::create(ST->getContext(), fieldTypes, legacyName);
  1027. DxilStructAnnotation *NewSA = TypeSys.AddStructAnnotation(NewST);
  1028. // Clone annotation.
  1029. *NewSA = *SA;
  1030. return NewST;
  1031. }
  1032. }
  1033. void UpdateStructTypeForLegacyLayout(DxilResourceBase &Res, DxilTypeSystem &TypeSys, Module &M) {
  1034. GlobalVariable *GV = cast<GlobalVariable>(Res.GetGlobalSymbol());
  1035. Type *Ty = GV->getType()->getPointerElementType();
  1036. bool IsResourceArray = Res.GetRangeSize() != 1;
  1037. if (IsResourceArray) {
  1038. // Support Array of struct buffer.
  1039. if (Ty->isArrayTy())
  1040. Ty = Ty->getArrayElementType();
  1041. }
  1042. StructType *ST = cast<StructType>(Ty);
  1043. if (ST->isOpaque()) {
  1044. DXASSERT(Res.GetClass() == DxilResourceBase::Class::CBuffer,
  1045. "Only cbuffer can have opaque struct.");
  1046. return;
  1047. }
  1048. Type *UpdatedST = UpdateStructTypeForLegacyLayout(ST, IsResourceArray, TypeSys, M);
  1049. if (ST != UpdatedST) {
  1050. Type *Ty = GV->getType()->getPointerElementType();
  1051. if (IsResourceArray) {
  1052. // Support Array of struct buffer.
  1053. if (Ty->isArrayTy()) {
  1054. UpdatedST = ArrayType::get(UpdatedST, Ty->getArrayNumElements());
  1055. }
  1056. }
  1057. GlobalVariable *NewGV = cast<GlobalVariable>(M.getOrInsertGlobal(GV->getName().str() + "_legacy", UpdatedST));
  1058. Res.SetGlobalSymbol(NewGV);
  1059. // Delete old GV.
  1060. for (auto UserIt = GV->user_begin(); UserIt != GV->user_end(); ) {
  1061. Value *User = *(UserIt++);
  1062. if (Instruction *I = dyn_cast<Instruction>(User)) {
  1063. if (!User->user_empty())
  1064. I->replaceAllUsesWith(UndefValue::get(I->getType()));
  1065. I->eraseFromParent();
  1066. } else {
  1067. ConstantExpr *CE = cast<ConstantExpr>(User);
  1068. if (!CE->user_empty())
  1069. CE->replaceAllUsesWith(UndefValue::get(CE->getType()));
  1070. }
  1071. }
  1072. GV->removeDeadConstantUsers();
  1073. GV->eraseFromParent();
  1074. }
  1075. }
  1076. void UpdateStructTypeForLegacyLayoutOnHLM(HLModule &HLM) {
  1077. DxilTypeSystem &TypeSys = HLM.GetTypeSystem();
  1078. Module &M = *HLM.GetModule();
  1079. for (auto &CBuf : HLM.GetCBuffers()) {
  1080. UpdateStructTypeForLegacyLayout(*CBuf.get(), TypeSys, M);
  1081. }
  1082. for (auto &UAV : HLM.GetUAVs()) {
  1083. if (UAV->GetKind() == DxilResourceBase::Kind::StructuredBuffer)
  1084. UpdateStructTypeForLegacyLayout(*UAV.get(), TypeSys, M);
  1085. }
  1086. for (auto &SRV : HLM.GetSRVs()) {
  1087. if (SRV->GetKind() == DxilResourceBase::Kind::StructuredBuffer)
  1088. UpdateStructTypeForLegacyLayout(*SRV.get(), TypeSys, M);
  1089. }
  1090. }
  1091. }
  1092. void DxilGenerationPass::UpdateStructTypeForLegacyLayout() {
  1093. UpdateStructTypeForLegacyLayoutOnHLM(*m_pHLModule);
  1094. }
  1095. ///////////////////////////////////////////////////////////////////////////////
  1096. namespace {
  1097. class HLEmitMetadata : public ModulePass {
  1098. public:
  1099. static char ID; // Pass identification, replacement for typeid
  1100. explicit HLEmitMetadata() : ModulePass(ID) {}
  1101. const char *getPassName() const override { return "HLSL High-Level Metadata Emit"; }
  1102. bool runOnModule(Module &M) override {
  1103. if (M.HasHLModule()) {
  1104. HLModule::ClearHLMetadata(M);
  1105. M.GetHLModule().EmitHLMetadata();
  1106. return true;
  1107. }
  1108. return false;
  1109. }
  1110. };
  1111. }
  1112. char HLEmitMetadata::ID = 0;
  1113. ModulePass *llvm::createHLEmitMetadataPass() {
  1114. return new HLEmitMetadata();
  1115. }
  1116. INITIALIZE_PASS(HLEmitMetadata, "hlsl-hlemit", "HLSL High-Level Metadata Emit", false, false)
  1117. ///////////////////////////////////////////////////////////////////////////////
  1118. namespace {
  1119. class HLEnsureMetadata : public ModulePass {
  1120. public:
  1121. static char ID; // Pass identification, replacement for typeid
  1122. explicit HLEnsureMetadata() : ModulePass(ID) {}
  1123. const char *getPassName() const override { return "HLSL High-Level Metadata Ensure"; }
  1124. bool runOnModule(Module &M) override {
  1125. if (!M.HasHLModule()) {
  1126. M.GetOrCreateHLModule();
  1127. return true;
  1128. }
  1129. return false;
  1130. }
  1131. };
  1132. }
  1133. char HLEnsureMetadata::ID = 0;
  1134. ModulePass *llvm::createHLEnsureMetadataPass() {
  1135. return new HLEnsureMetadata();
  1136. }
  1137. INITIALIZE_PASS(HLEnsureMetadata, "hlsl-hlensure", "HLSL High-Level Metadata Ensure", false, false)
  1138. ///////////////////////////////////////////////////////////////////////////////
  1139. // Precise propagate.
  1140. namespace {
  1141. class DxilPrecisePropagatePass : public ModulePass {
  1142. HLModule *m_pHLModule;
  1143. public:
  1144. static char ID; // Pass identification, replacement for typeid
  1145. explicit DxilPrecisePropagatePass() : ModulePass(ID), m_pHLModule(nullptr) {}
  1146. const char *getPassName() const override { return "DXIL Precise Propagate"; }
  1147. bool runOnModule(Module &M) override {
  1148. DxilModule &dxilModule = M.GetOrCreateDxilModule();
  1149. DxilTypeSystem &typeSys = dxilModule.GetTypeSystem();
  1150. std::vector<Function*> deadList;
  1151. for (Function &F : M.functions()) {
  1152. if (HLModule::HasPreciseAttribute(&F)) {
  1153. PropagatePreciseOnFunctionUser(F, typeSys);
  1154. deadList.emplace_back(&F);
  1155. }
  1156. }
  1157. for (Function *F : deadList)
  1158. F->eraseFromParent();
  1159. return true;
  1160. }
  1161. private:
  1162. void PropagatePreciseOnFunctionUser(Function &F, DxilTypeSystem &typeSys);
  1163. };
  1164. char DxilPrecisePropagatePass::ID = 0;
  1165. }
  1166. static void PropagatePreciseAttribute(Instruction *I, DxilTypeSystem &typeSys);
  1167. static void PropagatePreciseAttributeOnOperand(Value *V, DxilTypeSystem &typeSys, LLVMContext &Context) {
  1168. Instruction *I = dyn_cast<Instruction>(V);
  1169. // Skip none inst.
  1170. if (!I)
  1171. return;
  1172. FPMathOperator *FPMath = dyn_cast<FPMathOperator>(I);
  1173. // Skip none FPMath
  1174. if (!FPMath)
  1175. return;
  1176. // Skip inst already marked.
  1177. if (DxilModule::HasPreciseFastMathFlags(I))
  1178. return;
  1179. // TODO: skip precise on integer type, sample instruction...
  1180. // Set precise fast math on those instructions that support it.
  1181. if (DxilModule::PreservesFastMathFlags(I))
  1182. DxilModule::SetPreciseFastMathFlags(I);
  1183. // Fast math not work on call, use metadata.
  1184. if (CallInst *CI = dyn_cast<CallInst>(I))
  1185. HLModule::MarkPreciseAttributeWithMetadata(CI);
  1186. PropagatePreciseAttribute(I, typeSys);
  1187. }
  1188. static void PropagatePreciseAttributeOnPointer(Value *Ptr, DxilTypeSystem &typeSys, LLVMContext &Context) {
  1189. // Find all store and propagate on the val operand of store.
  1190. // For CallInst, if Ptr is used as out parameter, mark it.
  1191. for (User *U : Ptr->users()) {
  1192. Instruction *user = cast<Instruction>(U);
  1193. if (StoreInst *stInst = dyn_cast<StoreInst>(user)) {
  1194. Value *val = stInst->getValueOperand();
  1195. PropagatePreciseAttributeOnOperand(val, typeSys, Context);
  1196. }
  1197. else if (CallInst *CI = dyn_cast<CallInst>(user)) {
  1198. bool bReadOnly = true;
  1199. Function *F = CI->getCalledFunction();
  1200. const DxilFunctionAnnotation *funcAnnotation = typeSys.GetFunctionAnnotation(F);
  1201. for (unsigned i = 0; i < CI->getNumArgOperands(); ++i) {
  1202. if (Ptr != CI->getArgOperand(i))
  1203. continue;
  1204. const DxilParameterAnnotation &paramAnnotation =
  1205. funcAnnotation->GetParameterAnnotation(i);
  1206. // OutputPatch and OutputStream will be checked after scalar repl.
  1207. // Here only check out/inout
  1208. if (paramAnnotation.GetParamInputQual() == DxilParamInputQual::Out ||
  1209. paramAnnotation.GetParamInputQual() == DxilParamInputQual::Inout) {
  1210. bReadOnly = false;
  1211. break;
  1212. }
  1213. }
  1214. if (!bReadOnly)
  1215. PropagatePreciseAttributeOnOperand(CI, typeSys, Context);
  1216. }
  1217. }
  1218. }
  1219. static void PropagatePreciseAttribute(Instruction *I, DxilTypeSystem &typeSys) {
  1220. LLVMContext &Context = I->getContext();
  1221. if (AllocaInst *AI = dyn_cast<AllocaInst>(I)) {
  1222. PropagatePreciseAttributeOnPointer(AI, typeSys, Context);
  1223. } else if (CallInst *CI = dyn_cast<CallInst>(I)) {
  1224. // Propagate every argument.
  1225. // TODO: only propagate precise argument.
  1226. for (Value *src : I->operands())
  1227. PropagatePreciseAttributeOnOperand(src, typeSys, Context);
  1228. } else if (FPMathOperator *FPMath = dyn_cast<FPMathOperator>(I)) {
  1229. // TODO: only propagate precise argument.
  1230. for (Value *src : I->operands())
  1231. PropagatePreciseAttributeOnOperand(src, typeSys, Context);
  1232. }
  1233. else if (LoadInst *ldInst = dyn_cast<LoadInst>(I)) {
  1234. Value *Ptr = ldInst->getPointerOperand();
  1235. PropagatePreciseAttributeOnPointer(Ptr, typeSys, Context);
  1236. } else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(I))
  1237. PropagatePreciseAttributeOnPointer(GEP, typeSys, Context);
  1238. // TODO: support more case which need
  1239. }
  1240. void DxilPrecisePropagatePass::PropagatePreciseOnFunctionUser(Function &F, DxilTypeSystem &typeSys) {
  1241. LLVMContext &Context = F.getContext();
  1242. for (auto U=F.user_begin(), E=F.user_end();U!=E;) {
  1243. CallInst *CI = cast<CallInst>(*(U++));
  1244. Value *V = CI->getArgOperand(0);
  1245. PropagatePreciseAttributeOnOperand(V, typeSys, Context);
  1246. CI->eraseFromParent();
  1247. }
  1248. }
  1249. ModulePass *llvm::createDxilPrecisePropagatePass() {
  1250. return new DxilPrecisePropagatePass();
  1251. }
  1252. INITIALIZE_PASS(DxilPrecisePropagatePass, "hlsl-dxil-precise", "DXIL precise attribute propagate", false, false)
  1253. ///////////////////////////////////////////////////////////////////////////////
  1254. namespace {
  1255. class HLDeadFunctionElimination : public ModulePass {
  1256. public:
  1257. static char ID; // Pass identification, replacement for typeid
  1258. explicit HLDeadFunctionElimination () : ModulePass(ID) {}
  1259. const char *getPassName() const override { return "Remove all unused function except entry from HLModule"; }
  1260. bool runOnModule(Module &M) override {
  1261. if (M.HasHLModule()) {
  1262. HLModule &HLM = M.GetHLModule();
  1263. bool IsLib = HLM.GetShaderModel()->IsLib();
  1264. // Remove unused functions except entry and patch constant func.
  1265. // For library profile, only remove unused external functions.
  1266. Function *EntryFunc = HLM.GetEntryFunction();
  1267. Function *PatchConstantFunc = HLM.GetPatchConstantFunction();
  1268. return dxilutil::RemoveUnusedFunctions(M, EntryFunc, PatchConstantFunc,
  1269. IsLib);
  1270. }
  1271. return false;
  1272. }
  1273. };
  1274. }
  1275. char HLDeadFunctionElimination::ID = 0;
  1276. ModulePass *llvm::createHLDeadFunctionEliminationPass() {
  1277. return new HLDeadFunctionElimination();
  1278. }
  1279. INITIALIZE_PASS(HLDeadFunctionElimination, "hl-dfe", "Remove all unused function except entry from HLModule", false, false)
  1280. ///////////////////////////////////////////////////////////////////////////////
  1281. // Legalize resource use.
  1282. // Map local or static global resource to global resource.
  1283. // Require inline for static global resource.
  1284. namespace {
  1285. class DxilLegalizeStaticResourceUsePass : public ModulePass {
  1286. public:
  1287. static char ID; // Pass identification, replacement for typeid
  1288. explicit DxilLegalizeStaticResourceUsePass()
  1289. : ModulePass(ID) {}
  1290. const char *getPassName() const override {
  1291. return "DXIL Legalize Static Resource Use";
  1292. }
  1293. bool runOnModule(Module &M) override {
  1294. HLModule &HLM = M.GetOrCreateHLModule();
  1295. OP *hlslOP = HLM.GetOP();
  1296. Type *HandleTy = hlslOP->GetHandleType();
  1297. // Promote static global variables.
  1298. PromoteStaticGlobalResources(M);
  1299. // Lower handle cast.
  1300. for (Function &F : M.functions()) {
  1301. if (!F.isDeclaration())
  1302. continue;
  1303. HLOpcodeGroup group = hlsl::GetHLOpcodeGroupByName(&F);
  1304. if (group != HLOpcodeGroup::HLCast)
  1305. continue;
  1306. Type *Ty = F.getFunctionType()->getReturnType();
  1307. if (Ty->isPointerTy())
  1308. Ty = Ty->getPointerElementType();
  1309. if (HLModule::IsHLSLObjectType(Ty)) {
  1310. TransformHandleCast(F);
  1311. }
  1312. }
  1313. Value *UndefHandle = UndefValue::get(HandleTy);
  1314. if (!UndefHandle->user_empty()) {
  1315. for (User *U : UndefHandle->users()) {
  1316. // Report error if undef handle used for function call.
  1317. if (isa<CallInst>(U)) {
  1318. M.getContext().emitError(kResourceMapErrorMsg);
  1319. }
  1320. }
  1321. }
  1322. return true;
  1323. }
  1324. private:
  1325. void PromoteStaticGlobalResources(Module &M);
  1326. void TransformHandleCast(Function &F);
  1327. };
  1328. char DxilLegalizeStaticResourceUsePass::ID = 0;
  1329. class DxilLegalizeResourceUsePass : public FunctionPass {
  1330. HLModule *m_pHLModule;
  1331. void getAnalysisUsage(AnalysisUsage &AU) const override;
  1332. public:
  1333. static char ID; // Pass identification, replacement for typeid
  1334. explicit DxilLegalizeResourceUsePass()
  1335. : FunctionPass(ID), m_pHLModule(nullptr) {}
  1336. const char *getPassName() const override {
  1337. return "DXIL Legalize Resource Use";
  1338. }
  1339. bool runOnFunction(Function &F) override {
  1340. // Promote local resource first.
  1341. PromoteLocalResource(F);
  1342. return true;
  1343. }
  1344. private:
  1345. void PromoteLocalResource(Function &F);
  1346. };
  1347. char DxilLegalizeResourceUsePass::ID = 0;
  1348. }
  1349. void DxilLegalizeResourceUsePass::getAnalysisUsage(AnalysisUsage &AU) const {
  1350. AU.addRequired<AssumptionCacheTracker>();
  1351. AU.addRequired<DominatorTreeWrapperPass>();
  1352. AU.setPreservesAll();
  1353. }
  1354. void DxilLegalizeResourceUsePass::PromoteLocalResource(Function &F) {
  1355. std::vector<AllocaInst *> Allocas;
  1356. DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
  1357. AssumptionCache &AC =
  1358. getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
  1359. HLModule &HLM = F.getParent()->GetOrCreateHLModule();
  1360. OP *hlslOP = HLM.GetOP();
  1361. Type *HandleTy = hlslOP->GetHandleType();
  1362. bool IsLib = HLM.GetShaderModel()->IsLib();
  1363. BasicBlock &BB = F.getEntryBlock();
  1364. unsigned allocaSize = 0;
  1365. while (1) {
  1366. Allocas.clear();
  1367. // Find allocas that are safe to promote, by looking at all instructions in
  1368. // the entry node
  1369. for (BasicBlock::iterator I = BB.begin(), E = --BB.end(); I != E; ++I)
  1370. if (AllocaInst *AI = dyn_cast<AllocaInst>(I)) { // Is it an alloca?
  1371. if (HandleTy == dxilutil::GetArrayEltTy(AI->getAllocatedType())) {
  1372. // Skip for unpromotable for lib.
  1373. if (!isAllocaPromotable(AI) && IsLib)
  1374. continue;
  1375. DXASSERT(isAllocaPromotable(AI), "otherwise, non-promotable resource array alloca found");
  1376. Allocas.push_back(AI);
  1377. }
  1378. }
  1379. if (Allocas.empty())
  1380. break;
  1381. // No update.
  1382. // Report error and break.
  1383. if (allocaSize == Allocas.size()) {
  1384. F.getContext().emitError(kResourceMapErrorMsg);
  1385. break;
  1386. }
  1387. allocaSize = Allocas.size();
  1388. PromoteMemToReg(Allocas, *DT, nullptr, &AC);
  1389. }
  1390. return;
  1391. }
  1392. FunctionPass *llvm::createDxilLegalizeResourceUsePass() {
  1393. return new DxilLegalizeResourceUsePass();
  1394. }
  1395. INITIALIZE_PASS_BEGIN(DxilLegalizeResourceUsePass,
  1396. "hlsl-dxil-legalize-resource-use",
  1397. "DXIL legalize resource use", false, true)
  1398. INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
  1399. INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
  1400. INITIALIZE_PASS_END(DxilLegalizeResourceUsePass,
  1401. "hlsl-dxil-legalize-resource-use",
  1402. "DXIL legalize resource use", false, true)
  1403. void DxilLegalizeStaticResourceUsePass::PromoteStaticGlobalResources(
  1404. Module &M) {
  1405. HLModule &HLM = M.GetOrCreateHLModule();
  1406. Type *HandleTy = HLM.GetOP()->GetHandleType();
  1407. std::set<GlobalVariable *> staticResources;
  1408. for (auto &GV : M.globals()) {
  1409. if (GV.getLinkage() == GlobalValue::LinkageTypes::InternalLinkage &&
  1410. HandleTy == dxilutil::GetArrayEltTy(GV.getType())) {
  1411. staticResources.insert(&GV);
  1412. }
  1413. }
  1414. SSAUpdater SSA;
  1415. SmallVector<Instruction *, 4> Insts;
  1416. // Make sure every resource load has mapped to global variable.
  1417. while (!staticResources.empty()) {
  1418. bool bUpdated = false;
  1419. for (auto it = staticResources.begin(); it != staticResources.end();) {
  1420. GlobalVariable *GV = *(it++);
  1421. // Build list of instructions to promote.
  1422. for (User *U : GV->users()) {
  1423. Instruction *I = cast<Instruction>(U);
  1424. Insts.emplace_back(I);
  1425. }
  1426. LoadAndStorePromoter(Insts, SSA).run(Insts);
  1427. if (GV->user_empty()) {
  1428. bUpdated = true;
  1429. staticResources.erase(GV);
  1430. }
  1431. Insts.clear();
  1432. }
  1433. if (!bUpdated) {
  1434. M.getContext().emitError(kResourceMapErrorMsg);
  1435. break;
  1436. }
  1437. }
  1438. }
  1439. static void ReplaceResUseWithHandle(Instruction *Res, Value *Handle) {
  1440. Type *HandleTy = Handle->getType();
  1441. for (auto ResU = Res->user_begin(); ResU != Res->user_end();) {
  1442. Instruction *I = cast<Instruction>(*(ResU++));
  1443. if (isa<LoadInst>(I)) {
  1444. ReplaceResUseWithHandle(I, Handle);
  1445. } else if (isa<CallInst>(I)) {
  1446. if (I->getType() == HandleTy)
  1447. I->replaceAllUsesWith(Handle);
  1448. else
  1449. DXASSERT(0, "must createHandle here");
  1450. } else {
  1451. DXASSERT(0, "should only used by load and createHandle");
  1452. }
  1453. if (I->user_empty()) {
  1454. I->eraseFromParent();
  1455. }
  1456. }
  1457. }
  1458. void DxilLegalizeStaticResourceUsePass::TransformHandleCast(Function &F) {
  1459. for (auto U = F.user_begin(); U != F.user_end(); ) {
  1460. CallInst *CI = cast<CallInst>(*(U++));
  1461. Value *Handle = CI->getArgOperand(HLOperandIndex::kUnaryOpSrc0Idx);
  1462. ReplaceResUseWithHandle(CI, Handle);
  1463. if (CI->user_empty())
  1464. CI->eraseFromParent();
  1465. }
  1466. }
  1467. ModulePass *llvm::createDxilLegalizeStaticResourceUsePass() {
  1468. return new DxilLegalizeStaticResourceUsePass();
  1469. }
  1470. INITIALIZE_PASS(DxilLegalizeStaticResourceUsePass,
  1471. "hlsl-dxil-legalize-static-resource-use",
  1472. "DXIL legalize static resource use", false, false)
  1473. ///////////////////////////////////////////////////////////////////////////////
  1474. // Legalize EvalOperations.
  1475. // Make sure src of EvalOperations are from function parameter.
  1476. // This is needed in order to translate EvaluateAttribute operations that traces
  1477. // back to LoadInput operations during translation stage. Promoting load/store
  1478. // instructions beforehand will allow us to easily trace back to loadInput from
  1479. // function call.
  1480. namespace {
  1481. class DxilLegalizeEvalOperations : public ModulePass {
  1482. public:
  1483. static char ID; // Pass identification, replacement for typeid
  1484. explicit DxilLegalizeEvalOperations() : ModulePass(ID) {}
  1485. const char *getPassName() const override {
  1486. return "DXIL Legalize EvalOperations";
  1487. }
  1488. bool runOnModule(Module &M) override {
  1489. for (Function &F : M.getFunctionList()) {
  1490. hlsl::HLOpcodeGroup group = hlsl::GetHLOpcodeGroup(&F);
  1491. if (group != HLOpcodeGroup::NotHL) {
  1492. std::vector<CallInst *> EvalFunctionCalls;
  1493. // Find all EvaluateAttribute calls
  1494. for (User *U : F.users()) {
  1495. if (CallInst *CI = dyn_cast<CallInst>(U)) {
  1496. IntrinsicOp evalOp =
  1497. static_cast<IntrinsicOp>(hlsl::GetHLOpcode(CI));
  1498. if (evalOp == IntrinsicOp::IOP_EvaluateAttributeAtSample ||
  1499. evalOp == IntrinsicOp::IOP_EvaluateAttributeCentroid ||
  1500. evalOp == IntrinsicOp::IOP_EvaluateAttributeSnapped) {
  1501. EvalFunctionCalls.push_back(CI);
  1502. }
  1503. }
  1504. }
  1505. if (EvalFunctionCalls.empty()) {
  1506. continue;
  1507. }
  1508. // Start from the call instruction, find all allocas that this call
  1509. // uses.
  1510. std::unordered_set<AllocaInst *> allocas;
  1511. for (CallInst *CI : EvalFunctionCalls) {
  1512. FindAllocasForEvalOperations(CI, allocas);
  1513. }
  1514. SSAUpdater SSA;
  1515. SmallVector<Instruction *, 4> Insts;
  1516. for (AllocaInst *AI : allocas) {
  1517. for (User *user : AI->users()) {
  1518. if (isa<LoadInst>(user) || isa<StoreInst>(user)) {
  1519. Insts.emplace_back(cast<Instruction>(user));
  1520. }
  1521. }
  1522. LoadAndStorePromoter(Insts, SSA).run(Insts);
  1523. Insts.clear();
  1524. }
  1525. }
  1526. }
  1527. return true;
  1528. }
  1529. private:
  1530. void FindAllocasForEvalOperations(Value *val,
  1531. std::unordered_set<AllocaInst *> &allocas);
  1532. };
  1533. char DxilLegalizeEvalOperations::ID = 0;
  1534. // Find allocas for EvaluateAttribute operations
  1535. void DxilLegalizeEvalOperations::FindAllocasForEvalOperations(
  1536. Value *val, std::unordered_set<AllocaInst *> &allocas) {
  1537. Value *CurVal = val;
  1538. while (!isa<AllocaInst>(CurVal)) {
  1539. if (CallInst *CI = dyn_cast<CallInst>(CurVal)) {
  1540. CurVal = CI->getOperand(HLOperandIndex::kUnaryOpSrc0Idx);
  1541. } else if (InsertElementInst *IE = dyn_cast<InsertElementInst>(CurVal)) {
  1542. Value *arg0 =
  1543. IE->getOperand(0); // Could be another insertelement or undef
  1544. Value *arg1 = IE->getOperand(1);
  1545. FindAllocasForEvalOperations(arg0, allocas);
  1546. CurVal = arg1;
  1547. } else if (ShuffleVectorInst *SV = dyn_cast<ShuffleVectorInst>(CurVal)) {
  1548. Value *arg0 = SV->getOperand(0);
  1549. Value *arg1 = SV->getOperand(1);
  1550. FindAllocasForEvalOperations(
  1551. arg0, allocas); // Shuffle vector could come from different allocas
  1552. CurVal = arg1;
  1553. } else if (ExtractElementInst *EE = dyn_cast<ExtractElementInst>(CurVal)) {
  1554. CurVal = EE->getOperand(0);
  1555. } else if (LoadInst *LI = dyn_cast<LoadInst>(CurVal)) {
  1556. CurVal = LI->getOperand(0);
  1557. } else {
  1558. break;
  1559. }
  1560. }
  1561. if (AllocaInst *AI = dyn_cast<AllocaInst>(CurVal)) {
  1562. allocas.insert(AI);
  1563. }
  1564. }
  1565. } // namespace
  1566. ModulePass *llvm::createDxilLegalizeEvalOperationsPass() {
  1567. return new DxilLegalizeEvalOperations();
  1568. }
  1569. INITIALIZE_PASS(DxilLegalizeEvalOperations,
  1570. "hlsl-dxil-legalize-eval-operations",
  1571. "DXIL legalize eval operations", false, false)