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