WaveSensitivityAnalysis.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  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<BasicBlock *> BBWorkList;
  60. bool CheckBBState(BasicBlock *BB, WaveSensitivity WS);
  61. WaveSensitivity GetInstState(Instruction *I);
  62. void UpdateBlock(BasicBlock *BB, WaveSensitivity WS);
  63. void UpdateInst(Instruction *I, WaveSensitivity WS);
  64. void VisitInst(Instruction *I);
  65. public:
  66. WaveSensitivityAnalyzer(PostDominatorTree &PDT) : pPDT(&PDT) {}
  67. void Analyze(Function *F);
  68. bool IsWaveSensitive(Instruction *op);
  69. };
  70. WaveSensitivityAnalysis* WaveSensitivityAnalysis::create(PostDominatorTree &PDT) {
  71. return new WaveSensitivityAnalyzer(PDT);
  72. }
  73. void WaveSensitivityAnalyzer::Analyze(Function *F) {
  74. UpdateBlock(&F->getEntryBlock(), KnownNotSensitive);
  75. while (!InstWorkList.empty() || !BBWorkList.empty()) {
  76. // Process the instruction work list.
  77. while (!InstWorkList.empty()) {
  78. Instruction *I = InstWorkList.back();
  79. InstWorkList.pop_back();
  80. // "I" got into the work list because it made a transition.
  81. for (User *U : I->users()) {
  82. Instruction *UI = cast<Instruction>(U);
  83. VisitInst(UI);
  84. }
  85. }
  86. // Process the basic block work list.
  87. while (!BBWorkList.empty()) {
  88. BasicBlock *BB = BBWorkList.back();
  89. BBWorkList.pop_back();
  90. // Notify all instructions in this basic block that they need to
  91. // be reevaluated (eg, a block previously though to be insensitive
  92. // is now sensitive).
  93. for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
  94. VisitInst(I);
  95. }
  96. }
  97. }
  98. bool WaveSensitivityAnalyzer::CheckBBState(BasicBlock *BB, WaveSensitivity WS) {
  99. auto c = BBState.find(BB);
  100. if (c == BBState.end()) {
  101. return WS == Unknown;
  102. }
  103. else {
  104. return (*c).second == WS;
  105. }
  106. }
  107. WaveSensitivityAnalyzer::WaveSensitivity
  108. WaveSensitivityAnalyzer::GetInstState(Instruction *I) {
  109. auto c = InstState.find(I);
  110. if (c == InstState.end())
  111. return Unknown;
  112. return (*c).second;
  113. }
  114. void WaveSensitivityAnalyzer::UpdateBlock(BasicBlock *BB, WaveSensitivity WS) {
  115. auto c = BBState.find(BB);
  116. // Do not update if an entry is already found and it hasn't changed or
  117. // has already been marked as wave sensitive (an insensitive term might
  118. // try to mark it as such, but this effectively implements the 'any pred'
  119. // rule).
  120. if (c != BBState.end() && ((*c).second == WS || (*c).second == KnownSensitive))
  121. return;
  122. BBState[BB] = WS;
  123. BBWorkList.push_back(BB);
  124. }
  125. void WaveSensitivityAnalyzer::UpdateInst(Instruction *I, WaveSensitivity WS) {
  126. auto c = InstState.find(I);
  127. if (c == InstState.end() || (*c).second != WS) {
  128. InstState[I] = WS;
  129. InstWorkList.push_back(I);
  130. if (TerminatorInst * TI = dyn_cast<TerminatorInst>(I)) {
  131. BasicBlock *CurBB = TI->getParent();
  132. for (unsigned i = 0; i < TI->getNumSuccessors(); ++i) {
  133. BasicBlock *BB = TI->getSuccessor(i);
  134. // Only propagate WS when BB not post dom CurBB.
  135. WaveSensitivity TmpWS = pPDT->properlyDominates(BB, CurBB)
  136. ? WaveSensitivity::KnownNotSensitive
  137. : WS;
  138. UpdateBlock(BB, TmpWS);
  139. }
  140. }
  141. }
  142. }
  143. void WaveSensitivityAnalyzer::VisitInst(Instruction *I) {
  144. unsigned firstArg = 0;
  145. if (CallInst *CI = dyn_cast<CallInst>(I)) {
  146. if (OP::IsDxilOpFuncCallInst(CI)) {
  147. firstArg = 1;
  148. OP::OpCode opcode = OP::GetDxilOpFuncCallInst(CI);
  149. if (OP::IsDxilOpWave(opcode)) {
  150. UpdateInst(I, KnownSensitive);
  151. return;
  152. }
  153. }
  154. }
  155. if (CheckBBState(I->getParent(), KnownSensitive)) {
  156. UpdateInst(I, KnownSensitive);
  157. return;
  158. }
  159. // Catch control flow wave sensitive for phi.
  160. if (PHINode *Phi = dyn_cast<PHINode>(I)) {
  161. for (unsigned i = 0; i < Phi->getNumIncomingValues(); i++) {
  162. BasicBlock *BB = Phi->getIncomingBlock(i);
  163. WaveSensitivity WS = GetInstState(BB->getTerminator());
  164. if (WS == KnownSensitive) {
  165. UpdateInst(I, KnownSensitive);
  166. return;
  167. }
  168. }
  169. }
  170. bool allKnownNotSensitive = true;
  171. for (unsigned i = firstArg; i < I->getNumOperands(); ++i) {
  172. Value *V = I->getOperand(i);
  173. if (Instruction *IArg = dyn_cast<Instruction>(V)) {
  174. WaveSensitivity WS = GetInstState(IArg);
  175. if (WS == KnownSensitive) {
  176. UpdateInst(I, KnownSensitive);
  177. return;
  178. }
  179. if (WS == Unknown) {
  180. allKnownNotSensitive = false;
  181. return;
  182. }
  183. }
  184. }
  185. if (allKnownNotSensitive) {
  186. UpdateInst(I, KnownNotSensitive);
  187. }
  188. }
  189. bool WaveSensitivityAnalyzer::IsWaveSensitive(Instruction *op) {
  190. auto c = InstState.find(op);
  191. DXASSERT(c != InstState.end(), "else analysis didn't complete");
  192. DXASSERT((*c).second != Unknown, "else analysis is missing a case");
  193. return (*c).second == KnownSensitive;
  194. }
  195. } // namespace hlsl