DxilDbgValueToDbgDeclare.cpp 23 KB

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