DxilPreparePasses.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // DxilPreparePasses.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. // Passes to prepare DxilModule. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #include "dxc/HLSL/DxilGenerationPass.h"
  12. #include "dxc/DXIL/DxilOperations.h"
  13. #include "dxc/HLSL/HLOperations.h"
  14. #include "dxc/DXIL/DxilModule.h"
  15. #include "dxc/Support/Global.h"
  16. #include "dxc/DXIL/DxilTypeSystem.h"
  17. #include "dxc/DXIL/DxilUtil.h"
  18. #include "dxc/DXIL/DxilFunctionProps.h"
  19. #include "llvm/IR/GetElementPtrTypeIterator.h"
  20. #include "llvm/IR/IRBuilder.h"
  21. #include "llvm/IR/Instructions.h"
  22. #include "llvm/IR/InstIterator.h"
  23. #include "llvm/IR/IntrinsicInst.h"
  24. #include "llvm/IR/Module.h"
  25. #include "llvm/IR/DebugInfo.h"
  26. #include "llvm/IR/PassManager.h"
  27. #include "llvm/ADT/BitVector.h"
  28. #include "llvm/Pass.h"
  29. #include "llvm/Transforms/Utils/Local.h"
  30. #include "llvm/Analysis/AssumptionCache.h"
  31. #include <memory>
  32. #include <unordered_set>
  33. using namespace llvm;
  34. using namespace hlsl;
  35. namespace {
  36. class FailUndefResource : public ModulePass {
  37. public:
  38. static char ID;
  39. explicit FailUndefResource() : ModulePass(ID) {
  40. initializeScalarizerPass(*PassRegistry::getPassRegistry());
  41. }
  42. const char *getPassName() const override { return "Fail on undef resource use"; }
  43. bool runOnModule(Module &M) override;
  44. };
  45. }
  46. char FailUndefResource::ID = 0;
  47. ModulePass *llvm::createFailUndefResourcePass() { return new FailUndefResource(); }
  48. INITIALIZE_PASS(FailUndefResource, "fail-undef-resource", "Fail on undef resource use", false, false)
  49. bool FailUndefResource::runOnModule(Module &M) {
  50. // Undef resources may be removed on simplify due to the interpretation
  51. // of undef that any value could be substituted for identical meaning.
  52. // However, these likely indicate uninitialized locals being used in
  53. // some code path, which we should catch and report.
  54. for (auto &F : M.functions()) {
  55. if (GetHLOpcodeGroupByName(&F) == HLOpcodeGroup::HLCreateHandle) {
  56. Type *ResTy = F.getFunctionType()->getParamType(
  57. HLOperandIndex::kCreateHandleResourceOpIdx);
  58. UndefValue *UndefRes = UndefValue::get(ResTy);
  59. for (auto U : UndefRes->users()) {
  60. // Only report instruction users.
  61. if (Instruction *I = dyn_cast<Instruction>(U))
  62. dxilutil::EmitResMappingError(I);
  63. }
  64. }
  65. }
  66. return false;
  67. }
  68. ///////////////////////////////////////////////////////////////////////////////
  69. namespace {
  70. class SimplifyInst : public FunctionPass {
  71. public:
  72. static char ID;
  73. SimplifyInst() : FunctionPass(ID) {
  74. initializeScalarizerPass(*PassRegistry::getPassRegistry());
  75. }
  76. bool runOnFunction(Function &F) override;
  77. private:
  78. };
  79. }
  80. char SimplifyInst::ID = 0;
  81. FunctionPass *llvm::createSimplifyInstPass() { return new SimplifyInst(); }
  82. INITIALIZE_PASS(SimplifyInst, "simplify-inst", "Simplify Instructions", false, false)
  83. bool SimplifyInst::runOnFunction(Function &F) {
  84. for (Function::iterator BBI = F.begin(), BBE = F.end(); BBI != BBE; ++BBI) {
  85. BasicBlock *BB = BBI;
  86. llvm::SimplifyInstructionsInBlock(BB, nullptr);
  87. }
  88. return true;
  89. }
  90. ///////////////////////////////////////////////////////////////////////////////
  91. namespace {
  92. class DxilDeadFunctionElimination : public ModulePass {
  93. public:
  94. static char ID; // Pass identification, replacement for typeid
  95. explicit DxilDeadFunctionElimination () : ModulePass(ID) {}
  96. const char *getPassName() const override { return "Remove all unused function except entry from DxilModule"; }
  97. bool runOnModule(Module &M) override {
  98. if (M.HasDxilModule()) {
  99. DxilModule &DM = M.GetDxilModule();
  100. bool IsLib = DM.GetShaderModel()->IsLib();
  101. // Remove unused functions except entry and patch constant func.
  102. // For library profile, only remove unused external functions.
  103. Function *EntryFunc = DM.GetEntryFunction();
  104. Function *PatchConstantFunc = DM.GetPatchConstantFunction();
  105. return dxilutil::RemoveUnusedFunctions(M, EntryFunc, PatchConstantFunc,
  106. IsLib);
  107. }
  108. return false;
  109. }
  110. };
  111. }
  112. char DxilDeadFunctionElimination::ID = 0;
  113. ModulePass *llvm::createDxilDeadFunctionEliminationPass() {
  114. return new DxilDeadFunctionElimination();
  115. }
  116. INITIALIZE_PASS(DxilDeadFunctionElimination, "dxil-dfe", "Remove all unused function except entry from DxilModule", false, false)
  117. ///////////////////////////////////////////////////////////////////////////////
  118. bool CleanupSharedMemoryAddrSpaceCast(Module &M);
  119. namespace {
  120. static void TransferEntryFunctionAttributes(Function *F, Function *NewFunc) {
  121. // Keep necessary function attributes
  122. AttributeSet attributeSet = F->getAttributes();
  123. StringRef attrKind, attrValue;
  124. if (attributeSet.hasAttribute(AttributeSet::FunctionIndex, DXIL::kFP32DenormKindString)) {
  125. Attribute attribute = attributeSet.getAttribute(AttributeSet::FunctionIndex, DXIL::kFP32DenormKindString);
  126. DXASSERT(attribute.isStringAttribute(), "otherwise we have wrong fp-denorm-mode attribute.");
  127. attrKind = attribute.getKindAsString();
  128. attrValue = attribute.getValueAsString();
  129. }
  130. if (F == NewFunc) {
  131. NewFunc->removeAttributes(AttributeSet::FunctionIndex, attributeSet);
  132. }
  133. if (!attrKind.empty() && !attrValue.empty())
  134. NewFunc->addFnAttr(attrKind, attrValue);
  135. }
  136. static Function *StripFunctionParameter(Function *F, DxilModule &DM,
  137. DenseMap<const Function *, DISubprogram *> &FunctionDIs) {
  138. if (F->arg_empty() && F->getReturnType()->isVoidTy()) {
  139. // This will strip non-entry function attributes
  140. TransferEntryFunctionAttributes(F, F);
  141. return nullptr;
  142. }
  143. Module &M = *DM.GetModule();
  144. Type *VoidTy = Type::getVoidTy(M.getContext());
  145. FunctionType *FT = FunctionType::get(VoidTy, false);
  146. for (auto &arg : F->args()) {
  147. if (!arg.user_empty())
  148. return nullptr;
  149. DbgDeclareInst *DDI = llvm::FindAllocaDbgDeclare(&arg);
  150. if (DDI) {
  151. DDI->eraseFromParent();
  152. }
  153. }
  154. Function *NewFunc = Function::Create(FT, F->getLinkage());
  155. M.getFunctionList().insert(F, NewFunc);
  156. // Splice the body of the old function right into the new function.
  157. NewFunc->getBasicBlockList().splice(NewFunc->begin(), F->getBasicBlockList());
  158. TransferEntryFunctionAttributes(F, NewFunc);
  159. // Patch the pointer to LLVM function in debug info descriptor.
  160. auto DI = FunctionDIs.find(F);
  161. if (DI != FunctionDIs.end()) {
  162. DISubprogram *SP = DI->second;
  163. SP->replaceFunction(NewFunc);
  164. // Ensure the map is updated so it can be reused on subsequent argument
  165. // promotions of the same function.
  166. FunctionDIs.erase(DI);
  167. FunctionDIs[NewFunc] = SP;
  168. }
  169. NewFunc->takeName(F);
  170. if (DM.HasDxilFunctionProps(F)) {
  171. DM.ReplaceDxilEntryProps(F, NewFunc);
  172. }
  173. DM.GetTypeSystem().EraseFunctionAnnotation(F);
  174. F->eraseFromParent();
  175. DM.GetTypeSystem().AddFunctionAnnotation(NewFunc);
  176. return NewFunc;
  177. }
  178. void CheckInBoundForTGSM(GlobalVariable &GV, const DataLayout &DL) {
  179. for (User *U : GV.users()) {
  180. if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(U)) {
  181. bool allImmIndex = true;
  182. for (auto Idx = GEP->idx_begin(), E = GEP->idx_end(); Idx != E; Idx++) {
  183. if (!isa<ConstantInt>(Idx)) {
  184. allImmIndex = false;
  185. break;
  186. }
  187. }
  188. if (!allImmIndex)
  189. GEP->setIsInBounds(false);
  190. else {
  191. Value *Ptr = GEP->getPointerOperand();
  192. unsigned size =
  193. DL.getTypeAllocSize(Ptr->getType()->getPointerElementType());
  194. unsigned valSize =
  195. DL.getTypeAllocSize(GEP->getType()->getPointerElementType());
  196. SmallVector<Value *, 8> Indices(GEP->idx_begin(), GEP->idx_end());
  197. unsigned offset =
  198. DL.getIndexedOffset(GEP->getPointerOperandType(), Indices);
  199. if ((offset + valSize) > size)
  200. GEP->setIsInBounds(false);
  201. }
  202. }
  203. }
  204. }
  205. class DxilFinalizeModule : public ModulePass {
  206. public:
  207. static char ID; // Pass identification, replacement for typeid
  208. explicit DxilFinalizeModule() : ModulePass(ID) {}
  209. const char *getPassName() const override { return "HLSL DXIL Finalize Module"; }
  210. void patchValidation_1_1(Module &M) {
  211. for (iplist<Function>::iterator F : M.getFunctionList()) {
  212. for (Function::iterator BBI = F->begin(), BBE = F->end(); BBI != BBE;
  213. ++BBI) {
  214. BasicBlock *BB = BBI;
  215. for (BasicBlock::iterator II = BB->begin(), IE = BB->end(); II != IE;
  216. ++II) {
  217. Instruction *I = II;
  218. if (I->hasMetadataOtherThanDebugLoc()) {
  219. SmallVector<std::pair<unsigned, MDNode*>, 2> MDs;
  220. I->getAllMetadataOtherThanDebugLoc(MDs);
  221. for (auto &MD : MDs) {
  222. unsigned kind = MD.first;
  223. // Remove Metadata which validation_1_0 not allowed.
  224. bool bNeedPatch = kind == LLVMContext::MD_tbaa ||
  225. kind == LLVMContext::MD_prof ||
  226. (kind > LLVMContext::MD_fpmath &&
  227. kind <= LLVMContext::MD_dereferenceable_or_null);
  228. if (bNeedPatch)
  229. I->setMetadata(kind, nullptr);
  230. }
  231. }
  232. }
  233. }
  234. }
  235. }
  236. bool runOnModule(Module &M) override {
  237. if (M.HasDxilModule()) {
  238. DxilModule &DM = M.GetDxilModule();
  239. bool IsLib = DM.GetShaderModel()->IsLib();
  240. // Skip validation patch for lib.
  241. if (!IsLib) {
  242. unsigned ValMajor = 0;
  243. unsigned ValMinor = 0;
  244. M.GetDxilModule().GetValidatorVersion(ValMajor, ValMinor);
  245. if (ValMajor == 1 && ValMinor <= 1) {
  246. patchValidation_1_1(M);
  247. }
  248. }
  249. // Remove store undef output.
  250. hlsl::OP *hlslOP = M.GetDxilModule().GetOP();
  251. RemoveStoreUndefOutput(M, hlslOP);
  252. RemoveUnusedStaticGlobal(M);
  253. // Remove unnecessary address space casts.
  254. CleanupSharedMemoryAddrSpaceCast(M);
  255. // Clear inbound for GEP which has none-const index.
  256. LegalizeSharedMemoryGEPInbound(M);
  257. // Strip parameters of entry function.
  258. StripEntryParameters(M, DM, IsLib);
  259. // Update flags to reflect any changes.
  260. DM.CollectShaderFlagsForModule();
  261. // Update Validator Version
  262. DM.UpgradeToMinValidatorVersion();
  263. // Clear intermediate options that shouldn't be in the final DXIL
  264. DM.ClearIntermediateOptions();
  265. return true;
  266. }
  267. return false;
  268. }
  269. private:
  270. void RemoveUnusedStaticGlobal(Module &M) {
  271. // Remove unused internal global.
  272. std::vector<GlobalVariable *> staticGVs;
  273. for (GlobalVariable &GV : M.globals()) {
  274. if (dxilutil::IsStaticGlobal(&GV) ||
  275. dxilutil::IsSharedMemoryGlobal(&GV)) {
  276. staticGVs.emplace_back(&GV);
  277. }
  278. }
  279. for (GlobalVariable *GV : staticGVs) {
  280. bool onlyStoreUse = true;
  281. for (User *user : GV->users()) {
  282. if (isa<StoreInst>(user))
  283. continue;
  284. if (isa<ConstantExpr>(user) && user->user_empty())
  285. continue;
  286. onlyStoreUse = false;
  287. break;
  288. }
  289. if (onlyStoreUse) {
  290. for (auto UserIt = GV->user_begin(); UserIt != GV->user_end();) {
  291. Value *User = *(UserIt++);
  292. if (Instruction *I = dyn_cast<Instruction>(User)) {
  293. I->eraseFromParent();
  294. } else {
  295. ConstantExpr *CE = cast<ConstantExpr>(User);
  296. CE->dropAllReferences();
  297. }
  298. }
  299. GV->eraseFromParent();
  300. }
  301. }
  302. }
  303. void RemoveStoreUndefOutput(Module &M, hlsl::OP *hlslOP) {
  304. for (iplist<Function>::iterator F : M.getFunctionList()) {
  305. if (!hlslOP->IsDxilOpFunc(F))
  306. continue;
  307. DXIL::OpCodeClass opClass;
  308. bool bHasOpClass = hlslOP->GetOpCodeClass(F, opClass);
  309. DXASSERT_LOCALVAR(bHasOpClass, bHasOpClass, "else not a dxil op func");
  310. if (opClass != DXIL::OpCodeClass::StoreOutput)
  311. continue;
  312. for (auto it = F->user_begin(); it != F->user_end();) {
  313. CallInst *CI = dyn_cast<CallInst>(*(it++));
  314. if (!CI)
  315. continue;
  316. Value *V = CI->getArgOperand(DXIL::OperandIndex::kStoreOutputValOpIdx);
  317. // Remove the store of undef.
  318. if (isa<UndefValue>(V))
  319. CI->eraseFromParent();
  320. }
  321. }
  322. }
  323. void LegalizeSharedMemoryGEPInbound(Module &M) {
  324. const DataLayout &DL = M.getDataLayout();
  325. // Clear inbound for GEP which has none-const index.
  326. for (GlobalVariable &GV : M.globals()) {
  327. if (dxilutil::IsSharedMemoryGlobal(&GV)) {
  328. CheckInBoundForTGSM(GV, DL);
  329. }
  330. }
  331. }
  332. void StripEntryParameters(Module &M, DxilModule &DM, bool IsLib) {
  333. DenseMap<const Function *, DISubprogram *> FunctionDIs =
  334. makeSubprogramMap(M);
  335. // Strip parameters of entry function.
  336. if (!IsLib) {
  337. if (Function *PatchConstantFunc = DM.GetPatchConstantFunction()) {
  338. PatchConstantFunc =
  339. StripFunctionParameter(PatchConstantFunc, DM, FunctionDIs);
  340. if (PatchConstantFunc) {
  341. DM.SetPatchConstantFunction(PatchConstantFunc);
  342. }
  343. }
  344. if (Function *EntryFunc = DM.GetEntryFunction()) {
  345. StringRef Name = DM.GetEntryFunctionName();
  346. EntryFunc->setName(Name);
  347. EntryFunc = StripFunctionParameter(EntryFunc, DM, FunctionDIs);
  348. if (EntryFunc) {
  349. DM.SetEntryFunction(EntryFunc);
  350. }
  351. }
  352. } else {
  353. std::vector<Function *> entries;
  354. // Handle when multiple hull shaders point to the same patch constant function
  355. DenseMap<Function*,Function*> patchConstantUpdates;
  356. for (iplist<Function>::iterator F : M.getFunctionList()) {
  357. if (DM.IsEntryThatUsesSignatures(F)) {
  358. auto *FT = F->getFunctionType();
  359. // Only do this when has parameters.
  360. if (FT->getNumParams() > 0 || !FT->getReturnType()->isVoidTy())
  361. entries.emplace_back(F);
  362. }
  363. }
  364. for (Function *entry : entries) {
  365. DxilFunctionProps &props = DM.GetDxilFunctionProps(entry);
  366. if (props.IsHS()) {
  367. // Strip patch constant function first.
  368. Function* patchConstFunc = props.ShaderProps.HS.patchConstantFunc;
  369. auto it = patchConstantUpdates.find(patchConstFunc);
  370. if (it == patchConstantUpdates.end()) {
  371. patchConstFunc = patchConstantUpdates[patchConstFunc] =
  372. StripFunctionParameter(patchConstFunc, DM, FunctionDIs);
  373. } else {
  374. patchConstFunc = it->second;
  375. }
  376. if (patchConstFunc)
  377. DM.SetPatchConstantFunctionForHS(entry, patchConstFunc);
  378. }
  379. StripFunctionParameter(entry, DM, FunctionDIs);
  380. }
  381. }
  382. }
  383. };
  384. }
  385. char DxilFinalizeModule::ID = 0;
  386. ModulePass *llvm::createDxilFinalizeModulePass() {
  387. return new DxilFinalizeModule();
  388. }
  389. INITIALIZE_PASS(DxilFinalizeModule, "hlsl-dxilfinalize", "HLSL DXIL Finalize Module", false, false)
  390. ///////////////////////////////////////////////////////////////////////////////
  391. namespace {
  392. typedef MapVector< PHINode*, SmallVector<Value*,8> > PHIReplacementMap;
  393. bool RemoveAddrSpaceCasts(Value *Val, Value *NewVal,
  394. PHIReplacementMap &phiReplacements,
  395. DenseMap<Value*, Value*> &valueMap) {
  396. bool bChanged = false;
  397. for (auto itU = Val->use_begin(), itEnd = Val->use_end(); itU != itEnd; ) {
  398. Use &use = *(itU++);
  399. User *user = use.getUser();
  400. Value *userReplacement = user;
  401. bool bConstructReplacement = false;
  402. bool bCleanupInst = false;
  403. auto valueMapIter = valueMap.find(user);
  404. if (valueMapIter != valueMap.end())
  405. userReplacement = valueMapIter->second;
  406. else if (Val != NewVal)
  407. bConstructReplacement = true;
  408. if (ConstantExpr* CE = dyn_cast<ConstantExpr>(user)) {
  409. if (CE->getOpcode() == Instruction::BitCast) {
  410. if (bConstructReplacement) {
  411. // Replicate bitcast in target address space
  412. Type* NewTy = PointerType::get(
  413. CE->getType()->getPointerElementType(),
  414. NewVal->getType()->getPointerAddressSpace());
  415. userReplacement = ConstantExpr::getBitCast(cast<Constant>(NewVal), NewTy);
  416. }
  417. } else if (CE->getOpcode() == Instruction::GetElementPtr) {
  418. if (bConstructReplacement) {
  419. // Replicate GEP in target address space
  420. GEPOperator *GEP = cast<GEPOperator>(CE);
  421. SmallVector<Value*, 8> idxList(GEP->idx_begin(), GEP->idx_end());
  422. userReplacement = ConstantExpr::getGetElementPtr(
  423. nullptr, cast<Constant>(NewVal), idxList, GEP->isInBounds());
  424. }
  425. } else if (CE->getOpcode() == Instruction::AddrSpaceCast) {
  426. userReplacement = NewVal;
  427. bConstructReplacement = false;
  428. } else {
  429. DXASSERT(false, "RemoveAddrSpaceCasts: unhandled pointer ConstantExpr");
  430. }
  431. } else if (Instruction *I = dyn_cast<Instruction>(user)) {
  432. if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(user)) {
  433. if (bConstructReplacement) {
  434. IRBuilder<> Builder(GEP);
  435. SmallVector<Value*, 8> idxList(GEP->idx_begin(), GEP->idx_end());
  436. if (GEP->isInBounds())
  437. userReplacement = Builder.CreateInBoundsGEP(NewVal, idxList, GEP->getName());
  438. else
  439. userReplacement = Builder.CreateGEP(NewVal, idxList, GEP->getName());
  440. }
  441. } else if (BitCastInst *BC = dyn_cast<BitCastInst>(user)) {
  442. if (bConstructReplacement) {
  443. IRBuilder<> Builder(BC);
  444. Type* NewTy = PointerType::get(
  445. BC->getType()->getPointerElementType(),
  446. NewVal->getType()->getPointerAddressSpace());
  447. userReplacement = Builder.CreateBitCast(NewVal, NewTy);
  448. }
  449. } else if (PHINode *PHI = dyn_cast<PHINode>(user)) {
  450. // set replacement phi values for PHI pass
  451. unsigned numValues = PHI->getNumIncomingValues();
  452. auto &phiValues = phiReplacements[PHI];
  453. if (phiValues.empty())
  454. phiValues.resize(numValues, nullptr);
  455. for (unsigned idx = 0; idx < numValues; ++idx) {
  456. if (phiValues[idx] == nullptr &&
  457. PHI->getIncomingValue(idx) == Val) {
  458. phiValues[idx] = NewVal;
  459. bChanged = true;
  460. }
  461. }
  462. continue;
  463. } else if (isa<AddrSpaceCastInst>(user)) {
  464. userReplacement = NewVal;
  465. bConstructReplacement = false;
  466. bCleanupInst = true;
  467. } else if (isa<CallInst>(user)) {
  468. continue;
  469. } else {
  470. if (Val != NewVal) {
  471. use.set(NewVal);
  472. bChanged = true;
  473. }
  474. continue;
  475. }
  476. }
  477. if (bConstructReplacement && user != userReplacement)
  478. valueMap[user] = userReplacement;
  479. bChanged |= RemoveAddrSpaceCasts(user, userReplacement, phiReplacements,
  480. valueMap);
  481. if (bCleanupInst && user->use_empty()) {
  482. // Clean up old instruction if it's now unused.
  483. // Safe during this use iteration when only one use of V in instruction.
  484. if (Instruction *I = dyn_cast<Instruction>(user))
  485. I->eraseFromParent();
  486. bChanged = true;
  487. }
  488. }
  489. return bChanged;
  490. }
  491. }
  492. bool CleanupSharedMemoryAddrSpaceCast(Module &M) {
  493. bool bChanged = false;
  494. // Eliminate address space casts if possible
  495. // Collect phi nodes so we can replace iteratively after pass over GVs
  496. PHIReplacementMap phiReplacements;
  497. DenseMap<Value*, Value*> valueMap;
  498. for (GlobalVariable &GV : M.globals()) {
  499. if (dxilutil::IsSharedMemoryGlobal(&GV)) {
  500. bChanged |= RemoveAddrSpaceCasts(&GV, &GV, phiReplacements,
  501. valueMap);
  502. }
  503. }
  504. bool bConverged = false;
  505. while (!phiReplacements.empty() && !bConverged) {
  506. bConverged = true;
  507. for (auto &phiReplacement : phiReplacements) {
  508. PHINode *PHI = phiReplacement.first;
  509. unsigned origAddrSpace = PHI->getType()->getPointerAddressSpace();
  510. unsigned incomingAddrSpace = UINT_MAX;
  511. bool bReplacePHI = true;
  512. bool bRemovePHI = false;
  513. for (auto V : phiReplacement.second) {
  514. if (nullptr == V) {
  515. // cannot replace phi (yet)
  516. bReplacePHI = false;
  517. break;
  518. }
  519. unsigned addrSpace = V->getType()->getPointerAddressSpace();
  520. if (incomingAddrSpace == UINT_MAX) {
  521. incomingAddrSpace = addrSpace;
  522. } else if (addrSpace != incomingAddrSpace) {
  523. bRemovePHI = true;
  524. break;
  525. }
  526. }
  527. if (origAddrSpace == incomingAddrSpace)
  528. bRemovePHI = true;
  529. if (bRemovePHI) {
  530. // Cannot replace phi. Remove it and restart.
  531. phiReplacements.erase(PHI);
  532. bConverged = false;
  533. break;
  534. }
  535. if (!bReplacePHI)
  536. continue;
  537. auto &NewVal = valueMap[PHI];
  538. PHINode *NewPHI = nullptr;
  539. if (NewVal) {
  540. NewPHI = cast<PHINode>(NewVal);
  541. } else {
  542. IRBuilder<> Builder(PHI);
  543. NewPHI = Builder.CreatePHI(
  544. PointerType::get(PHI->getType()->getPointerElementType(),
  545. incomingAddrSpace),
  546. PHI->getNumIncomingValues(),
  547. PHI->getName());
  548. NewVal = NewPHI;
  549. for (unsigned idx = 0; idx < PHI->getNumIncomingValues(); idx++) {
  550. NewPHI->addIncoming(phiReplacement.second[idx],
  551. PHI->getIncomingBlock(idx));
  552. }
  553. }
  554. if (RemoveAddrSpaceCasts(PHI, NewPHI, phiReplacements,
  555. valueMap)) {
  556. bConverged = false;
  557. bChanged = true;
  558. }
  559. if (PHI->use_empty()) {
  560. phiReplacements.erase(PHI);
  561. bConverged = false;
  562. bChanged = true;
  563. break;
  564. }
  565. }
  566. }
  567. // Cleanup unused replacement instructions
  568. SmallVector<WeakVH, 8> cleanupInsts;
  569. for (auto it : valueMap) {
  570. if (isa<Instruction>(it.first))
  571. cleanupInsts.push_back(it.first);
  572. if (isa<Instruction>(it.second))
  573. cleanupInsts.push_back(it.second);
  574. }
  575. for (auto V : cleanupInsts) {
  576. if (!V)
  577. continue;
  578. if (PHINode *PHI = dyn_cast<PHINode>(V))
  579. RecursivelyDeleteDeadPHINode(PHI);
  580. else if (Instruction *I = dyn_cast<Instruction>(V))
  581. RecursivelyDeleteTriviallyDeadInstructions(I);
  582. }
  583. return bChanged;
  584. }
  585. class DxilCleanupAddrSpaceCast : public ModulePass {
  586. public:
  587. static char ID; // Pass identification, replacement for typeid
  588. explicit DxilCleanupAddrSpaceCast() : ModulePass(ID) {}
  589. const char *getPassName() const override { return "HLSL DXIL Cleanup Address Space Cast"; }
  590. bool runOnModule(Module &M) override {
  591. return CleanupSharedMemoryAddrSpaceCast(M);
  592. }
  593. };
  594. char DxilCleanupAddrSpaceCast::ID = 0;
  595. ModulePass *llvm::createDxilCleanupAddrSpaceCastPass() {
  596. return new DxilCleanupAddrSpaceCast();
  597. }
  598. INITIALIZE_PASS(DxilCleanupAddrSpaceCast, "hlsl-dxil-cleanup-addrspacecast", "HLSL DXIL Cleanup Address Space Cast", false, false)
  599. ///////////////////////////////////////////////////////////////////////////////
  600. namespace {
  601. class DxilEmitMetadata : public ModulePass {
  602. public:
  603. static char ID; // Pass identification, replacement for typeid
  604. explicit DxilEmitMetadata() : ModulePass(ID) {}
  605. const char *getPassName() const override { return "HLSL DXIL Metadata Emit"; }
  606. bool runOnModule(Module &M) override {
  607. if (M.HasDxilModule()) {
  608. DxilModule::ClearDxilMetadata(M);
  609. patchIsFrontfaceTy(M);
  610. M.GetDxilModule().EmitDxilMetadata();
  611. return true;
  612. }
  613. return false;
  614. }
  615. private:
  616. void patchIsFrontfaceTy(Module &M);
  617. };
  618. void patchIsFrontface(DxilSignatureElement &Elt, bool bForceUint) {
  619. // If force to uint, change i1 to u32.
  620. // If not force to uint, change u32 to i1.
  621. if (bForceUint && Elt.GetCompType() == CompType::Kind::I1)
  622. Elt.SetCompType(CompType::Kind::U32);
  623. else if (!bForceUint && Elt.GetCompType() == CompType::Kind::U32)
  624. Elt.SetCompType(CompType::Kind::I1);
  625. }
  626. void patchIsFrontface(DxilSignature &sig, bool bForceUint) {
  627. for (auto &Elt : sig.GetElements()) {
  628. if (Elt->GetSemantic()->GetKind() == Semantic::Kind::IsFrontFace) {
  629. patchIsFrontface(*Elt, bForceUint);
  630. }
  631. }
  632. }
  633. void DxilEmitMetadata::patchIsFrontfaceTy(Module &M) {
  634. DxilModule &DM = M.GetDxilModule();
  635. const ShaderModel *pSM = DM.GetShaderModel();
  636. if (!pSM->IsGS() && !pSM->IsPS())
  637. return;
  638. unsigned ValMajor, ValMinor;
  639. DM.GetValidatorVersion(ValMajor, ValMinor);
  640. bool bForceUint = ValMajor == 0 || (ValMajor >= 1 && ValMinor >= 2);
  641. if (pSM->IsPS()) {
  642. patchIsFrontface(DM.GetInputSignature(), bForceUint);
  643. } else if (pSM->IsGS()) {
  644. patchIsFrontface(DM.GetOutputSignature(), bForceUint);
  645. }
  646. }
  647. }
  648. char DxilEmitMetadata::ID = 0;
  649. ModulePass *llvm::createDxilEmitMetadataPass() {
  650. return new DxilEmitMetadata();
  651. }
  652. INITIALIZE_PASS(DxilEmitMetadata, "hlsl-dxilemit", "HLSL DXIL Metadata Emit", false, false)