LLVM: lib/Transforms/Scalar/DivRemPairs.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

26#include

27

28using namespace llvm;

30

31#define DEBUG_TYPE "div-rem-pairs"

32STATISTIC(NumPairs, "Number of div/rem pairs");

33STATISTIC(NumRecomposed, "Number of instructions recomposed");

34STATISTIC(NumHoisted, "Number of instructions hoisted");

35STATISTIC(NumDecomposed, "Number of instructions decomposed");

37 "Controls transformations in div-rem-pairs pass");

38

39namespace {

40struct ExpandedMatch {

43};

44}

45

46

47

48

49

51 Value *Dividend, *XroundedDownToMultipleOfY;

53 return std::nullopt;

54

57

59 XroundedDownToMultipleOfY,

63 return std::nullopt;

64

65 ExpandedMatch M;

66 M.Key.SignedOp = Div->getOpcode() == Instruction::SDiv;

67 M.Key.Dividend = Dividend;

68 M.Key.Divisor = Divisor;

70 return M;

71}

72

73namespace {

74

75

76struct DivRemPairWorklistEntry {

77

78 AssertingVH DivInst;

79

80

81

82 AssertingVH RemInst;

83

84 DivRemPairWorklistEntry(Instruction *DivInst_, Instruction *RemInst_)

85 : DivInst(DivInst_), RemInst(RemInst_) {

86 assert((DivInst->getOpcode() == Instruction::UDiv ||

87 DivInst->getOpcode() == Instruction::SDiv) &&

88 "Not a division.");

89 assert(DivInst->getType() == RemInst->getType() && "Types should match.");

90

91

92 }

93

94

95 Type *getType() const { return DivInst->getType(); }

96

97

98 bool isSigned() const { return DivInst->getOpcode() == Instruction::SDiv; }

99

100

101 Value *getDividend() const { return DivInst->getOperand(0); }

102 Value *getDivisor() const { return DivInst->getOperand(1); }

103

104 bool isRemExpanded() const {

105 switch (RemInst->getOpcode()) {

106 case Instruction::SRem:

107 case Instruction::URem:

108 return false;

109 default:

110 return true;

111 }

112 }

113};

114}

116

117

118

119

120

121

123

124

126

127

129 for (auto &BB : F) {

130 for (auto &I : BB) {

131 if (I.getOpcode() == Instruction::SDiv)

132 DivMap[DivRemMapKey(true, I.getOperand(0), I.getOperand(1))] = &I;

133 else if (I.getOpcode() == Instruction::UDiv)

134 DivMap[DivRemMapKey(false, I.getOperand(0), I.getOperand(1))] = &I;

135 else if (I.getOpcode() == Instruction::SRem)

136 RemMap[DivRemMapKey(true, I.getOperand(0), I.getOperand(1))] = &I;

137 else if (I.getOpcode() == Instruction::URem)

138 RemMap[DivRemMapKey(false, I.getOperand(0), I.getOperand(1))] = &I;

140 RemMap[Match->Key] = Match->Value;

141 }

142 }

143

144

146

147

148

149

150 for (auto &RemPair : RemMap) {

151

152 auto It = DivMap.find(RemPair.first);

153 if (It == DivMap.end())

154 continue;

155

156

157 NumPairs++;

159

160

162 }

163

164 return Worklist;

165}

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

184

185

186

188

189

190 for (DivRemPairWorklistEntry &E : Worklist) {

192 continue;

193

194 bool HasDivRemOp = TTI.hasDivRemOp(E.getType(), E.isSigned());

195

196 auto &DivInst = E.DivInst;

197 auto &RemInst = E.RemInst;

198

199 const bool RemOriginallyWasInExpandedForm = E.isRemExpanded();

200 (void)RemOriginallyWasInExpandedForm;

201

202 if (HasDivRemOp && E.isRemExpanded()) {

203

204

205 Value *X = E.getDividend();

206 Value *Y = E.getDivisor();

207 Instruction *RealRem = E.isSigned() ? BinaryOperator::CreateSRem(X, Y)

208 : BinaryOperator::CreateURem(X, Y);

209

210

211 RealRem->setName(RemInst->getName() + ".recomposed");

212 RealRem->insertAfter(RemInst->getIterator());

214

215 RemInst = RealRem;

216

220 NumRecomposed++;

221

222

224 }

225

226 assert((E.isRemExpanded() || !HasDivRemOp) &&

227 "*If* the target supports div-rem, then by now the RemInst *is* "

228 "Instruction::[US]Rem.");

229

230

231

232

233 if (HasDivRemOp && RemInst->getParent() == DivInst->getParent())

234 continue;

235

236 bool DivDominates = DT.dominates(DivInst, RemInst);

237 if (!DivDominates && !DT.dominates(RemInst, DivInst)) {

238

239

240

242 BasicBlock *DivBB = DivInst->getParent();

243 BasicBlock *RemBB = RemInst->getParent();

244

245

246

248 for (auto I = ParentBB->begin(), E = DivOrRem->getIterator(); I != E;

249 ++I)

251 return false;

252

253 return true;

254 };

255

256

257

258

259

260

261

262

263

264

265

266

267

270

271

272

273

274

275

276

277

278

279

280

281

282

283

285

287 PredBB = RemPredBB;

288 }

