blob: b043687e6ff5129a71216a3d99c010f74f79e009 [file] [log] [blame]
Roman Lebedevc75cdd02019-07-30 07:10:00 +00001//===- DivRemPairs.cpp - Hoist/[dr]ecompose division and remainder --------===//
Sanjay Patel6fd43912017-09-09 13:38:18 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Sanjay Patel6fd43912017-09-09 13:38:18 +00006//
7//===----------------------------------------------------------------------===//
8//
Roman Lebedevc75cdd02019-07-30 07:10:00 +00009// This pass hoists and/or decomposes/recomposes integer division and remainder
Sanjay Patel6fd43912017-09-09 13:38:18 +000010// instructions to enable CFG improvements and better codegen.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/Transforms/Scalar/DivRemPairs.h"
Geoff Berry2af5f3c2018-04-25 02:17:56 +000015#include "llvm/ADT/DenseMap.h"
16#include "llvm/ADT/MapVector.h"
Sanjay Patel6fd43912017-09-09 13:38:18 +000017#include "llvm/ADT/Statistic.h"
18#include "llvm/Analysis/GlobalsModRef.h"
19#include "llvm/Analysis/TargetTransformInfo.h"
20#include "llvm/IR/Dominators.h"
21#include "llvm/IR/Function.h"
Roman Lebedevc75cdd02019-07-30 07:10:00 +000022#include "llvm/IR/PatternMatch.h"
Sanjay Patel6fd43912017-09-09 13:38:18 +000023#include "llvm/Pass.h"
George Burgess IV213d1d22018-08-01 23:14:14 +000024#include "llvm/Support/DebugCounter.h"
Sanjay Patel6fd43912017-09-09 13:38:18 +000025#include "llvm/Transforms/Scalar.h"
26#include "llvm/Transforms/Utils/BypassSlowDivision.h"
Roman Lebedevc75cdd02019-07-30 07:10:00 +000027
Sanjay Patel6fd43912017-09-09 13:38:18 +000028using namespace llvm;
Roman Lebedevc75cdd02019-07-30 07:10:00 +000029using namespace llvm::PatternMatch;
Sanjay Patel6fd43912017-09-09 13:38:18 +000030
31#define DEBUG_TYPE "div-rem-pairs"
32STATISTIC(NumPairs, "Number of div/rem pairs");
Roman Lebedevc75cdd02019-07-30 07:10:00 +000033STATISTIC(NumRecomposed, "Number of instructions recomposed");
Sanjay Patel6fd43912017-09-09 13:38:18 +000034STATISTIC(NumHoisted, "Number of instructions hoisted");
35STATISTIC(NumDecomposed, "Number of instructions decomposed");
George Burgess IV213d1d22018-08-01 23:14:14 +000036DEBUG_COUNTER(DRPCounter, "div-rem-pairs-transform",
37 "Controls transformations in div-rem-pairs pass");
Sanjay Patel6fd43912017-09-09 13:38:18 +000038
Roman Lebedevc75cdd02019-07-30 07:10:00 +000039namespace {
40using InstructionWithInfo = PointerIntPair<Instruction *, 1, bool /*Expanded*/>;
41
42struct ExpandedMatch {
43 DivRemMapKey Key;
44 InstructionWithInfo Value;
45};
46} // namespace
47
48/// See if we can match: (which is the form we expand into)
49/// X - ((X ?/ Y) * Y)
50/// which is equivalent to:
51/// X ?% Y
52static llvm::Optional<ExpandedMatch> matchExpandedRem(Instruction &I) {
53 ExpandedMatch M;
54 M.Value.setPointer(&I);
55 M.Value.setInt(/*Expanded=*/true);
56
57 Value *XroundedDownToMultipleOfY;
58 if (!match(&I, m_Sub(m_Value(M.Key.Dividend),
59 m_Value(XroundedDownToMultipleOfY))))
60 return llvm::None;
61
62 Instruction *Div;
63 // Look for ((X / Y) * Y)
64 if (!match(XroundedDownToMultipleOfY,
65 m_c_Mul(m_CombineAnd(m_IDiv(m_Specific(M.Key.Dividend),
66 m_Value(M.Key.Divisor)),
67 m_Instruction(Div)),
68 m_Deferred(M.Key.Divisor))))
69 return llvm::None;
70
71 M.Key.SignedOp = Div->getOpcode() == Instruction::SDiv;
72 return M;
73}
74
Sanjay Patel6fd43912017-09-09 13:38:18 +000075/// Find matching pairs of integer div/rem ops (they have the same numerator,
76/// denominator, and signedness). If they exist in different basic blocks, bring
77/// them together by hoisting or replace the common division operation that is
78/// implicit in the remainder:
79/// X % Y <--> X - ((X / Y) * Y).
80///
81/// We can largely ignore the normal safety and cost constraints on speculation
82/// of these ops when we find a matching pair. This is because we are already
83/// guaranteed that any exceptions and most cost are already incurred by the
84/// first member of the pair.
85///
86/// Note: This transform could be an oddball enhancement to EarlyCSE, GVN, or
87/// SimplifyCFG, but it's split off on its own because it's different enough
88/// that it doesn't quite match the stated objectives of those passes.
89static bool optimizeDivRem(Function &F, const TargetTransformInfo &TTI,
90 const DominatorTree &DT) {
91 bool Changed = false;
92
93 // Insert all divide and remainder instructions into maps keyed by their
94 // operands and opcode (signed or unsigned).
Geoff Berry2af5f3c2018-04-25 02:17:56 +000095 DenseMap<DivRemMapKey, Instruction *> DivMap;
96 // Use a MapVector for RemMap so that instructions are moved/inserted in a
97 // deterministic order.
Roman Lebedevc75cdd02019-07-30 07:10:00 +000098 MapVector<DivRemMapKey, InstructionWithInfo> RemMap;
Sanjay Patel6fd43912017-09-09 13:38:18 +000099 for (auto &BB : F) {
100 for (auto &I : BB) {
101 if (I.getOpcode() == Instruction::SDiv)
102 DivMap[DivRemMapKey(true, I.getOperand(0), I.getOperand(1))] = &I;
103 else if (I.getOpcode() == Instruction::UDiv)
104 DivMap[DivRemMapKey(false, I.getOperand(0), I.getOperand(1))] = &I;
105 else if (I.getOpcode() == Instruction::SRem)
Roman Lebedevc75cdd02019-07-30 07:10:00 +0000106 RemMap[DivRemMapKey(true, I.getOperand(0), I.getOperand(1))] = {
107 &I, /*Expanded=*/false};
Sanjay Patel6fd43912017-09-09 13:38:18 +0000108 else if (I.getOpcode() == Instruction::URem)
Roman Lebedevc75cdd02019-07-30 07:10:00 +0000109 RemMap[DivRemMapKey(false, I.getOperand(0), I.getOperand(1))] = {
110 &I, /*Expanded=*/false};
111 else if (auto Match = matchExpandedRem(I))
112 RemMap[Match->Key] = Match->Value;
Sanjay Patel6fd43912017-09-09 13:38:18 +0000113 }
114 }
115
116 // We can iterate over either map because we are only looking for matched
117 // pairs. Choose remainders for efficiency because they are usually even more
118 // rare than division.
119 for (auto &RemPair : RemMap) {
120 // Find the matching division instruction from the division map.
Geoff Berry2af5f3c2018-04-25 02:17:56 +0000121 Instruction *DivInst = DivMap[RemPair.first];
Sanjay Patel6fd43912017-09-09 13:38:18 +0000122 if (!DivInst)
123 continue;
124
Roman Lebedevc75cdd02019-07-30 07:10:00 +0000125 // We have a matching pair of div/rem instructions.
126 // If the rem is in expanded form, collapse it into rem first.
127 // If one dominates the other, hoist and/or replace one.
Sanjay Patel6fd43912017-09-09 13:38:18 +0000128 NumPairs++;
Roman Lebedevc75cdd02019-07-30 07:10:00 +0000129 InstructionWithInfo RemLike = RemPair.second;
130 // NOTE: RemInst may be in expanded form!
131 Instruction *RemInst = RemLike.getPointer();
132 bool IsInExpandedForm = RemLike.getInt();
133 bool IsSigned = RemPair.first.SignedOp;
Sanjay Patel6fd43912017-09-09 13:38:18 +0000134 bool HasDivRemOp = TTI.hasDivRemOp(DivInst->getType(), IsSigned);
135
Roman Lebedevc75cdd02019-07-30 07:10:00 +0000136 if (!DebugCounter::shouldExecute(DRPCounter))
137 continue;
138
139 if (HasDivRemOp && IsInExpandedForm) {
140 // The target supports div+rem but the rem is expanded.
141 // We should recompose it first.
142 Value *X = RemPair.first.Dividend;
143 Value *Y = RemPair.first.Divisor;
144 Instruction *RealRem = IsSigned ? BinaryOperator::CreateSRem(X, Y)
145 : BinaryOperator::CreateURem(X, Y);
146 // Note that we place it right next to the original expanded instruction,
147 // and letting further handling to move it if needed.
148 RealRem->takeName(RemInst);
149 RealRem->insertAfter(RemInst);
150 RemInst->replaceAllUsesWith(RealRem);
151 RemInst->eraseFromParent();
152 RemInst = RealRem;
153 NumRecomposed++;
154 // Note that we have left ((X / Y) * Y) around.
155 // If it had other uses we could rewrite it as X - X % Y
156 }
157
158 assert(((RemInst->getOpcode() == Instruction::SRem ||
159 RemInst->getOpcode() == Instruction::URem) ||
160 !HasDivRemOp) &&
161 "*If* the target supports div-rem, then by now the RemInst *is* "
162 "Instruction::[US]Rem.");
163
Sanjay Patel6fd43912017-09-09 13:38:18 +0000164 // If the target supports div+rem and the instructions are in the same block
165 // already, there's nothing to do. The backend should handle this. If the
166 // target does not support div+rem, then we will decompose the rem.
167 if (HasDivRemOp && RemInst->getParent() == DivInst->getParent())
168 continue;
169
170 bool DivDominates = DT.dominates(DivInst, RemInst);
Roman Lebedevc75cdd02019-07-30 07:10:00 +0000171 if (!DivDominates && !DT.dominates(RemInst, DivInst)) {
172 // We have matching div-rem pair, but they are in two different blocks,
173 // neither of which dominates one another.
174 assert(!IsInExpandedForm && "Won't happen if matched expanded form.");
175 // FIXME: We could hoist both ops to the common predecessor block?
Sanjay Patel6fd43912017-09-09 13:38:18 +0000176 continue;
Roman Lebedevc75cdd02019-07-30 07:10:00 +0000177 }
Sanjay Patel6fd43912017-09-09 13:38:18 +0000178
Roman Lebedevc75cdd02019-07-30 07:10:00 +0000179 // The target does not have a single div/rem operation,
180 // and the rem is already in expanded form. Nothing to do.
181 if (!HasDivRemOp && IsInExpandedForm)
George Burgess IV213d1d22018-08-01 23:14:14 +0000182 continue;
183
Sanjay Patel6fd43912017-09-09 13:38:18 +0000184 if (HasDivRemOp) {
185 // The target has a single div/rem operation. Hoist the lower instruction
186 // to make the matched pair visible to the backend.
187 if (DivDominates)
188 RemInst->moveAfter(DivInst);
189 else
190 DivInst->moveAfter(RemInst);
191 NumHoisted++;
192 } else {
Roman Lebedevc75cdd02019-07-30 07:10:00 +0000193 // The target does not have a single div/rem operation,
194 // and the rem is *not* in a already-expanded form.
195 // Decompose the remainder calculation as:
Sanjay Patel6fd43912017-09-09 13:38:18 +0000196 // X % Y --> X - ((X / Y) * Y).
197 Value *X = RemInst->getOperand(0);
198 Value *Y = RemInst->getOperand(1);
199 Instruction *Mul = BinaryOperator::CreateMul(DivInst, Y);
200 Instruction *Sub = BinaryOperator::CreateSub(X, Mul);
201
202 // If the remainder dominates, then hoist the division up to that block:
203 //
204 // bb1:
205 // %rem = srem %x, %y
206 // bb2:
207 // %div = sdiv %x, %y
208 // -->
209 // bb1:
210 // %div = sdiv %x, %y
211 // %mul = mul %div, %y
212 // %rem = sub %x, %mul
213 //
214 // If the division dominates, it's already in the right place. The mul+sub
215 // will be in a different block because we don't assume that they are
216 // cheap to speculatively execute:
217 //
218 // bb1:
219 // %div = sdiv %x, %y
220 // bb2:
221 // %rem = srem %x, %y
222 // -->
223 // bb1:
224 // %div = sdiv %x, %y
225 // bb2:
226 // %mul = mul %div, %y
227 // %rem = sub %x, %mul
228 //
229 // If the div and rem are in the same block, we do the same transform,
230 // but any code movement would be within the same block.
231
232 if (!DivDominates)
233 DivInst->moveBefore(RemInst);
234 Mul->insertAfter(RemInst);
235 Sub->insertAfter(Mul);
236
237 // Now kill the explicit remainder. We have replaced it with:
238 // (sub X, (mul (div X, Y), Y)
239 RemInst->replaceAllUsesWith(Sub);
240 RemInst->eraseFromParent();
241 NumDecomposed++;
242 }
243 Changed = true;
244 }
245
246 return Changed;
247}
248
249// Pass manager boilerplate below here.
250
251namespace {
252struct DivRemPairsLegacyPass : public FunctionPass {
253 static char ID;
254 DivRemPairsLegacyPass() : FunctionPass(ID) {
255 initializeDivRemPairsLegacyPassPass(*PassRegistry::getPassRegistry());
256 }
257
258 void getAnalysisUsage(AnalysisUsage &AU) const override {
259 AU.addRequired<DominatorTreeWrapperPass>();
260 AU.addRequired<TargetTransformInfoWrapperPass>();
261 AU.setPreservesCFG();
262 AU.addPreserved<DominatorTreeWrapperPass>();
263 AU.addPreserved<GlobalsAAWrapperPass>();
264 FunctionPass::getAnalysisUsage(AU);
265 }
266
267 bool runOnFunction(Function &F) override {
268 if (skipFunction(F))
269 return false;
270 auto &TTI = getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
271 auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
272 return optimizeDivRem(F, TTI, DT);
273 }
274};
275}
276
277char DivRemPairsLegacyPass::ID = 0;
278INITIALIZE_PASS_BEGIN(DivRemPairsLegacyPass, "div-rem-pairs",
279 "Hoist/decompose integer division and remainder", false,
280 false)
281INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
282INITIALIZE_PASS_END(DivRemPairsLegacyPass, "div-rem-pairs",
283 "Hoist/decompose integer division and remainder", false,
284 false)
285FunctionPass *llvm::createDivRemPairsPass() {
286 return new DivRemPairsLegacyPass();
287}
288
289PreservedAnalyses DivRemPairsPass::run(Function &F,
290 FunctionAnalysisManager &FAM) {
291 TargetTransformInfo &TTI = FAM.getResult<TargetIRAnalysis>(F);
292 DominatorTree &DT = FAM.getResult<DominatorTreeAnalysis>(F);
293 if (!optimizeDivRem(F, TTI, DT))
294 return PreservedAnalyses::all();
295 // TODO: This pass just hoists/replaces math ops - all analyses are preserved?
296 PreservedAnalyses PA;
297 PA.preserveSet<CFGAnalyses>();
298 PA.preserve<GlobalsAA>();
299 return PA;
300}