186de486dSMatt Arsenault //===-- AMDGPUCodeGenPrepare.cpp ------------------------------------------===// 286de486dSMatt Arsenault // 386de486dSMatt Arsenault // The LLVM Compiler Infrastructure 486de486dSMatt Arsenault // 586de486dSMatt Arsenault // This file is distributed under the University of Illinois Open Source 686de486dSMatt Arsenault // License. See LICENSE.TXT for details. 786de486dSMatt Arsenault // 886de486dSMatt Arsenault //===----------------------------------------------------------------------===// 986de486dSMatt Arsenault // 1086de486dSMatt Arsenault /// \file 1186de486dSMatt Arsenault /// This pass does misc. AMDGPU optimizations on IR before instruction 1286de486dSMatt Arsenault /// selection. 1386de486dSMatt Arsenault // 1486de486dSMatt Arsenault //===----------------------------------------------------------------------===// 1586de486dSMatt Arsenault 1686de486dSMatt Arsenault #include "AMDGPU.h" 17*a1fe17c9SMatt Arsenault #include "AMDGPUIntrinsicInfo.h" 1886de486dSMatt Arsenault #include "AMDGPUSubtarget.h" 19*a1fe17c9SMatt Arsenault #include "AMDGPUTargetMachine.h" 2086de486dSMatt Arsenault 2186de486dSMatt Arsenault #include "llvm/Analysis/DivergenceAnalysis.h" 2286de486dSMatt Arsenault #include "llvm/CodeGen/Passes.h" 2386de486dSMatt Arsenault #include "llvm/IR/InstVisitor.h" 2486de486dSMatt Arsenault #include "llvm/IR/IRBuilder.h" 2586de486dSMatt Arsenault #include "llvm/Support/Debug.h" 2686de486dSMatt Arsenault #include "llvm/Support/raw_ostream.h" 2786de486dSMatt Arsenault 2886de486dSMatt Arsenault #define DEBUG_TYPE "amdgpu-codegenprepare" 2986de486dSMatt Arsenault 3086de486dSMatt Arsenault using namespace llvm; 3186de486dSMatt Arsenault 3286de486dSMatt Arsenault namespace { 3386de486dSMatt Arsenault 3486de486dSMatt Arsenault class AMDGPUCodeGenPrepare : public FunctionPass, 35*a1fe17c9SMatt Arsenault public InstVisitor<AMDGPUCodeGenPrepare, bool> { 36*a1fe17c9SMatt Arsenault const GCNTargetMachine *TM; 37*a1fe17c9SMatt Arsenault const SISubtarget *ST; 3886de486dSMatt Arsenault DivergenceAnalysis *DA; 39*a1fe17c9SMatt Arsenault Module *Mod; 40*a1fe17c9SMatt Arsenault bool HasUnsafeFPMath; 4186de486dSMatt Arsenault 4286de486dSMatt Arsenault public: 4386de486dSMatt Arsenault static char ID; 4486de486dSMatt Arsenault AMDGPUCodeGenPrepare(const TargetMachine *TM = nullptr) : 4586de486dSMatt Arsenault FunctionPass(ID), 46*a1fe17c9SMatt Arsenault TM(static_cast<const GCNTargetMachine *>(TM)), 47*a1fe17c9SMatt Arsenault ST(nullptr), 48*a1fe17c9SMatt Arsenault DA(nullptr), 49*a1fe17c9SMatt Arsenault Mod(nullptr), 50*a1fe17c9SMatt Arsenault HasUnsafeFPMath(false) { } 51*a1fe17c9SMatt Arsenault 52*a1fe17c9SMatt Arsenault bool visitFDiv(BinaryOperator &I); 53*a1fe17c9SMatt Arsenault 54*a1fe17c9SMatt Arsenault bool visitInstruction(Instruction &I) { 55*a1fe17c9SMatt Arsenault return false; 56*a1fe17c9SMatt Arsenault } 5786de486dSMatt Arsenault 5886de486dSMatt Arsenault bool doInitialization(Module &M) override; 5986de486dSMatt Arsenault bool runOnFunction(Function &F) override; 6086de486dSMatt Arsenault 6186de486dSMatt Arsenault const char *getPassName() const override { 6286de486dSMatt Arsenault return "AMDGPU IR optimizations"; 6386de486dSMatt Arsenault } 6486de486dSMatt Arsenault 6586de486dSMatt Arsenault void getAnalysisUsage(AnalysisUsage &AU) const override { 6686de486dSMatt Arsenault AU.addRequired<DivergenceAnalysis>(); 6786de486dSMatt Arsenault AU.setPreservesAll(); 6886de486dSMatt Arsenault } 6986de486dSMatt Arsenault }; 7086de486dSMatt Arsenault 7186de486dSMatt Arsenault } // End anonymous namespace 7286de486dSMatt Arsenault 73*a1fe17c9SMatt Arsenault static bool shouldKeepFDivF32(Value *Num, bool UnsafeDiv) { 74*a1fe17c9SMatt Arsenault const ConstantFP *CNum = dyn_cast<ConstantFP>(Num); 75*a1fe17c9SMatt Arsenault if (!CNum) 76*a1fe17c9SMatt Arsenault return false; 77*a1fe17c9SMatt Arsenault 78*a1fe17c9SMatt Arsenault // Reciprocal f32 is handled separately without denormals. 79*a1fe17c9SMatt Arsenault return UnsafeDiv && CNum->isExactlyValue(+1.0); 80*a1fe17c9SMatt Arsenault } 81*a1fe17c9SMatt Arsenault 82*a1fe17c9SMatt Arsenault // Insert an intrinsic for fast fdiv for safe math situations where we can 83*a1fe17c9SMatt Arsenault // reduce precision. Leave fdiv for situations where the generic node is 84*a1fe17c9SMatt Arsenault // expected to be optimized. 85*a1fe17c9SMatt Arsenault bool AMDGPUCodeGenPrepare::visitFDiv(BinaryOperator &FDiv) { 86*a1fe17c9SMatt Arsenault Type *Ty = FDiv.getType(); 87*a1fe17c9SMatt Arsenault 88*a1fe17c9SMatt Arsenault // TODO: Handle half 89*a1fe17c9SMatt Arsenault if (!Ty->getScalarType()->isFloatTy()) 90*a1fe17c9SMatt Arsenault return false; 91*a1fe17c9SMatt Arsenault 92*a1fe17c9SMatt Arsenault MDNode *FPMath = FDiv.getMetadata(LLVMContext::MD_fpmath); 93*a1fe17c9SMatt Arsenault if (!FPMath) 94*a1fe17c9SMatt Arsenault return false; 95*a1fe17c9SMatt Arsenault 96*a1fe17c9SMatt Arsenault const FPMathOperator *FPOp = cast<const FPMathOperator>(&FDiv); 97*a1fe17c9SMatt Arsenault float ULP = FPOp->getFPAccuracy(); 98*a1fe17c9SMatt Arsenault if (ULP < 2.5f) 99*a1fe17c9SMatt Arsenault return false; 100*a1fe17c9SMatt Arsenault 101*a1fe17c9SMatt Arsenault FastMathFlags FMF = FPOp->getFastMathFlags(); 102*a1fe17c9SMatt Arsenault bool UnsafeDiv = HasUnsafeFPMath || FMF.unsafeAlgebra() || 103*a1fe17c9SMatt Arsenault FMF.allowReciprocal(); 104*a1fe17c9SMatt Arsenault if (ST->hasFP32Denormals() && !UnsafeDiv) 105*a1fe17c9SMatt Arsenault return false; 106*a1fe17c9SMatt Arsenault 107*a1fe17c9SMatt Arsenault IRBuilder<> Builder(FDiv.getParent(), std::next(FDiv.getIterator()), FPMath); 108*a1fe17c9SMatt Arsenault Builder.setFastMathFlags(FMF); 109*a1fe17c9SMatt Arsenault Builder.SetCurrentDebugLocation(FDiv.getDebugLoc()); 110*a1fe17c9SMatt Arsenault 111*a1fe17c9SMatt Arsenault const AMDGPUIntrinsicInfo *II = TM->getIntrinsicInfo(); 112*a1fe17c9SMatt Arsenault Function *Decl 113*a1fe17c9SMatt Arsenault = II->getDeclaration(Mod, AMDGPUIntrinsic::amdgcn_fdiv_fast, {}); 114*a1fe17c9SMatt Arsenault 115*a1fe17c9SMatt Arsenault Value *Num = FDiv.getOperand(0); 116*a1fe17c9SMatt Arsenault Value *Den = FDiv.getOperand(1); 117*a1fe17c9SMatt Arsenault 118*a1fe17c9SMatt Arsenault Value *NewFDiv = nullptr; 119*a1fe17c9SMatt Arsenault 120*a1fe17c9SMatt Arsenault if (VectorType *VT = dyn_cast<VectorType>(Ty)) { 121*a1fe17c9SMatt Arsenault NewFDiv = UndefValue::get(VT); 122*a1fe17c9SMatt Arsenault 123*a1fe17c9SMatt Arsenault // FIXME: Doesn't do the right thing for cases where the vector is partially 124*a1fe17c9SMatt Arsenault // constant. This works when the scalarizer pass is run first. 125*a1fe17c9SMatt Arsenault for (unsigned I = 0, E = VT->getNumElements(); I != E; ++I) { 126*a1fe17c9SMatt Arsenault Value *NumEltI = Builder.CreateExtractElement(Num, I); 127*a1fe17c9SMatt Arsenault Value *DenEltI = Builder.CreateExtractElement(Den, I); 128*a1fe17c9SMatt Arsenault Value *NewElt; 129*a1fe17c9SMatt Arsenault 130*a1fe17c9SMatt Arsenault if (shouldKeepFDivF32(NumEltI, UnsafeDiv)) { 131*a1fe17c9SMatt Arsenault NewElt = Builder.CreateFDiv(NumEltI, DenEltI); 132*a1fe17c9SMatt Arsenault } else { 133*a1fe17c9SMatt Arsenault NewElt = Builder.CreateCall(Decl, { NumEltI, DenEltI }); 134*a1fe17c9SMatt Arsenault } 135*a1fe17c9SMatt Arsenault 136*a1fe17c9SMatt Arsenault NewFDiv = Builder.CreateInsertElement(NewFDiv, NewElt, I); 137*a1fe17c9SMatt Arsenault } 138*a1fe17c9SMatt Arsenault } else { 139*a1fe17c9SMatt Arsenault if (!shouldKeepFDivF32(Num, UnsafeDiv)) 140*a1fe17c9SMatt Arsenault NewFDiv = Builder.CreateCall(Decl, { Num, Den }); 141*a1fe17c9SMatt Arsenault } 142*a1fe17c9SMatt Arsenault 143*a1fe17c9SMatt Arsenault if (NewFDiv) { 144*a1fe17c9SMatt Arsenault FDiv.replaceAllUsesWith(NewFDiv); 145*a1fe17c9SMatt Arsenault NewFDiv->takeName(&FDiv); 146*a1fe17c9SMatt Arsenault FDiv.eraseFromParent(); 147*a1fe17c9SMatt Arsenault } 148*a1fe17c9SMatt Arsenault 149*a1fe17c9SMatt Arsenault return true; 150*a1fe17c9SMatt Arsenault } 151*a1fe17c9SMatt Arsenault 152*a1fe17c9SMatt Arsenault static bool hasUnsafeFPMath(const Function &F) { 153*a1fe17c9SMatt Arsenault Attribute Attr = F.getFnAttribute("unsafe-fp-math"); 154*a1fe17c9SMatt Arsenault return Attr.getValueAsString() == "true"; 155*a1fe17c9SMatt Arsenault } 156*a1fe17c9SMatt Arsenault 15786de486dSMatt Arsenault bool AMDGPUCodeGenPrepare::doInitialization(Module &M) { 158*a1fe17c9SMatt Arsenault Mod = &M; 15986de486dSMatt Arsenault return false; 16086de486dSMatt Arsenault } 16186de486dSMatt Arsenault 16286de486dSMatt Arsenault bool AMDGPUCodeGenPrepare::runOnFunction(Function &F) { 16386de486dSMatt Arsenault if (!TM || skipFunction(F)) 16486de486dSMatt Arsenault return false; 16586de486dSMatt Arsenault 166*a1fe17c9SMatt Arsenault ST = &TM->getSubtarget<SISubtarget>(F); 16786de486dSMatt Arsenault DA = &getAnalysis<DivergenceAnalysis>(); 168*a1fe17c9SMatt Arsenault HasUnsafeFPMath = hasUnsafeFPMath(F); 16986de486dSMatt Arsenault 170*a1fe17c9SMatt Arsenault bool MadeChange = false; 171*a1fe17c9SMatt Arsenault 172*a1fe17c9SMatt Arsenault for (BasicBlock &BB : F) { 173*a1fe17c9SMatt Arsenault BasicBlock::iterator Next; 174*a1fe17c9SMatt Arsenault for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; I = Next) { 175*a1fe17c9SMatt Arsenault Next = std::next(I); 176*a1fe17c9SMatt Arsenault MadeChange |= visit(*I); 177*a1fe17c9SMatt Arsenault } 178*a1fe17c9SMatt Arsenault } 179*a1fe17c9SMatt Arsenault 180*a1fe17c9SMatt Arsenault return MadeChange; 18186de486dSMatt Arsenault } 18286de486dSMatt Arsenault 18386de486dSMatt Arsenault INITIALIZE_TM_PASS_BEGIN(AMDGPUCodeGenPrepare, DEBUG_TYPE, 18486de486dSMatt Arsenault "AMDGPU IR optimizations", false, false) 18586de486dSMatt Arsenault INITIALIZE_PASS_DEPENDENCY(DivergenceAnalysis) 18686de486dSMatt Arsenault INITIALIZE_TM_PASS_END(AMDGPUCodeGenPrepare, DEBUG_TYPE, 18786de486dSMatt Arsenault "AMDGPU IR optimizations", false, false) 18886de486dSMatt Arsenault 18986de486dSMatt Arsenault char AMDGPUCodeGenPrepare::ID = 0; 19086de486dSMatt Arsenault 191*a1fe17c9SMatt Arsenault FunctionPass *llvm::createAMDGPUCodeGenPreparePass(const GCNTargetMachine *TM) { 19286de486dSMatt Arsenault return new AMDGPUCodeGenPrepare(TM); 19386de486dSMatt Arsenault } 194