DxilGenerationPass.cpp 63 KB

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