Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 1 | //===-- BypassSlowDivision.cpp - Bypass slow division ---------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file contains an optimization for div and rem on architectures that |
| 11 | // execute short instructions significantly faster than longer instructions. |
| 12 | // For example, on Intel Atom 32-bit divides are slow enough that during |
| 13 | // runtime it is profitable to check the value of the operands, and if they are |
| 14 | // positive and less than 256 use an unsigned 8-bit divide. |
| 15 | // |
| 16 | //===----------------------------------------------------------------------===// |
| 17 | |
Chandler Carruth | ed0881b | 2012-12-03 16:50:05 +0000 | [diff] [blame] | 18 | #include "llvm/Transforms/Utils/BypassSlowDivision.h" |
| 19 | #include "llvm/ADT/DenseMap.h" |
Chandler Carruth | 9fb823b | 2013-01-02 11:36:10 +0000 | [diff] [blame] | 20 | #include "llvm/IR/Function.h" |
| 21 | #include "llvm/IR/IRBuilder.h" |
| 22 | #include "llvm/IR/Instructions.h" |
Justin Lebar | 0ede5fb | 2016-10-28 21:43:54 +0000 | [diff] [blame] | 23 | #include "llvm/Transforms/Utils/Local.h" |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 24 | |
| 25 | using namespace llvm; |
| 26 | |
Chandler Carruth | 964daaa | 2014-04-22 02:55:47 +0000 | [diff] [blame] | 27 | #define DEBUG_TYPE "bypass-slow-division" |
| 28 | |
Benjamin Kramer | 1f66f88 | 2012-09-10 11:52:08 +0000 | [diff] [blame] | 29 | namespace { |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 30 | struct DivOpInfo { |
| 31 | bool SignedOp; |
| 32 | Value *Dividend; |
| 33 | Value *Divisor; |
| 34 | |
| 35 | DivOpInfo(bool InSignedOp, Value *InDividend, Value *InDivisor) |
| 36 | : SignedOp(InSignedOp), Dividend(InDividend), Divisor(InDivisor) {} |
| 37 | }; |
| 38 | |
| 39 | struct DivPhiNodes { |
| 40 | PHINode *Quotient; |
| 41 | PHINode *Remainder; |
| 42 | |
| 43 | DivPhiNodes(PHINode *InQuotient, PHINode *InRemainder) |
| 44 | : Quotient(InQuotient), Remainder(InRemainder) {} |
| 45 | }; |
Alexander Kornienko | f00654e | 2015-06-23 09:49:53 +0000 | [diff] [blame] | 46 | } |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 47 | |
Benjamin Kramer | 1f66f88 | 2012-09-10 11:52:08 +0000 | [diff] [blame] | 48 | namespace llvm { |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 49 | template<> |
| 50 | struct DenseMapInfo<DivOpInfo> { |
| 51 | static bool isEqual(const DivOpInfo &Val1, const DivOpInfo &Val2) { |
| 52 | return Val1.SignedOp == Val2.SignedOp && |
| 53 | Val1.Dividend == Val2.Dividend && |
| 54 | Val1.Divisor == Val2.Divisor; |
| 55 | } |
| 56 | |
| 57 | static DivOpInfo getEmptyKey() { |
Craig Topper | f40110f | 2014-04-25 05:29:35 +0000 | [diff] [blame] | 58 | return DivOpInfo(false, nullptr, nullptr); |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 59 | } |
| 60 | |
| 61 | static DivOpInfo getTombstoneKey() { |
Craig Topper | f40110f | 2014-04-25 05:29:35 +0000 | [diff] [blame] | 62 | return DivOpInfo(true, nullptr, nullptr); |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 63 | } |
| 64 | |
| 65 | static unsigned getHashValue(const DivOpInfo &Val) { |
| 66 | return (unsigned)(reinterpret_cast<uintptr_t>(Val.Dividend) ^ |
| 67 | reinterpret_cast<uintptr_t>(Val.Divisor)) ^ |
Jakub Staszak | 46beca6 | 2012-09-04 20:48:24 +0000 | [diff] [blame] | 68 | (unsigned)Val.SignedOp; |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 69 | } |
| 70 | }; |
| 71 | |
| 72 | typedef DenseMap<DivOpInfo, DivPhiNodes> DivCacheTy; |
Alexander Kornienko | f00654e | 2015-06-23 09:49:53 +0000 | [diff] [blame] | 73 | } |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 74 | |
| 75 | // insertFastDiv - Substitutes the div/rem instruction with code that checks the |
| 76 | // value of the operands and uses a shorter-faster div/rem instruction when |
| 77 | // possible and the longer-slower div/rem instruction otherwise. |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 78 | static bool insertFastDiv(Instruction *I, IntegerType *BypassType, |
| 79 | bool UseDivOp, bool UseSignedOp, |
Jakub Staszak | 46beca6 | 2012-09-04 20:48:24 +0000 | [diff] [blame] | 80 | DivCacheTy &PerBBDivCache) { |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 81 | Function *F = I->getParent()->getParent(); |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 82 | // Get instruction operands |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 83 | Value *Dividend = I->getOperand(0); |
| 84 | Value *Divisor = I->getOperand(1); |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 85 | |
Justin Lebar | 583b868 | 2016-11-16 00:44:43 +0000 | [diff] [blame] | 86 | if (isa<ConstantInt>(Divisor)) { |
| 87 | // Division by a constant should have been been solved and replaced earlier |
| 88 | // in the pipeline. |
Jakub Staszak | 46beca6 | 2012-09-04 20:48:24 +0000 | [diff] [blame] | 89 | return false; |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 90 | } |
| 91 | |
Justin Lebar | 2860573 | 2016-11-16 00:44:47 +0000 | [diff] [blame] | 92 | // If the numerator is a constant, bail if it doesn't fit into BypassType. |
| 93 | if (ConstantInt *ConstDividend = dyn_cast<ConstantInt>(Dividend)) |
| 94 | if (ConstDividend->getValue().getActiveBits() > BypassType->getBitWidth()) |
| 95 | return false; |
| 96 | |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 97 | // Basic Block is split before divide |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 98 | BasicBlock *MainBB = &*I->getParent(); |
| 99 | BasicBlock *SuccessorBB = MainBB->splitBasicBlock(I); |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 100 | |
| 101 | // Add new basic block for slow divide operation |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 102 | BasicBlock *SlowBB = |
| 103 | BasicBlock::Create(F->getContext(), "", MainBB->getParent(), SuccessorBB); |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 104 | SlowBB->moveBefore(SuccessorBB); |
| 105 | IRBuilder<> SlowBuilder(SlowBB, SlowBB->begin()); |
| 106 | Value *SlowQuotientV; |
| 107 | Value *SlowRemainderV; |
| 108 | if (UseSignedOp) { |
| 109 | SlowQuotientV = SlowBuilder.CreateSDiv(Dividend, Divisor); |
| 110 | SlowRemainderV = SlowBuilder.CreateSRem(Dividend, Divisor); |
| 111 | } else { |
| 112 | SlowQuotientV = SlowBuilder.CreateUDiv(Dividend, Divisor); |
| 113 | SlowRemainderV = SlowBuilder.CreateURem(Dividend, Divisor); |
| 114 | } |
| 115 | SlowBuilder.CreateBr(SuccessorBB); |
| 116 | |
| 117 | // Add new basic block for fast divide operation |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 118 | BasicBlock *FastBB = |
| 119 | BasicBlock::Create(F->getContext(), "", MainBB->getParent(), SuccessorBB); |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 120 | FastBB->moveBefore(SlowBB); |
| 121 | IRBuilder<> FastBuilder(FastBB, FastBB->begin()); |
Jakub Staszak | 46beca6 | 2012-09-04 20:48:24 +0000 | [diff] [blame] | 122 | Value *ShortDivisorV = FastBuilder.CreateCast(Instruction::Trunc, Divisor, |
| 123 | BypassType); |
| 124 | Value *ShortDividendV = FastBuilder.CreateCast(Instruction::Trunc, Dividend, |
| 125 | BypassType); |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 126 | |
| 127 | // udiv/urem because optimization only handles positive numbers |
Justin Lebar | 468bf73 | 2016-10-28 21:43:51 +0000 | [diff] [blame] | 128 | Value *ShortQuotientV = FastBuilder.CreateUDiv(ShortDividendV, ShortDivisorV); |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 129 | Value *ShortRemainderV = FastBuilder.CreateURem(ShortDividendV, |
| 130 | ShortDivisorV); |
| 131 | Value *FastQuotientV = FastBuilder.CreateCast(Instruction::ZExt, |
Jakub Staszak | 46beca6 | 2012-09-04 20:48:24 +0000 | [diff] [blame] | 132 | ShortQuotientV, |
| 133 | Dividend->getType()); |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 134 | Value *FastRemainderV = FastBuilder.CreateCast(Instruction::ZExt, |
| 135 | ShortRemainderV, |
| 136 | Dividend->getType()); |
| 137 | FastBuilder.CreateBr(SuccessorBB); |
| 138 | |
| 139 | // Phi nodes for result of div and rem |
| 140 | IRBuilder<> SuccessorBuilder(SuccessorBB, SuccessorBB->begin()); |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 141 | PHINode *QuoPhi = SuccessorBuilder.CreatePHI(I->getType(), 2); |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 142 | QuoPhi->addIncoming(SlowQuotientV, SlowBB); |
| 143 | QuoPhi->addIncoming(FastQuotientV, FastBB); |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 144 | PHINode *RemPhi = SuccessorBuilder.CreatePHI(I->getType(), 2); |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 145 | RemPhi->addIncoming(SlowRemainderV, SlowBB); |
| 146 | RemPhi->addIncoming(FastRemainderV, FastBB); |
| 147 | |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 148 | // Replace I with appropriate phi node |
Jakub Staszak | 46beca6 | 2012-09-04 20:48:24 +0000 | [diff] [blame] | 149 | if (UseDivOp) |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 150 | I->replaceAllUsesWith(QuoPhi); |
Jakub Staszak | 46beca6 | 2012-09-04 20:48:24 +0000 | [diff] [blame] | 151 | else |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 152 | I->replaceAllUsesWith(RemPhi); |
| 153 | I->eraseFromParent(); |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 154 | |
| 155 | // Combine operands into a single value with OR for value testing below |
| 156 | MainBB->getInstList().back().eraseFromParent(); |
| 157 | IRBuilder<> MainBuilder(MainBB, MainBB->end()); |
Justin Lebar | 2860573 | 2016-11-16 00:44:47 +0000 | [diff] [blame] | 158 | |
| 159 | // We should have bailed out above if the divisor is a constant, but the |
| 160 | // dividend may still be a constant. Set OrV to our non-constant operands |
| 161 | // OR'ed together. |
| 162 | assert(!isa<ConstantInt>(Divisor)); |
| 163 | |
| 164 | Value *OrV; |
| 165 | if (!isa<ConstantInt>(Dividend)) |
| 166 | OrV = MainBuilder.CreateOr(Dividend, Divisor); |
| 167 | else |
| 168 | OrV = Divisor; |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 169 | |
| 170 | // BitMask is inverted to check if the operands are |
| 171 | // larger than the bypass type |
| 172 | uint64_t BitMask = ~BypassType->getBitMask(); |
| 173 | Value *AndV = MainBuilder.CreateAnd(OrV, BitMask); |
| 174 | |
| 175 | // Compare operand values and branch |
Preston Gurd | 485296d | 2013-03-04 18:13:57 +0000 | [diff] [blame] | 176 | Value *ZeroV = ConstantInt::getSigned(Dividend->getType(), 0); |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 177 | Value *CmpV = MainBuilder.CreateICmpEQ(AndV, ZeroV); |
| 178 | MainBuilder.CreateCondBr(CmpV, FastBB, SlowBB); |
| 179 | |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 180 | // Cache phi nodes to be used later in place of other instances |
| 181 | // of div or rem with the same sign, dividend, and divisor |
| 182 | DivOpInfo Key(UseSignedOp, Dividend, Divisor); |
| 183 | DivPhiNodes Value(QuoPhi, RemPhi); |
| 184 | PerBBDivCache.insert(std::pair<DivOpInfo, DivPhiNodes>(Key, Value)); |
Jakub Staszak | 46beca6 | 2012-09-04 20:48:24 +0000 | [diff] [blame] | 185 | return true; |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 186 | } |
| 187 | |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 188 | // reuseOrInsertFastDiv - Reuses previously computed dividend or remainder from |
| 189 | // the current BB if operands and operation are identical. Otherwise calls |
| 190 | // insertFastDiv to perform the optimization and caches the resulting dividend |
| 191 | // and remainder. |
| 192 | static bool reuseOrInsertFastDiv(Instruction *I, IntegerType *BypassType, |
| 193 | bool UseDivOp, bool UseSignedOp, |
Jakub Staszak | 46beca6 | 2012-09-04 20:48:24 +0000 | [diff] [blame] | 194 | DivCacheTy &PerBBDivCache) { |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 195 | // Get instruction operands |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 196 | DivOpInfo Key(UseSignedOp, I->getOperand(0), I->getOperand(1)); |
Jakub Staszak | e535c1a | 2012-09-04 23:11:11 +0000 | [diff] [blame] | 197 | DivCacheTy::iterator CacheI = PerBBDivCache.find(Key); |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 198 | |
| 199 | if (CacheI == PerBBDivCache.end()) { |
| 200 | // If previous instance does not exist, insert fast div |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 201 | return insertFastDiv(I, BypassType, UseDivOp, UseSignedOp, PerBBDivCache); |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 202 | } |
| 203 | |
| 204 | // Replace operation value with previously generated phi node |
Jakub Staszak | e535c1a | 2012-09-04 23:11:11 +0000 | [diff] [blame] | 205 | DivPhiNodes &Value = CacheI->second; |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 206 | if (UseDivOp) { |
| 207 | // Replace all uses of div instruction with quotient phi node |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 208 | I->replaceAllUsesWith(Value.Quotient); |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 209 | } else { |
| 210 | // Replace all uses of rem instruction with remainder phi node |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 211 | I->replaceAllUsesWith(Value.Remainder); |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 212 | } |
| 213 | |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 214 | // Remove redundant operation |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 215 | I->eraseFromParent(); |
Jakub Staszak | 46beca6 | 2012-09-04 20:48:24 +0000 | [diff] [blame] | 216 | return true; |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 217 | } |
| 218 | |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 219 | // bypassSlowDivision - This optimization identifies DIV instructions in a BB |
| 220 | // that can be profitably bypassed and carried out with a shorter, faster |
| 221 | // divide. |
| 222 | bool llvm::bypassSlowDivision( |
| 223 | BasicBlock *BB, const DenseMap<unsigned int, unsigned int> &BypassWidths) { |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 224 | DivCacheTy DivCache; |
| 225 | |
| 226 | bool MadeChange = false; |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 227 | Instruction* Next = &*BB->begin(); |
| 228 | while (Next != nullptr) { |
| 229 | // We may add instructions immediately after I, but we want to skip over |
| 230 | // them. |
| 231 | Instruction* I = Next; |
| 232 | Next = Next->getNextNode(); |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 233 | |
| 234 | // Get instruction details |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 235 | unsigned Opcode = I->getOpcode(); |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 236 | bool UseDivOp = Opcode == Instruction::SDiv || Opcode == Instruction::UDiv; |
| 237 | bool UseRemOp = Opcode == Instruction::SRem || Opcode == Instruction::URem; |
Jakub Staszak | 46beca6 | 2012-09-04 20:48:24 +0000 | [diff] [blame] | 238 | bool UseSignedOp = Opcode == Instruction::SDiv || |
| 239 | Opcode == Instruction::SRem; |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 240 | |
| 241 | // Only optimize div or rem ops |
Jakub Staszak | 46beca6 | 2012-09-04 20:48:24 +0000 | [diff] [blame] | 242 | if (!UseDivOp && !UseRemOp) |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 243 | continue; |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 244 | |
Preston Gurd | 5509e3d | 2012-10-03 16:11:44 +0000 | [diff] [blame] | 245 | // Skip division on vector types, only optimize integer instructions |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 246 | if (!I->getType()->isIntegerTy()) |
Jakub Staszak | 46beca6 | 2012-09-04 20:48:24 +0000 | [diff] [blame] | 247 | continue; |
| 248 | |
Preston Gurd | 0d67f51 | 2012-10-04 21:33:40 +0000 | [diff] [blame] | 249 | // Get bitwidth of div/rem instruction |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 250 | IntegerType *T = cast<IntegerType>(I->getType()); |
Preston Gurd | 485296d | 2013-03-04 18:13:57 +0000 | [diff] [blame] | 251 | unsigned int bitwidth = T->getBitWidth(); |
Preston Gurd | 5509e3d | 2012-10-03 16:11:44 +0000 | [diff] [blame] | 252 | |
Preston Gurd | 0d67f51 | 2012-10-04 21:33:40 +0000 | [diff] [blame] | 253 | // Continue if bitwidth is not bypassed |
| 254 | DenseMap<unsigned int, unsigned int>::const_iterator BI = BypassWidths.find(bitwidth); |
| 255 | if (BI == BypassWidths.end()) |
Preston Gurd | 5509e3d | 2012-10-03 16:11:44 +0000 | [diff] [blame] | 256 | continue; |
| 257 | |
Preston Gurd | 0d67f51 | 2012-10-04 21:33:40 +0000 | [diff] [blame] | 258 | // Get type for div/rem instruction with bypass bitwidth |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 259 | IntegerType *BT = IntegerType::get(I->getContext(), BI->second); |
Preston Gurd | 5509e3d | 2012-10-03 16:11:44 +0000 | [diff] [blame] | 260 | |
Eric Christopher | 49a7d6c | 2016-01-04 23:18:58 +0000 | [diff] [blame] | 261 | MadeChange |= reuseOrInsertFastDiv(I, BT, UseDivOp, UseSignedOp, DivCache); |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 262 | } |
| 263 | |
Justin Lebar | 0ede5fb | 2016-10-28 21:43:54 +0000 | [diff] [blame] | 264 | // Above we eagerly create divs and rems, as pairs, so that we can efficiently |
| 265 | // create divrem machine instructions. Now erase any unused divs / rems so we |
| 266 | // don't leave extra instructions sitting around. |
| 267 | for (auto &KV : DivCache) |
| 268 | for (Instruction *Phi : {KV.second.Quotient, KV.second.Remainder}) |
| 269 | RecursivelyDeleteTriviallyDeadInstructions(Phi); |
| 270 | |
Preston Gurd | cdf540d | 2012-09-04 18:22:17 +0000 | [diff] [blame] | 271 | return MadeChange; |
| 272 | } |