xref: /llvm-project/llvm/lib/CodeGen/ExpandLargeDivRem.cpp (revision 735ab61ac828bd61398e6847d60e308fdf2b54ec)
13e39b271SMatthias Gehre //===--- ExpandLargeDivRem.cpp - Expand large div/rem ---------------------===//
23e39b271SMatthias Gehre //
33e39b271SMatthias Gehre // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43e39b271SMatthias Gehre // See https://llvm.org/LICENSE.txt for license information.
53e39b271SMatthias Gehre // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63e39b271SMatthias Gehre //
73e39b271SMatthias Gehre //===----------------------------------------------------------------------===//
83e39b271SMatthias Gehre //
93e39b271SMatthias Gehre // This pass expands div/rem instructions with a bitwidth above a threshold
103e39b271SMatthias Gehre // into a call to auto-generated functions.
113e39b271SMatthias Gehre // This is useful for targets like x86_64 that cannot lower divisions
123e39b271SMatthias Gehre // with more than 128 bits or targets like x86_32 that cannot lower divisions
133e39b271SMatthias Gehre // with more than 64 bits.
143e39b271SMatthias Gehre //
153e39b271SMatthias Gehre //===----------------------------------------------------------------------===//
163e39b271SMatthias Gehre 
1794202e7bSMatt Arsenault #include "llvm/CodeGen/ExpandLargeDivRem.h"
183e39b271SMatthias Gehre #include "llvm/ADT/SmallVector.h"
193e39b271SMatthias Gehre #include "llvm/Analysis/GlobalsModRef.h"
203e39b271SMatthias Gehre #include "llvm/CodeGen/Passes.h"
21c1502425SMatthias Gehre #include "llvm/CodeGen/TargetLowering.h"
22c1502425SMatthias Gehre #include "llvm/CodeGen/TargetPassConfig.h"
23c1502425SMatthias Gehre #include "llvm/CodeGen/TargetSubtargetInfo.h"
243e39b271SMatthias Gehre #include "llvm/IR/IRBuilder.h"
253e39b271SMatthias Gehre #include "llvm/IR/InstIterator.h"
263e39b271SMatthias Gehre #include "llvm/IR/PassManager.h"
273e39b271SMatthias Gehre #include "llvm/InitializePasses.h"
283e39b271SMatthias Gehre #include "llvm/Pass.h"
293e39b271SMatthias Gehre #include "llvm/Support/CommandLine.h"
30c1502425SMatthias Gehre #include "llvm/Target/TargetMachine.h"
313e39b271SMatthias Gehre #include "llvm/Transforms/Utils/IntegerDivision.h"
323e39b271SMatthias Gehre 
333e39b271SMatthias Gehre using namespace llvm;
343e39b271SMatthias Gehre 
353e39b271SMatthias Gehre static cl::opt<unsigned>
362090e85fSMatthias Gehre     ExpandDivRemBits("expand-div-rem-bits", cl::Hidden,
372090e85fSMatthias Gehre                      cl::init(llvm::IntegerType::MAX_INT_BITS),
383e39b271SMatthias Gehre                      cl::desc("div and rem instructions on integers with "
393e39b271SMatthias Gehre                               "more than <N> bits are expanded."));
403e39b271SMatthias Gehre 
412090e85fSMatthias Gehre static bool isConstantPowerOfTwo(llvm::Value *V, bool SignedOp) {
422090e85fSMatthias Gehre   auto *C = dyn_cast<ConstantInt>(V);
432090e85fSMatthias Gehre   if (!C)
442090e85fSMatthias Gehre     return false;
452090e85fSMatthias Gehre 
462090e85fSMatthias Gehre   APInt Val = C->getValue();
472090e85fSMatthias Gehre   if (SignedOp && Val.isNegative())
482090e85fSMatthias Gehre     Val = -Val;
492090e85fSMatthias Gehre   return Val.isPowerOf2();
502090e85fSMatthias Gehre }
512090e85fSMatthias Gehre 
522090e85fSMatthias Gehre static bool isSigned(unsigned int Opcode) {
532090e85fSMatthias Gehre   return Opcode == Instruction::SDiv || Opcode == Instruction::SRem;
542090e85fSMatthias Gehre }
552090e85fSMatthias Gehre 
56*cd6434f9SBevin Hansson static void scalarize(BinaryOperator *BO,
57*cd6434f9SBevin Hansson                       SmallVectorImpl<BinaryOperator *> &Replace) {
58*cd6434f9SBevin Hansson   VectorType *VTy = cast<FixedVectorType>(BO->getType());
59*cd6434f9SBevin Hansson 
60*cd6434f9SBevin Hansson   IRBuilder<> Builder(BO);
61*cd6434f9SBevin Hansson 
62*cd6434f9SBevin Hansson   unsigned NumElements = VTy->getElementCount().getFixedValue();
63*cd6434f9SBevin Hansson   Value *Result = PoisonValue::get(VTy);
64*cd6434f9SBevin Hansson   for (unsigned Idx = 0; Idx < NumElements; ++Idx) {
65*cd6434f9SBevin Hansson     Value *LHS = Builder.CreateExtractElement(BO->getOperand(0), Idx);
66*cd6434f9SBevin Hansson     Value *RHS = Builder.CreateExtractElement(BO->getOperand(1), Idx);
67*cd6434f9SBevin Hansson     Value *Op = Builder.CreateBinOp(BO->getOpcode(), LHS, RHS);
68*cd6434f9SBevin Hansson     Result = Builder.CreateInsertElement(Result, Op, Idx);
69*cd6434f9SBevin Hansson     if (auto *NewBO = dyn_cast<BinaryOperator>(Op)) {
70*cd6434f9SBevin Hansson       NewBO->copyIRFlags(Op, true);
71*cd6434f9SBevin Hansson       Replace.push_back(NewBO);
72*cd6434f9SBevin Hansson     }
73*cd6434f9SBevin Hansson   }
74*cd6434f9SBevin Hansson   BO->replaceAllUsesWith(Result);
75*cd6434f9SBevin Hansson   BO->dropAllReferences();
76*cd6434f9SBevin Hansson   BO->eraseFromParent();
77*cd6434f9SBevin Hansson }
78*cd6434f9SBevin Hansson 
79c1502425SMatthias Gehre static bool runImpl(Function &F, const TargetLowering &TLI) {
803e39b271SMatthias Gehre   SmallVector<BinaryOperator *, 4> Replace;
81*cd6434f9SBevin Hansson   SmallVector<BinaryOperator *, 4> ReplaceVector;
823e39b271SMatthias Gehre   bool Modified = false;
833e39b271SMatthias Gehre 
84c1502425SMatthias Gehre   unsigned MaxLegalDivRemBitWidth = TLI.getMaxDivRemBitWidthSupported();
852090e85fSMatthias Gehre   if (ExpandDivRemBits != llvm::IntegerType::MAX_INT_BITS)
862090e85fSMatthias Gehre     MaxLegalDivRemBitWidth = ExpandDivRemBits;
872090e85fSMatthias Gehre 
882090e85fSMatthias Gehre   if (MaxLegalDivRemBitWidth >= llvm::IntegerType::MAX_INT_BITS)
892090e85fSMatthias Gehre     return false;
902090e85fSMatthias Gehre 
913e39b271SMatthias Gehre   for (auto &I : instructions(F)) {
923e39b271SMatthias Gehre     switch (I.getOpcode()) {
933e39b271SMatthias Gehre     case Instruction::UDiv:
943e39b271SMatthias Gehre     case Instruction::SDiv:
953e39b271SMatthias Gehre     case Instruction::URem:
963e39b271SMatthias Gehre     case Instruction::SRem: {
97*cd6434f9SBevin Hansson       // TODO: This pass doesn't handle scalable vectors.
98*cd6434f9SBevin Hansson       if (I.getOperand(0)->getType()->isScalableTy())
99*cd6434f9SBevin Hansson         continue;
100*cd6434f9SBevin Hansson 
101*cd6434f9SBevin Hansson       auto *IntTy = dyn_cast<IntegerType>(I.getType()->getScalarType());
1022090e85fSMatthias Gehre       if (!IntTy || IntTy->getIntegerBitWidth() <= MaxLegalDivRemBitWidth)
1032090e85fSMatthias Gehre         continue;
1042090e85fSMatthias Gehre 
1052090e85fSMatthias Gehre       // The backend has peephole optimizations for powers of two.
106*cd6434f9SBevin Hansson       // TODO: We don't consider vectors here.
1072090e85fSMatthias Gehre       if (isConstantPowerOfTwo(I.getOperand(1), isSigned(I.getOpcode())))
1083e39b271SMatthias Gehre         continue;
1093e39b271SMatthias Gehre 
110*cd6434f9SBevin Hansson       if (I.getOperand(0)->getType()->isVectorTy())
111*cd6434f9SBevin Hansson         ReplaceVector.push_back(&cast<BinaryOperator>(I));
112*cd6434f9SBevin Hansson       else
1133e39b271SMatthias Gehre         Replace.push_back(&cast<BinaryOperator>(I));
1143e39b271SMatthias Gehre       Modified = true;
1153e39b271SMatthias Gehre       break;
1163e39b271SMatthias Gehre     }
1173e39b271SMatthias Gehre     default:
1183e39b271SMatthias Gehre       break;
1193e39b271SMatthias Gehre     }
1203e39b271SMatthias Gehre   }
1213e39b271SMatthias Gehre 
122*cd6434f9SBevin Hansson   while (!ReplaceVector.empty()) {
123*cd6434f9SBevin Hansson     BinaryOperator *BO = ReplaceVector.pop_back_val();
124*cd6434f9SBevin Hansson     scalarize(BO, Replace);
125*cd6434f9SBevin Hansson   }
126*cd6434f9SBevin Hansson 
1273e39b271SMatthias Gehre   if (Replace.empty())
1283e39b271SMatthias Gehre     return false;
1293e39b271SMatthias Gehre 
1303e39b271SMatthias Gehre   while (!Replace.empty()) {
1313e39b271SMatthias Gehre     BinaryOperator *I = Replace.pop_back_val();
1323e39b271SMatthias Gehre 
1333e39b271SMatthias Gehre     if (I->getOpcode() == Instruction::UDiv ||
1343e39b271SMatthias Gehre         I->getOpcode() == Instruction::SDiv) {
1353e39b271SMatthias Gehre       expandDivision(I);
1363e39b271SMatthias Gehre     } else {
1373e39b271SMatthias Gehre       expandRemainder(I);
1383e39b271SMatthias Gehre     }
1393e39b271SMatthias Gehre   }
1403e39b271SMatthias Gehre 
1413e39b271SMatthias Gehre   return Modified;
1423e39b271SMatthias Gehre }
1433e39b271SMatthias Gehre 
144b6942a28SBenjamin Kramer namespace {
1453e39b271SMatthias Gehre class ExpandLargeDivRemLegacyPass : public FunctionPass {
1463e39b271SMatthias Gehre public:
1473e39b271SMatthias Gehre   static char ID;
1483e39b271SMatthias Gehre 
1493e39b271SMatthias Gehre   ExpandLargeDivRemLegacyPass() : FunctionPass(ID) {
1503e39b271SMatthias Gehre     initializeExpandLargeDivRemLegacyPassPass(*PassRegistry::getPassRegistry());
1513e39b271SMatthias Gehre   }
1523e39b271SMatthias Gehre 
1532090e85fSMatthias Gehre   bool runOnFunction(Function &F) override {
154c1502425SMatthias Gehre     auto *TM = &getAnalysis<TargetPassConfig>().getTM<TargetMachine>();
155c1502425SMatthias Gehre     auto *TLI = TM->getSubtargetImpl(F)->getTargetLowering();
156c1502425SMatthias Gehre     return runImpl(F, *TLI);
1572090e85fSMatthias Gehre   }
1583e39b271SMatthias Gehre 
1593e39b271SMatthias Gehre   void getAnalysisUsage(AnalysisUsage &AU) const override {
160c1502425SMatthias Gehre     AU.addRequired<TargetPassConfig>();
1613e39b271SMatthias Gehre     AU.addPreserved<AAResultsWrapperPass>();
1623e39b271SMatthias Gehre     AU.addPreserved<GlobalsAAWrapperPass>();
1633e39b271SMatthias Gehre   }
1643e39b271SMatthias Gehre };
165b6942a28SBenjamin Kramer } // namespace
1663e39b271SMatthias Gehre 
16794202e7bSMatt Arsenault PreservedAnalyses ExpandLargeDivRemPass::run(Function &F,
16894202e7bSMatt Arsenault                                              FunctionAnalysisManager &FAM) {
16994202e7bSMatt Arsenault   const TargetSubtargetInfo *STI = TM->getSubtargetImpl(F);
17094202e7bSMatt Arsenault   return runImpl(F, *STI->getTargetLowering()) ? PreservedAnalyses::none()
17194202e7bSMatt Arsenault                                                : PreservedAnalyses::all();
17294202e7bSMatt Arsenault }
17394202e7bSMatt Arsenault 
1743e39b271SMatthias Gehre char ExpandLargeDivRemLegacyPass::ID = 0;
1753e39b271SMatthias Gehre INITIALIZE_PASS_BEGIN(ExpandLargeDivRemLegacyPass, "expand-large-div-rem",
1763e39b271SMatthias Gehre                       "Expand large div/rem", false, false)
1773e39b271SMatthias Gehre INITIALIZE_PASS_END(ExpandLargeDivRemLegacyPass, "expand-large-div-rem",
1783e39b271SMatthias Gehre                     "Expand large div/rem", false, false)
1793e39b271SMatthias Gehre 
1803e39b271SMatthias Gehre FunctionPass *llvm::createExpandLargeDivRemPass() {
1813e39b271SMatthias Gehre   return new ExpandLargeDivRemLegacyPass();
1823e39b271SMatthias Gehre }
183