DxilGenerationPass.cpp 76 KB

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