WaveSensitivityAnalysis.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // WaveSensitivityAnalysis.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. // This file provides support for doing analysis that are aware of wave //
  9. // intrinsics. //
  10. // //
  11. ///////////////////////////////////////////////////////////////////////////////
  12. #include "dxc/HLSL/DxilValidation.h"
  13. #include "dxc/HLSL/DxilGenerationPass.h"
  14. #include "dxc/DXIL/DxilOperations.h"
  15. #include "dxc/DXIL/DxilModule.h"
  16. #include "dxc/DXIL/DxilShaderModel.h"
  17. #include "dxc/DxilContainer/DxilContainer.h"
  18. #include "dxc/Support/Global.h"
  19. #include "dxc/HLSL/HLOperations.h"
  20. #include "dxc/HLSL/HLModule.h"
  21. #include "dxc/DXIL/DxilInstructions.h"
  22. #include "llvm/ADT/ArrayRef.h"
  23. #include "llvm/IR/LLVMContext.h"
  24. #include "llvm/IR/Module.h"
  25. #include "llvm/IR/Type.h"
  26. #include "llvm/IR/Instructions.h"
  27. #include "llvm/IR/InstIterator.h"
  28. #include "llvm/IR/Constants.h"
  29. #include "llvm/IR/DiagnosticInfo.h"
  30. #include "llvm/IR/DiagnosticPrinter.h"
  31. #include "llvm/ADT/BitVector.h"
  32. #include "llvm/Analysis/PostDominators.h"
  33. #ifdef _WIN32
  34. #include <winerror.h>
  35. #endif
  36. #include "llvm/Support/raw_ostream.h"
  37. #include <unordered_set>
  38. using namespace llvm;
  39. using namespace std;
  40. namespace hlsl {
  41. // WaveSensitivityAnalysis is created to validate Gradient operations.
  42. // Gradient operations require all neighbor lanes to be active when calculated,
  43. // compiler will enable lanes to meet this requirement. If a wave operation
  44. // contributed to gradient operation, it will get unexpected result because the
  45. // active lanes are modified.
  46. // To avoid unexpected result, validation will fail if gradient operations
  47. // are dependent on wave-sensitive data or control flow.
  48. class WaveSensitivityAnalyzer : public WaveSensitivityAnalysis {
  49. private:
  50. enum WaveSensitivity {
  51. KnownSensitive,
  52. KnownNotSensitive,
  53. Unknown
  54. };
  55. PostDominatorTree *pPDT;
  56. map<Instruction *, WaveSensitivity> InstState;
  57. map<BasicBlock *, WaveSensitivity> BBState;
  58. std::vector<Instruction *> InstWorkList;
  59. std::vector<PHINode *> UnknownPhis; // currently unknown phis. Indicate cycles after Analyze
  60. std::vector<BasicBlock *> BBWorkList;
  61. bool CheckBBState(BasicBlock *BB, WaveSensitivity WS);
  62. WaveSensitivity GetInstState(Instruction *I);
  63. void UpdateBlock(BasicBlock *BB, WaveSensitivity WS);
  64. void UpdateInst(Instruction *I, WaveSensitivity WS);
  65. void VisitInst(Instruction *I);
  66. public:
  67. WaveSensitivityAnalyzer(PostDominatorTree &PDT) : pPDT(&PDT) {}
  68. void Analyze(Function *F);
  69. void Analyze();
  70. bool IsWaveSensitive(Instruction *op);
  71. };
  72. WaveSensitivityAnalysis* WaveSensitivityAnalysis::create(PostDominatorTree &PDT) {
  73. return new WaveSensitivityAnalyzer(PDT);
  74. }
  75. // Analyze the given function's instructions as wave-sensitive or not
  76. void WaveSensitivityAnalyzer::Analyze(Function *F) {
  77. // Add all blocks but the entry in reverse order so they come out in order
  78. auto it = F->getBasicBlockList().end();
  79. for ( it-- ; it != F->getBasicBlockList().begin(); it--)
  80. BBWorkList.emplace_back(&*it);
  81. // Add entry block as non-sensitive
  82. UpdateBlock(&*it, KnownNotSensitive);
  83. // First analysis
  84. Analyze();
  85. // If any phis with explored preds remain unknown
  86. // it has to be in a loop that don't include wave sensitivity
  87. // Update each as such and redo Analyze to mark the descendents
  88. while (!UnknownPhis.empty() || !InstWorkList.empty() || !BBWorkList.empty()) {
  89. while (!UnknownPhis.empty()) {
  90. PHINode *Phi = UnknownPhis.back();
  91. UnknownPhis.pop_back();
  92. // UnknownPhis might have actually known phis that were changed. skip them
  93. if (Unknown == GetInstState(Phi)) {
  94. // If any of the preds have not been visited, we can't assume a cycle yet
  95. bool allPredsVisited = true;
  96. for (unsigned i = 0; i < Phi->getNumIncomingValues(); i++) {
  97. if (!BBState.count(Phi->getIncomingBlock(i))) {
  98. allPredsVisited = false;
  99. break;
  100. }
  101. }
  102. #ifndef NDEBUG
  103. for (unsigned i = 0; i < Phi->getNumIncomingValues(); i++) {
  104. if (Instruction *IArg = dyn_cast<Instruction>(Phi->getIncomingValue(i))) {
  105. DXASSERT_LOCALVAR(IArg, GetInstState(IArg) != KnownSensitive,
  106. "Unknown wave-status Phi argument should not be able to be known sensitive");
  107. }
  108. }
  109. #endif
  110. if (allPredsVisited)
  111. UpdateInst(Phi, KnownNotSensitive);
  112. }
  113. }
  114. Analyze();
  115. }
  116. #ifndef NDEBUG
  117. for (BasicBlock &BB : *F) {
  118. for (Instruction &I : BB) {
  119. DXASSERT_LOCALVAR(I, Unknown != GetInstState(&I), "Wave sensitivity analysis exited without finding results for all instructions");
  120. }
  121. }
  122. #endif
  123. }
  124. // Analyze the member instruction and BBlock worklists
  125. void WaveSensitivityAnalyzer::Analyze() {
  126. while (!InstWorkList.empty() || !BBWorkList.empty()) {
  127. // Process the instruction work list.
  128. while (!InstWorkList.empty()) {
  129. Instruction *I = InstWorkList.back();
  130. InstWorkList.pop_back();
  131. // "I" got into the work list because it made a transition.
  132. for (User *U : I->users()) {
  133. Instruction *UI = cast<Instruction>(U);
  134. VisitInst(UI);
  135. }
  136. }
  137. // Process one entry of the basic block work list.
  138. if (!BBWorkList.empty()) {
  139. BasicBlock *BB = BBWorkList.back();
  140. BBWorkList.pop_back();
  141. // Notify all instructions in this basic block that they need to
  142. // be reevaluated (eg, a block previously though to be insensitive
  143. // is now sensitive).
  144. for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
  145. VisitInst(I);
  146. }
  147. }
  148. }
  149. bool WaveSensitivityAnalyzer::CheckBBState(BasicBlock *BB, WaveSensitivity WS) {
  150. auto c = BBState.find(BB);
  151. if (c == BBState.end()) {
  152. return WS == Unknown;
  153. }
  154. else {
  155. return (*c).second == WS;
  156. }
  157. }
  158. WaveSensitivityAnalyzer::WaveSensitivity
  159. WaveSensitivityAnalyzer::GetInstState(Instruction *I) {
  160. auto c = InstState.find(I);
  161. if (c == InstState.end())
  162. return Unknown;
  163. return (*c).second;
  164. }
  165. void WaveSensitivityAnalyzer::UpdateBlock(BasicBlock *BB, WaveSensitivity WS) {
  166. auto c = BBState.find(BB);
  167. // Do not update if an entry is already found and it hasn't changed or
  168. // has already been marked as wave sensitive (an insensitive term might
  169. // try to mark it as such, but this effectively implements the 'any pred'
  170. // rule).
  171. if (c != BBState.end() && ((*c).second == WS || (*c).second == KnownSensitive))
  172. return;
  173. BBState[BB] = WS;
  174. BBWorkList.push_back(BB);
  175. }
  176. void WaveSensitivityAnalyzer::UpdateInst(Instruction *I, WaveSensitivity WS) {
  177. auto c = InstState.find(I);
  178. if (c == InstState.end() || (*c).second != WS) {
  179. InstState[I] = WS;
  180. InstWorkList.push_back(I);
  181. if (TerminatorInst * TI = dyn_cast<TerminatorInst>(I)) {
  182. BasicBlock *CurBB = TI->getParent();
  183. for (unsigned i = 0; i < TI->getNumSuccessors(); ++i) {
  184. BasicBlock *BB = TI->getSuccessor(i);
  185. // Only propagate WS when BB not post dom CurBB.
  186. WaveSensitivity TmpWS = pPDT->properlyDominates(BB, CurBB)
  187. ? WaveSensitivity::KnownNotSensitive
  188. : WS;
  189. UpdateBlock(BB, TmpWS);
  190. }
  191. }
  192. }
  193. }
  194. void WaveSensitivityAnalyzer::VisitInst(Instruction *I) {
  195. unsigned firstArg = 0;
  196. if (CallInst *CI = dyn_cast<CallInst>(I)) {
  197. if (OP::IsDxilOpFuncCallInst(CI)) {
  198. firstArg = 1;
  199. OP::OpCode opcode = OP::GetDxilOpFuncCallInst(CI);
  200. if (OP::IsDxilOpWave(opcode)) {
  201. UpdateInst(I, KnownSensitive);
  202. return;
  203. }
  204. }
  205. }
  206. if (CheckBBState(I->getParent(), KnownSensitive)) {
  207. UpdateInst(I, KnownSensitive);
  208. return;
  209. }
  210. // Catch control flow wave sensitive for phi.
  211. if (PHINode *Phi = dyn_cast<PHINode>(I)) {
  212. for (unsigned i = 0; i < Phi->getNumIncomingValues(); i++) {
  213. BasicBlock *BB = Phi->getIncomingBlock(i);
  214. WaveSensitivity WS = GetInstState(BB->getTerminator());
  215. if (WS == KnownSensitive) {
  216. UpdateInst(I, KnownSensitive);
  217. return;
  218. } else if (Unknown == GetInstState(I)) {
  219. UnknownPhis.emplace_back(Phi);
  220. }
  221. }
  222. }
  223. bool allKnownNotSensitive = true;
  224. for (unsigned i = firstArg; i < I->getNumOperands(); ++i) {
  225. Value *V = I->getOperand(i);
  226. if (Instruction *IArg = dyn_cast<Instruction>(V)) {
  227. WaveSensitivity WS = GetInstState(IArg);
  228. if (WS == KnownSensitive) {
  229. UpdateInst(I, KnownSensitive);
  230. return;
  231. } else if (WS == Unknown) {
  232. allKnownNotSensitive = false;
  233. }
  234. }
  235. }
  236. if (allKnownNotSensitive) {
  237. UpdateInst(I, KnownNotSensitive);
  238. }
  239. }
  240. bool WaveSensitivityAnalyzer::IsWaveSensitive(Instruction *op) {
  241. auto c = InstState.find(op);
  242. if(c == InstState.end()) {
  243. DXASSERT(false, "Instruction sensitivity not foud. Analysis didn't complete!");
  244. return false;
  245. }
  246. DXASSERT((*c).second != Unknown, "else analysis is missing a case");
  247. return (*c).second == KnownSensitive;
  248. }
  249. } // namespace hlsl