2
0

DxilCondenseResources.cpp 92 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // DxilCondenseResources.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. // Provides a pass to make resource IDs zero-based and dense. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #include "dxc/HLSL/DxilGenerationPass.h"
  12. #include "dxc/DXIL/DxilOperations.h"
  13. #include "dxc/DXIL/DxilSignatureElement.h"
  14. #include "dxc/DXIL/DxilModule.h"
  15. #include "dxc/Support/Global.h"
  16. #include "dxc/DXIL/DxilTypeSystem.h"
  17. #include "dxc/DXIL/DxilInstructions.h"
  18. #include "dxc/DXIL/DxilResourceBinding.h"
  19. #include "dxc/HLSL/DxilSpanAllocator.h"
  20. #include "dxc/HLSL/HLMatrixType.h"
  21. #include "dxc/DXIL/DxilUtil.h"
  22. #include "dxc/HLSL/HLMatrixType.h"
  23. #include "dxc/HLSL/HLModule.h"
  24. #include "llvm/Analysis/DxilValueCache.h"
  25. #include "dxc/DXIL/DxilMetadataHelper.h"
  26. #include "llvm/IR/Instructions.h"
  27. #include "llvm/IR/IntrinsicInst.h"
  28. #include "llvm/IR/InstIterator.h"
  29. #include "llvm/IR/Module.h"
  30. #include "llvm/IR/PassManager.h"
  31. #include "llvm/IR/DebugInfo.h"
  32. #include "llvm/Analysis/ValueTracking.h"
  33. #include "llvm/ADT/BitVector.h"
  34. #include "llvm/ADT/SetVector.h"
  35. #include "llvm/ADT/DenseSet.h"
  36. #include "llvm/Pass.h"
  37. #include "llvm/Transforms/Utils/Local.h"
  38. #include <memory>
  39. #include <unordered_set>
  40. using namespace llvm;
  41. using namespace hlsl;
  42. // Resource rangeID remap.
  43. namespace {
  44. struct ResourceID {
  45. DXIL::ResourceClass Class; // Resource class.
  46. unsigned ID; // Resource ID, as specified on entry.
  47. bool operator<(const ResourceID &other) const {
  48. if (Class < other.Class)
  49. return true;
  50. if (Class > other.Class)
  51. return false;
  52. if (ID < other.ID)
  53. return true;
  54. return false;
  55. }
  56. };
  57. struct RemapEntry {
  58. ResourceID ResID; // Resource identity, as specified on entry.
  59. DxilResourceBase *Resource; // In-memory resource representation.
  60. unsigned Index; // Index in resource vector - new ID for the resource.
  61. };
  62. typedef std::map<ResourceID, RemapEntry> RemapEntryCollection;
  63. template <typename TResource>
  64. void BuildRewrites(const std::vector<std::unique_ptr<TResource>> &Rs,
  65. RemapEntryCollection &C) {
  66. const unsigned s = (unsigned)Rs.size();
  67. for (unsigned i = 0; i < s; ++i) {
  68. const std::unique_ptr<TResource> &R = Rs[i];
  69. if (R->GetID() != i) {
  70. ResourceID RId = {R->GetClass(), R->GetID()};
  71. RemapEntry RE = {RId, R.get(), i};
  72. C[RId] = RE;
  73. }
  74. }
  75. }
  76. // Build m_rewrites, returns 'true' if any rewrites are needed.
  77. bool BuildRewriteMap(RemapEntryCollection &rewrites, DxilModule &DM) {
  78. BuildRewrites(DM.GetCBuffers(), rewrites);
  79. BuildRewrites(DM.GetSRVs(), rewrites);
  80. BuildRewrites(DM.GetUAVs(), rewrites);
  81. BuildRewrites(DM.GetSamplers(), rewrites);
  82. return !rewrites.empty();
  83. }
  84. } // namespace
  85. class DxilResourceRegisterAllocator {
  86. private:
  87. SpacesAllocator<unsigned, hlsl::DxilCBuffer> m_reservedCBufferRegisters;
  88. SpacesAllocator<unsigned, hlsl::DxilSampler> m_reservedSamplerRegisters;
  89. SpacesAllocator<unsigned, hlsl::DxilResource> m_reservedUAVRegisters;
  90. SpacesAllocator<unsigned, hlsl::DxilResource> m_reservedSRVRegisters;
  91. template<typename T>
  92. static void GatherReservedRegisters(
  93. const std::vector<std::unique_ptr<T>> &ResourceList,
  94. SpacesAllocator<unsigned, T> &SAlloc) {
  95. for (auto &res : ResourceList) {
  96. if (res->IsAllocated()) {
  97. typename SpacesAllocator<unsigned, T>::Allocator &Alloc = SAlloc.Get(res->GetSpaceID());
  98. Alloc.ForceInsertAndClobber(res.get(), res->GetLowerBound(), res->GetUpperBound());
  99. if (res->IsUnbounded())
  100. Alloc.SetUnbounded(res.get());
  101. }
  102. }
  103. }
  104. template <typename T>
  105. static bool
  106. AllocateRegisters(LLVMContext &Ctx, const std::vector<std::unique_ptr<T>> &resourceList,
  107. SpacesAllocator<unsigned, T> &ReservedRegisters,
  108. unsigned AutoBindingSpace) {
  109. bool bChanged = false;
  110. SpacesAllocator<unsigned, T> SAlloc;
  111. // Reserve explicitly allocated resources
  112. for (auto &res : resourceList) {
  113. const unsigned space = res->GetSpaceID();
  114. typename SpacesAllocator<unsigned, T>::Allocator &alloc = SAlloc.Get(space);
  115. typename SpacesAllocator<unsigned, T>::Allocator &reservedAlloc = ReservedRegisters.Get(space);
  116. if (res->IsAllocated()) {
  117. const unsigned reg = res->GetLowerBound();
  118. const T *conflict = nullptr;
  119. if (res->IsUnbounded()) {
  120. const T *unbounded = alloc.GetUnbounded();
  121. if (unbounded) {
  122. dxilutil::EmitErrorOnGlobalVariable(Ctx, dyn_cast<GlobalVariable>(res->GetGlobalSymbol()),
  123. Twine("more than one unbounded resource (") +
  124. unbounded->GetGlobalName() + (" and ") +
  125. res->GetGlobalName() + (") in space ") + Twine(space));
  126. }
  127. else {
  128. conflict = alloc.Insert(res.get(), reg, res->GetUpperBound());
  129. if (!conflict) {
  130. alloc.SetUnbounded(res.get());
  131. reservedAlloc.SetUnbounded(res.get());
  132. }
  133. }
  134. }
  135. else {
  136. conflict = alloc.Insert(res.get(), reg, res->GetUpperBound());
  137. }
  138. if (conflict) {
  139. dxilutil::EmitErrorOnGlobalVariable(Ctx, dyn_cast<GlobalVariable>(res->GetGlobalSymbol()),
  140. ((res->IsUnbounded()) ? Twine("unbounded ") : Twine("")) +
  141. Twine("resource ") + res->GetGlobalName() +
  142. Twine(" at register ") + Twine(reg) +
  143. Twine(" overlaps with resource ") +
  144. conflict->GetGlobalName() + Twine(" at register ") +
  145. Twine(conflict->GetLowerBound()) + Twine(", space ") +
  146. Twine(space));
  147. }
  148. else {
  149. // Also add this to the reserved (unallocatable) range, if it wasn't already there.
  150. reservedAlloc.ForceInsertAndClobber(res.get(), res->GetLowerBound(), res->GetUpperBound());
  151. }
  152. }
  153. }
  154. // Allocate unallocated resources
  155. for (auto &res : resourceList) {
  156. if (res->IsAllocated())
  157. continue;
  158. unsigned space = res->GetSpaceID();
  159. if (space == UINT_MAX) space = AutoBindingSpace;
  160. typename SpacesAllocator<unsigned, T>::Allocator& alloc = SAlloc.Get(space);
  161. typename SpacesAllocator<unsigned, T>::Allocator& reservedAlloc = ReservedRegisters.Get(space);
  162. unsigned reg = 0;
  163. unsigned end = 0;
  164. bool allocateSpaceFound = false;
  165. if (res->IsUnbounded()) {
  166. if (alloc.GetUnbounded() != nullptr) {
  167. const T *unbounded = alloc.GetUnbounded();
  168. dxilutil::EmitErrorOnGlobalVariable(Ctx, dyn_cast<GlobalVariable>(res->GetGlobalSymbol()),
  169. Twine("more than one unbounded resource (") +
  170. unbounded->GetGlobalName() + Twine(" and ") +
  171. res->GetGlobalName() + Twine(") in space ") +
  172. Twine(space));
  173. continue;
  174. }
  175. if (reservedAlloc.FindForUnbounded(reg)) {
  176. end = UINT_MAX;
  177. allocateSpaceFound = true;
  178. }
  179. }
  180. else if (reservedAlloc.Find(res->GetRangeSize(), reg)) {
  181. end = reg + res->GetRangeSize() - 1;
  182. allocateSpaceFound = true;
  183. }
  184. if (allocateSpaceFound) {
  185. bool success = reservedAlloc.Insert(res.get(), reg, end) == nullptr;
  186. DXASSERT_NOMSG(success);
  187. success = alloc.Insert(res.get(), reg, end) == nullptr;
  188. DXASSERT_NOMSG(success);
  189. if (res->IsUnbounded()) {
  190. alloc.SetUnbounded(res.get());
  191. reservedAlloc.SetUnbounded(res.get());
  192. }
  193. res->SetLowerBound(reg);
  194. res->SetSpaceID(space);
  195. bChanged = true;
  196. } else {
  197. dxilutil::EmitErrorOnGlobalVariable(Ctx, dyn_cast<GlobalVariable>(res->GetGlobalSymbol()),
  198. ((res->IsUnbounded()) ? Twine("unbounded ") : Twine("")) +
  199. Twine("resource ") + res->GetGlobalName() +
  200. Twine(" could not be allocated"));
  201. }
  202. }
  203. return bChanged;
  204. }
  205. public:
  206. void GatherReservedRegisters(DxilModule &DM) {
  207. // For backcompat with FXC, shader models 5.0 and below will not auto-allocate
  208. // resources at a register explicitely assigned to even an unused resource.
  209. if (DM.GetLegacyResourceReservation()) {
  210. GatherReservedRegisters(DM.GetCBuffers(), m_reservedCBufferRegisters);
  211. GatherReservedRegisters(DM.GetSamplers(), m_reservedSamplerRegisters);
  212. GatherReservedRegisters(DM.GetUAVs(), m_reservedUAVRegisters);
  213. GatherReservedRegisters(DM.GetSRVs(), m_reservedSRVRegisters);
  214. }
  215. }
  216. bool AllocateRegisters(DxilModule &DM) {
  217. uint32_t AutoBindingSpace = DM.GetAutoBindingSpace();
  218. if (AutoBindingSpace == UINT_MAX) {
  219. // For libraries, we don't allocate unless AutoBindingSpace is set.
  220. if (DM.GetShaderModel()->IsLib())
  221. return false;
  222. // For shaders, we allocate in space 0 by default.
  223. AutoBindingSpace = 0;
  224. }
  225. bool bChanged = false;
  226. bChanged |= AllocateRegisters(DM.GetCtx(), DM.GetCBuffers(), m_reservedCBufferRegisters, AutoBindingSpace);
  227. bChanged |= AllocateRegisters(DM.GetCtx(), DM.GetSamplers(), m_reservedSamplerRegisters, AutoBindingSpace);
  228. bChanged |= AllocateRegisters(DM.GetCtx(), DM.GetUAVs(), m_reservedUAVRegisters, AutoBindingSpace);
  229. bChanged |= AllocateRegisters(DM.GetCtx(), DM.GetSRVs(), m_reservedSRVRegisters, AutoBindingSpace);
  230. return bChanged;
  231. }
  232. };
  233. bool llvm::AreDxilResourcesDense(llvm::Module *M, hlsl::DxilResourceBase **ppNonDense) {
  234. DxilModule &DM = M->GetOrCreateDxilModule();
  235. RemapEntryCollection rewrites;
  236. if (BuildRewriteMap(rewrites, DM)) {
  237. *ppNonDense = rewrites.begin()->second.Resource;
  238. return false;
  239. }
  240. else {
  241. *ppNonDense = nullptr;
  242. return true;
  243. }
  244. }
  245. static bool GetConstantLegalGepForSplitAlloca(GetElementPtrInst *gep, DxilValueCache *DVC, int64_t *ret) {
  246. if (gep->getNumIndices() != 2) {
  247. return false;
  248. }
  249. if (ConstantInt *Index0 = dyn_cast<ConstantInt>(gep->getOperand(1))) {
  250. if (Index0->getLimitedValue() != 0) {
  251. return false;
  252. }
  253. }
  254. else {
  255. return false;
  256. }
  257. if (ConstantInt *C = DVC->GetConstInt(gep->getOperand(2))) {
  258. int64_t index = C->getSExtValue();
  259. *ret = index;
  260. return true;
  261. }
  262. return false;
  263. }
  264. static bool LegalizeResourceArrays(Module &M, DxilValueCache *DVC) {
  265. SmallVector<AllocaInst *,16> Allocas;
  266. bool Changed = false;
  267. // Find all allocas
  268. for (Function &F : M) {
  269. if (F.empty())
  270. continue;
  271. BasicBlock &BB = F.getEntryBlock();
  272. for (Instruction &I : BB) {
  273. if (AllocaInst *AI = dyn_cast<AllocaInst>(&I)) {
  274. Type *ty = AI->getAllocatedType();
  275. // Only handle single dimentional array. Since this pass runs after MultiDimArrayToOneDimArray,
  276. // it should handle all arrays.
  277. if (ty->isArrayTy() && hlsl::dxilutil::IsHLSLResourceType(ty->getArrayElementType()))
  278. Allocas.push_back(AI);
  279. }
  280. }
  281. }
  282. SmallVector<AllocaInst *,16> ScalarAllocas;
  283. std::unordered_map<GetElementPtrInst *, int64_t> ConstIndices;
  284. for (AllocaInst *AI : Allocas) {
  285. Type *ty = AI->getAllocatedType();
  286. Type *resType = ty->getArrayElementType();
  287. ScalarAllocas.clear();
  288. ConstIndices.clear();
  289. bool SplitAlloca = true;
  290. for (User *U : AI->users()) {
  291. if (GetElementPtrInst *gep = dyn_cast<GetElementPtrInst>(U)) {
  292. int64_t index = 0;
  293. if (!GetConstantLegalGepForSplitAlloca(gep, DVC, &index)) {
  294. SplitAlloca = false;
  295. break;
  296. }
  297. // Out of bounds. Out of bounds GEP's will trigger and error later.
  298. if (index < 0 || index >= (int64_t)ty->getArrayNumElements()) {
  299. SplitAlloca = false;
  300. Changed = true;
  301. dxilutil::EmitErrorOnInstruction(gep, "Accessing resource array with out-out-bounds index.");
  302. }
  303. ConstIndices[gep] = index;
  304. }
  305. else {
  306. SplitAlloca = false;
  307. break;
  308. }
  309. }
  310. if (SplitAlloca) {
  311. IRBuilder<> B(AI);
  312. ScalarAllocas.resize(ty->getArrayNumElements());
  313. for (auto it = AI->user_begin(),end = AI->user_end(); it != end;) {
  314. GetElementPtrInst *gep = cast<GetElementPtrInst>(*(it++));
  315. assert(ConstIndices.count(gep));
  316. int64_t idx = ConstIndices[gep];
  317. AllocaInst *ScalarAI = ScalarAllocas[idx];
  318. if (!ScalarAI) {
  319. ScalarAI = B.CreateAlloca(resType);
  320. ScalarAllocas[idx] = ScalarAI;
  321. }
  322. gep->replaceAllUsesWith(ScalarAI);
  323. gep->eraseFromParent();
  324. }
  325. AI->eraseFromParent();
  326. Changed = true;
  327. }
  328. }
  329. return Changed;
  330. }
  331. static bool LegalizeResources(Module &M, DxilValueCache *DVC) {
  332. bool Changed = false;
  333. Changed |= LegalizeResourceArrays(M, DVC);
  334. // Simple pass to collect resource PHI's
  335. SmallVector<PHINode *, 8> PHIs;
  336. for (Function &F : M) {
  337. for (BasicBlock &BB : F) {
  338. for (Instruction &I : BB) {
  339. if (PHINode *PN = dyn_cast<PHINode>(&I)) {
  340. if (hlsl::dxilutil::IsHLSLResourceType(PN->getType())) {
  341. PHIs.push_back(PN);
  342. }
  343. }
  344. else {
  345. break;
  346. }
  347. }
  348. }
  349. }
  350. SmallVector<Instruction *, 8> DCEWorklist;
  351. // Try to simplify those PHI's with DVC and collect them in DCEWorklist
  352. for (unsigned Attempt = 0, MaxAttempt = PHIs.size(); Attempt < MaxAttempt; Attempt++) {
  353. bool LocalChanged = false;
  354. for (unsigned i = 0; i < PHIs.size(); i++) {
  355. PHINode *PN = PHIs[i];
  356. if (Value *V = DVC->GetValue(PN)) {
  357. PN->replaceAllUsesWith(V);
  358. LocalChanged = true;
  359. DCEWorklist.push_back(PN);
  360. PHIs.erase(PHIs.begin() + i);
  361. }
  362. else {
  363. i++;
  364. }
  365. }
  366. Changed |= LocalChanged;
  367. if (!LocalChanged)
  368. break;
  369. }
  370. // Collect Resource GV loads
  371. for (GlobalVariable &GV : M.globals()) {
  372. Type *Ty = GV.getType()->getPointerElementType();
  373. while (Ty->isArrayTy())
  374. Ty = Ty->getArrayElementType();
  375. if (!hlsl::dxilutil::IsHLSLResourceType(Ty))
  376. continue;
  377. SmallVector<User *, 4> WorkList(GV.user_begin(), GV.user_end());
  378. while (WorkList.size()) {
  379. User *U = WorkList.pop_back_val();
  380. if (LoadInst *Load = dyn_cast<LoadInst>(U)) {
  381. DCEWorklist.push_back(Load);
  382. }
  383. else if (GEPOperator *GEP = dyn_cast<GEPOperator>(U)) {
  384. for (User *GepU : GEP->users())
  385. WorkList.push_back(GepU);
  386. }
  387. }
  388. }
  389. // Simple DCE
  390. while (DCEWorklist.size()) {
  391. Instruction *I = DCEWorklist.back();
  392. DCEWorklist.pop_back();
  393. if (llvm::isInstructionTriviallyDead(I)) {
  394. for (Use &Op : I->operands())
  395. if (Instruction *OpI = dyn_cast<Instruction>(Op.get()))
  396. DCEWorklist.push_back(OpI);
  397. I->eraseFromParent();
  398. // Remove the instruction from the worklist if it still exists in it.
  399. DCEWorklist.erase(std::remove(DCEWorklist.begin(), DCEWorklist.end(), I),
  400. DCEWorklist.end());
  401. Changed = true;
  402. }
  403. }
  404. return Changed;
  405. }
  406. namespace {
  407. class DxilLowerCreateHandleForLib : public ModulePass {
  408. private:
  409. RemapEntryCollection m_rewrites;
  410. DxilModule *m_DM;
  411. bool m_HasDbgInfo;
  412. bool m_bIsLib;
  413. bool m_bLegalizationFailed;
  414. public:
  415. static char ID; // Pass identification, replacement for typeid
  416. explicit DxilLowerCreateHandleForLib() : ModulePass(ID) {}
  417. void getAnalysisUsage(AnalysisUsage &AU) const override {
  418. AU.addRequired<DxilValueCache>();
  419. }
  420. const char *getPassName() const override {
  421. return "DXIL Lower createHandleForLib";
  422. }
  423. bool runOnModule(Module &M) override {
  424. DxilModule &DM = M.GetOrCreateDxilModule();
  425. m_DM = &DM;
  426. // Clear llvm used to remove unused resource.
  427. m_DM->ClearLLVMUsed();
  428. m_bIsLib = DM.GetShaderModel()->IsLib();
  429. m_bLegalizationFailed = false;
  430. FailOnPoisonResources();
  431. bool bChanged = false;
  432. if (DM.GetShaderModel()->IsSM66Plus()) {
  433. bChanged = PatchDynamicTBuffers(DM);
  434. SetNonUniformIndexForDynamicResource(DM);
  435. }
  436. unsigned numResources = DM.GetCBuffers().size() + DM.GetUAVs().size() +
  437. DM.GetSRVs().size() + DM.GetSamplers().size();
  438. if (!numResources)
  439. return false;
  440. // Switch tbuffers to SRVs, as they have been treated as cbuffers up to this
  441. // point.
  442. if (DM.GetCBuffers().size())
  443. bChanged |= PatchTBuffers(DM);
  444. // Gather reserved resource registers while we still have
  445. // unused resources that might have explicit register assignments.
  446. DxilResourceRegisterAllocator ResourceRegisterAllocator;
  447. ResourceRegisterAllocator.GatherReservedRegisters(DM);
  448. // Remove unused resources.
  449. DM.RemoveResourcesWithUnusedSymbols();
  450. unsigned newResources = DM.GetCBuffers().size() + DM.GetUAVs().size() +
  451. DM.GetSRVs().size() + DM.GetSamplers().size();
  452. bChanged = bChanged || (numResources != newResources);
  453. if (0 == newResources)
  454. return bChanged;
  455. {
  456. DxilValueCache *DVC = &getAnalysis<DxilValueCache>();
  457. bool bLocalChanged = LegalizeResources(M, DVC);
  458. if (bLocalChanged) {
  459. // Remove unused resources.
  460. DM.RemoveResourcesWithUnusedSymbols();
  461. }
  462. bChanged |= bLocalChanged;
  463. }
  464. bChanged |= ResourceRegisterAllocator.AllocateRegisters(DM);
  465. // Fill in top-level CBuffer variable usage bit
  466. UpdateCBufferUsage();
  467. if (m_bIsLib && DM.GetShaderModel()->GetMinor() == ShaderModel::kOfflineMinor)
  468. return bChanged;
  469. // Make sure no select on resource.
  470. bChanged |= RemovePhiOnResource();
  471. if (m_bIsLib || m_bLegalizationFailed)
  472. return bChanged;
  473. bChanged = true;
  474. // Load up debug information, to cross-reference values and the instructions
  475. // used to load them.
  476. m_HasDbgInfo = hasDebugInfo(M);
  477. GenerateDxilResourceHandles();
  478. // TODO: Update types earlier for libraries and replace users, to
  479. // avoid having to preserve HL struct annotation.
  480. // Note 1: Needs to happen after legalize
  481. // Note 2: Cannot do this easily/trivially if any functions have
  482. // resource arguments (in offline linking target).
  483. if (DM.GetOP()->UseMinPrecision())
  484. UpdateStructTypeForLegacyLayout();
  485. // Change resource symbol into undef.
  486. UpdateResourceSymbols();
  487. // Remove unused createHandleForLib functions.
  488. dxilutil::RemoveUnusedFunctions(M, DM.GetEntryFunction(),
  489. DM.GetPatchConstantFunction(), m_bIsLib);
  490. return bChanged;
  491. }
  492. private:
  493. void FailOnPoisonResources();
  494. bool RemovePhiOnResource();
  495. void UpdateResourceSymbols();
  496. void TranslateDxilResourceUses(DxilResourceBase &res);
  497. void GenerateDxilResourceHandles();
  498. void UpdateStructTypeForLegacyLayout();
  499. // Switch CBuffer for SRV for TBuffers.
  500. bool PatchDynamicTBuffers(DxilModule &DM);
  501. bool PatchTBuffers(DxilModule &DM);
  502. void PatchTBufferUse(Value *V, DxilModule &DM, DenseSet<Value *> &patchedSet);
  503. void UpdateCBufferUsage();
  504. void SetNonUniformIndexForDynamicResource(DxilModule &DM);
  505. };
  506. } // namespace
  507. // Phi on resource.
  508. namespace {
  509. typedef std::unordered_map<Value*, Value*> ValueToValueMap;
  510. typedef llvm::SetVector<Value*> ValueSetVector;
  511. typedef llvm::SmallVector<Value*, 4> IndexVector;
  512. typedef std::unordered_map<Value*, IndexVector> ValueToIdxMap;
  513. //#define SUPPORT_SELECT_ON_ALLOCA
  514. // Errors:
  515. class ResourceUseErrors
  516. {
  517. bool m_bErrorsReported;
  518. public:
  519. ResourceUseErrors() : m_bErrorsReported(false) {}
  520. enum ErrorCode {
  521. // Collision between use of one resource GV and another.
  522. // All uses must be guaranteed to resolve to only one GV.
  523. // Additionally, when writing resource to alloca, all uses
  524. // of that alloca are considered resolving to a single GV.
  525. GVConflicts,
  526. // static global resources are disallowed for libraries at this time.
  527. // for non-library targets, they should have been eliminated already.
  528. StaticGVUsed,
  529. // user function calls with resource params or return type are
  530. // are currently disallowed for libraries.
  531. UserCallsWithResources,
  532. // When searching up from store pointer looking for alloca,
  533. // we encountered an unexpted value type
  534. UnexpectedValuesFromStorePointer,
  535. // When remapping values to be replaced, we add them to RemappedValues
  536. // so we don't use dead values stored in other sets/maps. Circular
  537. // remaps that should not happen are aadded to RemappingCyclesDetected.
  538. RemappingCyclesDetected,
  539. // Without SUPPORT_SELECT_ON_ALLOCA, phi/select on alloca based
  540. // pointer is disallowed, since this scenario is still untested.
  541. // This error also covers any other unknown alloca pointer uses.
  542. // Supported:
  543. // alloca (-> gep)? -> load -> ...
  544. // alloca (-> gep)? -> store.
  545. // Unsupported without SUPPORT_SELECT_ON_ALLOCA:
  546. // alloca (-> gep)? -> phi/select -> ...
  547. AllocaUserDisallowed,
  548. #ifdef SUPPORT_SELECT_ON_ALLOCA
  549. // Conflict in select/phi between GV pointer and alloca pointer. This
  550. // algorithm can't handle this case.
  551. AllocaSelectConflict,
  552. #endif
  553. ErrorCodeCount
  554. };
  555. const StringRef ErrorText[ErrorCodeCount] = {
  556. "local resource not guaranteed to map to unique global resource.",
  557. "static global resource use is disallowed for library functions.",
  558. "exported library functions cannot have resource parameters or return value.",
  559. "internal error: unexpected instruction type when looking for alloca from store.",
  560. "internal error: cycles detected in value remapping.",
  561. "phi/select disallowed on pointers to local resources."
  562. #ifdef SUPPORT_SELECT_ON_ALLOCA
  563. ,"unable to resolve merge of global and local resource pointers."
  564. #endif
  565. };
  566. ValueSetVector ErrorSets[ErrorCodeCount];
  567. // Ulitimately, the goal of ErrorUsers is to mark all create handles
  568. // so we don't try to report errors on them again later.
  569. std::unordered_set<Value*> ErrorUsers; // users of error values
  570. bool AddErrorUsers(Value* V) {
  571. auto it = ErrorUsers.insert(V);
  572. if (!it.second)
  573. return false; // already there
  574. if (isa<GEPOperator>(V) ||
  575. isa<LoadInst>(V) ||
  576. isa<PHINode>(V) ||
  577. isa<SelectInst>(V) ||
  578. isa<AllocaInst>(V)) {
  579. for (auto U : V->users()) {
  580. AddErrorUsers(U);
  581. }
  582. } else if(isa<StoreInst>(V)) {
  583. AddErrorUsers(cast<StoreInst>(V)->getPointerOperand());
  584. }
  585. // create handle will be marked, but users not followed
  586. return true;
  587. }
  588. void ReportError(ErrorCode ec, Value* V) {
  589. DXASSERT_NOMSG(ec < ErrorCodeCount);
  590. if (!ErrorSets[ec].insert(V))
  591. return; // Error already reported
  592. AddErrorUsers(V);
  593. m_bErrorsReported = true;
  594. if (Instruction *I = dyn_cast<Instruction>(V)) {
  595. dxilutil::EmitErrorOnInstruction(I, ErrorText[ec]);
  596. } else {
  597. StringRef Name = V->getName();
  598. std::string escName;
  599. if (isa<Function>(V)) {
  600. llvm::raw_string_ostream os(escName);
  601. dxilutil::PrintEscapedString(Name, os);
  602. os.flush();
  603. Name = escName;
  604. }
  605. V->getContext().emitError(Twine(ErrorText[ec]) + " Value: " + Name);
  606. }
  607. }
  608. bool ErrorsReported() {
  609. return m_bErrorsReported;
  610. }
  611. };
  612. unsigned CountArrayDimensions(Type* Ty,
  613. // Optionally collect dimensions
  614. SmallVector<unsigned, 4> *dims = nullptr) {
  615. if (Ty->isPointerTy())
  616. Ty = Ty->getPointerElementType();
  617. unsigned dim = 0;
  618. if (dims)
  619. dims->clear();
  620. while (Ty->isArrayTy()) {
  621. if (dims)
  622. dims->push_back(Ty->getArrayNumElements());
  623. dim++;
  624. Ty = Ty->getArrayElementType();
  625. }
  626. return dim;
  627. }
  628. // Helper class for legalizing resource use
  629. // Convert select/phi on resources to select/phi on index to GEP on GV.
  630. // Convert resource alloca to index alloca.
  631. // Assumes createHandleForLib has no select/phi
  632. class LegalizeResourceUseHelper {
  633. // Change:
  634. // gep1 = GEP gRes, i1
  635. // res1 = load gep1
  636. // gep2 = GEP gRes, i2
  637. // gep3 = GEP gRes, i3
  638. // gep4 = phi gep2, gep3 <-- handle select/phi on GEP
  639. // res4 = load gep4
  640. // res5 = phi res1, res4
  641. // res6 = load GEP gRes, 23 <-- handle constant GepExpression
  642. // res = select cnd2, res5, res6
  643. // handle = createHandleForLib(res)
  644. // To:
  645. // i4 = phi i2, i3
  646. // i5 = phi i1, i4
  647. // i6 = select cnd, i5, 23
  648. // gep = GEP gRes, i6
  649. // res = load gep
  650. // handle = createHandleForLib(res)
  651. // Also handles alloca
  652. // resArray = alloca [2 x Resource]
  653. // gep1 = GEP gRes, i1
  654. // res1 = load gep1
  655. // gep2 = GEP gRes, i2
  656. // gep3 = GEP gRes, i3
  657. // phi4 = phi gep2, gep3
  658. // res4 = load phi4
  659. // gep5 = GEP resArray, 0
  660. // gep6 = GEP resArray, 1
  661. // store gep5, res1
  662. // store gep6, res4
  663. // gep7 = GEP resArray, i7 <-- dynamically index array
  664. // res = load gep7
  665. // handle = createHandleForLib(res)
  666. // Desired result:
  667. // idxArray = alloca [2 x i32]
  668. // phi4 = phi i2, i3
  669. // gep5 = GEP idxArray, 0
  670. // gep6 = GEP idxArray, 1
  671. // store gep5, i1
  672. // store gep6, phi4
  673. // gep7 = GEP idxArray, i7
  674. // gep8 = GEP gRes, gep7
  675. // res = load gep8
  676. // handle = createHandleForLib(res)
  677. // Also handles multi-dim resource index and multi-dim resource array allocas
  678. // Basic algorithm:
  679. // - recursively mark each GV user with GV (ValueToResourceGV)
  680. // - verify only one GV used for any given value
  681. // - handle allocas by searching up from store for alloca
  682. // - then recursively mark alloca users
  683. // - ResToIdxReplacement keeps track of vector of indices that
  684. // will be used to replace a given resource value or pointer
  685. // - Next, create selects/phis for indices corresponding to
  686. // selects/phis on resource pointers or values.
  687. // - leave incoming index values undef for now
  688. // - Create index allocas to replace resource allocas
  689. // - Create GEPs on index allocas to replace GEPs on resource allocas
  690. // - Create index loads on index allocas to replace loads on resource alloca GEP
  691. // - Fill in replacements for GEPs on resource GVs
  692. // - copy replacement index vectors to corresponding loads
  693. // - Create index stores to replace resource stores to alloca/GEPs
  694. // - Update selects/phis incoming index values
  695. // - SimplifyMerges: replace index phis/selects on same value with that value
  696. // - RemappedValues[phi/select] set to replacement value
  697. // - use LookupValue from now on when reading from ResToIdxReplacement
  698. // - Update handles by replacing load/GEP chains that go through select/phi
  699. // with direct GV GEP + load, with select/phi on GEP indices instead.
  700. public:
  701. ResourceUseErrors m_Errors;
  702. ValueToValueMap ValueToResourceGV;
  703. ValueToIdxMap ResToIdxReplacement;
  704. // Value sets we can use to iterate
  705. ValueSetVector Selects, GEPs, Stores, Handles;
  706. ValueSetVector Allocas, AllocaGEPs, AllocaLoads;
  707. #ifdef SUPPORT_SELECT_ON_ALLOCA
  708. ValueSetVector AllocaSelects;
  709. #endif
  710. std::unordered_set<Value *> NonUniformSet;
  711. // New index selects created by pass, so we can try simplifying later
  712. ValueSetVector NewSelects;
  713. // Values that have been replaced with other values need remapping
  714. ValueToValueMap RemappedValues;
  715. // Things to clean up if no users:
  716. std::unordered_set<Instruction*> CleanupInsts;
  717. GlobalVariable *LookupResourceGV(Value *V) {
  718. auto itGV = ValueToResourceGV.find(V);
  719. if (itGV == ValueToResourceGV.end())
  720. return nullptr;
  721. return cast<GlobalVariable>(itGV->second);
  722. }
  723. // Follow RemappedValues, return input if not remapped
  724. Value *LookupValue(Value *V) {
  725. auto it = RemappedValues.find(V);
  726. SmallPtrSet<Value*, 4> visited;
  727. while (it != RemappedValues.end()) {
  728. // Cycles should not happen, but are bad if they do.
  729. if (visited.count(it->second)) {
  730. DXASSERT(false, "otherwise, circular remapping");
  731. m_Errors.ReportError(ResourceUseErrors::RemappingCyclesDetected, V);
  732. break;
  733. }
  734. V = it->second;
  735. it = RemappedValues.find(V);
  736. if (it != RemappedValues.end())
  737. visited.insert(V);
  738. }
  739. return V;
  740. }
  741. bool AreLoadUsersTrivial(LoadInst *LI) {
  742. for (auto U : LI->users()) {
  743. if (CallInst *CI = dyn_cast<CallInst>(U)) {
  744. Function *F = CI->getCalledFunction();
  745. DxilModule &DM = F->getParent()->GetDxilModule();
  746. hlsl::OP *hlslOP = DM.GetOP();
  747. if (hlslOP->IsDxilOpFunc(F)) {
  748. hlsl::OP::OpCodeClass opClass;
  749. if (hlslOP->GetOpCodeClass(F, opClass) &&
  750. opClass == DXIL::OpCodeClass::CreateHandleForLib) {
  751. continue;
  752. }
  753. }
  754. }
  755. return false;
  756. }
  757. return true;
  758. }
  759. // This is used to quickly skip the common case where no work is needed
  760. bool AreGEPUsersTrivial(GEPOperator *GEP) {
  761. if (GlobalVariable *GV = LookupResourceGV(GEP)) {
  762. if (GEP->getPointerOperand() != LookupResourceGV(GEP))
  763. return false;
  764. }
  765. for (auto U : GEP->users()) {
  766. if (LoadInst *LI = dyn_cast<LoadInst>(U)) {
  767. if (AreLoadUsersTrivial(LI))
  768. continue;
  769. }
  770. return false;
  771. }
  772. return true;
  773. }
  774. // AssignResourceGVFromStore is used on pointer being stored to.
  775. // Follow GEP/Phi/Select up to Alloca, then CollectResourceGVUsers on Alloca
  776. void AssignResourceGVFromStore(GlobalVariable *GV, Value *V,
  777. SmallPtrSet<Value*, 4> &visited,
  778. bool bNonUniform) {
  779. // Prevent cycles as we search up
  780. if (visited.count(V) != 0)
  781. return;
  782. // Verify and skip if already processed
  783. auto it = ValueToResourceGV.find(V);
  784. if (it != ValueToResourceGV.end()) {
  785. if (it->second != GV) {
  786. m_Errors.ReportError(ResourceUseErrors::GVConflicts, V);
  787. }
  788. return;
  789. }
  790. if (AllocaInst *AI = dyn_cast<AllocaInst>(V)) {
  791. CollectResourceGVUsers(GV, AI, /*bAlloca*/true, bNonUniform);
  792. return;
  793. } else if (GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
  794. // follow the pointer up
  795. AssignResourceGVFromStore(GV, GEP->getPointerOperand(), visited, bNonUniform);
  796. return;
  797. } else if (PHINode *Phi = dyn_cast<PHINode>(V)) {
  798. #ifdef SUPPORT_SELECT_ON_ALLOCA
  799. // follow all incoming values
  800. for (auto it : Phi->operand_values())
  801. AssignResourceGVFromStore(GV, it, visited, bNonUniform);
  802. #else
  803. m_Errors.ReportError(ResourceUseErrors::AllocaUserDisallowed, V);
  804. #endif
  805. return;
  806. } else if (SelectInst *Sel = dyn_cast<SelectInst>(V)) {
  807. #ifdef SUPPORT_SELECT_ON_ALLOCA
  808. // follow all incoming values
  809. AssignResourceGVFromStore(GV, Sel->getTrueValue(), visited, bNonUniform);
  810. AssignResourceGVFromStore(GV, Sel->getFalseValue(), visited, bNonUniform);
  811. #else
  812. m_Errors.ReportError(ResourceUseErrors::AllocaUserDisallowed, V);
  813. #endif
  814. return;
  815. } else if (isa<GlobalVariable>(V) &&
  816. cast<GlobalVariable>(V)->getLinkage() ==
  817. GlobalVariable::LinkageTypes::InternalLinkage) {
  818. // this is writing to global static, which is disallowed at this point.
  819. m_Errors.ReportError(ResourceUseErrors::StaticGVUsed, V);
  820. return;
  821. } else {
  822. // Most likely storing to output parameter
  823. m_Errors.ReportError(ResourceUseErrors::UserCallsWithResources, V);
  824. return;
  825. }
  826. return;
  827. }
  828. // Recursively mark values with GV, following users.
  829. // Starting value V should be GV itself.
  830. // Returns true if value/uses reference no other GV in map.
  831. void CollectResourceGVUsers(GlobalVariable *GV, Value *V, bool bAlloca = false, bool bNonUniform = false) {
  832. // Recursively tag value V and its users as using GV.
  833. auto it = ValueToResourceGV.find(V);
  834. if (it != ValueToResourceGV.end()) {
  835. if (it->second != GV) {
  836. m_Errors.ReportError(ResourceUseErrors::GVConflicts, V);
  837. #ifdef SUPPORT_SELECT_ON_ALLOCA
  838. } else {
  839. // if select/phi, make sure bAlloca is consistent
  840. if (isa<PHINode>(V) || isa<SelectInst>(V))
  841. if ((bAlloca && AllocaSelects.count(V) == 0) ||
  842. (!bAlloca && Selects.count(V) == 0))
  843. m_Errors.ReportError(ResourceUseErrors::AllocaSelectConflict, V);
  844. #endif
  845. }
  846. return;
  847. }
  848. ValueToResourceGV[V] = GV;
  849. if (GV == V) {
  850. // Just add and recurse users
  851. // make sure bAlloca is clear for users
  852. bAlloca = false;
  853. } else if (GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
  854. if (bAlloca)
  855. AllocaGEPs.insert(GEP);
  856. else if (!AreGEPUsersTrivial(GEP))
  857. GEPs.insert(GEP);
  858. else
  859. return; // Optimization: skip trivial GV->GEP->load->createHandle
  860. if (GetElementPtrInst *GEPInst = dyn_cast<GetElementPtrInst>(GEP)) {
  861. if (DxilMDHelper::IsMarkedNonUniform(GEPInst))
  862. bNonUniform = true;
  863. }
  864. } else if (LoadInst *LI = dyn_cast<LoadInst>(V)) {
  865. if (bAlloca)
  866. AllocaLoads.insert(LI);
  867. // clear bAlloca for users
  868. bAlloca = false;
  869. if (bNonUniform)
  870. NonUniformSet.insert(LI);
  871. } else if (StoreInst *SI = dyn_cast<StoreInst>(V)) {
  872. Stores.insert(SI);
  873. if (!bAlloca) {
  874. // Find and mark allocas this store could be storing to
  875. SmallPtrSet<Value*, 4> visited;
  876. AssignResourceGVFromStore(GV, SI->getPointerOperand(), visited, bNonUniform);
  877. }
  878. return;
  879. } else if (PHINode *Phi = dyn_cast<PHINode>(V)) {
  880. if (bAlloca) {
  881. #ifdef SUPPORT_SELECT_ON_ALLOCA
  882. AllocaSelects.insert(Phi);
  883. #else
  884. m_Errors.ReportError(ResourceUseErrors::AllocaUserDisallowed, V);
  885. #endif
  886. } else {
  887. Selects.insert(Phi);
  888. }
  889. } else if (SelectInst *Sel = dyn_cast<SelectInst>(V)) {
  890. if (bAlloca) {
  891. #ifdef SUPPORT_SELECT_ON_ALLOCA
  892. AllocaSelects.insert(Sel);
  893. #else
  894. m_Errors.ReportError(ResourceUseErrors::AllocaUserDisallowed, V);
  895. #endif
  896. } else {
  897. Selects.insert(Sel);
  898. }
  899. } else if (AllocaInst *AI = dyn_cast<AllocaInst>(V)) {
  900. Allocas.insert(AI);
  901. // set bAlloca for users
  902. bAlloca = true;
  903. } else if (Constant *C = dyn_cast<Constant>(V)) {
  904. // skip @llvm.used entry
  905. return;
  906. } else if (BitCastInst *BCI = dyn_cast<BitCastInst>(V)) {
  907. DXASSERT(onlyUsedByLifetimeMarkers(BCI),
  908. "expected bitcast to only be used by lifetime intrinsics");
  909. return;
  910. } else if (bAlloca) {
  911. m_Errors.ReportError(ResourceUseErrors::AllocaUserDisallowed, V);
  912. } else {
  913. // Must be createHandleForLib or user function call.
  914. CallInst *CI = cast<CallInst>(V);
  915. Function *F = CI->getCalledFunction();
  916. DxilModule &DM = GV->getParent()->GetDxilModule();
  917. hlsl::OP *hlslOP = DM.GetOP();
  918. if (hlslOP->IsDxilOpFunc(F)) {
  919. hlsl::OP::OpCodeClass opClass;
  920. if (hlslOP->GetOpCodeClass(F, opClass) &&
  921. opClass == DXIL::OpCodeClass::CreateHandleForLib) {
  922. Handles.insert(CI);
  923. if (bNonUniform)
  924. NonUniformSet.insert(CI);
  925. return;
  926. }
  927. }
  928. // This could be user call with resource param, which is disallowed for lib_6_3
  929. m_Errors.ReportError(ResourceUseErrors::UserCallsWithResources, V);
  930. return;
  931. }
  932. // Recurse users
  933. for (auto U : V->users())
  934. CollectResourceGVUsers(GV, U, bAlloca, bNonUniform);
  935. return;
  936. }
  937. // Remove conflicting values from sets before
  938. // transforming the remainder.
  939. void RemoveConflictingValue(Value* V) {
  940. bool bRemoved = false;
  941. if (isa<GEPOperator>(V)) {
  942. bRemoved = GEPs.remove(V) || AllocaGEPs.remove(V);
  943. } else if (isa<LoadInst>(V)) {
  944. bRemoved = AllocaLoads.remove(V);
  945. } else if (isa<StoreInst>(V)) {
  946. bRemoved = Stores.remove(V);
  947. } else if (isa<PHINode>(V) || isa<SelectInst>(V)) {
  948. bRemoved = Selects.remove(V);
  949. #ifdef SUPPORT_SELECT_ON_ALLOCA
  950. bRemoved |= AllocaSelects.remove(V);
  951. #endif
  952. } else if (isa<AllocaInst>(V)) {
  953. bRemoved = Allocas.remove(V);
  954. } else if (isa<CallInst>(V)) {
  955. bRemoved = Handles.remove(V);
  956. return; // don't recurse
  957. }
  958. if (bRemoved) {
  959. // Recurse users
  960. for (auto U : V->users())
  961. RemoveConflictingValue(U);
  962. }
  963. }
  964. void RemoveConflicts() {
  965. for (auto V : m_Errors.ErrorSets[ResourceUseErrors::GVConflicts]) {
  966. RemoveConflictingValue(V);
  967. ValueToResourceGV.erase(V);
  968. }
  969. }
  970. void CreateSelects() {
  971. if (Selects.empty()
  972. #ifdef SUPPORT_SELECT_ON_ALLOCA
  973. && AllocaSelects.empty()
  974. #endif
  975. )
  976. return;
  977. LLVMContext &Ctx =
  978. #ifdef SUPPORT_SELECT_ON_ALLOCA
  979. Selects.empty() ? AllocaSelects[0]->getContext() :
  980. #endif
  981. Selects[0]->getContext();
  982. Type *i32Ty = IntegerType::getInt32Ty(Ctx);
  983. #ifdef SUPPORT_SELECT_ON_ALLOCA
  984. for (auto &SelectSet : {Selects, AllocaSelects}) {
  985. bool bAlloca = !(&SelectSet == &Selects);
  986. #else
  987. for (auto &SelectSet : { Selects }) {
  988. #endif
  989. for (auto pValue : SelectSet) {
  990. Type *SelectTy = i32Ty;
  991. #ifdef SUPPORT_SELECT_ON_ALLOCA
  992. // For alloca case, type needs to match dimensionality of incoming value
  993. if (bAlloca) {
  994. // TODO: Not sure if this case will actually work
  995. // (or whether it can even be generated from HLSL)
  996. Type *Ty = pValue->getType();
  997. SmallVector<unsigned, 4> dims;
  998. unsigned dim = CountArrayDimensions(Ty, &dims);
  999. for (unsigned i = 0; i < dim; i++)
  1000. SelectTy = ArrayType::get(SelectTy, (uint64_t)dims[dim - i - 1]);
  1001. if (Ty->isPointerTy())
  1002. SelectTy = PointerType::get(SelectTy, 0);
  1003. }
  1004. #endif
  1005. Value *UndefValue = UndefValue::get(SelectTy);
  1006. if (PHINode *Phi = dyn_cast<PHINode>(pValue)) {
  1007. GlobalVariable *GV = LookupResourceGV(Phi);
  1008. if (!GV)
  1009. continue; // skip value removed due to conflict
  1010. IRBuilder<> PhiBuilder(Phi);
  1011. unsigned gvDim = CountArrayDimensions(GV->getType());
  1012. IndexVector &idxVector = ResToIdxReplacement[Phi];
  1013. idxVector.resize(gvDim, nullptr);
  1014. unsigned numIncoming = Phi->getNumIncomingValues();
  1015. for (unsigned i = 0; i < gvDim; i++) {
  1016. PHINode *newPhi = PhiBuilder.CreatePHI(SelectTy, numIncoming);
  1017. NewSelects.insert(newPhi);
  1018. idxVector[i] = newPhi;
  1019. for (unsigned j = 0; j < numIncoming; j++) {
  1020. // Set incoming values to undef until next pass
  1021. newPhi->addIncoming(UndefValue, Phi->getIncomingBlock(j));
  1022. }
  1023. }
  1024. } else if (SelectInst *Sel = dyn_cast<SelectInst>(pValue)) {
  1025. GlobalVariable *GV = LookupResourceGV(Sel);
  1026. if (!GV)
  1027. continue; // skip value removed due to conflict
  1028. IRBuilder<> Builder(Sel);
  1029. unsigned gvDim = CountArrayDimensions(GV->getType());
  1030. IndexVector &idxVector = ResToIdxReplacement[Sel];
  1031. idxVector.resize(gvDim, nullptr);
  1032. for (unsigned i = 0; i < gvDim; i++) {
  1033. Value *newSel = Builder.CreateSelect(Sel->getCondition(), UndefValue, UndefValue);
  1034. NewSelects.insert(newSel);
  1035. idxVector[i] = newSel;
  1036. }
  1037. } else {
  1038. DXASSERT(false, "otherwise, non-select/phi in Selects set");
  1039. }
  1040. }
  1041. }
  1042. }
  1043. // Create index allocas to replace resource allocas
  1044. void CreateIndexAllocas() {
  1045. if (Allocas.empty())
  1046. return;
  1047. Type *i32Ty = IntegerType::getInt32Ty(Allocas[0]->getContext());
  1048. for (auto pValue : Allocas) {
  1049. AllocaInst *pAlloca = cast<AllocaInst>(pValue);
  1050. GlobalVariable *GV = LookupResourceGV(pAlloca);
  1051. if (!GV)
  1052. continue; // skip value removed due to conflict
  1053. IRBuilder<> AllocaBuilder(pAlloca);
  1054. unsigned gvDim = CountArrayDimensions(GV->getType());
  1055. SmallVector<unsigned, 4> dimVector;
  1056. unsigned allocaTyDim = CountArrayDimensions(pAlloca->getType(), &dimVector);
  1057. Type *pIndexType = i32Ty;
  1058. for (unsigned i = 0; i < allocaTyDim; i++) {
  1059. pIndexType = ArrayType::get(pIndexType, dimVector[allocaTyDim - i - 1]);
  1060. }
  1061. Value *arraySize = pAlloca->getArraySize();
  1062. IndexVector &idxVector = ResToIdxReplacement[pAlloca];
  1063. idxVector.resize(gvDim, nullptr);
  1064. for (unsigned i = 0; i < gvDim; i++) {
  1065. AllocaInst *pAlloca = AllocaBuilder.CreateAlloca(pIndexType, arraySize);
  1066. pAlloca->setAlignment(4);
  1067. idxVector[i] = pAlloca;
  1068. }
  1069. }
  1070. }
  1071. // Add corresponding GEPs for index allocas
  1072. IndexVector &ReplaceAllocaGEP(GetElementPtrInst *GEP) {
  1073. IndexVector &idxVector = ResToIdxReplacement[GEP];
  1074. if (!idxVector.empty())
  1075. return idxVector;
  1076. Value *Ptr = GEP->getPointerOperand();
  1077. // Recurse for partial GEPs
  1078. IndexVector &ptrIndices = isa<GetElementPtrInst>(Ptr) ?
  1079. ReplaceAllocaGEP(cast<GetElementPtrInst>(Ptr)) : ResToIdxReplacement[Ptr];
  1080. IRBuilder<> Builder(GEP);
  1081. SmallVector<Value*, 4> gepIndices;
  1082. for (auto it = GEP->idx_begin(), idxEnd = GEP->idx_end(); it != idxEnd; it++)
  1083. gepIndices.push_back(*it);
  1084. idxVector.resize(ptrIndices.size(), nullptr);
  1085. for (unsigned i = 0; i < ptrIndices.size(); i++) {
  1086. idxVector[i] = Builder.CreateInBoundsGEP(ptrIndices[i], gepIndices);
  1087. }
  1088. return idxVector;
  1089. }
  1090. void ReplaceAllocaGEPs() {
  1091. for (auto V : AllocaGEPs) {
  1092. ReplaceAllocaGEP(cast<GetElementPtrInst>(V));
  1093. }
  1094. }
  1095. void ReplaceAllocaLoads() {
  1096. for (auto V : AllocaLoads) {
  1097. LoadInst *LI = cast<LoadInst>(V);
  1098. Value *Ptr = LI->getPointerOperand();
  1099. IRBuilder<> Builder(LI);
  1100. IndexVector &idxVector = ResToIdxReplacement[V];
  1101. IndexVector &ptrIndices = ResToIdxReplacement[Ptr];
  1102. idxVector.resize(ptrIndices.size(), nullptr);
  1103. for (unsigned i = 0; i < ptrIndices.size(); i++) {
  1104. idxVector[i] = Builder.CreateLoad(ptrIndices[i]);
  1105. }
  1106. }
  1107. }
  1108. // Add GEP to ResToIdxReplacement with indices from incoming + GEP
  1109. IndexVector &ReplaceGVGEPs(GEPOperator *GEP) {
  1110. IndexVector &idxVector = ResToIdxReplacement[GEP];
  1111. // Skip if already done
  1112. // (we recurse into partial GEP and iterate all GEPs)
  1113. if (!idxVector.empty())
  1114. return idxVector;
  1115. Type *i32Ty = IntegerType::getInt32Ty(GEP->getContext());
  1116. Constant *Zero = Constant::getIntegerValue(i32Ty, APInt(32, 0));
  1117. Value *Ptr = GEP->getPointerOperand();
  1118. unsigned idx = 0;
  1119. if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Ptr)) {
  1120. unsigned gvDim = CountArrayDimensions(GV->getType());
  1121. idxVector.resize(gvDim, Zero);
  1122. } else if (isa<GEPOperator>(Ptr) || isa<PHINode>(Ptr) || isa<SelectInst>(Ptr)) {
  1123. // Recurse for partial GEPs
  1124. IndexVector &ptrIndices = isa<GEPOperator>(Ptr) ?
  1125. ReplaceGVGEPs(cast<GEPOperator>(Ptr)) : ResToIdxReplacement[Ptr];
  1126. unsigned ptrDim = CountArrayDimensions(Ptr->getType());
  1127. unsigned gvDim = ptrIndices.size();
  1128. DXASSERT(ptrDim <= gvDim, "otherwise incoming pointer has more dimensions than associated GV");
  1129. unsigned gepStart = gvDim - ptrDim;
  1130. // Copy indices and add ours
  1131. idxVector.resize(ptrIndices.size(), Zero);
  1132. for (; idx < gepStart; idx++)
  1133. idxVector[idx] = ptrIndices[idx];
  1134. }
  1135. if (GEP->hasIndices()) {
  1136. auto itIdx = GEP->idx_begin();
  1137. ++itIdx; // Always skip leading zero (we don't support GV+n pointer arith)
  1138. while (itIdx != GEP->idx_end())
  1139. idxVector[idx++] = *itIdx++;
  1140. }
  1141. return idxVector;
  1142. }
  1143. // Add GEPs to ResToIdxReplacement and update loads
  1144. void ReplaceGVGEPs() {
  1145. if (GEPs.empty())
  1146. return;
  1147. for (auto V : GEPs) {
  1148. GEPOperator *GEP = cast<GEPOperator>(V);
  1149. IndexVector &gepVector = ReplaceGVGEPs(GEP);
  1150. for (auto U : GEP->users()) {
  1151. if (LoadInst *LI = dyn_cast<LoadInst>(U)) {
  1152. // Just copy incoming indices
  1153. ResToIdxReplacement[LI] = gepVector;
  1154. }
  1155. }
  1156. }
  1157. }
  1158. // Create new index stores for incoming indices
  1159. void ReplaceStores() {
  1160. // generate stores of incoming indices to corresponding index pointers
  1161. if (Stores.empty())
  1162. return;
  1163. Type *i32Ty = IntegerType::getInt32Ty(Stores[0]->getContext());
  1164. for (auto V : Stores) {
  1165. StoreInst *SI = cast<StoreInst>(V);
  1166. IRBuilder<> Builder(SI);
  1167. IndexVector &idxVector = ResToIdxReplacement[SI];
  1168. Value *Ptr = SI->getPointerOperand();
  1169. Value *Val = SI->getValueOperand();
  1170. IndexVector &ptrIndices = ResToIdxReplacement[Ptr];
  1171. IndexVector &valIndices = ResToIdxReplacement[Val];
  1172. // If Val is not found, it is treated as an undef value that will translate
  1173. // to an undef index, which may still be valid if it's never used.
  1174. Value *UndefIndex = valIndices.size() > 0 ? nullptr : UndefValue::get(i32Ty);
  1175. DXASSERT_NOMSG(valIndices.size() == 0 || ptrIndices.size() == valIndices.size());
  1176. idxVector.resize(ptrIndices.size(), nullptr);
  1177. for (unsigned i = 0; i < idxVector.size(); i++) {
  1178. idxVector[i] = Builder.CreateStore(
  1179. UndefIndex ? UndefIndex : valIndices[i],
  1180. ptrIndices[i]);
  1181. }
  1182. }
  1183. }
  1184. // For each Phi/Select: update matching incoming values for new phis
  1185. void UpdateSelects() {
  1186. if (Selects.empty())
  1187. return;
  1188. Type *i32Ty = IntegerType::getInt32Ty(Selects[0]->getContext());
  1189. for (auto V : Selects) {
  1190. // update incoming index values corresponding to incoming resource values
  1191. IndexVector &idxVector = ResToIdxReplacement[V];
  1192. Instruction *I = cast<Instruction>(V);
  1193. unsigned numOperands = I->getNumOperands();
  1194. unsigned startOp = isa<PHINode>(V) ? 0 : 1;
  1195. for (unsigned iOp = startOp; iOp < numOperands; iOp++) {
  1196. Value *Val = I->getOperand(iOp);
  1197. IndexVector &incomingIndices = ResToIdxReplacement[Val];
  1198. // If Val is not found, it is treated as an undef value that will translate
  1199. // to an undef index, which may still be valid if it's never used.
  1200. Value *UndefIndex = incomingIndices.size() > 0 ? nullptr : UndefValue::get(i32Ty);
  1201. DXASSERT_NOMSG(incomingIndices.size() == 0 || idxVector.size() == incomingIndices.size());
  1202. for (unsigned i = 0; i < idxVector.size(); i++) {
  1203. // must be instruction (phi/select)
  1204. Instruction *indexI = cast<Instruction>(idxVector[i]);
  1205. indexI->setOperand(iOp,
  1206. UndefIndex ? UndefIndex : incomingIndices[i]);
  1207. }
  1208. // Now clear incoming operand (adding to cleanup) to break cycles
  1209. if (Instruction *OpI = dyn_cast<Instruction>(I->getOperand(iOp)))
  1210. CleanupInsts.insert(OpI);
  1211. I->setOperand(iOp, UndefValue::get(I->getType()));
  1212. }
  1213. }
  1214. }
  1215. // ReplaceHandles
  1216. // - iterate handles
  1217. // - insert GEP using new indices associated with resource value
  1218. // - load resource from new GEP
  1219. // - replace resource use in createHandleForLib with new load
  1220. // Assumes: no users of handle are phi/select or store
  1221. void ReplaceHandles() {
  1222. if (Handles.empty())
  1223. return;
  1224. Type *i32Ty = IntegerType::getInt32Ty(Handles[0]->getContext());
  1225. Constant *Zero = Constant::getIntegerValue(i32Ty, APInt(32, 0));
  1226. for (auto V : Handles) {
  1227. CallInst *CI = cast<CallInst>(V);
  1228. DxilInst_CreateHandleForLib createHandle(CI);
  1229. Value *res = createHandle.get_Resource();
  1230. // Skip extra work if nothing between load and create handle
  1231. if (LoadInst *LI = dyn_cast<LoadInst>(res)) {
  1232. Value *Ptr = LI->getPointerOperand();
  1233. if (GEPOperator *GEP = dyn_cast<GEPOperator>(Ptr))
  1234. Ptr = GEP->getPointerOperand();
  1235. if (isa<GlobalVariable>(Ptr))
  1236. continue;
  1237. }
  1238. GlobalVariable *GV = LookupResourceGV(res);
  1239. if (!GV)
  1240. continue; // skip value removed due to conflict
  1241. IRBuilder<> Builder(CI);
  1242. IndexVector &idxVector = ResToIdxReplacement[res];
  1243. DXASSERT(idxVector.size() == CountArrayDimensions(GV->getType()), "replacements empty or invalid");
  1244. SmallVector<Value*, 4> gepIndices;
  1245. gepIndices.push_back(Zero);
  1246. for (auto idxVal : idxVector)
  1247. gepIndices.push_back(LookupValue(idxVal));
  1248. Value *GEP = Builder.CreateInBoundsGEP(GV, gepIndices);
  1249. // Mark new GEP instruction non-uniform if necessary
  1250. if (NonUniformSet.count(res) != 0 || NonUniformSet.count(CI) != 0)
  1251. if (GetElementPtrInst *GEPInst = dyn_cast<GetElementPtrInst>(GEP))
  1252. DxilMDHelper::MarkNonUniform(GEPInst);
  1253. LoadInst *LI = Builder.CreateLoad(GEP);
  1254. createHandle.set_Resource(LI);
  1255. if (Instruction *resI = dyn_cast<Instruction>(res))
  1256. CleanupInsts.insert(resI);
  1257. }
  1258. }
  1259. // Delete unused CleanupInsts, restarting when changed
  1260. // Return true if something was deleted
  1261. bool CleanupUnusedValues() {
  1262. // - delete unused CleanupInsts, restarting when changed
  1263. bool bAnyChanges = false;
  1264. bool bChanged = false;
  1265. do {
  1266. bChanged = false;
  1267. for (auto it = CleanupInsts.begin(); it != CleanupInsts.end();) {
  1268. Instruction *I = *(it++);
  1269. if (I->user_empty()) {
  1270. // Add instructions operands CleanupInsts
  1271. for (unsigned iOp = 0; iOp < I->getNumOperands(); iOp++) {
  1272. if (Instruction *opI = dyn_cast<Instruction>(I->getOperand(iOp)))
  1273. CleanupInsts.insert(opI);
  1274. }
  1275. I->eraseFromParent();
  1276. CleanupInsts.erase(I);
  1277. bChanged = true;
  1278. }
  1279. }
  1280. if (bChanged)
  1281. bAnyChanges = true;
  1282. } while (bChanged);
  1283. return bAnyChanges;
  1284. }
  1285. void SimplifyMerges() {
  1286. // Loop if changed
  1287. bool bChanged = false;
  1288. do {
  1289. bChanged = false;
  1290. for (auto V : NewSelects) {
  1291. if (LookupValue(V) != V)
  1292. continue;
  1293. Instruction *I = cast<Instruction>(V);
  1294. unsigned startOp = isa<PHINode>(I) ? 0 : 1;
  1295. Value *newV = dxilutil::MergeSelectOnSameValue(
  1296. cast<Instruction>(V), startOp, I->getNumOperands());
  1297. if (newV) {
  1298. RemappedValues[V] = newV;
  1299. bChanged = true;
  1300. }
  1301. }
  1302. } while (bChanged);
  1303. }
  1304. void CleanupDeadInsts() {
  1305. // Assuming everything was successful:
  1306. // delete stores to allocas to remove cycles
  1307. for (auto V : Stores) {
  1308. StoreInst *SI = cast<StoreInst>(V);
  1309. if (Instruction *I = dyn_cast<Instruction>(SI->getValueOperand()))
  1310. CleanupInsts.insert(I);
  1311. if (Instruction *I = dyn_cast<Instruction>(SI->getPointerOperand()))
  1312. CleanupInsts.insert(I);
  1313. SI->eraseFromParent();
  1314. }
  1315. CleanupUnusedValues();
  1316. }
  1317. void VerifyComplete(DxilModule &DM) {
  1318. // Check that all handles now resolve to a global variable, otherwise,
  1319. // they are likely loading from resource function parameter, which
  1320. // is disallowed.
  1321. hlsl::OP *hlslOP = DM.GetOP();
  1322. for (Function &F : DM.GetModule()->functions()) {
  1323. if (hlslOP->IsDxilOpFunc(&F)) {
  1324. hlsl::OP::OpCodeClass opClass;
  1325. if (hlslOP->GetOpCodeClass(&F, opClass) &&
  1326. opClass == DXIL::OpCodeClass::CreateHandleForLib) {
  1327. for (auto U : F.users()) {
  1328. CallInst *CI = cast<CallInst>(U);
  1329. if (m_Errors.ErrorUsers.count(CI))
  1330. continue; // Error already reported
  1331. DxilInst_CreateHandleForLib createHandle(CI);
  1332. Value *res = createHandle.get_Resource();
  1333. LoadInst *LI = dyn_cast<LoadInst>(res);
  1334. if (LI) {
  1335. Value *Ptr = LI->getPointerOperand();
  1336. if (GEPOperator *GEP = dyn_cast<GEPOperator>(Ptr))
  1337. Ptr = GEP->getPointerOperand();
  1338. if (isa<GlobalVariable>(Ptr))
  1339. continue;
  1340. }
  1341. // handle wasn't processed
  1342. // Right now, the most likely cause is user call with resources, but
  1343. // this should be updated if there are other reasons for this to happen.
  1344. m_Errors.ReportError(ResourceUseErrors::UserCallsWithResources, U);
  1345. }
  1346. }
  1347. }
  1348. }
  1349. }
  1350. // Fix resource global variable properties to external constant
  1351. bool SetExternalConstant(GlobalVariable *GV) {
  1352. if (GV->hasInitializer() || !GV->isConstant() ||
  1353. GV->getLinkage() != GlobalVariable::LinkageTypes::ExternalLinkage) {
  1354. GV->setInitializer(nullptr);
  1355. GV->setConstant(true);
  1356. GV->setLinkage(GlobalVariable::LinkageTypes::ExternalLinkage);
  1357. return true;
  1358. }
  1359. return false;
  1360. }
  1361. bool CollectResources(DxilModule &DM) {
  1362. bool bChanged = false;
  1363. for (const auto &res : DM.GetCBuffers()) {
  1364. if (GlobalVariable *GV = dyn_cast<GlobalVariable>(res->GetGlobalSymbol())) {
  1365. bChanged |= SetExternalConstant(GV);
  1366. CollectResourceGVUsers(GV, GV);
  1367. }
  1368. }
  1369. for (const auto &res : DM.GetSRVs()) {
  1370. if (GlobalVariable *GV = dyn_cast<GlobalVariable>(res->GetGlobalSymbol())) {
  1371. bChanged |= SetExternalConstant(GV);
  1372. CollectResourceGVUsers(GV, GV);
  1373. }
  1374. }
  1375. for (const auto &res : DM.GetUAVs()) {
  1376. if (GlobalVariable *GV = dyn_cast<GlobalVariable>(res->GetGlobalSymbol())) {
  1377. bChanged |= SetExternalConstant(GV);
  1378. CollectResourceGVUsers(GV, GV);
  1379. }
  1380. }
  1381. for (const auto &res : DM.GetSamplers()) {
  1382. if (GlobalVariable *GV = dyn_cast<GlobalVariable>(res->GetGlobalSymbol())) {
  1383. bChanged |= SetExternalConstant(GV);
  1384. CollectResourceGVUsers(GV, GV);
  1385. }
  1386. }
  1387. return bChanged;
  1388. }
  1389. void DoTransform() {
  1390. RemoveConflicts();
  1391. CreateSelects();
  1392. CreateIndexAllocas();
  1393. ReplaceAllocaGEPs();
  1394. ReplaceAllocaLoads();
  1395. ReplaceGVGEPs();
  1396. ReplaceStores();
  1397. UpdateSelects();
  1398. SimplifyMerges();
  1399. ReplaceHandles();
  1400. if (!m_Errors.ErrorsReported())
  1401. CleanupDeadInsts();
  1402. }
  1403. bool ErrorsReported() {
  1404. return m_Errors.ErrorsReported();
  1405. }
  1406. bool runOnModule(llvm::Module &M) {
  1407. DxilModule &DM = M.GetOrCreateDxilModule();
  1408. bool bChanged = CollectResources(DM);
  1409. // If no selects or allocas are involved, there isn't anything to do
  1410. if (Selects.empty() && Allocas.empty())
  1411. return bChanged;
  1412. DoTransform();
  1413. VerifyComplete(DM);
  1414. return true;
  1415. }
  1416. };
  1417. class DxilLegalizeResources : public ModulePass {
  1418. public:
  1419. static char ID; // Pass identification, replacement for typeid
  1420. explicit DxilLegalizeResources()
  1421. : ModulePass(ID) {}
  1422. const char *getPassName() const override {
  1423. return "DXIL Legalize Resource Use";
  1424. }
  1425. bool runOnModule(Module &M) override {
  1426. LegalizeResourceUseHelper helper;
  1427. return helper.runOnModule(M);
  1428. }
  1429. private:
  1430. };
  1431. } // namespace
  1432. char DxilLegalizeResources::ID = 0;
  1433. ModulePass *llvm::createDxilLegalizeResources() {
  1434. return new DxilLegalizeResources();
  1435. }
  1436. INITIALIZE_PASS(DxilLegalizeResources,
  1437. "hlsl-dxil-legalize-resources",
  1438. "DXIL legalize resource use", false, false)
  1439. bool DxilLowerCreateHandleForLib::RemovePhiOnResource() {
  1440. LegalizeResourceUseHelper helper;
  1441. bool bChanged = helper.runOnModule(*m_DM->GetModule());
  1442. if (helper.ErrorsReported())
  1443. m_bLegalizationFailed = true;
  1444. return bChanged;
  1445. }
  1446. // LegacyLayout.
  1447. namespace {
  1448. StructType *UpdateStructTypeForLegacyLayout(StructType *ST,
  1449. DxilTypeSystem &TypeSys, Module &M);
  1450. Type *UpdateFieldTypeForLegacyLayout(Type *Ty,
  1451. DxilFieldAnnotation &annotation,
  1452. DxilTypeSystem &TypeSys, Module &M) {
  1453. DXASSERT(!Ty->isPointerTy(), "struct field should not be a pointer");
  1454. if (Ty->isArrayTy()) {
  1455. Type *EltTy = Ty->getArrayElementType();
  1456. Type *UpdatedTy =
  1457. UpdateFieldTypeForLegacyLayout(EltTy, annotation, TypeSys, M);
  1458. if (EltTy == UpdatedTy)
  1459. return Ty;
  1460. else
  1461. return ArrayType::get(UpdatedTy, Ty->getArrayNumElements());
  1462. } else if (hlsl::HLMatrixType::isa(Ty)) {
  1463. DXASSERT(annotation.HasMatrixAnnotation(), "must a matrix");
  1464. HLMatrixType MatTy = HLMatrixType::cast(Ty);
  1465. unsigned rows = MatTy.getNumRows();
  1466. unsigned cols = MatTy.getNumColumns();
  1467. Type *EltTy = MatTy.getElementTypeForReg();
  1468. // Get cols and rows from annotation.
  1469. const DxilMatrixAnnotation &matrix = annotation.GetMatrixAnnotation();
  1470. if (matrix.Orientation == MatrixOrientation::RowMajor) {
  1471. rows = matrix.Rows;
  1472. cols = matrix.Cols;
  1473. } else {
  1474. DXASSERT_NOMSG(matrix.Orientation == MatrixOrientation::ColumnMajor);
  1475. cols = matrix.Rows;
  1476. rows = matrix.Cols;
  1477. }
  1478. EltTy =
  1479. UpdateFieldTypeForLegacyLayout(EltTy, annotation, TypeSys, M);
  1480. Type *rowTy = VectorType::get(EltTy, cols);
  1481. // Matrix should be aligned like array if rows > 1,
  1482. // otherwise, it's just like a vector.
  1483. if (rows > 1)
  1484. return ArrayType::get(rowTy, rows);
  1485. else
  1486. return rowTy;
  1487. } else if (StructType *ST = dyn_cast<StructType>(Ty)) {
  1488. return UpdateStructTypeForLegacyLayout(ST, TypeSys, M);
  1489. } else if (Ty->isVectorTy()) {
  1490. Type *EltTy = Ty->getVectorElementType();
  1491. Type *UpdatedTy =
  1492. UpdateFieldTypeForLegacyLayout(EltTy, annotation, TypeSys, M);
  1493. if (EltTy == UpdatedTy)
  1494. return Ty;
  1495. else
  1496. return VectorType::get(UpdatedTy, Ty->getVectorNumElements());
  1497. } else {
  1498. Type *i32Ty = Type::getInt32Ty(Ty->getContext());
  1499. // Basic types.
  1500. if (Ty->isHalfTy()) {
  1501. return Type::getFloatTy(Ty->getContext());
  1502. } else if (IntegerType *ITy = dyn_cast<IntegerType>(Ty)) {
  1503. if (ITy->getBitWidth() < 32)
  1504. return i32Ty;
  1505. else
  1506. return Ty;
  1507. } else
  1508. return Ty;
  1509. }
  1510. }
  1511. StructType *UpdateStructTypeForLegacyLayout(StructType *ST,
  1512. DxilTypeSystem &TypeSys,
  1513. Module &M) {
  1514. bool bUpdated = false;
  1515. unsigned fieldsCount = ST->getNumElements();
  1516. std::vector<Type *> fieldTypes(fieldsCount);
  1517. DxilStructAnnotation *SA = TypeSys.GetStructAnnotation(ST);
  1518. // After reflection is stripped from library, this will be null if no update is required.
  1519. if (!SA) {
  1520. return ST;
  1521. }
  1522. if (SA->IsEmptyStruct()) {
  1523. return ST;
  1524. }
  1525. for (unsigned i = 0; i < fieldsCount; i++) {
  1526. Type *EltTy = ST->getElementType(i);
  1527. Type *UpdatedTy = UpdateFieldTypeForLegacyLayout(
  1528. EltTy, SA->GetFieldAnnotation(i), TypeSys, M);
  1529. fieldTypes[i] = UpdatedTy;
  1530. if (EltTy != UpdatedTy)
  1531. bUpdated = true;
  1532. }
  1533. if (!bUpdated) {
  1534. return ST;
  1535. } else {
  1536. std::string legacyName = "dx.alignment.legacy." + ST->getName().str();
  1537. if (StructType *legacyST = M.getTypeByName(legacyName))
  1538. return legacyST;
  1539. StructType *NewST =
  1540. StructType::create(ST->getContext(), fieldTypes, legacyName);
  1541. DxilStructAnnotation *NewSA = TypeSys.AddStructAnnotation(NewST);
  1542. // Clone annotation.
  1543. *NewSA = *SA;
  1544. // Make sure we set the struct type back to the new one, since the
  1545. // clone would have clobbered it with the old one.
  1546. NewSA->SetStructType(NewST);
  1547. return NewST;
  1548. }
  1549. }
  1550. void UpdateStructTypeForLegacyLayout(DxilResourceBase &Res,
  1551. DxilTypeSystem &TypeSys, Module &M) {
  1552. Constant *Symbol = Res.GetGlobalSymbol();
  1553. Type *ElemTy = Res.GetHLSLType()->getPointerElementType();
  1554. // Support Array of ConstantBuffer/StructuredBuffer.
  1555. llvm::SmallVector<unsigned, 4> arrayDims;
  1556. ElemTy = dxilutil::StripArrayTypes(ElemTy, &arrayDims);
  1557. StructType *ST = cast<StructType>(ElemTy);
  1558. if (ST->isOpaque()) {
  1559. DXASSERT(Res.GetClass() == DxilResourceBase::Class::CBuffer,
  1560. "Only cbuffer can have opaque struct.");
  1561. return;
  1562. }
  1563. Type *UpdatedST =
  1564. UpdateStructTypeForLegacyLayout(ST, TypeSys, M);
  1565. if (ST != UpdatedST) {
  1566. // Support Array of ConstantBuffer/StructuredBuffer.
  1567. UpdatedST = dxilutil::WrapInArrayTypes(UpdatedST, arrayDims);
  1568. GlobalVariable *NewGV = cast<GlobalVariable>(
  1569. M.getOrInsertGlobal(Symbol->getName().str() + "_legacy", UpdatedST));
  1570. Res.SetGlobalSymbol(NewGV);
  1571. // Delete old GV.
  1572. for (auto UserIt = Symbol->user_begin(); UserIt != Symbol->user_end();) {
  1573. Value *User = *(UserIt++);
  1574. if (Instruction *I = dyn_cast<Instruction>(User)) {
  1575. if (!User->user_empty())
  1576. I->replaceAllUsesWith(UndefValue::get(I->getType()));
  1577. I->eraseFromParent();
  1578. } else {
  1579. ConstantExpr *CE = cast<ConstantExpr>(User);
  1580. if (!CE->user_empty())
  1581. CE->replaceAllUsesWith(UndefValue::get(CE->getType()));
  1582. }
  1583. }
  1584. Symbol->removeDeadConstantUsers();
  1585. if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Symbol))
  1586. GV->eraseFromParent();
  1587. }
  1588. }
  1589. void UpdateStructTypeForLegacyLayoutOnDM(DxilModule &DM) {
  1590. DxilTypeSystem &TypeSys = DM.GetTypeSystem();
  1591. Module &M = *DM.GetModule();
  1592. for (auto &CBuf : DM.GetCBuffers()) {
  1593. UpdateStructTypeForLegacyLayout(*CBuf.get(), TypeSys, M);
  1594. }
  1595. for (auto &UAV : DM.GetUAVs()) {
  1596. if (DXIL::IsStructuredBuffer(UAV->GetKind()))
  1597. UpdateStructTypeForLegacyLayout(*UAV.get(), TypeSys, M);
  1598. }
  1599. for (auto &SRV : DM.GetSRVs()) {
  1600. if (SRV->IsStructuredBuffer() || SRV->IsTBuffer())
  1601. UpdateStructTypeForLegacyLayout(*SRV.get(), TypeSys, M);
  1602. }
  1603. }
  1604. } // namespace
  1605. void DxilLowerCreateHandleForLib::FailOnPoisonResources() {
  1606. // A previous pass replaced all undef resources with constant zero resources.
  1607. // If those made it here, the program is malformed.
  1608. for (Function &Func : this->m_DM->GetModule()->functions()) {
  1609. hlsl::OP::OpCodeClass OpcodeClass;
  1610. if (m_DM->GetOP()->GetOpCodeClass(&Func, OpcodeClass)
  1611. && OpcodeClass == OP::OpCodeClass::CreateHandleForLib) {
  1612. Type *ResTy = Func.getFunctionType()->getParamType(
  1613. DXIL::OperandIndex::kCreateHandleForLibResOpIdx);
  1614. Constant *PoisonRes = ConstantAggregateZero::get(ResTy);
  1615. for (User *PoisonUser : PoisonRes->users())
  1616. if (Instruction *PoisonUserInst = dyn_cast<Instruction>(PoisonUser))
  1617. dxilutil::EmitResMappingError(PoisonUserInst);
  1618. }
  1619. }
  1620. }
  1621. void DxilLowerCreateHandleForLib::UpdateStructTypeForLegacyLayout() {
  1622. UpdateStructTypeForLegacyLayoutOnDM(*m_DM);
  1623. }
  1624. // Change ResourceSymbol to undef if don't need.
  1625. void DxilLowerCreateHandleForLib::UpdateResourceSymbols() {
  1626. auto UpdateResourceSymbol = [](DxilResourceBase *res) {
  1627. if (GlobalVariable *GV = dyn_cast<GlobalVariable>(res->GetGlobalSymbol())) {
  1628. GV->removeDeadConstantUsers();
  1629. DXASSERT(GV->user_empty(), "else resource not lowered");
  1630. res->SetGlobalSymbol(UndefValue::get(GV->getType()));
  1631. }
  1632. };
  1633. for (auto &&C : m_DM->GetCBuffers()) {
  1634. UpdateResourceSymbol(C.get());
  1635. }
  1636. for (auto &&Srv : m_DM->GetSRVs()) {
  1637. UpdateResourceSymbol(Srv.get());
  1638. }
  1639. for (auto &&Uav : m_DM->GetUAVs()) {
  1640. UpdateResourceSymbol(Uav.get());
  1641. }
  1642. for (auto &&S : m_DM->GetSamplers()) {
  1643. UpdateResourceSymbol(S.get());
  1644. }
  1645. }
  1646. // Lower createHandleForLib
  1647. namespace {
  1648. void ReplaceResourceUserWithHandle(
  1649. DxilResource &res,
  1650. LoadInst *load, Value *handle)
  1651. {
  1652. for (auto resUser = load->user_begin(); resUser != load->user_end();) {
  1653. Value *V = *(resUser++);
  1654. CallInst *CI = dyn_cast<CallInst>(V);
  1655. DxilInst_CreateHandleForLib createHandle(CI);
  1656. DXASSERT(createHandle, "must be createHandle");
  1657. CI->replaceAllUsesWith(handle);
  1658. CI->eraseFromParent();
  1659. }
  1660. if (res.GetClass() == DXIL::ResourceClass::UAV) {
  1661. // Before this pass, the global resources might not have been mapped with all the uses.
  1662. // Now we're 100% sure who uses what resources (otherwise the compilation would have failed),
  1663. // so we do a round on marking UAV's as having counter.
  1664. static auto IsDxilOp = [](Value *V, hlsl::OP::OpCode Op) -> bool {
  1665. Instruction *I = dyn_cast<Instruction>(V);
  1666. if (!I)
  1667. return false;
  1668. return hlsl::OP::IsDxilOpFuncCallInst(I, Op);
  1669. };
  1670. // Search all users for update counter
  1671. bool updateAnnotateHandle = false;
  1672. if (!res.HasCounter()) {
  1673. for (User *U : handle->users()) {
  1674. if (IsDxilOp(U, hlsl::OP::OpCode::BufferUpdateCounter)) {
  1675. res.SetHasCounter(true);
  1676. break;
  1677. }
  1678. else if (IsDxilOp(U, hlsl::OP::OpCode::AnnotateHandle)) {
  1679. for (User *UU : U->users()) {
  1680. if (IsDxilOp(UU, hlsl::OP::OpCode::BufferUpdateCounter)) {
  1681. res.SetHasCounter(true);
  1682. updateAnnotateHandle = true;
  1683. break;
  1684. }
  1685. }
  1686. if (updateAnnotateHandle)
  1687. break;
  1688. }
  1689. }
  1690. if (updateAnnotateHandle) {
  1691. // Update resource props with counter flag
  1692. DxilResourceProperties RP =
  1693. resource_helper::loadPropsFromResourceBase(&res);
  1694. // Require ShaderModule to reconstruct resource property constant
  1695. const ShaderModel *pSM = load->getParent()->getParent()->getParent()
  1696. ->GetDxilModule().GetShaderModel();
  1697. for (User *U : handle->users()) {
  1698. DxilInst_AnnotateHandle annotateHandle(cast<Instruction>(U));
  1699. if (annotateHandle) {
  1700. annotateHandle.set_props(
  1701. resource_helper::getAsConstant(
  1702. RP, annotateHandle.get_props()->getType(), *pSM));
  1703. }
  1704. }
  1705. }
  1706. }
  1707. }
  1708. load->eraseFromParent();
  1709. }
  1710. Value *flattenGepIdx(GEPOperator *GEP) {
  1711. Value *idx = nullptr;
  1712. if (GEP->getNumIndices() == 2) {
  1713. // one dim array of resource
  1714. idx = (GEP->idx_begin() + 1)->get();
  1715. } else {
  1716. gep_type_iterator GEPIt = gep_type_begin(GEP), E = gep_type_end(GEP);
  1717. // Must be instruction for multi dim array.
  1718. std::unique_ptr<IRBuilder<>> Builder;
  1719. if (GetElementPtrInst *GEPInst = dyn_cast<GetElementPtrInst>(GEP)) {
  1720. Builder = llvm::make_unique<IRBuilder<>>(GEPInst);
  1721. } else {
  1722. Builder = llvm::make_unique<IRBuilder<>>(GEP->getContext());
  1723. }
  1724. for (; GEPIt != E; ++GEPIt) {
  1725. if (GEPIt->isArrayTy()) {
  1726. unsigned arraySize = GEPIt->getArrayNumElements();
  1727. Value *tmpIdx = GEPIt.getOperand();
  1728. if (idx == nullptr)
  1729. idx = tmpIdx;
  1730. else {
  1731. idx = Builder->CreateMul(idx, Builder->getInt32(arraySize));
  1732. idx = Builder->CreateAdd(idx, tmpIdx);
  1733. }
  1734. }
  1735. }
  1736. }
  1737. return idx;
  1738. }
  1739. } // namespace
  1740. void DxilLowerCreateHandleForLib::TranslateDxilResourceUses(
  1741. DxilResourceBase &res) {
  1742. OP *hlslOP = m_DM->GetOP();
  1743. // Generate createHandleFromBinding for sm66 and later.
  1744. bool bCreateFromBinding = m_DM->GetShaderModel()->IsSM66Plus();
  1745. OP::OpCode createOp = bCreateFromBinding ? OP::OpCode::CreateHandleFromBinding
  1746. : OP::OpCode::CreateHandle;
  1747. Function *createHandle = hlslOP->GetOpFunc(
  1748. createOp, llvm::Type::getVoidTy(m_DM->GetCtx()));
  1749. Value *opArg = hlslOP->GetU32Const((unsigned)createOp);
  1750. bool isViewResource = res.GetClass() == DXIL::ResourceClass::SRV ||
  1751. res.GetClass() == DXIL::ResourceClass::UAV;
  1752. bool isROV = isViewResource && static_cast<DxilResource &>(res).IsROV();
  1753. std::string handleName =
  1754. (res.GetGlobalName() + Twine("_") + Twine(res.GetResClassName())).str();
  1755. if (isViewResource)
  1756. handleName += (Twine("_") + Twine(res.GetResDimName())).str();
  1757. if (isROV)
  1758. handleName += "_ROV";
  1759. Value *resClassArg = hlslOP->GetU8Const(
  1760. static_cast<std::underlying_type<DxilResourceBase::Class>::type>(
  1761. res.GetClass()));
  1762. Value *resIDArg = hlslOP->GetU32Const(res.GetID());
  1763. // resLowerBound will be added after allocation in DxilCondenseResources.
  1764. Value *resLowerBound = hlslOP->GetU32Const(res.GetLowerBound());
  1765. Value *isUniformRes = hlslOP->GetI1Const(0);
  1766. Value *GV = res.GetGlobalSymbol();
  1767. DXASSERT(isa<GlobalValue>(GV), "DxilLowerCreateHandleForLib cannot deal with unused resources.");
  1768. Module *pM = m_DM->GetModule();
  1769. // TODO: add debug info to create handle.
  1770. DIVariable *DIV = nullptr;
  1771. DILocation *DL = nullptr;
  1772. if (m_HasDbgInfo) {
  1773. DebugInfoFinder &Finder = m_DM->GetOrCreateDebugInfoFinder();
  1774. DIV = dxilutil::FindGlobalVariableDebugInfo(cast<GlobalVariable>(GV), Finder);
  1775. if (DIV)
  1776. // TODO: how to get col?
  1777. DL =
  1778. DILocation::get(pM->getContext(), DIV->getLine(), 1, DIV->getScope());
  1779. }
  1780. bool isResArray = res.GetRangeSize() > 1;
  1781. std::unordered_map<Function *, Instruction *> handleMapOnFunction;
  1782. Value *createHandleArgs[] = {opArg, resClassArg, resIDArg, resLowerBound,
  1783. isUniformRes};
  1784. DxilResourceBinding binding = resource_helper::loadBindingFromResourceBase(&res);
  1785. Value *bindingV = resource_helper::getAsConstant(
  1786. binding, hlslOP->GetResourceBindingType(), *m_DM->GetShaderModel());
  1787. Value *createHandleFromBindingArgs[] = {opArg, bindingV, resLowerBound, isUniformRes};
  1788. MutableArrayRef<Value *> Args(bCreateFromBinding ? createHandleFromBindingArgs
  1789. : createHandleArgs,
  1790. bCreateFromBinding ? 4 : 5);
  1791. const unsigned resIdxOpIdx = bCreateFromBinding
  1792. ? DxilInst_CreateHandleFromBinding::arg_index
  1793. : DxilInst_CreateHandle::arg_index;
  1794. const unsigned nonUniformOpIdx = bCreateFromBinding
  1795. ? DxilInst_CreateHandleFromBinding::arg_nonUniformIndex
  1796. : DxilInst_CreateHandle::arg_nonUniformIndex;
  1797. for (iplist<Function>::iterator F : pM->getFunctionList()) {
  1798. if (!F->isDeclaration()) {
  1799. if (!isResArray) {
  1800. IRBuilder<> Builder(dxilutil::FindAllocaInsertionPt(F));
  1801. if (m_HasDbgInfo) {
  1802. // TODO: set debug info.
  1803. // Builder.SetCurrentDebugLocation(DL);
  1804. }
  1805. handleMapOnFunction[F] =
  1806. Builder.CreateCall(createHandle, Args, handleName);
  1807. }
  1808. }
  1809. }
  1810. for (auto U = GV->user_begin(), E = GV->user_end(); U != E;) {
  1811. User *user = *(U++);
  1812. // Skip unused user.
  1813. if (user->user_empty())
  1814. continue;
  1815. if (LoadInst *ldInst = dyn_cast<LoadInst>(user)) {
  1816. Function *userF = ldInst->getParent()->getParent();
  1817. DXASSERT(handleMapOnFunction.count(userF), "must exist");
  1818. Value *handle = handleMapOnFunction[userF];
  1819. ReplaceResourceUserWithHandle(static_cast<DxilResource &>(res), ldInst, handle);
  1820. } else if (GEPOperator *GEP = dyn_cast<GEPOperator>(user)) {
  1821. Value *idx = flattenGepIdx(GEP);
  1822. Args[resIdxOpIdx] = idx;
  1823. Args[nonUniformOpIdx] =
  1824. isUniformRes;
  1825. Value *handle = nullptr;
  1826. if (GetElementPtrInst *GEPInst = dyn_cast<GetElementPtrInst>(GEP)) {
  1827. IRBuilder<> Builder = IRBuilder<>(GEPInst);
  1828. if (DxilMDHelper::IsMarkedNonUniform(GEPInst)) {
  1829. // Mark nonUniform.
  1830. Args[nonUniformOpIdx] =
  1831. hlslOP->GetI1Const(1);
  1832. // Clear nonUniform on GEP.
  1833. GEPInst->setMetadata(DxilMDHelper::kDxilNonUniformAttributeMDName, nullptr);
  1834. }
  1835. Args[resIdxOpIdx] = Builder.CreateAdd(idx, resLowerBound);
  1836. handle = Builder.CreateCall(createHandle, Args, handleName);
  1837. }
  1838. for (auto GEPU = GEP->user_begin(), GEPE = GEP->user_end();
  1839. GEPU != GEPE;) {
  1840. // Must be load inst.
  1841. LoadInst *ldInst = cast<LoadInst>(*(GEPU++));
  1842. if (handle) {
  1843. ReplaceResourceUserWithHandle(static_cast<DxilResource &>(res), ldInst, handle);
  1844. } else {
  1845. IRBuilder<> Builder = IRBuilder<>(ldInst);
  1846. Args[resIdxOpIdx] = Builder.CreateAdd(idx, resLowerBound);
  1847. Value *localHandle =
  1848. Builder.CreateCall(createHandle, Args, handleName);
  1849. ReplaceResourceUserWithHandle(static_cast<DxilResource &>(res), ldInst, localHandle);
  1850. }
  1851. }
  1852. if (Instruction *I = dyn_cast<Instruction>(GEP)) {
  1853. I->eraseFromParent();
  1854. }
  1855. } else if (BitCastInst *BCI = dyn_cast<BitCastInst>(user)) {
  1856. DXASSERT(onlyUsedByLifetimeMarkers(BCI),
  1857. "expected bitcast to only be used by lifetime intrinsics");
  1858. for (auto BCIU = BCI->user_begin(), BCIE = BCI->user_end(); BCIU != BCIE;) {
  1859. IntrinsicInst *II = cast<IntrinsicInst>(*(BCIU++));
  1860. II->eraseFromParent();
  1861. }
  1862. BCI->eraseFromParent();
  1863. } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(user)) {
  1864. // A GEPOperator can also be a ConstantExpr, so it must be checked before
  1865. // this code.
  1866. DXASSERT(CE->getOpcode() == Instruction::BitCast, "expected bitcast");
  1867. DXASSERT(onlyUsedByLifetimeMarkers(CE),
  1868. "expected ConstantExpr to only be used by lifetime intrinsics");
  1869. for (auto CEU = CE->user_begin(), CEE = CE->user_end(); CEU != CEE;) {
  1870. IntrinsicInst *II = cast<IntrinsicInst>(*(CEU++));
  1871. II->eraseFromParent();
  1872. }
  1873. } else {
  1874. DXASSERT(false,
  1875. "AddOpcodeParamForIntrinsic in CodeGen did not patch uses "
  1876. "to only have ld/st refer to temp object");
  1877. }
  1878. }
  1879. // Erase unused handle.
  1880. for (auto It : handleMapOnFunction) {
  1881. Instruction *I = It.second;
  1882. if (I->user_empty())
  1883. I->eraseFromParent();
  1884. }
  1885. }
  1886. void DxilLowerCreateHandleForLib::GenerateDxilResourceHandles() {
  1887. for (size_t i = 0; i < m_DM->GetCBuffers().size(); i++) {
  1888. DxilCBuffer &C = m_DM->GetCBuffer(i);
  1889. TranslateDxilResourceUses(C);
  1890. }
  1891. // Create sampler handle first, may be used by SRV operations.
  1892. for (size_t i = 0; i < m_DM->GetSamplers().size(); i++) {
  1893. DxilSampler &S = m_DM->GetSampler(i);
  1894. TranslateDxilResourceUses(S);
  1895. }
  1896. for (size_t i = 0; i < m_DM->GetSRVs().size(); i++) {
  1897. DxilResource &SRV = m_DM->GetSRV(i);
  1898. TranslateDxilResourceUses(SRV);
  1899. }
  1900. for (size_t i = 0; i < m_DM->GetUAVs().size(); i++) {
  1901. DxilResource &UAV = m_DM->GetUAV(i);
  1902. TranslateDxilResourceUses(UAV);
  1903. }
  1904. }
  1905. // TBuffer.
  1906. namespace {
  1907. void InitTBuffer(const DxilCBuffer *pSource, DxilResource *pDest) {
  1908. pDest->SetKind(pSource->GetKind());
  1909. pDest->SetCompType(DXIL::ComponentType::U32);
  1910. pDest->SetSampleCount(0);
  1911. pDest->SetElementStride(0);
  1912. pDest->SetGloballyCoherent(false);
  1913. pDest->SetHasCounter(false);
  1914. pDest->SetRW(false);
  1915. pDest->SetROV(false);
  1916. pDest->SetID(pSource->GetID());
  1917. pDest->SetSpaceID(pSource->GetSpaceID());
  1918. pDest->SetLowerBound(pSource->GetLowerBound());
  1919. pDest->SetRangeSize(pSource->GetRangeSize());
  1920. pDest->SetGlobalSymbol(pSource->GetGlobalSymbol());
  1921. pDest->SetGlobalName(pSource->GetGlobalName());
  1922. pDest->SetHandle(pSource->GetHandle());
  1923. pDest->SetHLSLType(pSource->GetHLSLType());
  1924. }
  1925. void PatchTBufferLoad(CallInst *handle, DxilModule &DM,
  1926. DenseSet<Value *> &patchedSet) {
  1927. if (patchedSet.count(handle))
  1928. return;
  1929. patchedSet.insert(handle);
  1930. hlsl::OP *hlslOP = DM.GetOP();
  1931. llvm::LLVMContext &Ctx = DM.GetCtx();
  1932. Type *doubleTy = Type::getDoubleTy(Ctx);
  1933. Type *i64Ty = Type::getInt64Ty(Ctx);
  1934. // Replace corresponding cbuffer loads with typed buffer loads
  1935. for (auto U = handle->user_begin(); U != handle->user_end();) {
  1936. CallInst *I = cast<CallInst>(*(U++));
  1937. DXASSERT(I && OP::IsDxilOpFuncCallInst(I),
  1938. "otherwise unexpected user of CreateHandle value");
  1939. DXIL::OpCode opcode = OP::GetDxilOpFuncCallInst(I);
  1940. if (opcode == DXIL::OpCode::CBufferLoadLegacy) {
  1941. DxilInst_CBufferLoadLegacy cbLoad(I);
  1942. StructType *cbRetTy = cast<StructType>(I->getType());
  1943. // elements will be 4, or 8 for native 16-bit types, which require special handling.
  1944. bool cbRet8Elt = cbRetTy->getNumElements() > 4;
  1945. // Replace with appropriate buffer load instruction
  1946. IRBuilder<> Builder(I);
  1947. opcode = OP::OpCode::BufferLoad;
  1948. Type *Ty = Type::getInt32Ty(Ctx);
  1949. Function *BufLoad = hlslOP->GetOpFunc(opcode, Ty);
  1950. Constant *opArg = hlslOP->GetU32Const((unsigned)opcode);
  1951. Value *undefI = UndefValue::get(Type::getInt32Ty(Ctx));
  1952. Value *offset = cbLoad.get_regIndex();
  1953. CallInst *load =
  1954. Builder.CreateCall(BufLoad, {opArg, handle, offset, undefI});
  1955. // Find extractelement uses of cbuffer load and replace + generate bitcast
  1956. // as necessary
  1957. for (auto LU = I->user_begin(); LU != I->user_end();) {
  1958. ExtractValueInst *evInst = dyn_cast<ExtractValueInst>(*(LU++));
  1959. DXASSERT(evInst && evInst->getNumIndices() == 1,
  1960. "user of cbuffer load result should be extractvalue");
  1961. uint64_t idx = evInst->getIndices()[0];
  1962. Type *EltTy = evInst->getType();
  1963. IRBuilder<> EEBuilder(evInst);
  1964. Value *result = nullptr;
  1965. if (EltTy != Ty) {
  1966. // extract two values and DXIL::OpCode::MakeDouble or construct i64
  1967. if ((EltTy == doubleTy) || (EltTy == i64Ty)) {
  1968. DXASSERT(idx < 2, "64-bit component index out of range");
  1969. // This assumes big endian order in tbuffer elements (is this
  1970. // correct?)
  1971. Value *low = EEBuilder.CreateExtractValue(load, idx * 2);
  1972. Value *high = EEBuilder.CreateExtractValue(load, idx * 2 + 1);
  1973. if (EltTy == doubleTy) {
  1974. opcode = OP::OpCode::MakeDouble;
  1975. Function *MakeDouble = hlslOP->GetOpFunc(opcode, doubleTy);
  1976. Constant *opArg = hlslOP->GetU32Const((unsigned)opcode);
  1977. result = EEBuilder.CreateCall(MakeDouble, {opArg, low, high});
  1978. } else {
  1979. high = EEBuilder.CreateZExt(high, i64Ty);
  1980. low = EEBuilder.CreateZExt(low, i64Ty);
  1981. high = EEBuilder.CreateShl(high, hlslOP->GetU64Const(32));
  1982. result = EEBuilder.CreateOr(high, low);
  1983. }
  1984. } else {
  1985. if (cbRet8Elt) {
  1986. DXASSERT_NOMSG(cbRetTy->getNumElements() == 8);
  1987. DXASSERT_NOMSG(EltTy->getScalarSizeInBits() == 16);
  1988. // Translate extract from 16bit x 8 to extract and translate from i32 by 4
  1989. result = EEBuilder.CreateExtractValue(load, idx >> 1);
  1990. if (idx & 1)
  1991. result = EEBuilder.CreateLShr(result, 16);
  1992. result = EEBuilder.CreateTrunc(result, Type::getInt16Ty(Ctx));
  1993. if (EltTy->isHalfTy())
  1994. result = EEBuilder.CreateBitCast(result, EltTy);
  1995. } else {
  1996. result = EEBuilder.CreateExtractValue(load, idx);
  1997. if (Ty->getScalarSizeInBits() > EltTy->getScalarSizeInBits()) {
  1998. if (EltTy->isIntegerTy()) {
  1999. result = EEBuilder.CreateTrunc(result, EltTy);
  2000. } else {
  2001. result = EEBuilder.CreateBitCast(result, Type::getFloatTy(Ctx));
  2002. result = EEBuilder.CreateFPTrunc(result, EltTy);
  2003. }
  2004. } else {
  2005. result = EEBuilder.CreateBitCast(result, EltTy);
  2006. }
  2007. }
  2008. }
  2009. } else {
  2010. result = EEBuilder.CreateExtractValue(load, idx);
  2011. }
  2012. evInst->replaceAllUsesWith(result);
  2013. evInst->eraseFromParent();
  2014. }
  2015. } else if (opcode == DXIL::OpCode::CBufferLoad) {
  2016. // TODO: Handle this, or prevent this for tbuffer
  2017. DXASSERT(false, "otherwise CBufferLoad used for tbuffer rather than "
  2018. "CBufferLoadLegacy");
  2019. } else if (opcode == DXIL::OpCode::AnnotateHandle) {
  2020. PatchTBufferLoad(cast<CallInst>(I), DM,
  2021. patchedSet);
  2022. continue;
  2023. } else {
  2024. DXASSERT(false, "otherwise unexpected user of CreateHandle value");
  2025. }
  2026. I->eraseFromParent();
  2027. }
  2028. }
  2029. } // namespace
  2030. void DxilLowerCreateHandleForLib::PatchTBufferUse(
  2031. Value *V, DxilModule &DM, DenseSet<Value *> &patchedSet) {
  2032. for (User *U : V->users()) {
  2033. if (CallInst *CI = dyn_cast<CallInst>(U)) {
  2034. // Patch dxil call.
  2035. if (hlsl::OP::IsDxilOpFuncCallInst(CI))
  2036. PatchTBufferLoad(CI, DM, patchedSet);
  2037. } else {
  2038. PatchTBufferUse(U, DM, patchedSet);
  2039. }
  2040. }
  2041. }
  2042. bool DxilLowerCreateHandleForLib::PatchDynamicTBuffers(DxilModule &DM) {
  2043. hlsl::OP *hlslOP = DM.GetOP();
  2044. Function *AnnotHandleFn = hlslOP->GetOpFunc(DXIL::OpCode::AnnotateHandle,
  2045. Type::getVoidTy(DM.GetCtx()));
  2046. if (AnnotHandleFn->user_empty()) {
  2047. AnnotHandleFn->eraseFromParent();
  2048. return false;
  2049. }
  2050. bool bUpdated = false;
  2051. for (User *U : AnnotHandleFn->users()) {
  2052. CallInst *CI = cast<CallInst>(U);
  2053. DxilInst_AnnotateHandle annot(CI);
  2054. DxilResourceProperties RP = resource_helper::loadPropsFromAnnotateHandle(
  2055. annot, *DM.GetShaderModel());
  2056. if (RP.getResourceKind() != DXIL::ResourceKind::TBuffer)
  2057. continue;
  2058. // Skip handle from createHandleForLib which take care in PatchTBuffers.
  2059. if (CallInst *HdlCI = dyn_cast<CallInst>(annot.get_res())) {
  2060. if (hlslOP->IsDxilOpFuncCallInst(HdlCI)) {
  2061. if (hlslOP->GetDxilOpFuncCallInst(HdlCI) == DXIL::OpCode::CreateHandleForLib)
  2062. continue;
  2063. }
  2064. }
  2065. DenseSet<Value *> patchedSet;
  2066. PatchTBufferLoad(CI, DM, patchedSet);
  2067. bUpdated = true;
  2068. }
  2069. return bUpdated;
  2070. }
  2071. bool DxilLowerCreateHandleForLib::PatchTBuffers(DxilModule &DM) {
  2072. bool bChanged = false;
  2073. // move tbuffer resources to SRVs
  2074. unsigned offset = DM.GetSRVs().size();
  2075. Module &M = *DM.GetModule();
  2076. for (auto it = DM.GetCBuffers().begin(); it != DM.GetCBuffers().end(); it++) {
  2077. DxilCBuffer *CB = it->get();
  2078. if (CB->GetKind() == DXIL::ResourceKind::TBuffer) {
  2079. auto srv = make_unique<DxilResource>();
  2080. InitTBuffer(CB, srv.get());
  2081. srv->SetID(offset++);
  2082. DM.AddSRV(std::move(srv));
  2083. GlobalVariable *GV = dyn_cast<GlobalVariable>(CB->GetGlobalSymbol());
  2084. if (GV == nullptr)
  2085. continue;
  2086. DenseSet<Value*> patchedSet;
  2087. PatchTBufferUse(GV, DM, patchedSet);
  2088. // Set global symbol for cbuffer to an unused value so it can be removed
  2089. // in RemoveUnusedResourceSymbols.
  2090. Type *Ty = GV->getType()->getElementType();
  2091. GlobalVariable *NewGV = new GlobalVariable(
  2092. M, Ty, GV->isConstant(), GV->getLinkage(), /*Initializer*/ nullptr,
  2093. GV->getName(),
  2094. /*InsertBefore*/ nullptr, GV->getThreadLocalMode(),
  2095. GV->getType()->getAddressSpace(), GV->isExternallyInitialized());
  2096. CB->SetGlobalSymbol(NewGV);
  2097. bChanged = true;
  2098. }
  2099. }
  2100. return bChanged;
  2101. }
  2102. typedef DenseMap<Value*, unsigned> OffsetForValueMap;
  2103. // Find the imm offset part from a value.
  2104. // It must exist unless offset is 0.
  2105. static unsigned GetCBOffset(Value *V, OffsetForValueMap &visited) {
  2106. auto it = visited.find(V);
  2107. if (it != visited.end())
  2108. return it->second;
  2109. visited[V] = 0;
  2110. unsigned result = 0;
  2111. if (ConstantInt *Imm = dyn_cast<ConstantInt>(V)) {
  2112. result = Imm->getLimitedValue();
  2113. } else if (BinaryOperator *BO = dyn_cast<BinaryOperator>(V)) {
  2114. switch (BO->getOpcode()) {
  2115. case Instruction::Add: {
  2116. unsigned left = GetCBOffset(BO->getOperand(0), visited);
  2117. unsigned right = GetCBOffset(BO->getOperand(1), visited);
  2118. result = left + right;
  2119. } break;
  2120. case Instruction::Or: {
  2121. unsigned left = GetCBOffset(BO->getOperand(0), visited);
  2122. unsigned right = GetCBOffset(BO->getOperand(1), visited);
  2123. result = left | right;
  2124. } break;
  2125. default:
  2126. break;
  2127. }
  2128. } else if (SelectInst *SI = dyn_cast<SelectInst>(V)) {
  2129. result = std::min(GetCBOffset(SI->getOperand(1), visited),
  2130. GetCBOffset(SI->getOperand(2), visited));
  2131. } else if (PHINode *PN = dyn_cast<PHINode>(V)) {
  2132. result = UINT_MAX;
  2133. for (unsigned i = 0, ops = PN->getNumIncomingValues(); i < ops; ++i) {
  2134. result = std::min(result, GetCBOffset(PN->getIncomingValue(i), visited));
  2135. }
  2136. }
  2137. visited[V] = result;
  2138. return result;
  2139. }
  2140. typedef std::map<unsigned, DxilFieldAnnotation*> FieldAnnotationByOffsetMap;
  2141. static void MarkCBUse(unsigned offset, FieldAnnotationByOffsetMap &fieldMap) {
  2142. auto it = fieldMap.upper_bound(offset);
  2143. it--;
  2144. if (it != fieldMap.end())
  2145. it->second->SetCBVarUsed(true);
  2146. }
  2147. // Detect patterns of lshr v,16 or trunc to 16-bits and return low and high
  2148. // word usage.
  2149. static const unsigned kLowWordUsed = 1;
  2150. static const unsigned kHighWordUsed = 2;
  2151. static const unsigned kLowHighWordMask = kLowWordUsed | kHighWordUsed;
  2152. static unsigned DetectLowAndHighWordUsage(ExtractValueInst *EV) {
  2153. unsigned result = 0;
  2154. if (EV->getType()->getScalarSizeInBits() == 32) {
  2155. for (auto U : EV->users()) {
  2156. Instruction *I = cast<Instruction>(U);
  2157. if (I->getOpcode() == LLVMLShr) {
  2158. ConstantInt *CShift = dyn_cast<ConstantInt>(I->getOperand(1));
  2159. if (CShift && CShift->getLimitedValue() == 16)
  2160. result |= kHighWordUsed;
  2161. } else if (I->getOpcode() == LLVMTrunc &&
  2162. I->getType()->getPrimitiveSizeInBits() == 16) {
  2163. result |= kLowWordUsed;
  2164. } else {
  2165. // Assume whole dword is used, return 0
  2166. return 0;
  2167. }
  2168. if ((result & kLowHighWordMask) == kLowHighWordMask)
  2169. break;
  2170. }
  2171. }
  2172. return result;
  2173. }
  2174. static unsigned GetOffsetForCBExtractValue(ExtractValueInst *EV, bool bMinPrecision,
  2175. unsigned &lowHighWordUsage) {
  2176. DXASSERT(EV->getNumIndices() == 1, "otherwise, unexpected indices/type for extractvalue");
  2177. unsigned typeSize = 4;
  2178. unsigned bits = EV->getType()->getScalarSizeInBits();
  2179. if (bits == 64)
  2180. typeSize = 8;
  2181. else if (bits == 16 && !bMinPrecision)
  2182. typeSize = 2;
  2183. lowHighWordUsage = DetectLowAndHighWordUsage(EV);
  2184. return (EV->getIndices().front() * typeSize);
  2185. }
  2186. // Marks up to two CB uses for the case where only 16-bit type(s)
  2187. // are being used from lower or upper word of a tbuffer load,
  2188. // which is always 4 x 32 instead of 8 x 16, like cbuffer.
  2189. static void MarkCBUsesForExtractElement(
  2190. unsigned offset, FieldAnnotationByOffsetMap &fieldMap,
  2191. ExtractValueInst *EV, bool bMinPrecision) {
  2192. unsigned lowHighWordUsage = 0;
  2193. unsigned evOffset = GetOffsetForCBExtractValue(EV, bMinPrecision, lowHighWordUsage);
  2194. if (!lowHighWordUsage || 0 != (lowHighWordUsage & kLowWordUsed))
  2195. MarkCBUse(offset + evOffset, fieldMap);
  2196. if (lowHighWordUsage & kHighWordUsed)
  2197. MarkCBUse(offset + evOffset + 2, fieldMap);
  2198. }
  2199. static void CollectInPhiChain(PHINode *cbUser, unsigned offset,
  2200. std::unordered_set<Value *> &userSet,
  2201. FieldAnnotationByOffsetMap &fieldMap,
  2202. bool bMinPrecision) {
  2203. if (userSet.count(cbUser) > 0)
  2204. return;
  2205. userSet.insert(cbUser);
  2206. for (User *cbU : cbUser->users()) {
  2207. if (ExtractValueInst *EV = dyn_cast<ExtractValueInst>(cbU)) {
  2208. MarkCBUsesForExtractElement(offset, fieldMap, EV, bMinPrecision);
  2209. } else {
  2210. PHINode *phi = cast<PHINode>(cbU);
  2211. CollectInPhiChain(phi, offset, userSet, fieldMap, bMinPrecision);
  2212. }
  2213. }
  2214. }
  2215. static void CollectCBufferMemberUsage(Value *V,
  2216. FieldAnnotationByOffsetMap &legacyFieldMap,
  2217. FieldAnnotationByOffsetMap &newFieldMap,
  2218. hlsl::OP *hlslOP, bool bMinPrecision,
  2219. OffsetForValueMap &visited) {
  2220. for (auto U : V->users()) {
  2221. if (Constant *C = dyn_cast<Constant>(U)) {
  2222. CollectCBufferMemberUsage(C, legacyFieldMap, newFieldMap, hlslOP, bMinPrecision, visited);
  2223. } else if (LoadInst *LI = dyn_cast<LoadInst>(U)) {
  2224. CollectCBufferMemberUsage(U, legacyFieldMap, newFieldMap, hlslOP, bMinPrecision, visited);
  2225. } else if (CallInst *CI = dyn_cast<CallInst>(U)) {
  2226. if (hlslOP->IsDxilOpFuncCallInst(CI)) {
  2227. hlsl::OP::OpCode op = hlslOP->GetDxilOpFuncCallInst(CI);
  2228. if (op == DXIL::OpCode::CreateHandleForLib) {
  2229. CollectCBufferMemberUsage(U, legacyFieldMap, newFieldMap, hlslOP, bMinPrecision, visited);
  2230. } else if (op == DXIL::OpCode::AnnotateHandle) {
  2231. CollectCBufferMemberUsage(U, legacyFieldMap, newFieldMap, hlslOP,
  2232. bMinPrecision, visited);
  2233. } else if (op == DXIL::OpCode::CBufferLoadLegacy ||
  2234. op == DXIL::OpCode::BufferLoad) {
  2235. Value *resIndex = (op == DXIL::OpCode::CBufferLoadLegacy) ?
  2236. DxilInst_CBufferLoadLegacy(CI).get_regIndex() :
  2237. DxilInst_BufferLoad(CI).get_index();
  2238. unsigned offset = GetCBOffset(resIndex, visited) << 4;
  2239. for (User *cbU : U->users()) {
  2240. if (ExtractValueInst *EV = dyn_cast<ExtractValueInst>(cbU)) {
  2241. MarkCBUsesForExtractElement(offset, legacyFieldMap, EV, bMinPrecision);
  2242. } else {
  2243. PHINode *phi = cast<PHINode>(cbU);
  2244. std::unordered_set<Value *> userSet;
  2245. CollectInPhiChain(phi, offset, userSet, legacyFieldMap, bMinPrecision);
  2246. }
  2247. }
  2248. } else if (op == DXIL::OpCode::CBufferLoad) {
  2249. DxilInst_CBufferLoad cbload(CI);
  2250. Value *byteOffset = cbload.get_byteOffset();
  2251. unsigned offset = GetCBOffset(byteOffset, visited);
  2252. MarkCBUse(offset, newFieldMap);
  2253. }
  2254. }
  2255. }
  2256. }
  2257. }
  2258. void DxilLowerCreateHandleForLib::UpdateCBufferUsage() {
  2259. DxilTypeSystem &TypeSys = m_DM->GetTypeSystem();
  2260. hlsl::OP *hlslOP = m_DM->GetOP();
  2261. const DataLayout &DL = m_DM->GetModule()->getDataLayout();
  2262. const auto &CBuffers = m_DM->GetCBuffers();
  2263. OffsetForValueMap visited;
  2264. SmallVector<GlobalVariable*, 4> CBufferVars;
  2265. // Collect cbuffers
  2266. for (auto it = CBuffers.begin(); it != CBuffers.end(); it++) {
  2267. DxilCBuffer *CB = it->get();
  2268. GlobalVariable *GV = dyn_cast<GlobalVariable>(CB->GetGlobalSymbol());
  2269. if (GV == nullptr)
  2270. continue;
  2271. CBufferVars.push_back(GV);
  2272. }
  2273. // Collect tbuffers
  2274. for (auto &it : m_DM->GetSRVs()) {
  2275. if (it->GetKind() != DXIL::ResourceKind::TBuffer)
  2276. continue;
  2277. GlobalVariable *GV = dyn_cast<GlobalVariable>(it->GetGlobalSymbol());
  2278. if (GV == nullptr)
  2279. continue;
  2280. CBufferVars.push_back(GV);
  2281. }
  2282. for (auto GV : CBufferVars) {
  2283. Type *ElemTy = GV->getType()->getPointerElementType();
  2284. ElemTy = dxilutil::StripArrayTypes(ElemTy, nullptr);
  2285. StructType *ST = cast<StructType>(ElemTy);
  2286. DxilStructAnnotation *SA = TypeSys.GetStructAnnotation(ST);
  2287. if (SA == nullptr)
  2288. continue;
  2289. // If elements < 2, it's used if it exists.
  2290. // Only old-style cbuffer { ... } will have more than one member, and
  2291. // old-style cbuffers are the only ones that report usage per member.
  2292. if (ST->getStructNumElements() < 2) {
  2293. continue;
  2294. }
  2295. // Create offset maps for legacy layout and new compact layout, while resetting usage flags
  2296. const StructLayout *SL = DL.getStructLayout(ST);
  2297. FieldAnnotationByOffsetMap legacyFieldMap, newFieldMap;
  2298. for (unsigned i = 0; i < SA->GetNumFields(); ++i) {
  2299. DxilFieldAnnotation &FA = SA->GetFieldAnnotation(i);
  2300. FA.SetCBVarUsed(false);
  2301. legacyFieldMap[FA.GetCBufferOffset()] = &FA;
  2302. newFieldMap[(unsigned)SL->getElementOffset(i)] = &FA;
  2303. }
  2304. CollectCBufferMemberUsage(GV, legacyFieldMap, newFieldMap, hlslOP, m_DM->GetUseMinPrecision(), visited);
  2305. }
  2306. }
  2307. void DxilLowerCreateHandleForLib::SetNonUniformIndexForDynamicResource(
  2308. DxilModule &DM) {
  2309. hlsl::OP *hlslOP = DM.GetOP();
  2310. Value *TrueVal = hlslOP->GetI1Const(true);
  2311. for (auto it : hlslOP->GetOpFuncList(DXIL::OpCode::CreateHandleFromHeap)) {
  2312. Function *F = it.second;
  2313. if (!F)
  2314. continue;
  2315. for (User *U : F->users()) {
  2316. CallInst *CI = cast<CallInst>(U);
  2317. if (!DxilMDHelper::IsMarkedNonUniform(CI))
  2318. continue;
  2319. // Set NonUniform to be true.
  2320. CI->setOperand(DxilInst_CreateHandleFromHeap::arg_nonUniformIndex,
  2321. TrueVal);
  2322. // Clear nonUniform metadata.
  2323. CI->setMetadata(DxilMDHelper::kDxilNonUniformAttributeMDName, nullptr);
  2324. }
  2325. }
  2326. }
  2327. char DxilLowerCreateHandleForLib::ID = 0;
  2328. ModulePass *llvm::createDxilLowerCreateHandleForLibPass() {
  2329. return new DxilLowerCreateHandleForLib();
  2330. }
  2331. INITIALIZE_PASS_BEGIN(DxilLowerCreateHandleForLib, "hlsl-dxil-lower-handle-for-lib", "DXIL Lower createHandleForLib", false, false)
  2332. INITIALIZE_PASS_DEPENDENCY(DxilValueCache)
  2333. INITIALIZE_PASS_END(DxilLowerCreateHandleForLib, "hlsl-dxil-lower-handle-for-lib", "DXIL Lower createHandleForLib", false, false)
  2334. class DxilAllocateResourcesForLib : public ModulePass {
  2335. private:
  2336. RemapEntryCollection m_rewrites;
  2337. public:
  2338. static char ID; // Pass identification, replacement for typeid
  2339. explicit DxilAllocateResourcesForLib() : ModulePass(ID), m_AutoBindingSpace(UINT_MAX) {}
  2340. void applyOptions(PassOptions O) override {
  2341. GetPassOptionUInt32(O, "auto-binding-space", &m_AutoBindingSpace, UINT_MAX);
  2342. }
  2343. const char *getPassName() const override { return "DXIL Condense Resources"; }
  2344. bool runOnModule(Module &M) override {
  2345. DxilModule &DM = M.GetOrCreateDxilModule();
  2346. // Must specify a default space, and must apply to library.
  2347. // Use DxilCondenseResources instead for shaders.
  2348. if ((m_AutoBindingSpace == UINT_MAX) || !DM.GetShaderModel()->IsLib())
  2349. return false;
  2350. bool hasResource = DM.GetCBuffers().size() ||
  2351. DM.GetUAVs().size() || DM.GetSRVs().size() || DM.GetSamplers().size();
  2352. if (hasResource) {
  2353. DM.SetAutoBindingSpace(m_AutoBindingSpace);
  2354. DxilResourceRegisterAllocator ResourceRegisterAllocator;
  2355. ResourceRegisterAllocator.AllocateRegisters(DM);
  2356. }
  2357. return true;
  2358. }
  2359. private:
  2360. uint32_t m_AutoBindingSpace;
  2361. };
  2362. char DxilAllocateResourcesForLib::ID = 0;
  2363. ModulePass *llvm::createDxilAllocateResourcesForLibPass() {
  2364. return new DxilAllocateResourcesForLib();
  2365. }
  2366. INITIALIZE_PASS(DxilAllocateResourcesForLib, "hlsl-dxil-allocate-resources-for-lib", "DXIL Allocate Resources For Library", false, false)