DxilNoops.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // DxilNoops.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 insert dx.noops() and replace them with llvm.donothing() //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. //
  12. // Here is how dx.preserve and dx.noop work.
  13. //
  14. // For example, the following HLSL code:
  15. //
  16. // float foo(float y) {
  17. // float x = 10;
  18. // x = 20;
  19. // x += y;
  20. // return x;
  21. // }
  22. //
  23. // float main() : SV_Target {
  24. // float ret = foo(10);
  25. // return ret;
  26. // }
  27. //
  28. // Ordinarily, it gets lowered as:
  29. //
  30. // dx.op.storeOutput(3.0)
  31. //
  32. // Intermediate steps at "x = 20;", "x += y;", "return x", and
  33. // even the call to "foo()" are lost.
  34. //
  35. // But with with Preserve and Noop:
  36. //
  37. // void call dx.noop() // float ret = foo(10);
  38. // %y = dx.preserve(10.0, 10.0) // argument: y=10
  39. // %x0 = dx.preserve(10.0, 10.0) // float x = 10;
  40. // %x1 = dx.preserve(20.0, %x0) // x = 20;
  41. // %x2 = fadd %x1, %y // x += y;
  42. // void call dx.noop() // return x
  43. // %ret = dx.preserve(%x2, %x2) // ret = returned from foo()
  44. // dx.op.storeOutput(%ret)
  45. //
  46. // All the intermediate transformations are visible and could be
  47. // made inspectable in the debugger.
  48. //
  49. // The reason why dx.preserve takes 2 arguments is so that the previous
  50. // value of a variable does not get cleaned up by DCE. For example:
  51. //
  52. // float x = ...;
  53. // do_some_stuff_with(x);
  54. // do_some_other_stuff(); // At this point, x's last values
  55. // // are dead and register allocators
  56. // // are free to reuse its location during
  57. // // call this code.
  58. // // So until x is assigned a new value below
  59. // // x could become unavailable.
  60. // //
  61. // // The second parameter in dx.preserve
  62. // // keeps x's previous value alive.
  63. //
  64. // x = ...; // Assign something else
  65. //
  66. //
  67. // When emitting proper DXIL, dx.noop and dx.preserve are lowered to
  68. // ordinary LLVM instructions that do not affect the semantic of the
  69. // shader, but can be used by a debugger or backend generator if they
  70. // know what to look for.
  71. //
  72. // We generate two special internal constant global vars:
  73. //
  74. // @dx.preserve.value = internal constant i1 false
  75. // @dx.nothing = internal constant i32 0
  76. //
  77. // "call dx.noop()" is lowered to "load @dx.nothing"
  78. //
  79. // "... = call dx.preserve(%cur_val, %last_val)" is lowered to:
  80. //
  81. // %p = load @dx.preserve.value
  82. // ... = select i1 %p, %last_val, %cur_val
  83. //
  84. // Since %p is guaranteed to be false, the select is guaranteed
  85. // to return %cur_val.
  86. //
  87. #include "llvm/Pass.h"
  88. #include "llvm/IR/Module.h"
  89. #include "llvm/IR/Instructions.h"
  90. #include "llvm/IR/IntrinsicInst.h"
  91. #include "llvm/IR/Intrinsics.h"
  92. #include "llvm/IR/IRBuilder.h"
  93. #include "llvm/Transforms/Scalar.h"
  94. #include "llvm/Transforms/Utils/Local.h"
  95. #include "llvm/IR/DIBuilder.h"
  96. #include "llvm/Support/raw_os_ostream.h"
  97. #include "dxc/DXIL/DxilMetadataHelper.h"
  98. #include "dxc/DXIL/DxilConstants.h"
  99. #include "dxc/HLSL/DxilNoops.h"
  100. #include "llvm/Analysis/DxilValueCache.h"
  101. #include <unordered_set>
  102. using namespace llvm;
  103. static Function *GetOrCreateNoopF(Module &M) {
  104. LLVMContext &Ctx = M.getContext();
  105. FunctionType *FT = FunctionType::get(Type::getVoidTy(Ctx), false);
  106. Function *NoopF = cast<Function>(M.getOrInsertFunction(hlsl::kNoopName, FT));
  107. NoopF->addFnAttr(Attribute::AttrKind::Convergent);
  108. return NoopF;
  109. }
  110. static Constant *GetConstGep(Constant *Ptr, unsigned Idx0, unsigned Idx1) {
  111. Type *i32Ty = Type::getInt32Ty(Ptr->getContext());
  112. Constant *Indices[] = { ConstantInt::get(i32Ty, Idx0), ConstantInt::get(i32Ty, Idx1) };
  113. return ConstantExpr::getGetElementPtr(nullptr, Ptr, Indices);
  114. }
  115. struct Store_Info {
  116. Instruction *StoreOrMC = nullptr;
  117. Value *Source = nullptr; // Alloca, GV, or Argument
  118. bool AllowLoads = false;
  119. };
  120. static void FindAllStores(Value *Ptr, std::vector<Store_Info> *Stores, std::vector<Value *> &WorklistStorage, std::unordered_set<Value *> &SeenStorage) {
  121. assert(isa<Argument>(Ptr) || isa<AllocaInst>(Ptr) || isa<GlobalVariable>(Ptr));
  122. WorklistStorage.clear();
  123. WorklistStorage.push_back(Ptr);
  124. // Don't clear Seen Storage because two pointers can be involved with the same
  125. // memcpy. Clearing it can get the memcpy added twice.
  126. unsigned StartIdx = Stores->size();
  127. bool AllowLoad = false;
  128. while (WorklistStorage.size()) {
  129. Value *V = WorklistStorage.back();
  130. WorklistStorage.pop_back();
  131. SeenStorage.insert(V);
  132. if (isa<BitCastOperator>(V) || isa<GEPOperator>(V) || isa<GlobalVariable>(V) || isa<AllocaInst>(V) || isa<Argument>(V)) {
  133. for (User *U : V->users()) {
  134. MemCpyInst *MC = nullptr;
  135. // Allow load if MC reads from pointer
  136. if ((MC = dyn_cast<MemCpyInst>(U)) && MC->getSource() == V) {
  137. AllowLoad = true;
  138. }
  139. else if (isa<LoadInst>(U)) {
  140. AllowLoad = true;
  141. }
  142. // Add to worklist if we haven't seen it before.
  143. else {
  144. if (!SeenStorage.count(U))
  145. WorklistStorage.push_back(U);
  146. }
  147. }
  148. }
  149. else if (StoreInst *Store = dyn_cast<StoreInst>(V)) {
  150. Store_Info Info;
  151. Info.StoreOrMC = Store;
  152. Info.Source = Ptr;
  153. Stores->push_back(Info);
  154. }
  155. else if (MemCpyInst *MC = dyn_cast<MemCpyInst>(V)) {
  156. Store_Info Info;
  157. Info.StoreOrMC = MC;
  158. Info.Source = Ptr;
  159. Stores->push_back(Info);
  160. }
  161. }
  162. if (isa<GlobalVariable>(Ptr)) {
  163. AllowLoad = true;
  164. }
  165. if (AllowLoad) {
  166. Store_Info *ptr = Stores->data();
  167. for (unsigned i = StartIdx; i < Stores->size(); i++)
  168. ptr[i].AllowLoads = true;
  169. }
  170. }
  171. static User *GetUniqueUser(Value *V) {
  172. if (V->user_begin() != V->user_end()) {
  173. if (std::next(V->user_begin()) == V->user_end())
  174. return *V->user_begin();
  175. }
  176. return nullptr;
  177. }
  178. static Value *GetOrCreatePreserveCond(Function *F) {
  179. assert(!F->isDeclaration());
  180. Module *M = F->getParent();
  181. GlobalVariable *GV = M->getGlobalVariable(hlsl::kPreserveName, true);
  182. if (!GV) {
  183. Type *i32Ty = Type::getInt32Ty(M->getContext());
  184. Type *i32ArrayTy = ArrayType::get(i32Ty, 1);
  185. unsigned int Values[1] = { 0 };
  186. Constant *InitialValue = llvm::ConstantDataArray::get(M->getContext(), Values);
  187. GV = new GlobalVariable(*M,
  188. i32ArrayTy, true,
  189. llvm::GlobalValue::InternalLinkage,
  190. InitialValue, hlsl::kPreserveName);
  191. }
  192. for (User *U : GV->users()) {
  193. GEPOperator *Gep = cast<GEPOperator>(U);
  194. for (User *GepU : Gep->users()) {
  195. LoadInst *LI = cast<LoadInst>(GepU);
  196. if (LI->getParent()->getParent() == F) {
  197. return GetUniqueUser(LI);
  198. }
  199. }
  200. }
  201. BasicBlock *BB = &F->getEntryBlock();
  202. Instruction *InsertPt = &BB->front();
  203. while (isa<AllocaInst>(InsertPt) || isa<DbgInfoIntrinsic>(InsertPt))
  204. InsertPt = InsertPt->getNextNode();
  205. IRBuilder<> B(InsertPt);
  206. Constant *Gep = GetConstGep(GV, 0, 0);
  207. LoadInst *Load = B.CreateLoad(Gep);
  208. return B.CreateTrunc(Load, B.getInt1Ty());
  209. }
  210. bool hlsl::IsPreserve(llvm::Instruction *I) {
  211. SelectInst *S = dyn_cast<SelectInst>(I);
  212. if (!S)
  213. return false;
  214. TruncInst *Trunc = dyn_cast<TruncInst>(S->getCondition());
  215. if (!Trunc)
  216. return false;
  217. LoadInst *Load = dyn_cast<LoadInst>(Trunc->getOperand(0));
  218. if (!Load)
  219. return false;
  220. GEPOperator *GEP = dyn_cast<GEPOperator>(Load->getPointerOperand());
  221. if (!GEP)
  222. return false;
  223. GlobalVariable *GV = dyn_cast<GlobalVariable>(GEP->getPointerOperand());
  224. return GV && GV->getLinkage() == GlobalVariable::LinkageTypes::InternalLinkage && GV->getName() == kPreserveName;
  225. }
  226. static Function *GetOrCreatePreserveF(Module *M, Type *Ty) {
  227. std::string str = hlsl::kPreservePrefix;
  228. raw_string_ostream os(str);
  229. Ty->print(os);
  230. os.flush();
  231. FunctionType *FT = FunctionType::get(Ty, { Ty, Ty }, false);
  232. Function *PreserveF = cast<Function>(M->getOrInsertFunction(str, FT));
  233. PreserveF->addFnAttr(Attribute::AttrKind::ReadNone);
  234. PreserveF->addFnAttr(Attribute::AttrKind::NoUnwind);
  235. return PreserveF;
  236. }
  237. static Instruction *CreatePreserve(Value *V, Value *LastV, Instruction *InsertPt) {
  238. assert(V->getType() == LastV->getType());
  239. Type *Ty = V->getType();
  240. Function *PreserveF = GetOrCreatePreserveF(InsertPt->getModule(), Ty);
  241. return CallInst::Create(PreserveF, ArrayRef<Value *> { V, LastV }, "", InsertPt);
  242. }
  243. static void LowerPreserveToSelect(CallInst *CI) {
  244. Value *V = CI->getArgOperand(0);
  245. Value *LastV = CI->getArgOperand(1);
  246. if (LastV == V)
  247. LastV = UndefValue::get(V->getType());
  248. Value *Cond = GetOrCreatePreserveCond(CI->getParent()->getParent());
  249. SelectInst *Select = SelectInst::Create(Cond, LastV, V, "", CI);
  250. Select->setDebugLoc(CI->getDebugLoc());
  251. CI->replaceAllUsesWith(Select);
  252. CI->eraseFromParent();
  253. }
  254. static void InsertNoopAt(Instruction *I) {
  255. Module &M = *I->getModule();
  256. Function *NoopF = GetOrCreateNoopF(M);
  257. CallInst *Noop = CallInst::Create(NoopF, {}, I);
  258. Noop->setDebugLoc(I->getDebugLoc());
  259. }
  260. static void InsertPreserve(bool AllowLoads, StoreInst *Store) {
  261. Value *V = Store->getValueOperand();
  262. IRBuilder<> B(Store);
  263. Value *Last_Value = nullptr;
  264. // If there's never any loads for this memory location,
  265. // don't generate a load.
  266. if (AllowLoads) {
  267. Last_Value = B.CreateLoad(Store->getPointerOperand());
  268. }
  269. else {
  270. Last_Value = UndefValue::get(V->getType());
  271. }
  272. Instruction *Preserve = CreatePreserve(V, Last_Value, Store);
  273. Preserve->setDebugLoc(Store->getDebugLoc());
  274. Store->replaceUsesOfWith(V, Preserve);
  275. }
  276. //==========================================================
  277. // Insertion pass
  278. //
  279. // This pass inserts dx.noop and dx.preserve where we want
  280. // to preserve line mapping or perserve some intermediate
  281. // values.
  282. struct DxilInsertPreserves : public ModulePass {
  283. static char ID;
  284. DxilInsertPreserves(bool AllowPreserves=false) : ModulePass(ID), AllowPreserves(AllowPreserves) {
  285. initializeDxilInsertPreservesPass(*PassRegistry::getPassRegistry());
  286. }
  287. bool AllowPreserves = false;
  288. // Function overrides that resolve options when used for DxOpt
  289. void applyOptions(PassOptions O) override {
  290. GetPassOptionBool(O, "AllowPreserves", &AllowPreserves, false);
  291. }
  292. void dumpConfig(raw_ostream &OS) override {
  293. ModulePass::dumpConfig(OS);
  294. OS << ",AllowPreserves=" << AllowPreserves;
  295. }
  296. bool runOnModule(Module &M) override {
  297. std::vector<Store_Info> Stores;
  298. std::vector<Value *> WorklistStorage;
  299. std::unordered_set<Value *> SeenStorage;
  300. for (GlobalVariable &GV : M.globals()) {
  301. if (GV.getLinkage() != GlobalValue::LinkageTypes::InternalLinkage ||
  302. GV.getType()->getPointerAddressSpace() == hlsl::DXIL::kTGSMAddrSpace)
  303. {
  304. continue;
  305. }
  306. for (User *U : GV.users()) {
  307. if (LoadInst *LI = dyn_cast<LoadInst>(U)) {
  308. InsertNoopAt(LI);
  309. }
  310. }
  311. FindAllStores(&GV, &Stores, WorklistStorage, SeenStorage);
  312. }
  313. bool Changed = false;
  314. for (Function &F : M) {
  315. if (F.isDeclaration())
  316. continue;
  317. // Collect Stores on Allocas in function
  318. BasicBlock *Entry = &*F.begin();
  319. for (Instruction &I : *Entry) {
  320. AllocaInst *AI = dyn_cast<AllocaInst>(&I);
  321. if (!AI)
  322. continue;
  323. // Skip temp allocas
  324. if (!AI->getMetadata(hlsl::DxilMDHelper::kDxilTempAllocaMDName))
  325. FindAllStores(AI, &Stores, WorklistStorage, SeenStorage);
  326. }
  327. // Collect Stores on pointer Arguments in function
  328. for (Argument &Arg : F.args()) {
  329. if (Arg.getType()->isPointerTy())
  330. FindAllStores(&Arg, &Stores, WorklistStorage, SeenStorage);
  331. }
  332. // For every real function call, insert a nop
  333. // so we can put a breakpoint there.
  334. for (User *U : F.users()) {
  335. if (CallInst *CI = dyn_cast<CallInst>(U)) {
  336. InsertNoopAt(CI);
  337. }
  338. }
  339. // Insert nops for void return statements
  340. for (BasicBlock &BB : F) {
  341. ReturnInst *Ret = dyn_cast<ReturnInst>(BB.getTerminator());
  342. if (Ret)
  343. InsertNoopAt(Ret);
  344. }
  345. }
  346. // Insert preserves or noops for these stores
  347. for (Store_Info &Info : Stores) {
  348. if (StoreInst *Store = dyn_cast<StoreInst>(Info.StoreOrMC)) {
  349. Value *V = Store->getValueOperand();
  350. if (this->AllowPreserves && V &&
  351. !V->getType()->isAggregateType() &&
  352. !V->getType()->isPointerTy())
  353. {
  354. InsertPreserve(Info.AllowLoads, Store);
  355. Changed = true;
  356. }
  357. else {
  358. InsertNoopAt(Store);
  359. Changed = true;
  360. }
  361. }
  362. else if (MemCpyInst *MC = cast<MemCpyInst>(Info.StoreOrMC)) {
  363. // TODO: Do something to preserve pointer's previous value.
  364. InsertNoopAt(MC);
  365. Changed = true;
  366. }
  367. }
  368. return Changed;
  369. }
  370. const char *getPassName() const override { return "Dxil Insert Preserves"; }
  371. };
  372. char DxilInsertPreserves::ID;
  373. Pass *llvm::createDxilInsertPreservesPass(bool AllowPreserves) {
  374. return new DxilInsertPreserves(AllowPreserves);
  375. }
  376. INITIALIZE_PASS(DxilInsertPreserves, "dxil-insert-preserves", "Dxil Insert Preserves", false, false)
  377. //==========================================================
  378. // Lower dx.preserve to select
  379. //
  380. // This pass replaces all dx.preserve calls to select
  381. //
  382. namespace {
  383. class DxilPreserveToSelect : public ModulePass {
  384. public:
  385. static char ID;
  386. SmallDenseMap<Type *, Function *> PreserveFunctions;
  387. DxilPreserveToSelect() : ModulePass(ID) {
  388. initializeDxilPreserveToSelectPass(*PassRegistry::getPassRegistry());
  389. }
  390. bool runOnModule(Module &M) override {
  391. bool Changed = false;
  392. for (auto fit = M.getFunctionList().begin(), end = M.getFunctionList().end();
  393. fit != end;)
  394. {
  395. Function *F = &*(fit++);
  396. if (!F->isDeclaration())
  397. continue;
  398. if (F->getName().startswith(hlsl::kPreservePrefix)) {
  399. for (auto uit = F->user_begin(), end = F->user_end(); uit != end;) {
  400. User *U = *(uit++);
  401. CallInst *CI = cast<CallInst>(U);
  402. LowerPreserveToSelect(CI);
  403. }
  404. F->eraseFromParent();
  405. Changed = true;
  406. }
  407. }
  408. return Changed;
  409. }
  410. const char *getPassName() const override { return "Dxil Lower Preserves to Selects"; }
  411. };
  412. char DxilPreserveToSelect::ID;
  413. }
  414. Pass *llvm::createDxilPreserveToSelectPass() {
  415. return new DxilPreserveToSelect();
  416. }
  417. INITIALIZE_PASS(DxilPreserveToSelect, "dxil-preserves-to-select", "Dxil Preserves To Select", false, false)
  418. //==========================================================
  419. // output Argument debug info rewrite
  420. //
  421. namespace {
  422. class DxilRewriteOutputArgDebugInfo : public ModulePass {
  423. public:
  424. static char ID;
  425. DxilRewriteOutputArgDebugInfo() : ModulePass(ID) {
  426. initializeDxilRewriteOutputArgDebugInfoPass(*PassRegistry::getPassRegistry());
  427. }
  428. bool runOnModule(Module &M) override {
  429. DITypeIdentifierMap EmptyMap;
  430. DIBuilder DIB(M);
  431. bool Changed = false;
  432. for (Function &F : M) {
  433. for (Argument &Arg : F.args()) {
  434. if (!Arg.getType()->isPointerTy())
  435. continue;
  436. DbgDeclareInst *Declare = llvm::FindAllocaDbgDeclare(&Arg);
  437. if (!Declare)
  438. continue;
  439. DILocalVariable *Var = Declare->getVariable();
  440. DIType *Ty = Var->getType().resolve(EmptyMap);
  441. DIExpression *Expr = Declare->getExpression();
  442. if (Expr->getNumElements() == 1 && Expr->getElement(0) == dwarf::DW_OP_deref) {
  443. while (Ty && (Ty->getTag() == dwarf::DW_TAG_reference_type ||
  444. Ty->getTag() == dwarf::DW_TAG_restrict_type))
  445. {
  446. Ty = cast<DIDerivedType>(Ty)->getBaseType().resolve(EmptyMap);
  447. }
  448. if (Ty) {
  449. DILocalVariable *NewVar =
  450. DIB.createLocalVariable(dwarf::DW_TAG_arg_variable,
  451. Var->getScope(), Var->getName(), Var->getFile(),
  452. Var->getLine(), Ty, false, 0, Var->getArg());
  453. DIExpression *EmptyExpr = DIExpression::get(M.getContext(), {});
  454. DIB.insertDeclare(&Arg, NewVar, EmptyExpr, Declare->getDebugLoc(), Declare);
  455. Declare->eraseFromParent();
  456. Changed = true;
  457. }
  458. }
  459. }
  460. }
  461. return Changed;
  462. }
  463. const char *getPassName() const override { return "Dxil Rewrite Output Arg Debug Info"; }
  464. };
  465. char DxilRewriteOutputArgDebugInfo::ID;
  466. }
  467. Pass *llvm::createDxilRewriteOutputArgDebugInfoPass() {
  468. return new DxilRewriteOutputArgDebugInfo();
  469. }
  470. INITIALIZE_PASS(DxilRewriteOutputArgDebugInfo, "dxil-rewrite-output-arg-debug-info", "Dxil Rewrite Output Arg Debug Info", false, false)
  471. //==========================================================
  472. // Finalize pass
  473. //
  474. namespace {
  475. class DxilFinalizePreserves : public ModulePass {
  476. public:
  477. static char ID;
  478. GlobalVariable *NothingGV = nullptr;
  479. DxilFinalizePreserves() : ModulePass(ID) {
  480. initializeDxilFinalizePreservesPass(*PassRegistry::getPassRegistry());
  481. }
  482. Instruction *GetFinalNoopInst(Module &M, Instruction *InsertBefore) {
  483. Type *i32Ty = Type::getInt32Ty(M.getContext());
  484. if (!NothingGV) {
  485. NothingGV = M.getGlobalVariable(hlsl::kNothingName);
  486. if (!NothingGV) {
  487. Type *i32ArrayTy = ArrayType::get(i32Ty, 1);
  488. unsigned int Values[1] = { 0 };
  489. Constant *InitialValue = llvm::ConstantDataArray::get(M.getContext(), Values);
  490. NothingGV = new GlobalVariable(M,
  491. i32ArrayTy, true,
  492. llvm::GlobalValue::InternalLinkage,
  493. InitialValue, hlsl::kNothingName);
  494. }
  495. }
  496. Constant *Gep = GetConstGep(NothingGV, 0, 0);
  497. return new llvm::LoadInst(Gep, nullptr, InsertBefore);
  498. }
  499. bool LowerPreserves(Module &M);
  500. bool LowerNoops(Module &M);
  501. bool runOnModule(Module &M) override;
  502. const char *getPassName() const override { return "Dxil Finalize Preserves"; }
  503. };
  504. char DxilFinalizePreserves::ID;
  505. }
  506. // Fix undefs in the dx.preserve -> selects
  507. bool DxilFinalizePreserves::LowerPreserves(Module &M) {
  508. bool Changed = false;
  509. GlobalVariable *GV = M.getGlobalVariable(hlsl::kPreserveName, true);
  510. if (GV) {
  511. for (User *U : GV->users()) {
  512. GEPOperator *Gep = cast<GEPOperator>(U);
  513. for (User *GepU : Gep->users()) {
  514. LoadInst *LI = cast<LoadInst>(GepU);
  515. assert(LI->user_begin() != LI->user_end() &&
  516. std::next(LI->user_begin()) == LI->user_end());
  517. Instruction *I = cast<Instruction>(*LI->user_begin());
  518. for (User *UU : I->users()) {
  519. SelectInst *P = cast<SelectInst>(UU);
  520. Value *PrevV = P->getTrueValue();
  521. Value *CurV = P->getFalseValue();
  522. if (isa<UndefValue>(PrevV) || isa<Constant>(PrevV)) {
  523. P->setOperand(1, CurV);
  524. Changed = true;
  525. }
  526. }
  527. }
  528. }
  529. }
  530. return Changed;
  531. }
  532. // Replace all @dx.noop's with load @dx.nothing.value
  533. bool DxilFinalizePreserves::LowerNoops(Module &M) {
  534. bool Changed = false;
  535. Function *NoopF = nullptr;
  536. for (Function &F : M) {
  537. if (!F.isDeclaration())
  538. continue;
  539. if (F.getName() == hlsl::kNoopName) {
  540. NoopF = &F;
  541. }
  542. }
  543. if (NoopF) {
  544. for (auto It = NoopF->user_begin(), E = NoopF->user_end(); It != E;) {
  545. User *U = *(It++);
  546. CallInst *CI = cast<CallInst>(U);
  547. Instruction *Nop = GetFinalNoopInst(M, CI);
  548. Nop->setDebugLoc(CI->getDebugLoc());
  549. CI->eraseFromParent();
  550. Changed = true;
  551. }
  552. assert(NoopF->user_empty() && "dx.noop calls must be all removed now");
  553. NoopF->eraseFromParent();
  554. }
  555. return Changed;
  556. }
  557. // Replace all preserves and nops
  558. bool DxilFinalizePreserves::runOnModule(Module &M) {
  559. bool Changed = false;
  560. Changed |= LowerPreserves(M);
  561. Changed |= LowerNoops(M);
  562. return Changed;
  563. }
  564. Pass *llvm::createDxilFinalizePreservesPass() {
  565. return new DxilFinalizePreserves();
  566. }
  567. INITIALIZE_PASS(DxilFinalizePreserves, "dxil-finalize-preserves", "Dxil Finalize Preserves", false, false)