1*fcaf7f86SDimitry Andric //===----- RISCVCodeGenPrepare.cpp ----------------------------------------===// 2*fcaf7f86SDimitry Andric // 3*fcaf7f86SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*fcaf7f86SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*fcaf7f86SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*fcaf7f86SDimitry Andric // 7*fcaf7f86SDimitry Andric //===----------------------------------------------------------------------===// 8*fcaf7f86SDimitry Andric // 9*fcaf7f86SDimitry Andric // This is a RISCV specific version of CodeGenPrepare. 10*fcaf7f86SDimitry Andric // It munges the code in the input function to better prepare it for 11*fcaf7f86SDimitry Andric // SelectionDAG-based code generation. This works around limitations in it's 12*fcaf7f86SDimitry Andric // basic-block-at-a-time approach. 13*fcaf7f86SDimitry Andric // 14*fcaf7f86SDimitry Andric //===----------------------------------------------------------------------===// 15*fcaf7f86SDimitry Andric 16*fcaf7f86SDimitry Andric #include "RISCV.h" 17*fcaf7f86SDimitry Andric #include "RISCVTargetMachine.h" 18*fcaf7f86SDimitry Andric #include "llvm/ADT/Statistic.h" 19*fcaf7f86SDimitry Andric #include "llvm/Analysis/ValueTracking.h" 20*fcaf7f86SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h" 21*fcaf7f86SDimitry Andric #include "llvm/InitializePasses.h" 22*fcaf7f86SDimitry Andric #include "llvm/Pass.h" 23*fcaf7f86SDimitry Andric 24*fcaf7f86SDimitry Andric using namespace llvm; 25*fcaf7f86SDimitry Andric 26*fcaf7f86SDimitry Andric #define DEBUG_TYPE "riscv-codegenprepare" 27*fcaf7f86SDimitry Andric #define PASS_NAME "RISCV CodeGenPrepare" 28*fcaf7f86SDimitry Andric 29*fcaf7f86SDimitry Andric STATISTIC(NumZExtToSExt, "Number of SExt instructions converted to ZExt"); 30*fcaf7f86SDimitry Andric 31*fcaf7f86SDimitry Andric namespace { 32*fcaf7f86SDimitry Andric 33*fcaf7f86SDimitry Andric class RISCVCodeGenPrepare : public FunctionPass { 34*fcaf7f86SDimitry Andric const DataLayout *DL; 35*fcaf7f86SDimitry Andric const RISCVSubtarget *ST; 36*fcaf7f86SDimitry Andric 37*fcaf7f86SDimitry Andric public: 38*fcaf7f86SDimitry Andric static char ID; 39*fcaf7f86SDimitry Andric 40*fcaf7f86SDimitry Andric RISCVCodeGenPrepare() : FunctionPass(ID) {} 41*fcaf7f86SDimitry Andric 42*fcaf7f86SDimitry Andric bool runOnFunction(Function &F) override; 43*fcaf7f86SDimitry Andric 44*fcaf7f86SDimitry Andric StringRef getPassName() const override { return PASS_NAME; } 45*fcaf7f86SDimitry Andric 46*fcaf7f86SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 47*fcaf7f86SDimitry Andric AU.setPreservesCFG(); 48*fcaf7f86SDimitry Andric AU.addRequired<TargetPassConfig>(); 49*fcaf7f86SDimitry Andric } 50*fcaf7f86SDimitry Andric 51*fcaf7f86SDimitry Andric private: 52*fcaf7f86SDimitry Andric bool optimizeZExt(ZExtInst *I); 53*fcaf7f86SDimitry Andric bool optimizeAndExt(BinaryOperator *BO); 54*fcaf7f86SDimitry Andric }; 55*fcaf7f86SDimitry Andric 56*fcaf7f86SDimitry Andric } // end anonymous namespace 57*fcaf7f86SDimitry Andric 58*fcaf7f86SDimitry Andric bool RISCVCodeGenPrepare::optimizeZExt(ZExtInst *ZExt) { 59*fcaf7f86SDimitry Andric if (!ST->is64Bit()) 60*fcaf7f86SDimitry Andric return false; 61*fcaf7f86SDimitry Andric 62*fcaf7f86SDimitry Andric Value *Src = ZExt->getOperand(0); 63*fcaf7f86SDimitry Andric 64*fcaf7f86SDimitry Andric // We only care about ZExt from i32 to i64. 65*fcaf7f86SDimitry Andric if (!ZExt->getType()->isIntegerTy(64) || !Src->getType()->isIntegerTy(32)) 66*fcaf7f86SDimitry Andric return false; 67*fcaf7f86SDimitry Andric 68*fcaf7f86SDimitry Andric // Look for an opportunity to replace (i64 (zext (i32 X))) with a sext if we 69*fcaf7f86SDimitry Andric // can determine that the sign bit of X is zero via a dominating condition. 70*fcaf7f86SDimitry Andric // This often occurs with widened induction variables. 71*fcaf7f86SDimitry Andric if (isImpliedByDomCondition(ICmpInst::ICMP_SGE, Src, 72*fcaf7f86SDimitry Andric Constant::getNullValue(Src->getType()), ZExt, 73*fcaf7f86SDimitry Andric *DL)) { 74*fcaf7f86SDimitry Andric auto *SExt = new SExtInst(Src, ZExt->getType(), "", ZExt); 75*fcaf7f86SDimitry Andric SExt->takeName(ZExt); 76*fcaf7f86SDimitry Andric SExt->setDebugLoc(ZExt->getDebugLoc()); 77*fcaf7f86SDimitry Andric 78*fcaf7f86SDimitry Andric ZExt->replaceAllUsesWith(SExt); 79*fcaf7f86SDimitry Andric ZExt->eraseFromParent(); 80*fcaf7f86SDimitry Andric ++NumZExtToSExt; 81*fcaf7f86SDimitry Andric return true; 82*fcaf7f86SDimitry Andric } 83*fcaf7f86SDimitry Andric 84*fcaf7f86SDimitry Andric return false; 85*fcaf7f86SDimitry Andric } 86*fcaf7f86SDimitry Andric 87*fcaf7f86SDimitry Andric // Try to optimize (i64 (and (zext/sext (i32 X), C1))) if C1 has bit 31 set, 88*fcaf7f86SDimitry Andric // but bits 63:32 are zero. If we can prove that bit 31 of X is 0, we can fill 89*fcaf7f86SDimitry Andric // the upper 32 bits with ones. A separate transform will turn (zext X) into 90*fcaf7f86SDimitry Andric // (sext X) for the same condition. 91*fcaf7f86SDimitry Andric bool RISCVCodeGenPrepare::optimizeAndExt(BinaryOperator *BO) { 92*fcaf7f86SDimitry Andric if (!ST->is64Bit()) 93*fcaf7f86SDimitry Andric return false; 94*fcaf7f86SDimitry Andric 95*fcaf7f86SDimitry Andric if (BO->getOpcode() != Instruction::And) 96*fcaf7f86SDimitry Andric return false; 97*fcaf7f86SDimitry Andric 98*fcaf7f86SDimitry Andric if (!BO->getType()->isIntegerTy(64)) 99*fcaf7f86SDimitry Andric return false; 100*fcaf7f86SDimitry Andric 101*fcaf7f86SDimitry Andric // Left hand side should be sext or zext. 102*fcaf7f86SDimitry Andric Instruction *LHS = dyn_cast<Instruction>(BO->getOperand(0)); 103*fcaf7f86SDimitry Andric if (!LHS || (!isa<SExtInst>(LHS) && !isa<ZExtInst>(LHS))) 104*fcaf7f86SDimitry Andric return false; 105*fcaf7f86SDimitry Andric 106*fcaf7f86SDimitry Andric Value *LHSSrc = LHS->getOperand(0); 107*fcaf7f86SDimitry Andric if (!LHSSrc->getType()->isIntegerTy(32)) 108*fcaf7f86SDimitry Andric return false; 109*fcaf7f86SDimitry Andric 110*fcaf7f86SDimitry Andric // Right hand side should be a constant. 111*fcaf7f86SDimitry Andric Value *RHS = BO->getOperand(1); 112*fcaf7f86SDimitry Andric 113*fcaf7f86SDimitry Andric auto *CI = dyn_cast<ConstantInt>(RHS); 114*fcaf7f86SDimitry Andric if (!CI) 115*fcaf7f86SDimitry Andric return false; 116*fcaf7f86SDimitry Andric uint64_t C = CI->getZExtValue(); 117*fcaf7f86SDimitry Andric 118*fcaf7f86SDimitry Andric // Look for constants that fit in 32 bits but not simm12, and can be made 119*fcaf7f86SDimitry Andric // into simm12 by sign extending bit 31. This will allow use of ANDI. 120*fcaf7f86SDimitry Andric // TODO: Is worth making simm32? 121*fcaf7f86SDimitry Andric if (!isUInt<32>(C) || isInt<12>(C) || !isInt<12>(SignExtend64<32>(C))) 122*fcaf7f86SDimitry Andric return false; 123*fcaf7f86SDimitry Andric 124*fcaf7f86SDimitry Andric // If we can determine the sign bit of the input is 0, we can replace the 125*fcaf7f86SDimitry Andric // And mask constant. 126*fcaf7f86SDimitry Andric if (!isImpliedByDomCondition(ICmpInst::ICMP_SGE, LHSSrc, 127*fcaf7f86SDimitry Andric Constant::getNullValue(LHSSrc->getType()), 128*fcaf7f86SDimitry Andric LHS, *DL)) 129*fcaf7f86SDimitry Andric return false; 130*fcaf7f86SDimitry Andric 131*fcaf7f86SDimitry Andric // Sign extend the constant and replace the And operand. 132*fcaf7f86SDimitry Andric C = SignExtend64<32>(C); 133*fcaf7f86SDimitry Andric BO->setOperand(1, ConstantInt::get(LHS->getType(), C)); 134*fcaf7f86SDimitry Andric 135*fcaf7f86SDimitry Andric return true; 136*fcaf7f86SDimitry Andric } 137*fcaf7f86SDimitry Andric 138*fcaf7f86SDimitry Andric bool RISCVCodeGenPrepare::runOnFunction(Function &F) { 139*fcaf7f86SDimitry Andric if (skipFunction(F)) 140*fcaf7f86SDimitry Andric return false; 141*fcaf7f86SDimitry Andric 142*fcaf7f86SDimitry Andric auto &TPC = getAnalysis<TargetPassConfig>(); 143*fcaf7f86SDimitry Andric auto &TM = TPC.getTM<RISCVTargetMachine>(); 144*fcaf7f86SDimitry Andric ST = &TM.getSubtarget<RISCVSubtarget>(F); 145*fcaf7f86SDimitry Andric 146*fcaf7f86SDimitry Andric DL = &F.getParent()->getDataLayout(); 147*fcaf7f86SDimitry Andric 148*fcaf7f86SDimitry Andric bool MadeChange = false; 149*fcaf7f86SDimitry Andric for (auto &BB : F) { 150*fcaf7f86SDimitry Andric for (Instruction &I : llvm::make_early_inc_range(BB)) { 151*fcaf7f86SDimitry Andric if (auto *ZExt = dyn_cast<ZExtInst>(&I)) 152*fcaf7f86SDimitry Andric MadeChange |= optimizeZExt(ZExt); 153*fcaf7f86SDimitry Andric else if (I.getOpcode() == Instruction::And) 154*fcaf7f86SDimitry Andric MadeChange |= optimizeAndExt(cast<BinaryOperator>(&I)); 155*fcaf7f86SDimitry Andric } 156*fcaf7f86SDimitry Andric } 157*fcaf7f86SDimitry Andric 158*fcaf7f86SDimitry Andric return MadeChange; 159*fcaf7f86SDimitry Andric } 160*fcaf7f86SDimitry Andric 161*fcaf7f86SDimitry Andric INITIALIZE_PASS_BEGIN(RISCVCodeGenPrepare, DEBUG_TYPE, PASS_NAME, false, false) 162*fcaf7f86SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) 163*fcaf7f86SDimitry Andric INITIALIZE_PASS_END(RISCVCodeGenPrepare, DEBUG_TYPE, PASS_NAME, false, false) 164*fcaf7f86SDimitry Andric 165*fcaf7f86SDimitry Andric char RISCVCodeGenPrepare::ID = 0; 166*fcaf7f86SDimitry Andric 167*fcaf7f86SDimitry Andric FunctionPass *llvm::createRISCVCodeGenPreparePass() { 168*fcaf7f86SDimitry Andric return new RISCVCodeGenPrepare(); 169*fcaf7f86SDimitry Andric } 170