DxilPreparePasses.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  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/HLSL/DxilOperations.h"
  13. #include "dxc/HLSL/HLOperations.h"
  14. #include "dxc/HLSL/DxilModule.h"
  15. #include "dxc/Support/Global.h"
  16. #include "dxc/HLSL/DxilTypeSystem.h"
  17. #include "dxc/HLSL/DxilUtil.h"
  18. #include "dxc/HLSL/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 DxilLoadMetadata : public ModulePass {
  93. public:
  94. static char ID; // Pass identification, replacement for typeid
  95. explicit DxilLoadMetadata () : ModulePass(ID) {}
  96. const char *getPassName() const override { return "HLSL load DxilModule from metadata"; }
  97. bool runOnModule(Module &M) override {
  98. if (!M.HasDxilModule()) {
  99. (void)M.GetOrCreateDxilModule();
  100. return true;
  101. }
  102. return false;
  103. }
  104. };
  105. }
  106. char DxilLoadMetadata::ID = 0;
  107. ModulePass *llvm::createDxilLoadMetadataPass() {
  108. return new DxilLoadMetadata();
  109. }
  110. INITIALIZE_PASS(DxilLoadMetadata, "hlsl-dxilload", "HLSL load DxilModule from metadata", false, false)
  111. ///////////////////////////////////////////////////////////////////////////////
  112. namespace {
  113. class DxilDeadFunctionElimination : public ModulePass {
  114. public:
  115. static char ID; // Pass identification, replacement for typeid
  116. explicit DxilDeadFunctionElimination () : ModulePass(ID) {}
  117. const char *getPassName() const override { return "Remove all unused function except entry from DxilModule"; }
  118. bool runOnModule(Module &M) override {
  119. if (M.HasDxilModule()) {
  120. DxilModule &DM = M.GetDxilModule();
  121. bool IsLib = DM.GetShaderModel()->IsLib();
  122. // Remove unused functions except entry and patch constant func.
  123. // For library profile, only remove unused external functions.
  124. Function *EntryFunc = DM.GetEntryFunction();
  125. Function *PatchConstantFunc = DM.GetPatchConstantFunction();
  126. return dxilutil::RemoveUnusedFunctions(M, EntryFunc, PatchConstantFunc,
  127. IsLib);
  128. }
  129. return false;
  130. }
  131. };
  132. }
  133. char DxilDeadFunctionElimination::ID = 0;
  134. ModulePass *llvm::createDxilDeadFunctionEliminationPass() {
  135. return new DxilDeadFunctionElimination();
  136. }
  137. INITIALIZE_PASS(DxilDeadFunctionElimination, "dxil-dfe", "Remove all unused function except entry from DxilModule", false, false)
  138. ///////////////////////////////////////////////////////////////////////////////
  139. namespace {
  140. static void TransferEntryFunctionAttributes(Function *F, Function *NewFunc) {
  141. // Keep necessary function attributes
  142. AttributeSet attributeSet = F->getAttributes();
  143. StringRef attrKind, attrValue;
  144. if (attributeSet.hasAttribute(AttributeSet::FunctionIndex, DXIL::kFP32DenormKindString)) {
  145. Attribute attribute = attributeSet.getAttribute(AttributeSet::FunctionIndex, DXIL::kFP32DenormKindString);
  146. DXASSERT(attribute.isStringAttribute(), "otherwise we have wrong fp-denorm-mode attribute.");
  147. attrKind = attribute.getKindAsString();
  148. attrValue = attribute.getValueAsString();
  149. }
  150. if (F == NewFunc) {
  151. NewFunc->removeAttributes(AttributeSet::FunctionIndex, attributeSet);
  152. }
  153. if (!attrKind.empty() && !attrValue.empty())
  154. NewFunc->addFnAttr(attrKind, attrValue);
  155. }
  156. static Function *StripFunctionParameter(Function *F, DxilModule &DM,
  157. DenseMap<const Function *, DISubprogram *> &FunctionDIs) {
  158. if (F->arg_empty() && F->getReturnType()->isVoidTy()) {
  159. // This will strip non-entry function attributes
  160. TransferEntryFunctionAttributes(F, F);
  161. return nullptr;
  162. }
  163. Module &M = *DM.GetModule();
  164. Type *VoidTy = Type::getVoidTy(M.getContext());
  165. FunctionType *FT = FunctionType::get(VoidTy, false);
  166. for (auto &arg : F->args()) {
  167. if (!arg.user_empty())
  168. return nullptr;
  169. DbgDeclareInst *DDI = llvm::FindAllocaDbgDeclare(&arg);
  170. if (DDI) {
  171. DDI->eraseFromParent();
  172. }
  173. }
  174. Function *NewFunc = Function::Create(FT, F->getLinkage());
  175. M.getFunctionList().insert(F, NewFunc);
  176. // Splice the body of the old function right into the new function.
  177. NewFunc->getBasicBlockList().splice(NewFunc->begin(), F->getBasicBlockList());
  178. TransferEntryFunctionAttributes(F, NewFunc);
  179. // Patch the pointer to LLVM function in debug info descriptor.
  180. auto DI = FunctionDIs.find(F);
  181. if (DI != FunctionDIs.end()) {
  182. DISubprogram *SP = DI->second;
  183. SP->replaceFunction(NewFunc);
  184. // Ensure the map is updated so it can be reused on subsequent argument
  185. // promotions of the same function.
  186. FunctionDIs.erase(DI);
  187. FunctionDIs[NewFunc] = SP;
  188. }
  189. NewFunc->takeName(F);
  190. if (DM.HasDxilFunctionProps(F)) {
  191. DM.ReplaceDxilEntryProps(F, NewFunc);
  192. }
  193. DM.GetTypeSystem().EraseFunctionAnnotation(F);
  194. F->eraseFromParent();
  195. DM.GetTypeSystem().AddFunctionAnnotation(NewFunc);
  196. return NewFunc;
  197. }
  198. void CheckInBoundForTGSM(GlobalVariable &GV, const DataLayout &DL) {
  199. for (User *U : GV.users()) {
  200. if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(U)) {
  201. bool allImmIndex = true;
  202. for (auto Idx = GEP->idx_begin(), E = GEP->idx_end(); Idx != E; Idx++) {
  203. if (!isa<ConstantInt>(Idx)) {
  204. allImmIndex = false;
  205. break;
  206. }
  207. }
  208. if (!allImmIndex)
  209. GEP->setIsInBounds(false);
  210. else {
  211. Value *Ptr = GEP->getPointerOperand();
  212. unsigned size =
  213. DL.getTypeAllocSize(Ptr->getType()->getPointerElementType());
  214. unsigned valSize =
  215. DL.getTypeAllocSize(GEP->getType()->getPointerElementType());
  216. SmallVector<Value *, 8> Indices(GEP->idx_begin(), GEP->idx_end());
  217. unsigned offset =
  218. DL.getIndexedOffset(GEP->getPointerOperandType(), Indices);
  219. if ((offset + valSize) > size)
  220. GEP->setIsInBounds(false);
  221. }
  222. }
  223. }
  224. }
  225. class DxilFinalizeModule : public ModulePass {
  226. public:
  227. static char ID; // Pass identification, replacement for typeid
  228. explicit DxilFinalizeModule() : ModulePass(ID) {}
  229. const char *getPassName() const override { return "HLSL DXIL Finalize Module"; }
  230. void patchValidation_1_1(Module &M) {
  231. for (iplist<Function>::iterator F : M.getFunctionList()) {
  232. for (Function::iterator BBI = F->begin(), BBE = F->end(); BBI != BBE;
  233. ++BBI) {
  234. BasicBlock *BB = BBI;
  235. for (BasicBlock::iterator II = BB->begin(), IE = BB->end(); II != IE;
  236. ++II) {
  237. Instruction *I = II;
  238. if (I->hasMetadataOtherThanDebugLoc()) {
  239. SmallVector<std::pair<unsigned, MDNode*>, 2> MDs;
  240. I->getAllMetadataOtherThanDebugLoc(MDs);
  241. for (auto &MD : MDs) {
  242. unsigned kind = MD.first;
  243. // Remove Metadata which validation_1_0 not allowed.
  244. bool bNeedPatch = kind == LLVMContext::MD_tbaa ||
  245. kind == LLVMContext::MD_prof ||
  246. (kind > LLVMContext::MD_fpmath &&
  247. kind <= LLVMContext::MD_dereferenceable_or_null);
  248. if (bNeedPatch)
  249. I->setMetadata(kind, nullptr);
  250. }
  251. }
  252. }
  253. }
  254. }
  255. }
  256. bool runOnModule(Module &M) override {
  257. if (M.HasDxilModule()) {
  258. DxilModule &DM = M.GetDxilModule();
  259. bool IsLib = DM.GetShaderModel()->IsLib();
  260. // Skip validation patch for lib.
  261. if (!IsLib) {
  262. unsigned ValMajor = 0;
  263. unsigned ValMinor = 0;
  264. M.GetDxilModule().GetValidatorVersion(ValMajor, ValMinor);
  265. if (ValMajor == 1 && ValMinor <= 1) {
  266. patchValidation_1_1(M);
  267. }
  268. }
  269. // Remove store undef output.
  270. hlsl::OP *hlslOP = M.GetDxilModule().GetOP();
  271. RemoveStoreUndefOutput(M, hlslOP);
  272. RemoveUnusedStaticGlobal(M);
  273. // Clear inbound for GEP which has none-const index.
  274. LegalizeShareMemoryGEPInbound(M);
  275. // Strip parameters of entry function.
  276. StripEntryParameters(M, DM, IsLib);
  277. // Update flags to reflect any changes.
  278. DM.CollectShaderFlagsForModule();
  279. // Update Validator Version
  280. DM.UpgradeToMinValidatorVersion();
  281. return true;
  282. }
  283. return false;
  284. }
  285. private:
  286. void RemoveUnusedStaticGlobal(Module &M) {
  287. // Remove unused internal global.
  288. std::vector<GlobalVariable *> staticGVs;
  289. for (GlobalVariable &GV : M.globals()) {
  290. if (dxilutil::IsStaticGlobal(&GV) ||
  291. dxilutil::IsSharedMemoryGlobal(&GV)) {
  292. staticGVs.emplace_back(&GV);
  293. }
  294. }
  295. for (GlobalVariable *GV : staticGVs) {
  296. bool onlyStoreUse = true;
  297. for (User *user : GV->users()) {
  298. if (isa<StoreInst>(user))
  299. continue;
  300. if (isa<ConstantExpr>(user) && user->user_empty())
  301. continue;
  302. onlyStoreUse = false;
  303. break;
  304. }
  305. if (onlyStoreUse) {
  306. for (auto UserIt = GV->user_begin(); UserIt != GV->user_end();) {
  307. Value *User = *(UserIt++);
  308. if (Instruction *I = dyn_cast<Instruction>(User)) {
  309. I->eraseFromParent();
  310. } else {
  311. ConstantExpr *CE = cast<ConstantExpr>(User);
  312. CE->dropAllReferences();
  313. }
  314. }
  315. GV->eraseFromParent();
  316. }
  317. }
  318. }
  319. void RemoveStoreUndefOutput(Module &M, hlsl::OP *hlslOP) {
  320. for (iplist<Function>::iterator F : M.getFunctionList()) {
  321. if (!hlslOP->IsDxilOpFunc(F))
  322. continue;
  323. DXIL::OpCodeClass opClass;
  324. bool bHasOpClass = hlslOP->GetOpCodeClass(F, opClass);
  325. DXASSERT_LOCALVAR(bHasOpClass, bHasOpClass, "else not a dxil op func");
  326. if (opClass != DXIL::OpCodeClass::StoreOutput)
  327. continue;
  328. for (auto it = F->user_begin(); it != F->user_end();) {
  329. CallInst *CI = dyn_cast<CallInst>(*(it++));
  330. if (!CI)
  331. continue;
  332. Value *V = CI->getArgOperand(DXIL::OperandIndex::kStoreOutputValOpIdx);
  333. // Remove the store of undef.
  334. if (isa<UndefValue>(V))
  335. CI->eraseFromParent();
  336. }
  337. }
  338. }
  339. void LegalizeShareMemoryGEPInbound(Module &M) {
  340. const DataLayout &DL = M.getDataLayout();
  341. // Clear inbound for GEP which has none-const index.
  342. for (GlobalVariable &GV : M.globals()) {
  343. if (dxilutil::IsSharedMemoryGlobal(&GV)) {
  344. CheckInBoundForTGSM(GV, DL);
  345. }
  346. }
  347. }
  348. void StripEntryParameters(Module &M, DxilModule &DM, bool IsLib) {
  349. DenseMap<const Function *, DISubprogram *> FunctionDIs =
  350. makeSubprogramMap(M);
  351. // Strip parameters of entry function.
  352. if (!IsLib) {
  353. if (Function *PatchConstantFunc = DM.GetPatchConstantFunction()) {
  354. PatchConstantFunc =
  355. StripFunctionParameter(PatchConstantFunc, DM, FunctionDIs);
  356. if (PatchConstantFunc) {
  357. DM.SetPatchConstantFunction(PatchConstantFunc);
  358. }
  359. }
  360. if (Function *EntryFunc = DM.GetEntryFunction()) {
  361. StringRef Name = DM.GetEntryFunctionName();
  362. EntryFunc->setName(Name);
  363. EntryFunc = StripFunctionParameter(EntryFunc, DM, FunctionDIs);
  364. if (EntryFunc) {
  365. DM.SetEntryFunction(EntryFunc);
  366. }
  367. }
  368. } else {
  369. std::vector<Function *> entries;
  370. // Handle when multiple hull shaders point to the same patch constant function
  371. DenseMap<Function*,Function*> patchConstantUpdates;
  372. for (iplist<Function>::iterator F : M.getFunctionList()) {
  373. if (DM.IsEntryThatUsesSignatures(F)) {
  374. auto *FT = F->getFunctionType();
  375. // Only do this when has parameters.
  376. if (FT->getNumParams() > 0 || !FT->getReturnType()->isVoidTy())
  377. entries.emplace_back(F);
  378. }
  379. }
  380. for (Function *entry : entries) {
  381. DxilFunctionProps &props = DM.GetDxilFunctionProps(entry);
  382. if (props.IsHS()) {
  383. // Strip patch constant function first.
  384. Function* patchConstFunc = props.ShaderProps.HS.patchConstantFunc;
  385. auto it = patchConstantUpdates.find(patchConstFunc);
  386. if (it == patchConstantUpdates.end()) {
  387. patchConstFunc = patchConstantUpdates[patchConstFunc] =
  388. StripFunctionParameter(patchConstFunc, DM, FunctionDIs);
  389. } else {
  390. patchConstFunc = it->second;
  391. }
  392. if (patchConstFunc)
  393. DM.SetPatchConstantFunctionForHS(entry, patchConstFunc);
  394. }
  395. StripFunctionParameter(entry, DM, FunctionDIs);
  396. }
  397. }
  398. }
  399. };
  400. }
  401. char DxilFinalizeModule::ID = 0;
  402. ModulePass *llvm::createDxilFinalizeModulePass() {
  403. return new DxilFinalizeModule();
  404. }
  405. INITIALIZE_PASS(DxilFinalizeModule, "hlsl-dxilfinalize", "HLSL DXIL Finalize Module", false, false)
  406. ///////////////////////////////////////////////////////////////////////////////
  407. namespace {
  408. class DxilEmitMetadata : public ModulePass {
  409. public:
  410. static char ID; // Pass identification, replacement for typeid
  411. explicit DxilEmitMetadata() : ModulePass(ID) {}
  412. const char *getPassName() const override { return "HLSL DXIL Metadata Emit"; }
  413. bool runOnModule(Module &M) override {
  414. if (M.HasDxilModule()) {
  415. DxilModule::ClearDxilMetadata(M);
  416. patchIsFrontfaceTy(M);
  417. M.GetDxilModule().EmitDxilMetadata();
  418. return true;
  419. }
  420. return false;
  421. }
  422. private:
  423. void patchIsFrontfaceTy(Module &M);
  424. };
  425. void patchIsFrontface(DxilSignatureElement &Elt, bool bForceUint) {
  426. // If force to uint, change i1 to u32.
  427. // If not force to uint, change u32 to i1.
  428. if (bForceUint && Elt.GetCompType() == CompType::Kind::I1)
  429. Elt.SetCompType(CompType::Kind::U32);
  430. else if (!bForceUint && Elt.GetCompType() == CompType::Kind::U32)
  431. Elt.SetCompType(CompType::Kind::I1);
  432. }
  433. void patchIsFrontface(DxilSignature &sig, bool bForceUint) {
  434. for (auto &Elt : sig.GetElements()) {
  435. if (Elt->GetSemantic()->GetKind() == Semantic::Kind::IsFrontFace) {
  436. patchIsFrontface(*Elt, bForceUint);
  437. }
  438. }
  439. }
  440. void DxilEmitMetadata::patchIsFrontfaceTy(Module &M) {
  441. DxilModule &DM = M.GetDxilModule();
  442. const ShaderModel *pSM = DM.GetShaderModel();
  443. if (!pSM->IsGS() && !pSM->IsPS())
  444. return;
  445. unsigned ValMajor, ValMinor;
  446. DM.GetValidatorVersion(ValMajor, ValMinor);
  447. bool bForceUint = ValMajor == 0 || (ValMajor >= 1 && ValMinor >= 2);
  448. if (pSM->IsPS()) {
  449. patchIsFrontface(DM.GetInputSignature(), bForceUint);
  450. } else if (pSM->IsGS()) {
  451. patchIsFrontface(DM.GetOutputSignature(), bForceUint);
  452. }
  453. }
  454. }
  455. char DxilEmitMetadata::ID = 0;
  456. ModulePass *llvm::createDxilEmitMetadataPass() {
  457. return new DxilEmitMetadata();
  458. }
  459. INITIALIZE_PASS(DxilEmitMetadata, "hlsl-dxilemit", "HLSL DXIL Metadata Emit", false, false)