1 /*========================== begin_copyright_notice ============================ 2 3 Copyright (C) 2017-2021 Intel Corporation 4 5 SPDX-License-Identifier: MIT 6 7 ============================= end_copyright_notice ===========================*/ 8 9 #pragma once 10 11 #include "Compiler/CISACodeGen/helper.h" 12 #include "Compiler/CISACodeGen/PixelShaderCodeGen.hpp" 13 #include "common/IGCIRBuilder.h" 14 15 #include "common/LLVMWarningsPush.hpp" 16 #include <llvm/IR/PassManager.h> 17 #include <llvm/IR/DebugLoc.h> 18 #include "common/LLVMWarningsPop.hpp" 19 20 namespace IGC 21 { 22 // Generate GetPixelMask intrinsics for RTWrites, and move InitPixelMask 23 // to the beginning of the entry block. This pass should be added after 24 // pre-RA scheduler & code sinking to avoid the InitPixelMask is moved again. 25 // InitPixelMask will create nomask instruction on ARF, and CS in visa 26 // won't move instruction across it, so if we put it in the middle of BB, 27 // it will hurt performance. 28 class PixelShaderAddMask : public llvm::FunctionPass 29 { 30 public: 31 PixelShaderAddMask(); 32 33 virtual bool runOnFunction(llvm::Function& F); 34 getAnalysisUsage(llvm::AnalysisUsage & AU) const35 virtual void getAnalysisUsage(llvm::AnalysisUsage& AU) const 36 { 37 AU.setPreservesCFG(); 38 AU.addRequired<MetaDataUtilsWrapper>(); 39 AU.addRequired<CodeGenContextWrapper>(); 40 } 41 42 static char ID; 43 44 protected: 45 IGC::ModuleMetaData* m_modMD; 46 CodeGenContext* m_cgCtx; 47 }; 48 void initializePixelShaderAddMaskPass(llvm::PassRegistry&); 49 50 class PixelShaderLowering : public llvm::FunctionPass 51 { 52 public: 53 PixelShaderLowering(); 54 55 virtual bool runOnFunction(llvm::Function& F) override; 56 getAnalysisUsage(llvm::AnalysisUsage & AU) const57 virtual void getAnalysisUsage(llvm::AnalysisUsage& AU) const override 58 { 59 AU.setPreservesCFG(); 60 AU.addRequired<MetaDataUtilsWrapper>(); 61 AU.addRequired<CodeGenContextWrapper>(); 62 } 63 getPassName() const64 virtual llvm::StringRef getPassName() const override 65 { 66 return "PixelShaderLowering"; 67 } 68 69 static char ID; 70 71 private: 72 struct ColorOutput 73 { 74 llvm::Value* color[4]; 75 llvm::Value* mask; 76 unsigned int RTindex; 77 llvm::Value* blendStateIndex; 78 llvm::BasicBlock* bb; 79 llvm::CallInst* inst; 80 ColorOutputIGC::PixelShaderLowering::ColorOutput81 ColorOutput() 82 { 83 memset(this, 0, sizeof(ColorOutput)); 84 } 85 86 }; 87 typedef smallvector<ColorOutput, 4> ColorOutputArray; 88 typedef smallvector<llvm::DebugLoc, 4> DebugLocArray; 89 90 // For multirate PS, output & discard will be lowered to RTWrite during 91 // unification. Some optimization (GVN) may convert the pixel mask in 92 // RTWrite from variable to constant (true). This will cause issue since 93 // if RTWrite with header, we need to fill the proper mask. 94 void FixSamplePhaseRTWriteMask(llvm::Function& F); 95 96 void FindIntrinsicOutput(ColorOutputArray& color, 97 llvm::Value*& depth, llvm::Value*& stencil, 98 llvm::Value*& mask, llvm::Value*& src0Alpha, 99 DebugLocArray& debugLocs); 100 101 void EmitMemoryFence(llvm::IRBuilder<>& builder, bool forceFlushNone = 0); 102 void EmitRTWrite(ColorOutputArray& color, llvm::Value* depth, 103 llvm::Value* stencil, llvm::Value* mask, 104 llvm::Value* src0Alpha, DebugLocArray& debugLocs); 105 void EmitCoarseMask(llvm::Value* mask); 106 fcmpUNEConst(llvm::IGCIRBuilder<> & irb,llvm::Value * value,llvm::ConstantFP * cmpConst)107 llvm::Value* fcmpUNEConst(llvm::IGCIRBuilder<>& irb, 108 llvm::Value* value, llvm::ConstantFP* cmpConst) 109 { 110 if (llvm::ConstantFP * cfp = llvm::dyn_cast<llvm::ConstantFP>(value)) 111 { 112 if (cfp->getType() == cmpConst->getType()) 113 { 114 if (cfp->getType()->isFloatTy() && 115 (cfp->getValueAPF().convertToFloat() == cmpConst->getValueAPF().convertToFloat())) 116 { 117 return irb.getInt1(false); 118 } 119 else if (cfp->getType()->isDoubleTy() && 120 (cfp->getValueAPF().convertToDouble() == cmpConst->getValueAPF().convertToDouble())) 121 { 122 return irb.getInt1(false); 123 } 124 } 125 return irb.getInt1(true); 126 } 127 else 128 { 129 return irb.CreateFCmpUNE(value, cmpConst); 130 } 131 } createOr(llvm::IGCIRBuilder<> & irb,llvm::Value * v0,llvm::Value * v1)132 llvm::Value* createOr(llvm::IGCIRBuilder<>& irb, 133 llvm::Value* v0, llvm::Value* v1) 134 { 135 llvm::Value* ctrue = irb.getInt1(true); 136 if (v0 == ctrue && v1 == ctrue) 137 return ctrue; 138 else 139 if (v0 == ctrue) 140 return v1; 141 else 142 if (v1 == ctrue) 143 return v0; 144 else 145 return irb.CreateOr(v0, v1); 146 } 147 148 bool optBlendState(USC::BLEND_OPTIMIZATION_MODE blendOpt, 149 ColorOutput& color, bool enableBlendToFill); 150 151 llvm::CallInst* addRTWrite( 152 llvm::BasicBlock* bbToAdd, llvm::Value* src0Alpha, 153 llvm::Value* oMask, ColorOutput& color, 154 llvm::Value* depth, llvm::Value* stencil); 155 156 llvm::CallInst* addDualBlendWrite( 157 llvm::BasicBlock* bbToAdd, llvm::Value* oMask, 158 ColorOutput& color0, ColorOutput& color1, 159 llvm::Value* depth, llvm::Value* stencil, 160 uint rtIndex); 161 162 void LowerPositionInput(llvm::GenIntrinsicInst* positionIntr, uint usage); 163 164 void moveRTWriteToBlock( 165 llvm::CallInst* rtWrite, 166 llvm::SmallVector<llvm::BasicBlock*, 8> & predBB, llvm::BasicBlock* toBB, 167 llvm::DenseMap<llvm::Value*, llvm::PHINode*>& valueToPhiMap); 168 169 void moveRTWritesToReturnBlock( 170 const ColorOutputArray& colors); 171 172 llvm::PHINode* createPhiForRTWrite(llvm::Value* val, 173 smallvector<llvm::BasicBlock*, 8> & predBB, llvm::BasicBlock* toBB); 174 175 void checkAndCreateNullRTWrite( 176 llvm::Value* oMask, llvm::Value* depth, llvm::Value* stencil); 177 useDualSrcBlend(const ColorOutputArray & colors)178 inline bool useDualSrcBlend(const ColorOutputArray& colors) 179 { 180 return (colors.size() == 2 && m_dualSrcBlendEnabled); 181 } 182 183 llvm::Module* m_module; 184 llvm::PostDominatorTree* PDT; 185 IGC::ModuleMetaData* m_modMD; 186 CodeGenContext* m_cgCtx; 187 188 llvm::BasicBlock* m_ReturnBlock; 189 llvm::BasicBlock* m_outputBlock; 190 191 bool SkipSrc0Alpha; 192 bool m_dualSrcBlendEnabled; 193 bool m_hasDiscard; 194 195 // whether the pixel shader is persample, see CPixelShader::IsPerSample() 196 bool m_isPerSample; 197 bool uavPixelSync; 198 }; 199 void initializePixelShaderLoweringPass(llvm::PassRegistry&); 200 201 class DiscardLowering : public llvm::FunctionPass 202 { 203 private: 204 CodeGenContext* m_cgCtx; 205 llvm::BasicBlock* m_entryBB; 206 llvm::BasicBlock* m_retBB = nullptr; 207 llvm::BasicBlock* m_earlyRet; 208 llvm::Module* m_module; 209 IGC::ModuleMetaData* m_modMD; 210 211 smallvector<llvm::GenIntrinsicInst*, 4> m_discards; 212 smallvector<llvm::GenIntrinsicInst*, 4> m_isHelperInvocationCalls; 213 214 bool lowerDiscards(llvm::Function& F); 215 216 public: 217 static char ID; 218 219 DiscardLowering(); 220 221 virtual bool runOnFunction(llvm::Function& F) override; getAnalysisUsage(llvm::AnalysisUsage & AU) const222 virtual void getAnalysisUsage(llvm::AnalysisUsage& AU) const override 223 { 224 AU.addRequired<MetaDataUtilsWrapper>(); 225 AU.addRequired<CodeGenContextWrapper>(); 226 } 227 getPassName() const228 virtual llvm::StringRef getPassName() const override 229 { 230 return "Lower Discard"; 231 } 232 }; 233 void initializeDiscardLoweringPass(llvm::PassRegistry&); 234 }//namespace IGC 235