1fcaf7f86SDimitry Andric //===----- RISCVCodeGenPrepare.cpp ----------------------------------------===// 2fcaf7f86SDimitry Andric // 3fcaf7f86SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fcaf7f86SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fcaf7f86SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fcaf7f86SDimitry Andric // 7fcaf7f86SDimitry Andric //===----------------------------------------------------------------------===// 8fcaf7f86SDimitry Andric // 906c3fb27SDimitry Andric // This is a RISC-V specific version of CodeGenPrepare. 10fcaf7f86SDimitry Andric // It munges the code in the input function to better prepare it for 11fcaf7f86SDimitry Andric // SelectionDAG-based code generation. This works around limitations in it's 12fcaf7f86SDimitry Andric // basic-block-at-a-time approach. 13fcaf7f86SDimitry Andric // 14fcaf7f86SDimitry Andric //===----------------------------------------------------------------------===// 15fcaf7f86SDimitry Andric 16fcaf7f86SDimitry Andric #include "RISCV.h" 17fcaf7f86SDimitry Andric #include "RISCVTargetMachine.h" 18fcaf7f86SDimitry Andric #include "llvm/ADT/Statistic.h" 19fcaf7f86SDimitry Andric #include "llvm/Analysis/ValueTracking.h" 20fcaf7f86SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h" 21bdd1243dSDimitry Andric #include "llvm/IR/InstVisitor.h" 22972a253aSDimitry Andric #include "llvm/IR/PatternMatch.h" 23fcaf7f86SDimitry Andric #include "llvm/InitializePasses.h" 24fcaf7f86SDimitry Andric #include "llvm/Pass.h" 25fcaf7f86SDimitry Andric 26fcaf7f86SDimitry Andric using namespace llvm; 27fcaf7f86SDimitry Andric 28fcaf7f86SDimitry Andric #define DEBUG_TYPE "riscv-codegenprepare" 2906c3fb27SDimitry Andric #define PASS_NAME "RISC-V CodeGenPrepare" 30fcaf7f86SDimitry Andric 31fcaf7f86SDimitry Andric namespace { 32fcaf7f86SDimitry Andric 33bdd1243dSDimitry Andric class RISCVCodeGenPrepare : public FunctionPass, 34bdd1243dSDimitry Andric public InstVisitor<RISCVCodeGenPrepare, bool> { 35fcaf7f86SDimitry Andric const DataLayout *DL; 36fcaf7f86SDimitry Andric const RISCVSubtarget *ST; 37fcaf7f86SDimitry Andric 38fcaf7f86SDimitry Andric public: 39fcaf7f86SDimitry Andric static char ID; 40fcaf7f86SDimitry Andric 41fcaf7f86SDimitry Andric RISCVCodeGenPrepare() : FunctionPass(ID) {} 42fcaf7f86SDimitry Andric 43fcaf7f86SDimitry Andric bool runOnFunction(Function &F) override; 44fcaf7f86SDimitry Andric 45fcaf7f86SDimitry Andric StringRef getPassName() const override { return PASS_NAME; } 46fcaf7f86SDimitry Andric 47fcaf7f86SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 48fcaf7f86SDimitry Andric AU.setPreservesCFG(); 49fcaf7f86SDimitry Andric AU.addRequired<TargetPassConfig>(); 50fcaf7f86SDimitry Andric } 51fcaf7f86SDimitry Andric 52bdd1243dSDimitry Andric bool visitInstruction(Instruction &I) { return false; } 53bdd1243dSDimitry Andric bool visitAnd(BinaryOperator &BO); 54fcaf7f86SDimitry Andric }; 55fcaf7f86SDimitry Andric 56fcaf7f86SDimitry Andric } // end anonymous namespace 57fcaf7f86SDimitry Andric 58fcaf7f86SDimitry Andric // Try to optimize (i64 (and (zext/sext (i32 X), C1))) if C1 has bit 31 set, 59*5f757f3fSDimitry Andric // but bits 63:32 are zero. If we know that bit 31 of X is 0, we can fill 60*5f757f3fSDimitry Andric // the upper 32 bits with ones. 61bdd1243dSDimitry Andric bool RISCVCodeGenPrepare::visitAnd(BinaryOperator &BO) { 62fcaf7f86SDimitry Andric if (!ST->is64Bit()) 63fcaf7f86SDimitry Andric return false; 64fcaf7f86SDimitry Andric 65bdd1243dSDimitry Andric if (!BO.getType()->isIntegerTy(64)) 66fcaf7f86SDimitry Andric return false; 67fcaf7f86SDimitry Andric 68*5f757f3fSDimitry Andric auto canBeSignExtend = [](Instruction *I) { 69*5f757f3fSDimitry Andric if (isa<SExtInst>(I)) 70*5f757f3fSDimitry Andric return true; 71*5f757f3fSDimitry Andric if (isa<ZExtInst>(I)) 72*5f757f3fSDimitry Andric return I->hasNonNeg(); 73*5f757f3fSDimitry Andric return false; 74*5f757f3fSDimitry Andric }; 75*5f757f3fSDimitry Andric 76*5f757f3fSDimitry Andric // Left hand side should be a sext or zext nneg. 77bdd1243dSDimitry Andric Instruction *LHS = dyn_cast<Instruction>(BO.getOperand(0)); 78*5f757f3fSDimitry Andric if (!LHS || !canBeSignExtend(LHS)) 79fcaf7f86SDimitry Andric return false; 80fcaf7f86SDimitry Andric 81fcaf7f86SDimitry Andric Value *LHSSrc = LHS->getOperand(0); 82fcaf7f86SDimitry Andric if (!LHSSrc->getType()->isIntegerTy(32)) 83fcaf7f86SDimitry Andric return false; 84fcaf7f86SDimitry Andric 85fcaf7f86SDimitry Andric // Right hand side should be a constant. 86bdd1243dSDimitry Andric Value *RHS = BO.getOperand(1); 87fcaf7f86SDimitry Andric 88fcaf7f86SDimitry Andric auto *CI = dyn_cast<ConstantInt>(RHS); 89fcaf7f86SDimitry Andric if (!CI) 90fcaf7f86SDimitry Andric return false; 91fcaf7f86SDimitry Andric uint64_t C = CI->getZExtValue(); 92fcaf7f86SDimitry Andric 93fcaf7f86SDimitry Andric // Look for constants that fit in 32 bits but not simm12, and can be made 94fcaf7f86SDimitry Andric // into simm12 by sign extending bit 31. This will allow use of ANDI. 95fcaf7f86SDimitry Andric // TODO: Is worth making simm32? 96fcaf7f86SDimitry Andric if (!isUInt<32>(C) || isInt<12>(C) || !isInt<12>(SignExtend64<32>(C))) 97fcaf7f86SDimitry Andric return false; 98fcaf7f86SDimitry Andric 99fcaf7f86SDimitry Andric // Sign extend the constant and replace the And operand. 100fcaf7f86SDimitry Andric C = SignExtend64<32>(C); 101bdd1243dSDimitry Andric BO.setOperand(1, ConstantInt::get(LHS->getType(), C)); 102fcaf7f86SDimitry Andric 103fcaf7f86SDimitry Andric return true; 104fcaf7f86SDimitry Andric } 105fcaf7f86SDimitry Andric 106fcaf7f86SDimitry Andric bool RISCVCodeGenPrepare::runOnFunction(Function &F) { 107fcaf7f86SDimitry Andric if (skipFunction(F)) 108fcaf7f86SDimitry Andric return false; 109fcaf7f86SDimitry Andric 110fcaf7f86SDimitry Andric auto &TPC = getAnalysis<TargetPassConfig>(); 111fcaf7f86SDimitry Andric auto &TM = TPC.getTM<RISCVTargetMachine>(); 112fcaf7f86SDimitry Andric ST = &TM.getSubtarget<RISCVSubtarget>(F); 113fcaf7f86SDimitry Andric 114fcaf7f86SDimitry Andric DL = &F.getParent()->getDataLayout(); 115fcaf7f86SDimitry Andric 116fcaf7f86SDimitry Andric bool MadeChange = false; 117bdd1243dSDimitry Andric for (auto &BB : F) 118bdd1243dSDimitry Andric for (Instruction &I : llvm::make_early_inc_range(BB)) 119bdd1243dSDimitry Andric MadeChange |= visit(I); 120fcaf7f86SDimitry Andric 121fcaf7f86SDimitry Andric return MadeChange; 122fcaf7f86SDimitry Andric } 123fcaf7f86SDimitry Andric 124fcaf7f86SDimitry Andric INITIALIZE_PASS_BEGIN(RISCVCodeGenPrepare, DEBUG_TYPE, PASS_NAME, false, false) 125fcaf7f86SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) 126fcaf7f86SDimitry Andric INITIALIZE_PASS_END(RISCVCodeGenPrepare, DEBUG_TYPE, PASS_NAME, false, false) 127fcaf7f86SDimitry Andric 128fcaf7f86SDimitry Andric char RISCVCodeGenPrepare::ID = 0; 129fcaf7f86SDimitry Andric 130fcaf7f86SDimitry Andric FunctionPass *llvm::createRISCVCodeGenPreparePass() { 131fcaf7f86SDimitry Andric return new RISCVCodeGenPrepare(); 132fcaf7f86SDimitry Andric } 133