xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVCodeGenPrepare.cpp (revision a4a491e2238b12ccd64d3faf9e6401487f6f1f1b)
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 //
9fcaf7f86SDimitry Andric // This is a RISCV 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"
21972a253aSDimitry Andric #include "llvm/IR/PatternMatch.h"
22fcaf7f86SDimitry Andric #include "llvm/InitializePasses.h"
23fcaf7f86SDimitry Andric #include "llvm/Pass.h"
24fcaf7f86SDimitry Andric 
25fcaf7f86SDimitry Andric using namespace llvm;
26fcaf7f86SDimitry Andric 
27fcaf7f86SDimitry Andric #define DEBUG_TYPE "riscv-codegenprepare"
28fcaf7f86SDimitry Andric #define PASS_NAME "RISCV CodeGenPrepare"
29fcaf7f86SDimitry Andric 
30fcaf7f86SDimitry Andric STATISTIC(NumZExtToSExt, "Number of SExt instructions converted to ZExt");
31fcaf7f86SDimitry Andric 
32fcaf7f86SDimitry Andric namespace {
33fcaf7f86SDimitry Andric 
34fcaf7f86SDimitry Andric class RISCVCodeGenPrepare : public FunctionPass {
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 
52fcaf7f86SDimitry Andric private:
53fcaf7f86SDimitry Andric   bool optimizeZExt(ZExtInst *I);
54fcaf7f86SDimitry Andric   bool optimizeAndExt(BinaryOperator *BO);
55fcaf7f86SDimitry Andric };
56fcaf7f86SDimitry Andric 
57fcaf7f86SDimitry Andric } // end anonymous namespace
58fcaf7f86SDimitry Andric 
59fcaf7f86SDimitry Andric bool RISCVCodeGenPrepare::optimizeZExt(ZExtInst *ZExt) {
60fcaf7f86SDimitry Andric   if (!ST->is64Bit())
61fcaf7f86SDimitry Andric     return false;
62fcaf7f86SDimitry Andric 
63fcaf7f86SDimitry Andric   Value *Src = ZExt->getOperand(0);
64fcaf7f86SDimitry Andric 
65fcaf7f86SDimitry Andric   // We only care about ZExt from i32 to i64.
66fcaf7f86SDimitry Andric   if (!ZExt->getType()->isIntegerTy(64) || !Src->getType()->isIntegerTy(32))
67fcaf7f86SDimitry Andric     return false;
68fcaf7f86SDimitry Andric 
69fcaf7f86SDimitry Andric   // Look for an opportunity to replace (i64 (zext (i32 X))) with a sext if we
70fcaf7f86SDimitry Andric   // can determine that the sign bit of X is zero via a dominating condition.
71fcaf7f86SDimitry Andric   // This often occurs with widened induction variables.
72fcaf7f86SDimitry Andric   if (isImpliedByDomCondition(ICmpInst::ICMP_SGE, Src,
73fcaf7f86SDimitry Andric                               Constant::getNullValue(Src->getType()), ZExt,
74*a4a491e2SDimitry Andric                               *DL).value_or(false)) {
75fcaf7f86SDimitry Andric     auto *SExt = new SExtInst(Src, ZExt->getType(), "", ZExt);
76fcaf7f86SDimitry Andric     SExt->takeName(ZExt);
77fcaf7f86SDimitry Andric     SExt->setDebugLoc(ZExt->getDebugLoc());
78fcaf7f86SDimitry Andric 
79fcaf7f86SDimitry Andric     ZExt->replaceAllUsesWith(SExt);
80fcaf7f86SDimitry Andric     ZExt->eraseFromParent();
81fcaf7f86SDimitry Andric     ++NumZExtToSExt;
82fcaf7f86SDimitry Andric     return true;
83fcaf7f86SDimitry Andric   }
84fcaf7f86SDimitry Andric 
85972a253aSDimitry Andric   // Convert (zext (abs(i32 X, i1 1))) -> (sext (abs(i32 X, i1 1))). If abs of
86972a253aSDimitry Andric   // INT_MIN is poison, the sign bit is zero.
87972a253aSDimitry Andric   using namespace PatternMatch;
88972a253aSDimitry Andric   if (match(Src, m_Intrinsic<Intrinsic::abs>(m_Value(), m_One()))) {
89972a253aSDimitry Andric     auto *SExt = new SExtInst(Src, ZExt->getType(), "", ZExt);
90972a253aSDimitry Andric     SExt->takeName(ZExt);
91972a253aSDimitry Andric     SExt->setDebugLoc(ZExt->getDebugLoc());
92972a253aSDimitry Andric 
93972a253aSDimitry Andric     ZExt->replaceAllUsesWith(SExt);
94972a253aSDimitry Andric     ZExt->eraseFromParent();
95972a253aSDimitry Andric     ++NumZExtToSExt;
96972a253aSDimitry Andric     return true;
97972a253aSDimitry Andric   }
98972a253aSDimitry Andric 
99fcaf7f86SDimitry Andric   return false;
100fcaf7f86SDimitry Andric }
101fcaf7f86SDimitry Andric 
102fcaf7f86SDimitry Andric // Try to optimize (i64 (and (zext/sext (i32 X), C1))) if C1 has bit 31 set,
103fcaf7f86SDimitry Andric // but bits 63:32 are zero. If we can prove that bit 31 of X is 0, we can fill
104fcaf7f86SDimitry Andric // the upper 32 bits with ones. A separate transform will turn (zext X) into
105fcaf7f86SDimitry Andric // (sext X) for the same condition.
106fcaf7f86SDimitry Andric bool RISCVCodeGenPrepare::optimizeAndExt(BinaryOperator *BO) {
107fcaf7f86SDimitry Andric   if (!ST->is64Bit())
108fcaf7f86SDimitry Andric     return false;
109fcaf7f86SDimitry Andric 
110fcaf7f86SDimitry Andric   if (BO->getOpcode() != Instruction::And)
111fcaf7f86SDimitry Andric     return false;
112fcaf7f86SDimitry Andric 
113fcaf7f86SDimitry Andric   if (!BO->getType()->isIntegerTy(64))
114fcaf7f86SDimitry Andric     return false;
115fcaf7f86SDimitry Andric 
116fcaf7f86SDimitry Andric   // Left hand side should be sext or zext.
117fcaf7f86SDimitry Andric   Instruction *LHS = dyn_cast<Instruction>(BO->getOperand(0));
118fcaf7f86SDimitry Andric   if (!LHS || (!isa<SExtInst>(LHS) && !isa<ZExtInst>(LHS)))
119fcaf7f86SDimitry Andric     return false;
120fcaf7f86SDimitry Andric 
121fcaf7f86SDimitry Andric   Value *LHSSrc = LHS->getOperand(0);
122fcaf7f86SDimitry Andric   if (!LHSSrc->getType()->isIntegerTy(32))
123fcaf7f86SDimitry Andric     return false;
124fcaf7f86SDimitry Andric 
125fcaf7f86SDimitry Andric   // Right hand side should be a constant.
126fcaf7f86SDimitry Andric   Value *RHS = BO->getOperand(1);
127fcaf7f86SDimitry Andric 
128fcaf7f86SDimitry Andric   auto *CI = dyn_cast<ConstantInt>(RHS);
129fcaf7f86SDimitry Andric   if (!CI)
130fcaf7f86SDimitry Andric     return false;
131fcaf7f86SDimitry Andric   uint64_t C = CI->getZExtValue();
132fcaf7f86SDimitry Andric 
133fcaf7f86SDimitry Andric   // Look for constants that fit in 32 bits but not simm12, and can be made
134fcaf7f86SDimitry Andric   // into simm12 by sign extending bit 31. This will allow use of ANDI.
135fcaf7f86SDimitry Andric   // TODO: Is worth making simm32?
136fcaf7f86SDimitry Andric   if (!isUInt<32>(C) || isInt<12>(C) || !isInt<12>(SignExtend64<32>(C)))
137fcaf7f86SDimitry Andric     return false;
138fcaf7f86SDimitry Andric 
139fcaf7f86SDimitry Andric   // If we can determine the sign bit of the input is 0, we can replace the
140fcaf7f86SDimitry Andric   // And mask constant.
141fcaf7f86SDimitry Andric   if (!isImpliedByDomCondition(ICmpInst::ICMP_SGE, LHSSrc,
142fcaf7f86SDimitry Andric                                Constant::getNullValue(LHSSrc->getType()),
143*a4a491e2SDimitry Andric                                LHS, *DL).value_or(false))
144fcaf7f86SDimitry Andric     return false;
145fcaf7f86SDimitry Andric 
146fcaf7f86SDimitry Andric   // Sign extend the constant and replace the And operand.
147fcaf7f86SDimitry Andric   C = SignExtend64<32>(C);
148fcaf7f86SDimitry Andric   BO->setOperand(1, ConstantInt::get(LHS->getType(), C));
149fcaf7f86SDimitry Andric 
150fcaf7f86SDimitry Andric   return true;
151fcaf7f86SDimitry Andric }
152fcaf7f86SDimitry Andric 
153fcaf7f86SDimitry Andric bool RISCVCodeGenPrepare::runOnFunction(Function &F) {
154fcaf7f86SDimitry Andric   if (skipFunction(F))
155fcaf7f86SDimitry Andric     return false;
156fcaf7f86SDimitry Andric 
157fcaf7f86SDimitry Andric   auto &TPC = getAnalysis<TargetPassConfig>();
158fcaf7f86SDimitry Andric   auto &TM = TPC.getTM<RISCVTargetMachine>();
159fcaf7f86SDimitry Andric   ST = &TM.getSubtarget<RISCVSubtarget>(F);
160fcaf7f86SDimitry Andric 
161fcaf7f86SDimitry Andric   DL = &F.getParent()->getDataLayout();
162fcaf7f86SDimitry Andric 
163fcaf7f86SDimitry Andric   bool MadeChange = false;
164fcaf7f86SDimitry Andric   for (auto &BB : F) {
165fcaf7f86SDimitry Andric     for (Instruction &I : llvm::make_early_inc_range(BB)) {
166fcaf7f86SDimitry Andric       if (auto *ZExt = dyn_cast<ZExtInst>(&I))
167fcaf7f86SDimitry Andric         MadeChange |= optimizeZExt(ZExt);
168fcaf7f86SDimitry Andric       else if (I.getOpcode() == Instruction::And)
169fcaf7f86SDimitry Andric         MadeChange |= optimizeAndExt(cast<BinaryOperator>(&I));
170fcaf7f86SDimitry Andric     }
171fcaf7f86SDimitry Andric   }
172fcaf7f86SDimitry Andric 
173fcaf7f86SDimitry Andric   return MadeChange;
174fcaf7f86SDimitry Andric }
175fcaf7f86SDimitry Andric 
176fcaf7f86SDimitry Andric INITIALIZE_PASS_BEGIN(RISCVCodeGenPrepare, DEBUG_TYPE, PASS_NAME, false, false)
177fcaf7f86SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
178fcaf7f86SDimitry Andric INITIALIZE_PASS_END(RISCVCodeGenPrepare, DEBUG_TYPE, PASS_NAME, false, false)
179fcaf7f86SDimitry Andric 
180fcaf7f86SDimitry Andric char RISCVCodeGenPrepare::ID = 0;
181fcaf7f86SDimitry Andric 
182fcaf7f86SDimitry Andric FunctionPass *llvm::createRISCVCodeGenPreparePass() {
183fcaf7f86SDimitry Andric   return new RISCVCodeGenPrepare();
184fcaf7f86SDimitry Andric }
185