Skip to content

Commit 3e39b27

Browse files
committed
[llvm/CodeGen] Add ExpandLargeDivRem pass
Adds a pass ExpandLargeDivRem to expand div/rem instructions with more than 128 bits into a loop computing that value. As discussed on https://reviews.llvm.org/D120327, this approach has the advantage that it is independent of the runtime library. This also helps the clang driver, which otherwise would need to understand enough about the runtime library to know whether to allow _BitInts with more than 128 bits. Targets are still free to disable this pass and instead provide a faster implementation in a runtime library. Fixes llvm#44994 Differential Revision: https://reviews.llvm.org/D126644
1 parent bb26ebb commit 3e39b27

File tree

15 files changed

+420
-67
lines changed

15 files changed

+420
-67
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//===----- ExpandLargeDivRem.h - Expand large div/rem ---------------------===//
2+
//
3+
// 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
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CODEGEN_EXPANDLARGEDIVREM_H
10+
#define LLVM_CODEGEN_EXPANDLARGEDIVREM_H
11+
12+
#include "llvm/IR/PassManager.h"
13+
14+
namespace llvm {
15+
16+
/// Expands div/rem instructions with a bitwidth above a threshold
17+
/// into a loop.
18+
/// This is useful for backends like x86 that cannot lower divisions
19+
/// with more than 128 bits.
20+
class ExpandLargeDivRemPass : public PassInfoMixin<ExpandLargeDivRemPass> {
21+
public:
22+
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
23+
24+
// The backend asserts when seeing large div/rem instructions.
25+
static bool isRequired() { return true; }
26+
};
27+
} // end namespace llvm
28+
29+
#endif // LLVM_CODEGEN_EXPANDLARGEDIVREM_H

llvm/include/llvm/CodeGen/MachinePassRegistry.def

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ FUNCTION_PASS("replace-with-veclib", ReplaceWithVeclib, ())
4343
FUNCTION_PASS("partially-inline-libcalls", PartiallyInlineLibCallsPass, ())
4444
FUNCTION_PASS("ee-instrument", EntryExitInstrumenterPass, (false))
4545
FUNCTION_PASS("post-inline-ee-instrument", EntryExitInstrumenterPass, (true))
46+
FUNCTION_PASS("expand-large-div-rem", ExpandLargeDivRemPass, ())
4647
FUNCTION_PASS("expand-reductions", ExpandReductionsPass, ())
4748
FUNCTION_PASS("expandvp", ExpandVectorPredicationPass, ())
4849
FUNCTION_PASS("lowerinvoke", LowerInvokePass, ())

llvm/include/llvm/CodeGen/Passes.h

