xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVCodeGenPrepare.cpp (revision fcaf7f8644a9988098ac6be2165bce3ea4786e91)
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