DxilPreparePasses.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  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/DxilModule.h"
  14. #include "dxc/Support/Global.h"
  15. #include "dxc/HLSL/DxilTypeSystem.h"
  16. #include "dxc/HLSL/DxilUtil.h"
  17. #include "dxc/HLSL/DxilFunctionProps.h"
  18. #include "llvm/IR/GetElementPtrTypeIterator.h"
  19. #include "llvm/IR/IRBuilder.h"
  20. #include "llvm/IR/Instructions.h"
  21. #include "llvm/IR/InstIterator.h"
  22. #include "llvm/IR/IntrinsicInst.h"
  23. #include "llvm/IR/Module.h"
  24. #include "llvm/IR/DebugInfo.h"
  25. #include "llvm/IR/PassManager.h"
  26. #include "llvm/ADT/BitVector.h"
  27. #include "llvm/Pass.h"
  28. #include "llvm/Transforms/Utils/Local.h"
  29. #include "llvm/Analysis/AssumptionCache.h"
  30. #include <memory>
  31. #include <unordered_set>
  32. using namespace llvm;
  33. using namespace hlsl;
  34. namespace {
  35. class SimplifyInst : public FunctionPass {
  36. public:
  37. static char ID;
  38. SimplifyInst() : FunctionPass(ID) {
  39. initializeScalarizerPass(*PassRegistry::getPassRegistry());
  40. }
  41. bool runOnFunction(Function &F) override;
  42. private:
  43. };
  44. }
  45. char SimplifyInst::ID = 0;
  46. FunctionPass *llvm::createSimplifyInstPass() { return new SimplifyInst(); }
  47. INITIALIZE_PASS(SimplifyInst, "simplify-inst", "Simplify Instructions", false, false)
  48. bool SimplifyInst::runOnFunction(Function &F) {
  49. for (Function::iterator BBI = F.begin(), BBE = F.end(); BBI != BBE; ++BBI) {
  50. BasicBlock *BB = BBI;
  51. llvm::SimplifyInstructionsInBlock(BB, nullptr);
  52. }
  53. return true;
  54. }
  55. ///////////////////////////////////////////////////////////////////////////////
  56. namespace {
  57. class DxilLoadMetadata : public ModulePass {
  58. public:
  59. static char ID; // Pass identification, replacement for typeid
  60. explicit DxilLoadMetadata () : ModulePass(ID) {}
  61. const char *getPassName() const override { return "HLSL load DxilModule from metadata"; }
  62. bool runOnModule(Module &M) override {
  63. if (!M.HasDxilModule()) {
  64. (void)M.GetOrCreateDxilModule();
  65. return true;
  66. }
  67. return false;
  68. }
  69. };
  70. }
  71. char DxilLoadMetadata::ID = 0;
  72. ModulePass *llvm::createDxilLoadMetadataPass() {
  73. return new DxilLoadMetadata();
  74. }
  75. INITIALIZE_PASS(DxilLoadMetadata, "hlsl-dxilload", "HLSL load DxilModule from metadata", false, false)
  76. ///////////////////////////////////////////////////////////////////////////////
  77. namespace {
  78. class DxilDeadFunctionElimination : public ModulePass {
  79. public:
  80. static char ID; // Pass identification, replacement for typeid
  81. explicit DxilDeadFunctionElimination () : ModulePass(ID) {}
  82. const char *getPassName() const override { return "Remove all unused function except entry from DxilModule"; }
  83. bool runOnModule(Module &M) override {
  84. if (M.HasDxilModule()) {
  85. DxilModule &DM = M.GetDxilModule();
  86. bool IsLib = DM.GetShaderModel()->IsLib();
  87. // Remove unused functions except entry and patch constant func.
  88. // For library profile, only remove unused external functions.
  89. Function *EntryFunc = DM.GetEntryFunction();
  90. Function *PatchConstantFunc = DM.GetPatchConstantFunction();
  91. return dxilutil::RemoveUnusedFunctions(M, EntryFunc, PatchConstantFunc,
  92. IsLib);
  93. }
  94. return false;
  95. }
  96. };
  97. }
  98. char DxilDeadFunctionElimination::ID = 0;
  99. ModulePass *llvm::createDxilDeadFunctionEliminationPass() {
  100. return new DxilDeadFunctionElimination();
  101. }
  102. INITIALIZE_PASS(DxilDeadFunctionElimination, "dxil-dfe", "Remove all unused function except entry from DxilModule", false, false)
  103. ///////////////////////////////////////////////////////////////////////////////
  104. namespace {
  105. Function *StripFunctionParameter(Function *F, DxilModule &DM,
  106. DenseMap<const Function *, DISubprogram *> &FunctionDIs) {
  107. Module &M = *DM.GetModule();
  108. Type *VoidTy = Type::getVoidTy(M.getContext());
  109. FunctionType *FT = FunctionType::get(VoidTy, false);
  110. for (auto &arg : F->args()) {
  111. if (!arg.user_empty())
  112. return nullptr;
  113. DbgDeclareInst *DDI = llvm::FindAllocaDbgDeclare(&arg);
  114. if (DDI) {
  115. DDI->eraseFromParent();
  116. }
  117. }
  118. Function *NewFunc = Function::Create(FT, F->getLinkage());
  119. M.getFunctionList().insert(F, NewFunc);
  120. // Splice the body of the old function right into the new function.
  121. NewFunc->getBasicBlockList().splice(NewFunc->begin(), F->getBasicBlockList());
  122. // Keep necessary function attributes
  123. AttributeSet attributeSet = F->getAttributes();
  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. NewFunc->addFnAttr(attribute.getKindAsString(), attribute.getValueAsString());
  128. }
  129. // Patch the pointer to LLVM function in debug info descriptor.
  130. auto DI = FunctionDIs.find(F);
  131. if (DI != FunctionDIs.end()) {
  132. DISubprogram *SP = DI->second;
  133. SP->replaceFunction(NewFunc);
  134. // Ensure the map is updated so it can be reused on subsequent argument
  135. // promotions of the same function.
  136. FunctionDIs.erase(DI);
  137. FunctionDIs[NewFunc] = SP;
  138. }
  139. NewFunc->takeName(F);
  140. if (DM.HasDxilFunctionProps(F)) {
  141. DM.ReplaceDxilEntrySignature(F, NewFunc);
  142. DM.ReplaceDxilFunctionProps(F, NewFunc);
  143. }
  144. DM.GetTypeSystem().EraseFunctionAnnotation(F);
  145. F->eraseFromParent();
  146. DM.GetTypeSystem().AddFunctionAnnotation(NewFunc);
  147. return NewFunc;
  148. }
  149. void CheckInBoundForTGSM(GlobalVariable &GV, const DataLayout &DL) {
  150. for (User *U : GV.users()) {
  151. if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(U)) {
  152. bool allImmIndex = true;
  153. for (auto Idx = GEP->idx_begin(), E = GEP->idx_end(); Idx != E; Idx++) {
  154. if (!isa<ConstantInt>(Idx)) {
  155. allImmIndex = false;
  156. break;
  157. }
  158. }
  159. if (!allImmIndex)
  160. GEP->setIsInBounds(false);
  161. else {
  162. Value *Ptr = GEP->getPointerOperand();
  163. unsigned size =
  164. DL.getTypeAllocSize(Ptr->getType()->getPointerElementType());
  165. unsigned valSize =
  166. DL.getTypeAllocSize(GEP->getType()->getPointerElementType());
  167. SmallVector<Value *, 8> Indices(GEP->idx_begin(), GEP->idx_end());
  168. unsigned offset =
  169. DL.getIndexedOffset(GEP->getPointerOperandType(), Indices);
  170. if ((offset + valSize) > size)
  171. GEP->setIsInBounds(false);
  172. }
  173. }
  174. }
  175. }
  176. class DxilFinalizeModule : public ModulePass {
  177. public:
  178. static char ID; // Pass identification, replacement for typeid
  179. explicit DxilFinalizeModule() : ModulePass(ID) {}
  180. const char *getPassName() const override { return "HLSL DXIL Finalize Module"; }
  181. void patchValidation_1_1(Module &M) {
  182. for (iplist<Function>::iterator F : M.getFunctionList()) {
  183. for (Function::iterator BBI = F->begin(), BBE = F->end(); BBI != BBE;
  184. ++BBI) {
  185. BasicBlock *BB = BBI;
  186. for (BasicBlock::iterator II = BB->begin(), IE = BB->end(); II != IE;
  187. ++II) {
  188. Instruction *I = II;
  189. if (I->hasMetadataOtherThanDebugLoc()) {
  190. SmallVector<std::pair<unsigned, MDNode*>, 2> MDs;
  191. I->getAllMetadataOtherThanDebugLoc(MDs);
  192. for (auto &MD : MDs) {
  193. unsigned kind = MD.first;
  194. // Remove Metadata which validation_1_0 not allowed.
  195. bool bNeedPatch = kind == LLVMContext::MD_tbaa ||
  196. kind == LLVMContext::MD_prof ||
  197. (kind > LLVMContext::MD_fpmath &&
  198. kind <= LLVMContext::MD_dereferenceable_or_null);
  199. if (bNeedPatch)
  200. I->setMetadata(kind, nullptr);
  201. }
  202. }
  203. }
  204. }
  205. }
  206. }
  207. bool runOnModule(Module &M) override {
  208. if (M.HasDxilModule()) {
  209. DxilModule &DM = M.GetDxilModule();
  210. bool IsLib = DM.GetShaderModel()->IsLib();
  211. // Skip validation patch for lib.
  212. if (!IsLib) {
  213. unsigned ValMajor = 0;
  214. unsigned ValMinor = 0;
  215. M.GetDxilModule().GetValidatorVersion(ValMajor, ValMinor);
  216. if (ValMajor == 1 && ValMinor <= 1) {
  217. patchValidation_1_1(M);
  218. }
  219. }
  220. // Remove store undef output.
  221. hlsl::OP *hlslOP = M.GetDxilModule().GetOP();
  222. RemoveStoreUndefOutput(M, hlslOP);
  223. RemoveUnusedStaticGlobal(M);
  224. // Clear inbound for GEP which has none-const index.
  225. LegalizeShareMemoryGEPInbound(M);
  226. // Strip parameters of entry function.
  227. StripEntryParameters(M, DM, IsLib);
  228. // Skip shader flag for library.
  229. if (!IsLib) {
  230. DM.CollectShaderFlags(); // Update flags to reflect any changes.
  231. // Update Validator Version
  232. DM.UpgradeToMinValidatorVersion();
  233. }
  234. return true;
  235. }
  236. return false;
  237. }
  238. private:
  239. void RemoveUnusedStaticGlobal(Module &M) {
  240. // Remove unused internal global.
  241. std::vector<GlobalVariable *> staticGVs;
  242. for (GlobalVariable &GV : M.globals()) {
  243. if (dxilutil::IsStaticGlobal(&GV) ||
  244. dxilutil::IsSharedMemoryGlobal(&GV)) {
  245. staticGVs.emplace_back(&GV);
  246. }
  247. }
  248. for (GlobalVariable *GV : staticGVs) {
  249. bool onlyStoreUse = true;
  250. for (User *user : GV->users()) {
  251. if (isa<StoreInst>(user))
  252. continue;
  253. if (isa<ConstantExpr>(user) && user->user_empty())
  254. continue;
  255. onlyStoreUse = false;
  256. break;
  257. }
  258. if (onlyStoreUse) {
  259. for (auto UserIt = GV->user_begin(); UserIt != GV->user_end();) {
  260. Value *User = *(UserIt++);
  261. if (Instruction *I = dyn_cast<Instruction>(User)) {
  262. I->eraseFromParent();
  263. } else {
  264. ConstantExpr *CE = cast<ConstantExpr>(User);
  265. CE->dropAllReferences();
  266. }
  267. }
  268. GV->eraseFromParent();
  269. }
  270. }
  271. }
  272. void RemoveStoreUndefOutput(Module &M, hlsl::OP *hlslOP) {
  273. for (iplist<Function>::iterator F : M.getFunctionList()) {
  274. if (!hlslOP->IsDxilOpFunc(F))
  275. continue;
  276. DXIL::OpCodeClass opClass;
  277. bool bHasOpClass = hlslOP->GetOpCodeClass(F, opClass);
  278. DXASSERT_LOCALVAR(bHasOpClass, bHasOpClass, "else not a dxil op func");
  279. if (opClass != DXIL::OpCodeClass::StoreOutput)
  280. continue;
  281. for (auto it = F->user_begin(); it != F->user_end();) {
  282. CallInst *CI = dyn_cast<CallInst>(*(it++));
  283. if (!CI)
  284. continue;
  285. Value *V = CI->getArgOperand(DXIL::OperandIndex::kStoreOutputValOpIdx);
  286. // Remove the store of undef.
  287. if (isa<UndefValue>(V))
  288. CI->eraseFromParent();
  289. }
  290. }
  291. }
  292. void LegalizeShareMemoryGEPInbound(Module &M) {
  293. const DataLayout &DL = M.getDataLayout();
  294. // Clear inbound for GEP which has none-const index.
  295. for (GlobalVariable &GV : M.globals()) {
  296. if (dxilutil::IsSharedMemoryGlobal(&GV)) {
  297. CheckInBoundForTGSM(GV, DL);
  298. }
  299. }
  300. }
  301. void StripEntryParameters(Module &M, DxilModule &DM, bool IsLib) {
  302. DenseMap<const Function *, DISubprogram *> FunctionDIs =
  303. makeSubprogramMap(M);
  304. // Strip parameters of entry function.
  305. if (!IsLib) {
  306. if (Function *PatchConstantFunc = DM.GetPatchConstantFunction()) {
  307. PatchConstantFunc =
  308. StripFunctionParameter(PatchConstantFunc, DM, FunctionDIs);
  309. if (PatchConstantFunc)
  310. DM.SetPatchConstantFunction(PatchConstantFunc);
  311. }
  312. if (Function *EntryFunc = DM.GetEntryFunction()) {
  313. StringRef Name = DM.GetEntryFunctionName();
  314. EntryFunc->setName(Name);
  315. EntryFunc = StripFunctionParameter(EntryFunc, DM, FunctionDIs);
  316. if (EntryFunc)
  317. DM.SetEntryFunction(EntryFunc);
  318. }
  319. } else {
  320. std::vector<Function *> entries;
  321. for (iplist<Function>::iterator F : M.getFunctionList()) {
  322. if (DM.HasDxilFunctionProps(F)) {
  323. entries.emplace_back(F);
  324. }
  325. }
  326. for (Function *entry : entries) {
  327. DxilFunctionProps &props = DM.GetDxilFunctionProps(entry);
  328. if (props.IsHS()) {
  329. // Strip patch constant function first.
  330. Function *patchConstFunc = StripFunctionParameter(
  331. props.ShaderProps.HS.patchConstantFunc, DM, FunctionDIs);
  332. props.ShaderProps.HS.patchConstantFunc = patchConstFunc;
  333. }
  334. StripFunctionParameter(entry, DM, FunctionDIs);
  335. }
  336. }
  337. }
  338. };
  339. }
  340. char DxilFinalizeModule::ID = 0;
  341. ModulePass *llvm::createDxilFinalizeModulePass() {
  342. return new DxilFinalizeModule();
  343. }
  344. INITIALIZE_PASS(DxilFinalizeModule, "hlsl-dxilfinalize", "HLSL DXIL Finalize Module", false, false)
  345. ///////////////////////////////////////////////////////////////////////////////
  346. namespace {
  347. class DxilEmitMetadata : public ModulePass {
  348. public:
  349. static char ID; // Pass identification, replacement for typeid
  350. explicit DxilEmitMetadata() : ModulePass(ID) {}
  351. const char *getPassName() const override { return "HLSL DXIL Metadata Emit"; }
  352. bool runOnModule(Module &M) override {
  353. if (M.HasDxilModule()) {
  354. DxilModule::ClearDxilMetadata(M);
  355. patchIsFrontfaceTy(M);
  356. M.GetDxilModule().EmitDxilMetadata();
  357. return true;
  358. }
  359. return false;
  360. }
  361. private:
  362. void patchIsFrontfaceTy(Module &M);
  363. };
  364. void patchIsFrontface(DxilSignatureElement &Elt, bool bForceUint) {
  365. // If force to uint, change i1 to u32.
  366. // If not force to uint, change u32 to i1.
  367. if (bForceUint && Elt.GetCompType() == CompType::Kind::I1)
  368. Elt.SetCompType(CompType::Kind::U32);
  369. else if (!bForceUint && Elt.GetCompType() == CompType::Kind::U32)
  370. Elt.SetCompType(CompType::Kind::I1);
  371. }
  372. void patchIsFrontface(DxilSignature &sig, bool bForceUint) {
  373. for (auto &Elt : sig.GetElements()) {
  374. if (Elt->GetSemantic()->GetKind() == Semantic::Kind::IsFrontFace) {
  375. patchIsFrontface(*Elt, bForceUint);
  376. }
  377. }
  378. }
  379. void DxilEmitMetadata::patchIsFrontfaceTy(Module &M) {
  380. DxilModule &DM = M.GetDxilModule();
  381. const ShaderModel *pSM = DM.GetShaderModel();
  382. if (!pSM->IsGS() && !pSM->IsPS())
  383. return;
  384. unsigned ValMajor, ValMinor;
  385. DM.GetValidatorVersion(ValMajor, ValMinor);
  386. bool bForceUint = ValMajor >= 1 && ValMinor >= 2;
  387. if (pSM->IsPS()) {
  388. patchIsFrontface(DM.GetInputSignature(), bForceUint);
  389. } else if (pSM->IsGS()) {
  390. patchIsFrontface(DM.GetOutputSignature(), bForceUint);
  391. }
  392. }
  393. }
  394. char DxilEmitMetadata::ID = 0;
  395. ModulePass *llvm::createDxilEmitMetadataPass() {
  396. return new DxilEmitMetadata();
  397. }
  398. INITIALIZE_PASS(DxilEmitMetadata, "hlsl-dxilemit", "HLSL DXIL Metadata Emit", false, false)