DxilDbgValueToDbgDeclare.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // DxilDbgValueToDbgDeclare.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. // Converts calls to llvm.dbg.value to llvm.dbg.declare + alloca + stores. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #include <algorithm>
  12. #include <memory>
  13. #include <map>
  14. #include <unordered_map>
  15. #include <utility>
  16. #include "dxc/DXIL/DxilConstants.h"
  17. #include "dxc/DXIL/DxilResourceBase.h"
  18. #include "dxc/DXIL/DxilModule.h"
  19. #include "dxc/DxilPIXPasses/DxilPIXPasses.h"
  20. #include "llvm/IR/DebugInfo.h"
  21. #include "llvm/IR/DebugInfoMetadata.h"
  22. #include "llvm/IR/Instructions.h"
  23. #include "llvm/IR/IntrinsicInst.h"
  24. #include "llvm/IR/Intrinsics.h"
  25. #include "llvm/IR/IRBuilder.h"
  26. #include "llvm/IR/Module.h"
  27. #include "llvm/Pass.h"
  28. #include "PixPassHelpers.h"
  29. #define DEBUG_TYPE "dxil-dbg-value-to-dbg-declare"
  30. namespace {
  31. using OffsetInBits = unsigned;
  32. using SizeInBits = unsigned;
  33. // OffsetManager is used to map between "packed" and aligned offsets.
  34. //
  35. // For example, the aligned offsets for a struct [float, half, int, double]
  36. // will be {0, 32, 64, 128} (assuming 32 bit alignments for ints, and 64
  37. // bit for doubles), while the packed offsets will be {0, 32, 48, 80}.
  38. //
  39. // This mapping makes it easier to deal with llvm.dbg.values whose value
  40. // operand does not match exactly the Variable operand's type.
  41. class OffsetManager
  42. {
  43. public:
  44. OffsetManager() = default;
  45. // AlignTo aligns the current aligned offset to Ty's natural alignment.
  46. void AlignTo(
  47. llvm::DIType *Ty
  48. )
  49. {
  50. // This is some magic arithmetic. Here's an example:
  51. //
  52. // Assume the natural alignment for Ty is 16 bits. Then
  53. //
  54. // AlignMask = 0x0000000f(15)
  55. //
  56. // If the current aligned offset is
  57. //
  58. // CurrentAlignedOffset = 0x00000048(72)
  59. //
  60. // Then
  61. //
  62. // T = CurrentAlignOffset + AlignMask = 0x00000057(87)
  63. //
  64. // Which mean
  65. //
  66. // T & ~CurrentOffset = 0x00000050(80)
  67. //
  68. // is the aligned offset where Ty should be placed.
  69. unsigned AlignMask = Ty->getAlignInBits();
  70. if (AlignMask == 0)
  71. {
  72. if (auto *DerivedTy = llvm::dyn_cast<llvm::DIDerivedType>(Ty)) {
  73. const llvm::DITypeIdentifierMap EmptyMap;
  74. switch (DerivedTy->getTag()) {
  75. case llvm::dwarf::DW_TAG_restrict_type:
  76. case llvm::dwarf::DW_TAG_reference_type:
  77. case llvm::dwarf::DW_TAG_const_type:
  78. case llvm::dwarf::DW_TAG_typedef:
  79. AlignMask = DerivedTy->getBaseType().resolve(EmptyMap)->getAlignInBits();
  80. assert(AlignMask != 0);
  81. }
  82. }
  83. }
  84. AlignMask = AlignMask - 1;
  85. m_CurrentAlignedOffset =
  86. (m_CurrentAlignedOffset + AlignMask) & ~AlignMask;
  87. }
  88. // Add is used to "add" an aggregate element (struct field, array element)
  89. // at the current aligned/packed offsets, bumping them by Ty's size.
  90. OffsetInBits Add(
  91. llvm::DIBasicType *Ty
  92. )
  93. {
  94. m_PackedOffsetToAlignedOffset[m_CurrentPackedOffset] = m_CurrentAlignedOffset;
  95. m_AlignedOffsetToPackedOffset[m_CurrentAlignedOffset] = m_CurrentPackedOffset;
  96. const OffsetInBits Ret = m_CurrentAlignedOffset;
  97. m_CurrentPackedOffset += Ty->getSizeInBits();
  98. m_CurrentAlignedOffset += Ty->getSizeInBits();
  99. return Ret;
  100. }
  101. // AlignToAndAddUnhandledType is used for error handling when Ty
  102. // could not be handled by the transformation. This is a best-effort
  103. // way to continue the pass by ignoring the current type and hoping
  104. // that adding Ty as a blob other fields/elements added will land
  105. // in the proper offset.
  106. void AlignToAndAddUnhandledType(
  107. llvm::DIType *Ty
  108. )
  109. {
  110. AlignTo(Ty);
  111. m_CurrentPackedOffset += Ty->getSizeInBits();
  112. m_CurrentAlignedOffset += Ty->getSizeInBits();
  113. }
  114. void AddResourceType(llvm::DIType *Ty)
  115. {
  116. m_PackedOffsetToAlignedOffset[m_CurrentPackedOffset] =
  117. m_CurrentAlignedOffset;
  118. m_AlignedOffsetToPackedOffset[m_CurrentAlignedOffset] =
  119. m_CurrentPackedOffset;
  120. m_CurrentPackedOffset += Ty->getSizeInBits();
  121. m_CurrentAlignedOffset += Ty->getSizeInBits();
  122. }
  123. bool GetAlignedOffsetFromPackedOffset(
  124. OffsetInBits PackedOffset,
  125. OffsetInBits *AlignedOffset
  126. ) const
  127. {
  128. return GetOffsetWithMap(
  129. m_PackedOffsetToAlignedOffset,
  130. PackedOffset,
  131. AlignedOffset);
  132. }
  133. bool GetPackedOffsetFromAlignedOffset(
  134. OffsetInBits AlignedOffset,
  135. OffsetInBits *PackedOffset
  136. ) const
  137. {
  138. return GetOffsetWithMap(
  139. m_AlignedOffsetToPackedOffset,
  140. AlignedOffset,
  141. PackedOffset);
  142. }
  143. OffsetInBits GetCurrentPackedOffset() const
  144. {
  145. return m_CurrentPackedOffset;
  146. }
  147. OffsetInBits GetCurrentAlignedOffset() const
  148. {
  149. return m_CurrentAlignedOffset;
  150. }
  151. private:
  152. OffsetInBits m_CurrentPackedOffset = 0;
  153. OffsetInBits m_CurrentAlignedOffset = 0;
  154. using OffsetMap = std::unordered_map<OffsetInBits, OffsetInBits>;
  155. OffsetMap m_PackedOffsetToAlignedOffset;
  156. OffsetMap m_AlignedOffsetToPackedOffset;
  157. static bool GetOffsetWithMap(
  158. const OffsetMap &Map,
  159. OffsetInBits SrcOffset,
  160. OffsetInBits *DstOffset
  161. )
  162. {
  163. auto it = Map.find(SrcOffset);
  164. if (it == Map.end())
  165. {
  166. return false;
  167. }
  168. *DstOffset = it->second;
  169. return true;
  170. }
  171. };
  172. // VariableRegisters contains the logic for traversing a DIType T and
  173. // creating AllocaInsts that map back to a specific offset within T.
  174. class VariableRegisters
  175. {
  176. public:
  177. VariableRegisters(
  178. llvm::DebugLoc const &,
  179. llvm::DIVariable *Variable,
  180. llvm::Module *M
  181. );
  182. llvm::AllocaInst *GetRegisterForAlignedOffset(
  183. OffsetInBits AlignedOffset
  184. ) const;
  185. const OffsetManager& GetOffsetManager() const
  186. {
  187. return m_Offsets;
  188. }
  189. private:
  190. void PopulateAllocaMap(
  191. llvm::DIType *Ty
  192. );
  193. void PopulateAllocaMap_BasicType(llvm::DIBasicType *Ty
  194. );
  195. void PopulateAllocaMap_ArrayType(llvm::DICompositeType *Ty
  196. );
  197. void PopulateAllocaMap_StructType(llvm::DICompositeType *Ty
  198. );
  199. llvm::DILocation *GetVariableLocation() const;
  200. llvm::Value *GetMetadataAsValue(
  201. llvm::Metadata *M
  202. ) const;
  203. llvm::DIExpression *GetDIExpression(
  204. llvm::DIType *Ty,
  205. OffsetInBits Offset
  206. ) const;
  207. llvm::DebugLoc const &m_dbgLoc;
  208. llvm::DIVariable *m_Variable = nullptr;
  209. llvm::IRBuilder<> m_B;
  210. llvm::Function *m_DbgDeclareFn = nullptr;
  211. OffsetManager m_Offsets;
  212. std::unordered_map<OffsetInBits, llvm::AllocaInst *> m_AlignedOffsetToAlloca;
  213. };
  214. class DxilDbgValueToDbgDeclare : public llvm::ModulePass {
  215. public:
  216. static char ID;
  217. DxilDbgValueToDbgDeclare() : llvm::ModulePass(ID)
  218. {
  219. }
  220. bool runOnModule(
  221. llvm::Module &M
  222. ) override;
  223. private:
  224. void handleDbgValue(
  225. llvm::Module &M,
  226. llvm::DbgValueInst *DbgValue);
  227. std::unordered_map<llvm::DIVariable *, std::unique_ptr<VariableRegisters>> m_Registers;
  228. };
  229. } // namespace
  230. char DxilDbgValueToDbgDeclare::ID = 0;
  231. struct ValueAndOffset
  232. {
  233. llvm::Value *m_V;
  234. OffsetInBits m_PackedOffset;
  235. };
  236. // SplitValue splits an llvm::Value into possibly multiple
  237. // scalar Values. Those scalar values will later be "stored"
  238. // into their corresponding register.
  239. static OffsetInBits SplitValue(
  240. llvm::Value *V,
  241. OffsetInBits CurrentOffset,
  242. std::vector<ValueAndOffset> *Values,
  243. llvm::IRBuilder<>& B
  244. )
  245. {
  246. auto *VTy = V->getType();
  247. if (auto *ArrTy = llvm::dyn_cast<llvm::ArrayType>(VTy))
  248. {
  249. for (unsigned i = 0; i < ArrTy->getNumElements(); ++i)
  250. {
  251. CurrentOffset = SplitValue(
  252. B.CreateExtractValue(V, {i}),
  253. CurrentOffset,
  254. Values,
  255. B);
  256. }
  257. }
  258. else if (auto *StTy = llvm::dyn_cast<llvm::StructType>(VTy))
  259. {
  260. for (unsigned i = 0; i < StTy->getNumElements(); ++i)
  261. {
  262. CurrentOffset = SplitValue(
  263. B.CreateExtractValue(V, {i}),
  264. CurrentOffset,
  265. Values,
  266. B);
  267. }
  268. }
  269. else if (auto *VecTy = llvm::dyn_cast<llvm::VectorType>(VTy))
  270. {
  271. for (unsigned i = 0; i < VecTy->getNumElements(); ++i)
  272. {
  273. CurrentOffset = SplitValue(
  274. B.CreateExtractElement(V, i),
  275. CurrentOffset,
  276. Values,
  277. B);
  278. }
  279. }
  280. else
  281. {
  282. assert(VTy->isFloatTy() || VTy->isDoubleTy() || VTy->isHalfTy() ||
  283. VTy->isIntegerTy(32) || VTy->isIntegerTy(64) || VTy->isIntegerTy(16));
  284. Values->emplace_back(ValueAndOffset{V, CurrentOffset});
  285. CurrentOffset += VTy->getScalarSizeInBits();
  286. }
  287. return CurrentOffset;
  288. }
  289. // A more convenient version of SplitValue.
  290. static std::vector<ValueAndOffset> SplitValue(
  291. llvm::Value* V,
  292. OffsetInBits CurrentOffset,
  293. llvm::IRBuilder<>& B
  294. )
  295. {
  296. std::vector<ValueAndOffset> Ret;
  297. SplitValue(V, CurrentOffset, &Ret, B);
  298. return Ret;
  299. }
  300. // Convenient helper for parsing a DIExpression's offset.
  301. static OffsetInBits GetAlignedOffsetFromDIExpression(
  302. llvm::DIExpression *Exp
  303. )
  304. {
  305. if (!Exp->isBitPiece())
  306. {
  307. return 0;
  308. }
  309. return Exp->getBitPieceOffset();
  310. }
  311. bool DxilDbgValueToDbgDeclare::runOnModule(
  312. llvm::Module &M
  313. )
  314. {
  315. auto *DbgValueFn =
  316. llvm::Intrinsic::getDeclaration(&M, llvm::Intrinsic::dbg_value);
  317. bool Changed = false;
  318. for (auto it = DbgValueFn->user_begin(); it != DbgValueFn->user_end(); )
  319. {
  320. llvm::User *User = *it++;
  321. if (auto *DbgValue = llvm::dyn_cast<llvm::DbgValueInst>(User))
  322. {
  323. llvm::Value *V = DbgValue->getValue();
  324. if (PIXPassHelpers::IsAllocateRayQueryInstruction(V)) {
  325. continue;
  326. }
  327. Changed = true;
  328. handleDbgValue(M, DbgValue);
  329. DbgValue->eraseFromParent();
  330. }
  331. }
  332. return Changed;
  333. }
  334. void DxilDbgValueToDbgDeclare::handleDbgValue(
  335. llvm::Module& M,
  336. llvm::DbgValueInst* DbgValue)
  337. {
  338. llvm::Value *V = DbgValue->getValue();
  339. if (V == nullptr) {
  340. // The metadata contained a null Value, so we ignore it. This
  341. // seems to be a dxcompiler bug.
  342. return;
  343. }
  344. if (auto *PtrTy = llvm::dyn_cast<llvm::PointerType>(V->getType())) {
  345. return;
  346. }
  347. llvm::DIVariable *Variable = DbgValue->getVariable();
  348. auto &Register = m_Registers[Variable];
  349. if (Register == nullptr)
  350. {
  351. Register.reset(new VariableRegisters(DbgValue->getDebugLoc(), Variable, &M));
  352. }
  353. // Convert the offset from DbgValue's expression to a packed
  354. // offset, which we'll need in order to determine the (packed)
  355. // offset of each scalar Value in DbgValue.
  356. llvm::DIExpression* expression = DbgValue->getExpression();
  357. const OffsetInBits AlignedOffsetFromVar =
  358. GetAlignedOffsetFromDIExpression(expression);
  359. OffsetInBits PackedOffsetFromVar;
  360. const OffsetManager& Offsets = Register->GetOffsetManager();
  361. if (!Offsets.GetPackedOffsetFromAlignedOffset(AlignedOffsetFromVar,
  362. &PackedOffsetFromVar))
  363. {
  364. // todo: output geometry for GS
  365. return;
  366. }
  367. const OffsetInBits InitialOffset = PackedOffsetFromVar;
  368. llvm::IRBuilder<> B(DbgValue->getCalledFunction()->getContext());
  369. auto* instruction = llvm::dyn_cast<llvm::Instruction>(V);
  370. if (instruction != nullptr) {
  371. instruction = instruction->getNextNode();
  372. if (instruction != nullptr) {
  373. B.SetInsertPoint(instruction);
  374. B.SetCurrentDebugLocation(llvm::DebugLoc());
  375. auto *Zero = B.getInt32(0);
  376. // Now traverse a list of pairs {Scalar Value, InitialOffset + Offset}.
  377. // InitialOffset is the offset from DbgValue's expression (i.e., the
  378. // offset from the Variable's start), and Offset is the Scalar Value's
  379. // packed offset from DbgValue's value.
  380. for (const ValueAndOffset &VO : SplitValue(V, InitialOffset, B)) {
  381. OffsetInBits AlignedOffset;
  382. if (!Offsets.GetAlignedOffsetFromPackedOffset(VO.m_PackedOffset,
  383. &AlignedOffset)) {
  384. continue;
  385. }
  386. auto *AllocaInst = Register->GetRegisterForAlignedOffset(AlignedOffset);
  387. if (AllocaInst == nullptr) {
  388. assert(!"Failed to find alloca for var[offset]");
  389. continue;
  390. }
  391. if (AllocaInst->getAllocatedType()->getArrayElementType() ==
  392. VO.m_V->getType()) {
  393. auto *GEP = B.CreateGEP(AllocaInst, {Zero, Zero});
  394. B.CreateStore(VO.m_V, GEP);
  395. }
  396. }
  397. }
  398. }
  399. }
  400. llvm::AllocaInst *VariableRegisters::GetRegisterForAlignedOffset(
  401. OffsetInBits Offset
  402. ) const
  403. {
  404. auto it = m_AlignedOffsetToAlloca.find(Offset);
  405. if (it == m_AlignedOffsetToAlloca.end())
  406. {
  407. return nullptr;
  408. }
  409. return it->second;
  410. }
  411. #ifndef NDEBUG
  412. // DITypePeelTypeAlias peels const, typedef, and other alias types off of Ty,
  413. // returning the unalised type.
  414. static llvm::DIType *DITypePeelTypeAlias(
  415. llvm::DIType* Ty
  416. )
  417. {
  418. if (auto *DerivedTy = llvm::dyn_cast<llvm::DIDerivedType>(Ty))
  419. {
  420. const llvm::DITypeIdentifierMap EmptyMap;
  421. switch (DerivedTy->getTag())
  422. {
  423. case llvm::dwarf::DW_TAG_restrict_type:
  424. case llvm::dwarf::DW_TAG_reference_type:
  425. case llvm::dwarf::DW_TAG_const_type:
  426. case llvm::dwarf::DW_TAG_typedef:
  427. case llvm::dwarf::DW_TAG_pointer_type:
  428. case llvm::dwarf::DW_TAG_member:
  429. return DITypePeelTypeAlias(
  430. DerivedTy->getBaseType().resolve(EmptyMap));
  431. }
  432. }
  433. return Ty;
  434. }
  435. #endif // NDEBUG
  436. VariableRegisters::VariableRegisters(
  437. llvm::DebugLoc const & dbgLoc,
  438. llvm::DIVariable *Variable,
  439. llvm::Module *M)
  440. : m_dbgLoc(dbgLoc)
  441. ,m_Variable(Variable)
  442. , m_B(M->GetOrCreateDxilModule().GetEntryFunction()->getEntryBlock().begin())
  443. , m_DbgDeclareFn(llvm::Intrinsic::getDeclaration(
  444. M, llvm::Intrinsic::dbg_declare))
  445. {
  446. const llvm::DITypeIdentifierMap EmptyMap;
  447. llvm::DIType* Ty = m_Variable->getType().resolve(EmptyMap);
  448. PopulateAllocaMap(Ty);
  449. assert(m_Offsets.GetCurrentPackedOffset() ==
  450. DITypePeelTypeAlias(Ty)->getSizeInBits());
  451. }
  452. void VariableRegisters::PopulateAllocaMap(
  453. llvm::DIType *Ty
  454. )
  455. {
  456. if (auto *DerivedTy = llvm::dyn_cast<llvm::DIDerivedType>(Ty))
  457. {
  458. const llvm::DITypeIdentifierMap EmptyMap;
  459. switch (DerivedTy->getTag())
  460. {
  461. default:
  462. assert(!"Unhandled DIDerivedType");
  463. m_Offsets.AlignToAndAddUnhandledType(DerivedTy);
  464. return;
  465. case llvm::dwarf::DW_TAG_arg_variable: // "this" pointer
  466. case llvm::dwarf::DW_TAG_pointer_type: // "this" pointer
  467. case llvm::dwarf::DW_TAG_restrict_type:
  468. case llvm::dwarf::DW_TAG_reference_type:
  469. case llvm::dwarf::DW_TAG_const_type:
  470. case llvm::dwarf::DW_TAG_typedef:
  471. case llvm::dwarf::DW_TAG_member:
  472. PopulateAllocaMap(
  473. DerivedTy->getBaseType().resolve(EmptyMap));
  474. return;
  475. case llvm::dwarf::DW_TAG_subroutine_type:
  476. //ignore member functions.
  477. return;
  478. }
  479. }
  480. else if (auto *CompositeTy = llvm::dyn_cast<llvm::DICompositeType>(Ty))
  481. {
  482. switch (CompositeTy->getTag())
  483. {
  484. default:
  485. assert(!"Unhandled DICompositeType");
  486. m_Offsets.AlignToAndAddUnhandledType(CompositeTy);
  487. return;
  488. case llvm::dwarf::DW_TAG_array_type:
  489. PopulateAllocaMap_ArrayType(CompositeTy);
  490. return;
  491. case llvm::dwarf::DW_TAG_structure_type:
  492. case llvm::dwarf::DW_TAG_class_type:
  493. PopulateAllocaMap_StructType(CompositeTy);
  494. return;
  495. }
  496. }
  497. else if (auto *BasicTy = llvm::dyn_cast<llvm::DIBasicType>(Ty))
  498. {
  499. PopulateAllocaMap_BasicType(BasicTy);
  500. return;
  501. }
  502. assert(!"Unhandled DIType");
  503. m_Offsets.AlignToAndAddUnhandledType(Ty);
  504. }
  505. static llvm::Type* GetLLVMTypeFromDIBasicType(
  506. llvm::IRBuilder<> &B,
  507. llvm::DIBasicType* Ty
  508. )
  509. {
  510. const SizeInBits Size = Ty->getSizeInBits();
  511. switch (Ty->getEncoding())
  512. {
  513. default:
  514. break;
  515. case llvm::dwarf::DW_ATE_boolean:
  516. case llvm::dwarf::DW_ATE_signed:
  517. case llvm::dwarf::DW_ATE_unsigned:
  518. switch(Size)
  519. {
  520. case 16:
  521. return B.getInt16Ty();
  522. case 32:
  523. return B.getInt32Ty();
  524. case 64:
  525. return B.getInt64Ty();
  526. }
  527. break;
  528. case llvm::dwarf::DW_ATE_float:
  529. switch(Size)
  530. {
  531. case 16:
  532. return B.getHalfTy();
  533. case 32:
  534. return B.getFloatTy();
  535. case 64:
  536. return B.getDoubleTy();
  537. }
  538. break;
  539. }
  540. return nullptr;
  541. }
  542. void VariableRegisters::PopulateAllocaMap_BasicType(
  543. llvm::DIBasicType *Ty
  544. )
  545. {
  546. llvm::Type* AllocaElementTy = GetLLVMTypeFromDIBasicType(m_B, Ty);
  547. assert(AllocaElementTy != nullptr);
  548. if (AllocaElementTy == nullptr)
  549. {
  550. return;
  551. }
  552. const OffsetInBits AlignedOffset = m_Offsets.Add(Ty);
  553. llvm::Type *AllocaTy = llvm::ArrayType::get(AllocaElementTy, 1);
  554. llvm::AllocaInst *&Alloca = m_AlignedOffsetToAlloca[AlignedOffset];
  555. Alloca = m_B.CreateAlloca(AllocaTy, m_B.getInt32(0));
  556. Alloca->setDebugLoc(llvm::DebugLoc());
  557. auto *Storage = GetMetadataAsValue(llvm::ValueAsMetadata::get(Alloca));
  558. auto *Variable = GetMetadataAsValue(m_Variable);
  559. auto *Expression = GetMetadataAsValue(GetDIExpression(Ty, AlignedOffset));
  560. auto *DbgDeclare = m_B.CreateCall(
  561. m_DbgDeclareFn,
  562. {Storage, Variable, Expression});
  563. DbgDeclare->setDebugLoc(m_dbgLoc);
  564. }
  565. static unsigned NumArrayElements(
  566. llvm::DICompositeType *Array
  567. )
  568. {
  569. if (Array->getElements().size() == 0)
  570. {
  571. return 0;
  572. }
  573. unsigned NumElements = 1;
  574. for (llvm::DINode *N : Array->getElements())
  575. {
  576. if (auto* Subrange = llvm::dyn_cast<llvm::DISubrange>(N))
  577. {
  578. NumElements *= Subrange->getCount();
  579. }
  580. else
  581. {
  582. assert(!"Unhandled array element");
  583. return 0;
  584. }
  585. }
  586. return NumElements;
  587. }
  588. void VariableRegisters::PopulateAllocaMap_ArrayType(
  589. llvm::DICompositeType* Ty
  590. )
  591. {
  592. unsigned NumElements = NumArrayElements(Ty);
  593. if (NumElements == 0)
  594. {
  595. m_Offsets.AlignToAndAddUnhandledType(Ty);
  596. return;
  597. }
  598. const SizeInBits ArraySizeInBits = Ty->getSizeInBits();
  599. (void)ArraySizeInBits;
  600. const llvm::DITypeIdentifierMap EmptyMap;
  601. llvm::DIType *ElementTy = Ty->getBaseType().resolve(EmptyMap);
  602. assert(ArraySizeInBits % NumElements == 0 &&
  603. " invalid DIArrayType"
  604. " - Size is not a multiple of NumElements");
  605. // After aligning the current aligned offset to ElementTy's natural
  606. // alignment, the current aligned offset must match Ty's offset
  607. // in bits.
  608. m_Offsets.AlignTo(ElementTy);
  609. for (unsigned i = 0; i < NumElements; ++i)
  610. {
  611. // This is only needed if ElementTy's size is not a multiple of
  612. // its natural alignment.
  613. m_Offsets.AlignTo(ElementTy);
  614. PopulateAllocaMap(ElementTy);
  615. }
  616. }
  617. // SortMembers traverses all of Ty's members and returns them sorted
  618. // by their offset from Ty's start. Returns true if the function succeeds
  619. // and false otherwise.
  620. static bool SortMembers(
  621. llvm::DICompositeType* Ty,
  622. std::map<OffsetInBits, llvm::DIDerivedType*> *SortedMembers
  623. )
  624. {
  625. auto Elements = Ty->getElements();
  626. if (Elements.begin() == Elements.end())
  627. {
  628. return false;
  629. }
  630. for (auto* Element : Elements)
  631. {
  632. switch (Element->getTag())
  633. {
  634. case llvm::dwarf::DW_TAG_member: {
  635. if (auto* Member = llvm::dyn_cast<llvm::DIDerivedType>(Element))
  636. {
  637. if (Member->getSizeInBits()) {
  638. auto it = SortedMembers->emplace(std::make_pair(Member->getOffsetInBits(), Member));
  639. (void)it;
  640. assert(it.second &&
  641. "Invalid DIStructType"
  642. " - members with the same offset -- are unions possible?");
  643. }
  644. break;
  645. }
  646. assert(!"member is not a Member");
  647. return false;
  648. }
  649. case llvm::dwarf::DW_TAG_subprogram: {
  650. if (auto* SubProgram = llvm::dyn_cast<llvm::DISubprogram>(Element)) {
  651. continue;
  652. }
  653. assert(!"DISubprogram not understood");
  654. return false;
  655. }
  656. case llvm::dwarf::DW_TAG_inheritance: {
  657. if (auto* Member = llvm::dyn_cast<llvm::DIDerivedType>(Element))
  658. {
  659. auto it = SortedMembers->emplace(
  660. std::make_pair(Member->getOffsetInBits(), Member));
  661. (void)it;
  662. assert(it.second &&
  663. "Invalid DIStructType"
  664. " - members with the same offset -- are unions possible?");
  665. }
  666. continue;
  667. }
  668. default:
  669. assert(!"Unhandled field type in DIStructType");
  670. return false;
  671. }
  672. }
  673. return true;
  674. }
  675. static bool IsResourceObject(llvm::DIDerivedType *DT) {
  676. const llvm::DITypeIdentifierMap EmptyMap;
  677. auto *BT = DT->getBaseType().resolve(EmptyMap);
  678. if (auto *CompositeTy = llvm::dyn_cast<llvm::DICompositeType>(BT)) {
  679. // Resource variables (e.g. TextureCube) are composite types but have no elements:
  680. if (CompositeTy->getElements().begin() ==
  681. CompositeTy->getElements().end()) {
  682. auto name = CompositeTy->getName();
  683. auto openTemplateListMarker = name.find_first_of('<');
  684. if (openTemplateListMarker != llvm::StringRef::npos) {
  685. auto hlslType = name.substr(0, openTemplateListMarker);
  686. for (int i = static_cast<int>(hlsl::DXIL::ResourceKind::Invalid) + 1;
  687. i < static_cast<int>(hlsl::DXIL::ResourceKind::NumEntries);
  688. ++i) {
  689. if (hlslType == hlsl::GetResourceKindName(static_cast<hlsl::DXIL::ResourceKind>(i))) {
  690. return true;
  691. }
  692. }
  693. }
  694. }
  695. }
  696. return false;
  697. }
  698. void VariableRegisters::PopulateAllocaMap_StructType(
  699. llvm::DICompositeType *Ty
  700. )
  701. {
  702. std::map<OffsetInBits, llvm::DIDerivedType*> SortedMembers;
  703. if (!SortMembers(Ty, &SortedMembers))
  704. {
  705. m_Offsets.AlignToAndAddUnhandledType(Ty);
  706. return;
  707. }
  708. m_Offsets.AlignTo(Ty);
  709. const OffsetInBits StructStart = m_Offsets.GetCurrentAlignedOffset();
  710. (void)StructStart;
  711. const llvm::DITypeIdentifierMap EmptyMap;
  712. for (auto OffsetAndMember : SortedMembers)
  713. {
  714. // Align the offsets to the member's type natural alignment. This
  715. // should always result in the current aligned offset being the
  716. // same as the member's offset.
  717. m_Offsets.AlignTo(OffsetAndMember.second);
  718. assert(m_Offsets.GetCurrentAlignedOffset() ==
  719. StructStart + OffsetAndMember.first &&
  720. "Offset mismatch in DIStructType");
  721. if (IsResourceObject(OffsetAndMember.second)) {
  722. m_Offsets.AddResourceType(OffsetAndMember.second);
  723. } else {
  724. PopulateAllocaMap(
  725. OffsetAndMember.second->getBaseType().resolve(EmptyMap));
  726. }
  727. }
  728. }
  729. llvm::DILocation *VariableRegisters::GetVariableLocation() const
  730. {
  731. const unsigned DefaultColumn = 1;
  732. return llvm::DILocation::get(
  733. m_B.getContext(),
  734. m_Variable->getLine(),
  735. DefaultColumn,
  736. m_Variable->getScope());
  737. }
  738. llvm::Value *VariableRegisters::GetMetadataAsValue(
  739. llvm::Metadata *M
  740. ) const
  741. {
  742. return llvm::MetadataAsValue::get(m_B.getContext(), M);
  743. }
  744. llvm::DIExpression *VariableRegisters::GetDIExpression(
  745. llvm::DIType *Ty,
  746. OffsetInBits Offset
  747. ) const
  748. {
  749. llvm::SmallVector<uint64_t, 3> ExpElements;
  750. if (Offset != 0)
  751. {
  752. ExpElements.emplace_back(llvm::dwarf::DW_OP_bit_piece);
  753. ExpElements.emplace_back(Offset);
  754. ExpElements.emplace_back(Ty->getSizeInBits());
  755. }
  756. return llvm::DIExpression::get(m_B.getContext(), ExpElements);
  757. }
  758. using namespace llvm;
  759. INITIALIZE_PASS(DxilDbgValueToDbgDeclare, DEBUG_TYPE,
  760. "Converts calls to dbg.value to dbg.declare + stores to new virtual registers",
  761. false, false)
  762. ModulePass *llvm::createDxilDbgValueToDbgDeclarePass() {
  763. return new DxilDbgValueToDbgDeclare();
  764. }