1bdd1243dSDimitry Andric //===--- ExpandLargeDivRem.cpp - Expand large div/rem ---------------------===// 2bdd1243dSDimitry Andric // 3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6bdd1243dSDimitry Andric // 7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 8bdd1243dSDimitry Andric // 9bdd1243dSDimitry Andric // This pass expands div/rem instructions with a bitwidth above a threshold 10bdd1243dSDimitry Andric // into a call to auto-generated functions. 11bdd1243dSDimitry Andric // This is useful for targets like x86_64 that cannot lower divisions 12bdd1243dSDimitry Andric // with more than 128 bits or targets like x86_32 that cannot lower divisions 13bdd1243dSDimitry Andric // with more than 64 bits. 14bdd1243dSDimitry Andric // 15bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 16bdd1243dSDimitry Andric 175f757f3fSDimitry Andric #include "llvm/CodeGen/ExpandLargeDivRem.h" 18bdd1243dSDimitry Andric #include "llvm/ADT/SmallVector.h" 19bdd1243dSDimitry Andric #include "llvm/ADT/StringExtras.h" 20bdd1243dSDimitry Andric #include "llvm/Analysis/GlobalsModRef.h" 21bdd1243dSDimitry Andric #include "llvm/CodeGen/Passes.h" 22bdd1243dSDimitry Andric #include "llvm/CodeGen/TargetLowering.h" 23bdd1243dSDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h" 24bdd1243dSDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 25bdd1243dSDimitry Andric #include "llvm/IR/IRBuilder.h" 26bdd1243dSDimitry Andric #include "llvm/IR/InstIterator.h" 27bdd1243dSDimitry Andric #include "llvm/IR/PassManager.h" 28bdd1243dSDimitry Andric #include "llvm/InitializePasses.h" 29bdd1243dSDimitry Andric #include "llvm/Pass.h" 30bdd1243dSDimitry Andric #include "llvm/Support/CommandLine.h" 31bdd1243dSDimitry Andric #include "llvm/Target/TargetMachine.h" 32bdd1243dSDimitry Andric #include "llvm/Transforms/Utils/IntegerDivision.h" 33bdd1243dSDimitry Andric 34bdd1243dSDimitry Andric using namespace llvm; 35bdd1243dSDimitry Andric 36bdd1243dSDimitry Andric static cl::opt<unsigned> 37bdd1243dSDimitry Andric ExpandDivRemBits("expand-div-rem-bits", cl::Hidden, 38bdd1243dSDimitry Andric cl::init(llvm::IntegerType::MAX_INT_BITS), 39bdd1243dSDimitry Andric cl::desc("div and rem instructions on integers with " 40bdd1243dSDimitry Andric "more than <N> bits are expanded.")); 41bdd1243dSDimitry Andric 42bdd1243dSDimitry Andric static bool isConstantPowerOfTwo(llvm::Value *V, bool SignedOp) { 43bdd1243dSDimitry Andric auto *C = dyn_cast<ConstantInt>(V); 44bdd1243dSDimitry Andric if (!C) 45bdd1243dSDimitry Andric return false; 46bdd1243dSDimitry Andric 47bdd1243dSDimitry Andric APInt Val = C->getValue(); 48bdd1243dSDimitry Andric if (SignedOp && Val.isNegative()) 49bdd1243dSDimitry Andric Val = -Val; 50bdd1243dSDimitry Andric return Val.isPowerOf2(); 51bdd1243dSDimitry Andric } 52bdd1243dSDimitry Andric 53bdd1243dSDimitry Andric static bool isSigned(unsigned int Opcode) { 54bdd1243dSDimitry Andric return Opcode == Instruction::SDiv || Opcode == Instruction::SRem; 55bdd1243dSDimitry Andric } 56bdd1243dSDimitry Andric 57*0fca6ea1SDimitry Andric static void scalarize(BinaryOperator *BO, 58*0fca6ea1SDimitry Andric SmallVectorImpl<BinaryOperator *> &Replace) { 59*0fca6ea1SDimitry Andric VectorType *VTy = cast<FixedVectorType>(BO->getType()); 60*0fca6ea1SDimitry Andric 61*0fca6ea1SDimitry Andric IRBuilder<> Builder(BO); 62*0fca6ea1SDimitry Andric 63*0fca6ea1SDimitry Andric unsigned NumElements = VTy->getElementCount().getFixedValue(); 64*0fca6ea1SDimitry Andric Value *Result = PoisonValue::get(VTy); 65*0fca6ea1SDimitry Andric for (unsigned Idx = 0; Idx < NumElements; ++Idx) { 66*0fca6ea1SDimitry Andric Value *LHS = Builder.CreateExtractElement(BO->getOperand(0), Idx); 67*0fca6ea1SDimitry Andric Value *RHS = Builder.CreateExtractElement(BO->getOperand(1), Idx); 68*0fca6ea1SDimitry Andric Value *Op = Builder.CreateBinOp(BO->getOpcode(), LHS, RHS); 69*0fca6ea1SDimitry Andric Result = Builder.CreateInsertElement(Result, Op, Idx); 70*0fca6ea1SDimitry Andric if (auto *NewBO = dyn_cast<BinaryOperator>(Op)) { 71*0fca6ea1SDimitry Andric NewBO->copyIRFlags(Op, true); 72*0fca6ea1SDimitry Andric Replace.push_back(NewBO); 73*0fca6ea1SDimitry Andric } 74*0fca6ea1SDimitry Andric } 75*0fca6ea1SDimitry Andric BO->replaceAllUsesWith(Result); 76*0fca6ea1SDimitry Andric BO->dropAllReferences(); 77*0fca6ea1SDimitry Andric BO->eraseFromParent(); 78*0fca6ea1SDimitry Andric } 79*0fca6ea1SDimitry Andric 80bdd1243dSDimitry Andric static bool runImpl(Function &F, const TargetLowering &TLI) { 81bdd1243dSDimitry Andric SmallVector<BinaryOperator *, 4> Replace; 82*0fca6ea1SDimitry Andric SmallVector<BinaryOperator *, 4> ReplaceVector; 83bdd1243dSDimitry Andric bool Modified = false; 84bdd1243dSDimitry Andric 85bdd1243dSDimitry Andric unsigned MaxLegalDivRemBitWidth = TLI.getMaxDivRemBitWidthSupported(); 86bdd1243dSDimitry Andric if (ExpandDivRemBits != llvm::IntegerType::MAX_INT_BITS) 87bdd1243dSDimitry Andric MaxLegalDivRemBitWidth = ExpandDivRemBits; 88bdd1243dSDimitry Andric 89bdd1243dSDimitry Andric if (MaxLegalDivRemBitWidth >= llvm::IntegerType::MAX_INT_BITS) 90bdd1243dSDimitry Andric return false; 91bdd1243dSDimitry Andric 92bdd1243dSDimitry Andric for (auto &I : instructions(F)) { 93bdd1243dSDimitry Andric switch (I.getOpcode()) { 94bdd1243dSDimitry Andric case Instruction::UDiv: 95bdd1243dSDimitry Andric case Instruction::SDiv: 96bdd1243dSDimitry Andric case Instruction::URem: 97bdd1243dSDimitry Andric case Instruction::SRem: { 98*0fca6ea1SDimitry Andric // TODO: This pass doesn't handle scalable vectors. 99*0fca6ea1SDimitry Andric if (I.getOperand(0)->getType()->isScalableTy()) 100*0fca6ea1SDimitry Andric continue; 101*0fca6ea1SDimitry Andric 102*0fca6ea1SDimitry Andric auto *IntTy = dyn_cast<IntegerType>(I.getType()->getScalarType()); 103bdd1243dSDimitry Andric if (!IntTy || IntTy->getIntegerBitWidth() <= MaxLegalDivRemBitWidth) 104bdd1243dSDimitry Andric continue; 105bdd1243dSDimitry Andric 106bdd1243dSDimitry Andric // The backend has peephole optimizations for powers of two. 107*0fca6ea1SDimitry Andric // TODO: We don't consider vectors here. 108bdd1243dSDimitry Andric if (isConstantPowerOfTwo(I.getOperand(1), isSigned(I.getOpcode()))) 109bdd1243dSDimitry Andric continue; 110bdd1243dSDimitry Andric 111*0fca6ea1SDimitry Andric if (I.getOperand(0)->getType()->isVectorTy()) 112*0fca6ea1SDimitry Andric ReplaceVector.push_back(&cast<BinaryOperator>(I)); 113*0fca6ea1SDimitry Andric else 114bdd1243dSDimitry Andric Replace.push_back(&cast<BinaryOperator>(I)); 115bdd1243dSDimitry Andric Modified = true; 116bdd1243dSDimitry Andric break; 117bdd1243dSDimitry Andric } 118bdd1243dSDimitry Andric default: 119bdd1243dSDimitry Andric break; 120bdd1243dSDimitry Andric } 121bdd1243dSDimitry Andric } 122bdd1243dSDimitry Andric 123*0fca6ea1SDimitry Andric while (!ReplaceVector.empty()) { 124*0fca6ea1SDimitry Andric BinaryOperator *BO = ReplaceVector.pop_back_val(); 125*0fca6ea1SDimitry Andric scalarize(BO, Replace); 126*0fca6ea1SDimitry Andric } 127*0fca6ea1SDimitry Andric 128bdd1243dSDimitry Andric if (Replace.empty()) 129bdd1243dSDimitry Andric return false; 130bdd1243dSDimitry Andric 131bdd1243dSDimitry Andric while (!Replace.empty()) { 132bdd1243dSDimitry Andric BinaryOperator *I = Replace.pop_back_val(); 133bdd1243dSDimitry Andric 134bdd1243dSDimitry Andric if (I->getOpcode() == Instruction::UDiv || 135bdd1243dSDimitry Andric I->getOpcode() == Instruction::SDiv) { 136bdd1243dSDimitry Andric expandDivision(I); 137bdd1243dSDimitry Andric } else { 138bdd1243dSDimitry Andric expandRemainder(I); 139bdd1243dSDimitry Andric } 140bdd1243dSDimitry Andric } 141bdd1243dSDimitry Andric 142bdd1243dSDimitry Andric return Modified; 143bdd1243dSDimitry Andric } 144bdd1243dSDimitry Andric 145bdd1243dSDimitry Andric namespace { 146bdd1243dSDimitry Andric class ExpandLargeDivRemLegacyPass : public FunctionPass { 147bdd1243dSDimitry Andric public: 148bdd1243dSDimitry Andric static char ID; 149bdd1243dSDimitry Andric 150bdd1243dSDimitry Andric ExpandLargeDivRemLegacyPass() : FunctionPass(ID) { 151bdd1243dSDimitry Andric initializeExpandLargeDivRemLegacyPassPass(*PassRegistry::getPassRegistry()); 152bdd1243dSDimitry Andric } 153bdd1243dSDimitry Andric 154bdd1243dSDimitry Andric bool runOnFunction(Function &F) override { 155bdd1243dSDimitry Andric auto *TM = &getAnalysis<TargetPassConfig>().getTM<TargetMachine>(); 156bdd1243dSDimitry Andric auto *TLI = TM->getSubtargetImpl(F)->getTargetLowering(); 157bdd1243dSDimitry Andric return runImpl(F, *TLI); 158bdd1243dSDimitry Andric } 159bdd1243dSDimitry Andric 160bdd1243dSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 161bdd1243dSDimitry Andric AU.addRequired<TargetPassConfig>(); 162bdd1243dSDimitry Andric AU.addPreserved<AAResultsWrapperPass>(); 163bdd1243dSDimitry Andric AU.addPreserved<GlobalsAAWrapperPass>(); 164bdd1243dSDimitry Andric } 165bdd1243dSDimitry Andric }; 166bdd1243dSDimitry Andric } // namespace 167bdd1243dSDimitry Andric 1685f757f3fSDimitry Andric PreservedAnalyses ExpandLargeDivRemPass::run(Function &F, 1695f757f3fSDimitry Andric FunctionAnalysisManager &FAM) { 1705f757f3fSDimitry Andric const TargetSubtargetInfo *STI = TM->getSubtargetImpl(F); 1715f757f3fSDimitry Andric return runImpl(F, *STI->getTargetLowering()) ? PreservedAnalyses::none() 1725f757f3fSDimitry Andric : PreservedAnalyses::all(); 1735f757f3fSDimitry Andric } 1745f757f3fSDimitry Andric 175bdd1243dSDimitry Andric char ExpandLargeDivRemLegacyPass::ID = 0; 176bdd1243dSDimitry Andric INITIALIZE_PASS_BEGIN(ExpandLargeDivRemLegacyPass, "expand-large-div-rem", 177bdd1243dSDimitry Andric "Expand large div/rem", false, false) 178bdd1243dSDimitry Andric INITIALIZE_PASS_END(ExpandLargeDivRemLegacyPass, "expand-large-div-rem", 179bdd1243dSDimitry Andric "Expand large div/rem", false, false) 180bdd1243dSDimitry Andric 181bdd1243dSDimitry Andric FunctionPass *llvm::createExpandLargeDivRemPass() { 182bdd1243dSDimitry Andric return new ExpandLargeDivRemLegacyPass(); 183bdd1243dSDimitry Andric } 184