289

290

293 IsSafeToHoist(RemInst, RemBB) && IsSafeToHoist(DivInst, DivBB) &&

295 [&](BasicBlock *BB) { return BB == DivBB || BB == RemBB; }) &&

297 [&](BasicBlock *BB) { return BB == RemBB || BB == PredBB; })) {

298 DivDominates = true;

301 if (HasDivRemOp) {

303 continue;

304 }

305 } else

306 continue;

307 }

308

309

310

311 if (!HasDivRemOp && E.isRemExpanded())

312 continue;

313

314 if (HasDivRemOp) {

315

316

317 if (DivDominates)

318 RemInst->moveAfter(DivInst);

319 else

320 DivInst->moveAfter(RemInst);

321 NumHoisted++;

322 } else {

323

324

325

326

327

328 assert(!RemOriginallyWasInExpandedForm &&

329 "We should not be expanding if the rem was in expanded form to "

330 "begin with.");

331

332 Value *X = E.getDividend();

333 Value *Y = E.getDivisor();

334 Instruction *Mul = BinaryOperator::CreateMul(DivInst, Y);

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367 if (!DivDominates)

368 DivInst->moveBefore(RemInst->getIterator());

369 Mul->insertAfter(RemInst->getIterator());

370 Mul->setDebugLoc(RemInst->getDebugLoc());

371 Sub->insertAfter(Mul->getIterator());

372 Sub->setDebugLoc(RemInst->getDebugLoc());

373

374

375

376 DivInst->dropPoisonGeneratingFlags();

377

378

379

380

381

382

383

384

385

386

388 auto *FrX =

389 new FreezeInst(X, X->getName() + ".frozen", DivInst->getIterator());

390 FrX->setDebugLoc(DivInst->getDebugLoc());

391 DivInst->setOperand(0, FrX);

392 Sub->setOperand(0, FrX);

393 }

394

395

397 auto *FrY =

398 new FreezeInst(Y, Y->getName() + ".frozen", DivInst->getIterator());

399 FrY->setDebugLoc(DivInst->getDebugLoc());

400 DivInst->setOperand(1, FrY);

401 Mul->setOperand(1, FrY);

402 }

403

404

405

406 Sub->setName(RemInst->getName() + ".decomposed");

408

409 RemInst = Sub;

410

413 NumDecomposed++;

414 }

416 }

417

419}

420

421

422

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")

This file provides an implementation of debug counters.

#define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC)

This file defines the DenseMap class.

static DivRemWorklistTy getWorklist(Function &F)

