//===----- RISCVCodeGenPrepare.cpp ----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This is a RISC-V specific version of CodeGenPrepare. // It munges the code in the input function to better prepare it for // SelectionDAG-based code generation. This works around limitations in it's // basic-block-at-a-time approach. // //===----------------------------------------------------------------------===// #include "RISCV.h" #include "RISCVTargetMachine.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/IR/InstVisitor.h" #include "llvm/IR/PatternMatch.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" using namespace llvm; #define DEBUG_TYPE "riscv-codegenprepare" #define PASS_NAME "RISC-V CodeGenPrepare" namespace { class RISCVCodeGenPrepare : public FunctionPass, public InstVisitor { const DataLayout *DL; const RISCVSubtarget *ST; public: static char ID; RISCVCodeGenPrepare() : FunctionPass(ID) {} bool runOnFunction(Function &F) override; StringRef getPassName() const override { return PASS_NAME; } void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesCFG(); AU.addRequired(); } bool visitInstruction(Instruction &I) { return false; } bool visitAnd(BinaryOperator &BO); }; } // end anonymous namespace // Try to optimize (i64 (and (zext/sext (i32 X), C1))) if C1 has bit 31 set, // but bits 63:32 are zero. If we know that bit 31 of X is 0, we can fill // the upper 32 bits with ones. bool RISCVCodeGenPrepare::visitAnd(BinaryOperator &BO) { if (!ST->is64Bit()) return false; if (!BO.getType()->isIntegerTy(64)) return false; auto canBeSignExtend = [](Instruction *I) { if (isa(I)) return true; if (isa(I)) return I->hasNonNeg(); return false; }; // Left hand side should be a sext or zext nneg. Instruction *LHS = dyn_cast(BO.getOperand(0)); if (!LHS || !canBeSignExtend(LHS)) return false; Value *LHSSrc = LHS->getOperand(0); if (!LHSSrc->getType()->isIntegerTy(32)) return false; // Right hand side should be a constant. Value *RHS = BO.getOperand(1); auto *CI = dyn_cast(RHS); if (!CI) return false; uint64_t C = CI->getZExtValue(); // Look for constants that fit in 32 bits but not simm12, and can be made // into simm12 by sign extending bit 31. This will allow use of ANDI. // TODO: Is worth making simm32? if (!isUInt<32>(C) || isInt<12>(C) || !isInt<12>(SignExtend64<32>(C))) return false; // Sign extend the constant and replace the And operand. C = SignExtend64<32>(C); BO.setOperand(1, ConstantInt::get(LHS->getType(), C)); return true; } bool RISCVCodeGenPrepare::runOnFunction(Function &F) { if (skipFunction(F)) return false; auto &TPC = getAnalysis(); auto &TM = TPC.getTM(); ST = &TM.getSubtarget(F); DL = &F.getParent()->getDataLayout(); bool MadeChange = false; for (auto &BB : F) for (Instruction &I : llvm::make_early_inc_range(BB)) MadeChange |= visit(I); return MadeChange; } INITIALIZE_PASS_BEGIN(RISCVCodeGenPrepare, DEBUG_TYPE, PASS_NAME, false, false) INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) INITIALIZE_PASS_END(RISCVCodeGenPrepare, DEBUG_TYPE, PASS_NAME, false, false) char RISCVCodeGenPrepare::ID = 0; FunctionPass *llvm::createRISCVCodeGenPreparePass() { return new RISCVCodeGenPrepare(); }