+3
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,9 @@ namespace llvm {
484484
/// predicate mask.
485485
FunctionPass *createExpandVectorPredicationPass();
486486

487+
// Expands large div/rem instructions.
488+
FunctionPass *createExpandLargeDivRemPass();
489+
487490
// This pass expands memcmp() to load/stores.
488491
FunctionPass *createExpandMemCmpPass();
489492

llvm/include/llvm/InitializePasses.h

+1
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ void initializeEarlyTailDuplicatePass(PassRegistry&);
145145
void initializeEdgeBundlesPass(PassRegistry&);
146146
void initializeEHContGuardCatchretPass(PassRegistry &);
147147
void initializeEliminateAvailableExternallyLegacyPassPass(PassRegistry&);
148+
void initializeExpandLargeDivRemLegacyPassPass(PassRegistry&);
148149
void initializeExpandMemCmpPassPass(PassRegistry&);
149150
void initializeExpandPostRAPass(PassRegistry&);
150151
void initializeExpandReductionsPass(PassRegistry&);

llvm/include/llvm/LinkAllPasses.h

+1
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ namespace {
190190
(void) llvm::createReversePostOrderFunctionAttrsPass();
191191
(void) llvm::createMergeFunctionsPass();
192192
(void) llvm::createMergeICmpsLegacyPass();
193+
(void) llvm::createExpandLargeDivRemPass();
193194
(void) llvm::createExpandMemCmpPass();
194195
(void) llvm::createExpandVectorPredicationPass();
195196
std::string buf;

llvm/lib/CodeGen/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ add_llvm_component_library(LLVMCodeGen
5252
EdgeBundles.cpp
5353
EHContGuardCatchret.cpp
5454
ExecutionDomainFix.cpp
55+
ExpandLargeDivRem.cpp
5556
ExpandMemCmp.cpp
5657
ExpandPostRAPseudos.cpp
5758
ExpandReductions.cpp

llvm/lib/CodeGen/CodeGen.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
3636
initializeEarlyIfPredicatorPass(Registry);
3737
initializeEarlyMachineLICMPass(Registry);
3838
initializeEarlyTailDuplicatePass(Registry);
39+
initializeExpandLargeDivRemLegacyPassPass(Registry);
3940
initializeExpandMemCmpPassPass(Registry);
4041
initializeExpandPostRAPass(Registry);
4142
initializeFEntryInserterPass(Registry);
+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
//===--- ExpandLargeDivRem.cpp - Expand large div/rem ---------------------===//
2+
//
3+
// 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
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This pass expands div/rem instructions with a bitwidth above a threshold
10+
// into a call to auto-generated functions.
11+
// This is useful for targets like x86_64 that cannot lower divisions
12+
// with more than 128 bits or targets like x86_32 that cannot lower divisions
13+
// with more than 64 bits.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#include "llvm/CodeGen/ExpandLargeDivRem.h"
18+
#include "llvm/ADT/SmallVector.h"
19+
#include "llvm/ADT/StringExtras.h"
20+
#include "llvm/Analysis/GlobalsModRef.h"
21+
#include "llvm/CodeGen/Passes.h"
22+
#include "llvm/IR/IRBuilder.h"
23+
#include "llvm/IR/InstIterator.h"
24+
#include "llvm/IR/PassManager.h"
25+
#include "llvm/InitializePasses.h"
26+
#include "llvm/Pass.h"
27+
#include "llvm/Support/CommandLine.h"
28+
#include "llvm/Transforms/Utils/IntegerDivision.h"
29+
30+
using namespace llvm;
31+
32+
static cl::opt<unsigned>
33+
ExpandDivRemBits("expand-div-rem-bits", cl::Hidden, cl::init(128),
34+
cl::desc("div and rem instructions on integers with "
35+
"more than <N> bits are expanded."));
36+
37+
static bool runImpl(Function &F) {
38+
SmallVector<BinaryOperator *, 4> Replace;
39+
bool Modified = false;
40+
41+
for (auto &I : instructions(F)) {
42+
switch (I.getOpcode()) {
43+
case Instruction::UDiv:
44+
case Instruction::SDiv:
45+
case Instruction::URem:
46+
case Instruction::SRem: {
47+
// TODO: This doesn't handle vectors.
48+
auto *IntTy = dyn_cast<IntegerType>(I.getType());
49+
if (!IntTy || IntTy->getIntegerBitWidth() <= ExpandDivRemBits)
50+
continue;
51+
52+
Replace.push_back(&cast<BinaryOperator>(I));
53+
Modified = true;
54+
break;
55+
}
56+
default:
57+
break;
58+
}
59+
}
60+
61+
if (Replace.empty())
62+
return false;
63+
64+
while (!Replace.empty()) {
65+
BinaryOperator *I = Replace.pop_back_val();
66+
67+
if (I->getOpcode() == Instruction::UDiv ||
68+
I->getOpcode() == Instruction::SDiv) {
69+
expandDivision(I);
70+
} else {
71+
expandRemainder(I);
72+
}
73+
}
74+
75+
return Modified;
76+
}
77+
78+
PreservedAnalyses ExpandLargeDivRemPass::run(Function &F,
79+
FunctionAnalysisManager &AM) {
80+
bool Changed = runImpl(F);
81+
82+
if (Changed)
83+
return PreservedAnalyses::none();
84+
85+
return PreservedAnalyses::all();
86+
}
87+
88+
class ExpandLargeDivRemLegacyPass : public FunctionPass {
89+
public:
90+
static char ID;
91+
92+
ExpandLargeDivRemLegacyPass() : FunctionPass(ID) {
93+
initializeExpandLargeDivRemLegacyPassPass(*PassRegistry::getPassRegistry());
94+
}
95+
96+
bool runOnFunction(Function &F) override { return runImpl(F); }
97+
98+
void getAnalysisUsage(AnalysisUsage &AU) const override {
99+
AU.addPreserved<AAResultsWrapperPass>();
100+
AU.addPreserved<GlobalsAAWrapperPass>();
101+
}
102+
};
103+
104+
char ExpandLargeDivRemLegacyPass::ID = 0;
105+
INITIALIZE_PASS_BEGIN(ExpandLargeDivRemLegacyPass, "expand-large-div-rem",
106+
"Expand large div/rem", false, false)
107+
INITIALIZE_PASS_END(ExpandLargeDivRemLegacyPass, "expand-large-div-rem",
108+
"Expand large div/rem", false, false)
109+
110+
FunctionPass *llvm::createExpandLargeDivRemPass() {
111+
return new ExpandLargeDivRemLegacyPass();
112+
}

llvm/lib/Transforms/Utils/IntegerDivision.cpp

+10-51
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,7 @@ using namespace llvm;
3232
static Value *generateSignedRemainderCode(Value *Dividend, Value *Divisor,
3333
IRBuilder<> &Builder) {
3434
unsigned BitWidth = Dividend->getType()->getIntegerBitWidth();
35-
ConstantInt *Shift;
36-
37-
if (BitWidth == 64) {
38-
Shift = Builder.getInt64(63);
39-
} else {
40-
assert(BitWidth == 32 && "Unexpected bit width");
41-
Shift = Builder.getInt32(31);
42-
}
35+
ConstantInt *Shift = Builder.getIntN(BitWidth, BitWidth - 1);
4336

4437
// Following instructions are generated for both i32 (shift 31) and
4538
// i64 (shift 63).
@@ -104,14 +97,7 @@ static Value *generateSignedDivisionCode(Value *Dividend, Value *Divisor,
10497
// Implementation taken from compiler-rt's __divsi3 and __divdi3
10598

10699
unsigned BitWidth = Dividend->getType()->getIntegerBitWidth();
107-
ConstantInt *Shift;
108-
109-
if (BitWidth == 64) {
110-
Shift = Builder.getInt64(63);
111-
} else {
112-
assert(BitWidth == 32 && "Unexpected bit width");
113-
Shift = Builder.getInt32(31);
114-
}
100+
ConstantInt *Shift = Builder.getIntN(BitWidth, BitWidth - 1);
115101

116102
// Following instructions are generated for both i32 (shift 31) and
117103
// i64 (shift 63).
@@ -156,23 +142,10 @@ static Value *generateUnsignedDivisionCode(Value *Dividend, Value *Divisor,
156142
IntegerType *DivTy = cast<IntegerType>(Dividend->getType());
157143
unsigned BitWidth = DivTy->getBitWidth();
158144

159-
ConstantInt *Zero;
160-
ConstantInt *One;
161-
ConstantInt *NegOne;
162-
ConstantInt *MSB;
163-
164-
if (BitWidth == 64) {
165-
Zero = Builder.getInt64(0);
166-
One = Builder.getInt64(1);
167-
NegOne = ConstantInt::getSigned(DivTy, -1);
168-
MSB = Builder.getInt64(63);
169-
} else {
170-
assert(BitWidth == 32 && "Unexpected bit width");
171-
Zero = Builder.getInt32(0);
172-
One = Builder.getInt32(1);
173-
NegOne = ConstantInt::getSigned(DivTy, -1);
174-
MSB = Builder.getInt32(31);
175-
}
145+
ConstantInt *Zero = ConstantInt::get(DivTy, 0);
146+
ConstantInt *One = ConstantInt::get(DivTy, 1);
147+
ConstantInt *NegOne = ConstantInt::getSigned(DivTy, -1);
148+
ConstantInt *MSB = ConstantInt::get(DivTy, BitWidth - 1);
176149

177150
ConstantInt *True = Builder.getTrue();
178151

@@ -367,8 +340,7 @@ static Value *generateUnsignedDivisionCode(Value *Dividend, Value *Divisor,
367340
/// Generate code to calculate the remainder of two integers, replacing Rem with
368341
/// the generated code. This currently generates code using the udiv expansion,
369342
/// but future work includes generating more specialized code, e.g. when more
370-
/// information about the operands are known. Implements both 32bit and 64bit
371-
/// scalar division.
343+
/// information about the operands are known.
372344
///
373345
/// Replace Rem with generated code.
374346
bool llvm::expandRemainder(BinaryOperator *Rem) {
@@ -379,9 +351,6 @@ bool llvm::expandRemainder(BinaryOperator *Rem) {
379351
IRBuilder<> Builder(Rem);
380352

381353
assert(!Rem->getType()->isVectorTy() && "Div over vectors not supported");
382-
assert((Rem->getType()->getIntegerBitWidth() == 32 ||
383-
Rem->getType()->getIntegerBitWidth() == 64) &&
384-
"Div of bitwidth other than 32 or 64 not supported");
385354

386355
// First prepare the sign if it's a signed remainder
387356
if (Rem->getOpcode() == Instruction::SRem) {
@@ -421,12 +390,10 @@ bool llvm::expandRemainder(BinaryOperator *Rem) {
421390
return true;
422391
}
423392

424-
425393
/// Generate code to divide two integers, replacing Div with the generated
426394
/// code. This currently generates code similarly to compiler-rt's
427395
/// implementations, but future work includes generating more specialized code
428-
/// when more information about the operands are known. Implements both
429-
/// 32bit and 64bit scalar division.
396+
/// when more information about the operands are known.
430397
///
431398
/// Replace Div with generated code.
432399
bool llvm::expandDivision(BinaryOperator *Div) {
@@ -437,9 +404,6 @@ bool llvm::expandDivision(BinaryOperator *Div) {
437404
IRBuilder<> Builder(Div);
438405

439406
assert(!Div->getType()->isVectorTy() && "Div over vectors not supported");
440-
assert((Div->getType()->getIntegerBitWidth() == 32 ||
441-
Div->getType()->getIntegerBitWidth() == 64) &&
442-
"Div of bitwidth other than 32 or 64 not supported");
443407

444408
// First prepare the sign if it's a signed division
445409
if (Div->getOpcode() == Instruction::SDiv) {
@@ -540,9 +504,7 @@ bool llvm::expandRemainderUpTo64Bits(BinaryOperator *Rem) {
540504

541505
unsigned RemTyBitWidth = RemTy->getIntegerBitWidth();
542506

543-
assert(RemTyBitWidth <= 64 && "Div of bitwidth greater than 64 not supported");
544-
545-
if (RemTyBitWidth == 64)
507+
if (RemTyBitWidth >= 64)
546508
return expandRemainder(Rem);
547509

548510
// If bitwidth smaller than 64 extend inputs, extend output and proceed
@@ -637,10 +599,7 @@ bool llvm::expandDivisionUpTo64Bits(BinaryOperator *Div) {
637599

638600
unsigned DivTyBitWidth = DivTy->getIntegerBitWidth();
639601

640-
assert(DivTyBitWidth <= 64 &&
641-
"Div of bitwidth greater than 64 not supported");
642-
643-
if (DivTyBitWidth == 64)
602+
if (DivTyBitWidth >= 64)
644603
return expandDivision(Div);
645604

646605
// If bitwidth smaller than 64 extend inputs, extend output and proceed

llvm/test/CodeGen/X86/urem-seteq.ll

-15
Original file line numberDiff line numberDiff line change
@@ -362,22 +362,7 @@ define i32 @test_urem_allones(i32 %X) nounwind {
362362
; https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=34366
363363
define void @ossfuzz34366() {
364364
; X86-LABEL: ossfuzz34366:
365-
; X86: # %bb.0:
366-
; X86-NEXT: movl (%eax), %eax
367-
; X86-NEXT: movl %eax, %ecx
368-
; X86-NEXT: andl $2147483647, %ecx # imm = 0x7FFFFFFF
369-
; X86-NEXT: orl %eax, %ecx
370-
; X86-NEXT: sete (%eax)
371-
; X86-NEXT: retl
372-
;
373365
; X64-LABEL: ossfuzz34366:
374-
; X64: # %bb.0:
375-
; X64-NEXT: movq (%rax), %rax
376-
; X64-NEXT: movabsq $9223372036854775807, %rcx # imm = 0x7FFFFFFFFFFFFFFF
377-
; X64-NEXT: andq %rax, %rcx
378-
; X64-NEXT: orq %rax, %rcx
379-
; X64-NEXT: sete (%rax)
380-
; X64-NEXT: retq
381366
%L10 = load i448, ptr undef, align 4
382367
%B18 = urem i448 %L10, -363419362147803445274661903944002267176820680343659030140745099590319644056698961663095525356881782780381260803133088966767300814307328
383368
%C13 = icmp ule i448 %B18, 0

0 commit comments

Comments
 (0)