Find matching pairs of integer div/rem ops (they have the same numerator, denominator,...

Definition DivRemPairs.cpp:122

SmallVector< DivRemPairWorklistEntry, 4 > DivRemWorklistTy

Definition DivRemPairs.cpp:115

static bool optimizeDivRem(Function &F, const TargetTransformInfo &TTI, const DominatorTree &DT)

Find matching pairs of integer div/rem ops (they have the same numerator, denominator,...

Definition DivRemPairs.cpp:181

static std::optional< ExpandedMatch > matchExpandedRem(Instruction &I)

See if we can match: (which is the form we expand into) X - ((X ?

Definition DivRemPairs.cpp:50

static bool isSigned(unsigned int Opcode)

This is the interface for a simple mod/ref and alias analysis over globals.

This file implements a map that provides insertion order iteration.

FunctionAnalysisManager FAM

This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...

#define STATISTIC(VARNAME, DESC)

static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")

static TableGen::Emitter::OptClass< SkeletonEmitter > X("gen-skeleton-class", "Generate example skeleton class")

static SymbolRef::Type getType(const Symbol *Sym)

This pass exposes codegen information to IR-level passes.

LLVM Basic Block Representation.

LLVM_ABI const BasicBlock * getUniquePredecessor() const

Return the predecessor of this block if it has a unique predecessor block.

LLVM_ABI const BasicBlock * getSingleSuccessor() const

Return the successor of this block if it has a single successor.

const Instruction * getTerminator() const LLVM_READONLY

Returns the terminator instruction if the block is well formed or null if the block is not well forme...

Represents analyses that only rely on functions' control flow.

static bool shouldExecute(CounterInfo &Counter)

iterator find(const_arg_type_t< KeyT > Val)

Analysis pass which computes a DominatorTree.

Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.

LLVM_ABI bool dominates(const BasicBlock *BB, const Use &U) const

Return true if the (end of the) basic block BB dominates the use U.

This class represents a freeze function that returns random concrete value if an operand is either a ...

const DebugLoc & getDebugLoc() const

Return the debug location for this node as a DebugLoc.

LLVM_ABI InstListType::iterator eraseFromParent()

This method unlinks 'this' from the containing basic block and deletes it.

unsigned getOpcode() const

Returns a member of one of the enums like Instruction::Add.

void setDebugLoc(DebugLoc Loc)

Set the debug location information for this instruction.

LLVM_ABI void insertAfter(Instruction *InsertPos)

Insert an unlinked instruction into a basic block immediately after the specified instruction.

This class implements a map that also provides access to all stored values in a deterministic order.

A set of analyses that are preserved following a run of a transformation pass.

static PreservedAnalyses all()

Construct a special preserved set that preserves all passes.

PreservedAnalyses & preserveSet()

Mark an analysis set as preserved.

reference emplace_back(ArgTypes &&... Args)

This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.

Analysis pass providing the TargetTransformInfo.

This pass provides access to the codegen interfaces that are needed for IR-level transformations.

LLVM Value Representation.

LLVM_ABI Value(Type *Ty, unsigned scid)

LLVM_ABI void setName(const Twine &Name)

Change the name of the value.

LLVM_ABI void replaceAllUsesWith(Value *V)

Change all uses of this to point to a new Value.

self_iterator getIterator()

bool match(Val *V, const Pattern &P)

BinOpPred_match< LHS, RHS, is_idiv_op > m_IDiv(const LHS &L, const RHS &R)

Matches integer division operations.

bind_ty< Instruction > m_Instruction(Instruction *&I)

Match an instruction, capturing it if we match.

specificval_ty m_Specific(const Value *V)

Match if we have a specific specified value.

match_combine_and< LTy, RTy > m_CombineAnd(const LTy &L, const RTy &R)

Combine two pattern matchers matching L && R.

deferredval_ty< Value > m_Deferred(Value *const &V)

Like m_Specific(), but works if the specific value to match is determined as part of the same match()...

class_match< Value > m_Value()

Match an arbitrary value and ignore it.

BinaryOp_match< LHS, RHS, Instruction::Mul, true > m_c_Mul(const LHS &L, const RHS &R)

Matches a Mul with LHS and RHS in either order.

BinaryOp_match< LHS, RHS, Instruction::Sub > m_Sub(const LHS &L, const RHS &R)

This is an optimization pass for GlobalISel generic memory operations.

FunctionAddr VTableAddr Value

bool all_of(R &&range, UnaryPredicate P)

Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.

auto successors(const MachineBasicBlock *BB)

LLVM_ABI bool isGuaranteedNotToBeUndef(const Value *V, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, unsigned Depth=0)

Returns true if V cannot be undef, but may be poison.

bool isa(const From &Val)

isa - Return true if the parameter to the template is an instance of one of the template type argu...

LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key

@ Sub

Subtraction of integers.

LLVM_ABI bool isGuaranteedToTransferExecutionToSuccessor(const Instruction *I)

Return true if this function can prove that the instruction I will always transfer execution to one o...

auto predecessors(const MachineBasicBlock *BB)

AnalysisManager< Function > FunctionAnalysisManager

Convenience typedef for the Function analysis manager.

PreservedAnalyses run(Function &F, FunctionAnalysisManager &)

Definition DivRemPairs.cpp:423