DxilPreparePasses.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  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. // Patch the pointer to LLVM function in debug info descriptor.
  123. auto DI = FunctionDIs.find(F);
  124. if (DI != FunctionDIs.end()) {
  125. DISubprogram *SP = DI->second;
  126. SP->replaceFunction(NewFunc);
  127. // Ensure the map is updated so it can be reused on subsequent argument
  128. // promotions of the same function.
  129. FunctionDIs.erase(DI);
  130. FunctionDIs[NewFunc] = SP;
  131. }
  132. NewFunc->takeName(F);
  133. if (DM.HasDxilFunctionProps(F)) {
  134. DM.ReplaceDxilEntrySignature(F, NewFunc);
  135. DM.ReplaceDxilFunctionProps(F, NewFunc);
  136. }
  137. // Save function fp flag
  138. DxilFunctionFPFlag flag;
  139. flag.SetFlagValue(DM.GetTypeSystem().GetFunctionAnnotation(F)->GetFlag().GetFlagValue());
  140. DM.GetTypeSystem().EraseFunctionAnnotation(F);
  141. F->eraseFromParent();
  142. DM.GetTypeSystem().AddFunctionAnnotationWithFPFlag(NewFunc, &flag);
  143. return NewFunc;
  144. }
  145. void CheckInBoundForTGSM(GlobalVariable &GV, const DataLayout &DL) {
  146. for (User *U : GV.users()) {
  147. if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(U)) {
  148. bool allImmIndex = true;
  149. for (auto Idx = GEP->idx_begin(), E = GEP->idx_end(); Idx != E; Idx++) {
  150. if (!isa<ConstantInt>(Idx)) {
  151. allImmIndex = false;
  152. break;
  153. }
  154. }
  155. if (!allImmIndex)
  156. GEP->setIsInBounds(false);
  157. else {
  158. Value *Ptr = GEP->getPointerOperand();
  159. unsigned size =
  160. DL.getTypeAllocSize(Ptr->getType()->getPointerElementType());
  161. unsigned valSize =
  162. DL.getTypeAllocSize(GEP->getType()->getPointerElementType());
  163. SmallVector<Value *, 8> Indices(GEP->idx_begin(), GEP->idx_end());
  164. unsigned offset =
  165. DL.getIndexedOffset(GEP->getPointerOperandType(), Indices);
  166. if ((offset + valSize) > size)
  167. GEP->setIsInBounds(false);
  168. }
  169. }
  170. }
  171. }
  172. class DxilFinalizeModule : public ModulePass {
  173. public:
  174. static char ID; // Pass identification, replacement for typeid
  175. explicit DxilFinalizeModule() : ModulePass(ID) {}
  176. const char *getPassName() const override { return "HLSL DXIL Metadata Emit"; }
  177. void patchValidation_1_1(Module &M) {
  178. for (iplist<Function>::iterator F : M.getFunctionList()) {
  179. for (Function::iterator BBI = F->begin(), BBE = F->end(); BBI != BBE;
  180. ++BBI) {
  181. BasicBlock *BB = BBI;
  182. for (BasicBlock::iterator II = BB->begin(), IE = BB->end(); II != IE;
  183. ++II) {
  184. Instruction *I = II;
  185. if (I->hasMetadataOtherThanDebugLoc()) {
  186. SmallVector<std::pair<unsigned, MDNode*>, 2> MDs;
  187. I->getAllMetadataOtherThanDebugLoc(MDs);
  188. for (auto &MD : MDs) {
  189. unsigned kind = MD.first;
  190. // Remove Metadata which validation_1_0 not allowed.
  191. bool bNeedPatch = kind == LLVMContext::MD_tbaa ||
  192. kind == LLVMContext::MD_prof ||
  193. (kind > LLVMContext::MD_fpmath &&
  194. kind <= LLVMContext::MD_dereferenceable_or_null);
  195. if (bNeedPatch)
  196. I->setMetadata(kind, nullptr);
  197. }
  198. }
  199. }
  200. }
  201. }
  202. }
  203. bool runOnModule(Module &M) override {
  204. if (M.HasDxilModule()) {
  205. DxilModule &DM = M.GetDxilModule();
  206. bool IsLib = DM.GetShaderModel()->IsLib();
  207. // Skip validation patch for lib.
  208. if (!IsLib) {
  209. unsigned ValMajor = 0;
  210. unsigned ValMinor = 0;
  211. M.GetDxilModule().GetValidatorVersion(ValMajor, ValMinor);
  212. if (ValMajor == 1 && ValMinor <= 1) {
  213. patchValidation_1_1(M);
  214. }
  215. }
  216. // Remove store undef output.
  217. hlsl::OP *hlslOP = M.GetDxilModule().GetOP();
  218. RemoveStoreUndefOutput(M, hlslOP);
  219. RemoveUnusedStaticGlobal(M);
  220. // Clear inbound for GEP which has none-const index.
  221. LegalizeShareMemoryGEPInbound(M);
  222. // Strip parameters of entry function.
  223. StripEntryParameters(M, DM, IsLib);
  224. // Skip shader flag for library.
  225. if (!IsLib) {
  226. DM.CollectShaderFlags(); // Update flags to reflect any changes.
  227. // Update Validator Version
  228. DM.UpgradeToMinValidatorVersion();
  229. }
  230. return true;
  231. }
  232. return false;
  233. }
  234. private:
  235. void RemoveUnusedStaticGlobal(Module &M) {
  236. // Remove unused internal global.
  237. std::vector<GlobalVariable *> staticGVs;
  238. for (GlobalVariable &GV : M.globals()) {
  239. if (dxilutil::IsStaticGlobal(&GV) ||
  240. dxilutil::IsSharedMemoryGlobal(&GV)) {
  241. staticGVs.emplace_back(&GV);
  242. }
  243. }
  244. for (GlobalVariable *GV : staticGVs) {
  245. bool onlyStoreUse = true;
  246. for (User *user : GV->users()) {
  247. if (isa<StoreInst>(user))
  248. continue;
  249. if (isa<ConstantExpr>(user) && user->user_empty())
  250. continue;
  251. onlyStoreUse = false;
  252. break;
  253. }
  254. if (onlyStoreUse) {
  255. for (auto UserIt = GV->user_begin(); UserIt != GV->user_end();) {
  256. Value *User = *(UserIt++);
  257. if (Instruction *I = dyn_cast<Instruction>(User)) {
  258. I->eraseFromParent();
  259. } else {
  260. ConstantExpr *CE = cast<ConstantExpr>(User);
  261. CE->dropAllReferences();
  262. }
  263. }
  264. GV->eraseFromParent();
  265. }
  266. }
  267. }
  268. void RemoveStoreUndefOutput(Module &M, hlsl::OP *hlslOP) {
  269. for (iplist<Function>::iterator F : M.getFunctionList()) {
  270. if (!hlslOP->IsDxilOpFunc(F))
  271. continue;
  272. DXIL::OpCodeClass opClass;
  273. bool bHasOpClass = hlslOP->GetOpCodeClass(F, opClass);
  274. DXASSERT_LOCALVAR(bHasOpClass, bHasOpClass, "else not a dxil op func");
  275. if (opClass != DXIL::OpCodeClass::StoreOutput)
  276. continue;
  277. for (auto it = F->user_begin(); it != F->user_end();) {
  278. CallInst *CI = dyn_cast<CallInst>(*(it++));
  279. if (!CI)
  280. continue;
  281. Value *V = CI->getArgOperand(DXIL::OperandIndex::kStoreOutputValOpIdx);
  282. // Remove the store of undef.
  283. if (isa<UndefValue>(V))
  284. CI->eraseFromParent();
  285. }
  286. }
  287. }
  288. void LegalizeShareMemoryGEPInbound(Module &M) {
  289. const DataLayout &DL = M.getDataLayout();
  290. // Clear inbound for GEP which has none-const index.
  291. for (GlobalVariable &GV : M.globals()) {
  292. if (dxilutil::IsSharedMemoryGlobal(&GV)) {
  293. CheckInBoundForTGSM(GV, DL);
  294. }
  295. }
  296. }
  297. void StripEntryParameters(Module &M, DxilModule &DM, bool IsLib) {
  298. DenseMap<const Function *, DISubprogram *> FunctionDIs =
  299. makeSubprogramMap(M);
  300. // Strip parameters of entry function.
  301. if (!IsLib) {
  302. if (Function *PatchConstantFunc = DM.GetPatchConstantFunction()) {
  303. PatchConstantFunc =
  304. StripFunctionParameter(PatchConstantFunc, DM, FunctionDIs);
  305. if (PatchConstantFunc)
  306. DM.SetPatchConstantFunction(PatchConstantFunc);
  307. }
  308. if (Function *EntryFunc = DM.GetEntryFunction()) {
  309. StringRef Name = DM.GetEntryFunctionName();
  310. EntryFunc->setName(Name);
  311. EntryFunc = StripFunctionParameter(EntryFunc, DM, FunctionDIs);
  312. if (EntryFunc)
  313. DM.SetEntryFunction(EntryFunc);
  314. }
  315. } else {
  316. std::vector<Function *> entries;
  317. for (iplist<Function>::iterator F : M.getFunctionList()) {
  318. if (DM.HasDxilFunctionProps(F)) {
  319. entries.emplace_back(F);
  320. }
  321. }
  322. for (Function *entry : entries) {
  323. DxilFunctionProps &props = DM.GetDxilFunctionProps(entry);
  324. if (props.IsHS()) {
  325. // Strip patch constant function first.
  326. Function *patchConstFunc = StripFunctionParameter(
  327. props.ShaderProps.HS.patchConstantFunc, DM, FunctionDIs);
  328. props.ShaderProps.HS.patchConstantFunc = patchConstFunc;
  329. }
  330. StripFunctionParameter(entry, DM, FunctionDIs);
  331. }
  332. }
  333. }
  334. };
  335. }
  336. char DxilFinalizeModule::ID = 0;
  337. ModulePass *llvm::createDxilFinalizeModulePass() {
  338. return new DxilFinalizeModule();
  339. }
  340. INITIALIZE_PASS(DxilFinalizeModule, "hlsl-dxilfinalize", "HLSL DXIL Finalize Module", false, false)
  341. ///////////////////////////////////////////////////////////////////////////////
  342. namespace {
  343. class DxilEmitMetadata : public ModulePass {
  344. public:
  345. static char ID; // Pass identification, replacement for typeid
  346. explicit DxilEmitMetadata() : ModulePass(ID) {}
  347. const char *getPassName() const override { return "HLSL DXIL Metadata Emit"; }
  348. bool runOnModule(Module &M) override {
  349. if (M.HasDxilModule()) {
  350. M.GetDxilModule().EmitDxilMetadata();
  351. return true;
  352. }
  353. return false;
  354. }
  355. };
  356. }
  357. char DxilEmitMetadata::ID = 0;
  358. ModulePass *llvm::createDxilEmitMetadataPass() {
  359. return new DxilEmitMetadata();
  360. }
  361. INITIALIZE_PASS(DxilEmitMetadata, "hlsl-dxilemit", "HLSL DXIL Metadata Emit", false, false)