Add support for software expansion of 64-bit integer division instructions.

Patch by Dmitri Shtilman!



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@195116 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Michael Ilseman 2013-11-19 06:54:19 +00:00
parent 0b843861c6
commit 1b3ab9199f
3 changed files with 346 additions and 59 deletions

View File

@ -7,10 +7,10 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// //
// This file contains an implementation of 32bit integer division for targets // This file contains an implementation of 32bit and 64bit scalar integer
// that don't have native support. It's largely derived from compiler-rt's // division for targets that don't have native support. It's largely derived
// implementation of __udivsi3, but hand-tuned for targets that prefer less // from compiler-rt's implementations of __udivsi3 and __udivmoddi4,
// control flow. // but hand-tuned for targets that prefer less control flow.
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -26,9 +26,8 @@ namespace llvm {
/// Generate code to calculate the remainder of two integers, replacing Rem /// Generate code to calculate the remainder of two integers, replacing Rem
/// with the generated code. This currently generates code using the udiv /// with the generated code. This currently generates code using the udiv
/// expansion, but future work includes generating more specialized code, /// expansion, but future work includes generating more specialized code,
/// e.g. when more information about the operands are known. Currently only /// e.g. when more information about the operands are known. Implements both
/// implements 32bit scalar division (due to udiv's limitation), but future /// 32bit and 64bit scalar division.
/// work is removing this limitation.
/// ///
/// @brief Replace Rem with generated code. /// @brief Replace Rem with generated code.
bool expandRemainder(BinaryOperator *Rem); bool expandRemainder(BinaryOperator *Rem);
@ -36,27 +35,39 @@ namespace llvm {
/// Generate code to divide two integers, replacing Div with the generated /// Generate code to divide two integers, replacing Div with the generated
/// code. This currently generates code similarly to compiler-rt's /// code. This currently generates code similarly to compiler-rt's
/// implementations, but future work includes generating more specialized code /// implementations, but future work includes generating more specialized code
/// when more information about the operands are known. Currently only /// when more information about the operands are known. Implements both
/// implements 32bit scalar division, but future work is removing this /// 32bit and 64bit scalar division.
/// limitation.
/// ///
/// @brief Replace Div with generated code. /// @brief Replace Div with generated code.
bool expandDivision(BinaryOperator* Div); bool expandDivision(BinaryOperator* Div);
/// Generate code to calculate the remainder of two integers, replacing Rem /// Generate code to calculate the remainder of two integers, replacing Rem
/// with the generated code. Uses the above 32bit routine, therefore adequate /// with the generated code. Uses ExpandReminder with a 32bit Rem which
/// for targets with little or no support for less than 32 bit arithmetic. /// makes it useful for targets with little or no support for less than
/// 32 bit arithmetic.
/// ///
/// @brief Replace Rem with generated code. /// @brief Replace Rem with generated code.
bool expandRemainderUpTo32Bits(BinaryOperator *Rem); bool expandRemainderUpTo32Bits(BinaryOperator *Rem);
/// Generate code to calculate the remainder of two integers, replacing Rem
/// with the generated code. Uses ExpandReminder with a 64bit Rem.
///
/// @brief Replace Rem with generated code.
bool expandRemainderUpTo64Bits(BinaryOperator *Rem);
/// Generate code to divide two integers, replacing Div with the generated /// Generate code to divide two integers, replacing Div with the generated
/// code. Uses the above 32bit routine, therefore adequate for targets with /// code. Uses ExpandDivision with a 32bit Div which makes it useful for
/// little or no support for less than 32 bit arithmetic. /// targets with little or no support for less than 32 bit arithmetic.
/// ///
/// @brief Replace Rem with generated code. /// @brief Replace Rem with generated code.
bool expandDivisionUpTo32Bits(BinaryOperator *Div); bool expandDivisionUpTo32Bits(BinaryOperator *Div);
/// Generate code to divide two integers, replacing Div with the generated
/// code. Uses ExpandDivision with a 64bit Div.
///
/// @brief Replace Rem with generated code.
bool expandDivisionUpTo64Bits(BinaryOperator *Div);
} // End llvm namespace } // End llvm namespace
#endif #endif

View File

@ -7,10 +7,10 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// //
// This file contains an implementation of 32bit scalar integer division for // This file contains an implementation of 32bit and 64bit scalar integer
// targets that don't have native support. It's largely derived from // division for targets that don't have native support. It's largely derived
// compiler-rt's implementation of __udivsi3, but hand-tuned to reduce the // from compiler-rt's implementations of __udivsi3 and __udivmoddi4,
// amount of control flow // but hand-tuned for targets that prefer less control flow.
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -20,6 +20,7 @@
#include "llvm/IR/IRBuilder.h" #include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h" #include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h" #include "llvm/IR/Intrinsics.h"
#include <utility>
using namespace llvm; using namespace llvm;
@ -31,7 +32,18 @@ using namespace llvm;
/// be expanded if the user wishes /// be expanded if the user wishes
static Value *generateSignedRemainderCode(Value *Dividend, Value *Divisor, static Value *generateSignedRemainderCode(Value *Dividend, Value *Divisor,
IRBuilder<> &Builder) { IRBuilder<> &Builder) {
ConstantInt *ThirtyOne = Builder.getInt32(31); unsigned BitWidth = Dividend->getType()->getIntegerBitWidth();
ConstantInt *Shift;
if (BitWidth == 64) {
Shift = Builder.getInt64(63);
} else {
assert(BitWidth == 32 && "Unexpected bit width");
Shift = Builder.getInt32(31);
}
// Following instructions are generated for both i32 (shift 31) and
// i64 (shift 63).
// ; %dividend_sgn = ashr i32 %dividend, 31 // ; %dividend_sgn = ashr i32 %dividend, 31
// ; %divisor_sgn = ashr i32 %divisor, 31 // ; %divisor_sgn = ashr i32 %divisor, 31
@ -42,8 +54,8 @@ static Value *generateSignedRemainderCode(Value *Dividend, Value *Divisor,
// ; %urem = urem i32 %dividend, %divisor // ; %urem = urem i32 %dividend, %divisor
// ; %xored = xor i32 %urem, %dividend_sgn // ; %xored = xor i32 %urem, %dividend_sgn
// ; %srem = sub i32 %xored, %dividend_sgn // ; %srem = sub i32 %xored, %dividend_sgn
Value *DividendSign = Builder.CreateAShr(Dividend, ThirtyOne); Value *DividendSign = Builder.CreateAShr(Dividend, Shift);
Value *DivisorSign = Builder.CreateAShr(Divisor, ThirtyOne); Value *DivisorSign = Builder.CreateAShr(Divisor, Shift);
Value *DvdXor = Builder.CreateXor(Dividend, DividendSign); Value *DvdXor = Builder.CreateXor(Dividend, DividendSign);
Value *DvsXor = Builder.CreateXor(Divisor, DivisorSign); Value *DvsXor = Builder.CreateXor(Divisor, DivisorSign);
Value *UDividend = Builder.CreateSub(DvdXor, DividendSign); Value *UDividend = Builder.CreateSub(DvdXor, DividendSign);
@ -68,6 +80,8 @@ static Value *generatedUnsignedRemainderCode(Value *Dividend, Value *Divisor,
IRBuilder<> &Builder) { IRBuilder<> &Builder) {
// Remainder = Dividend - Quotient*Divisor // Remainder = Dividend - Quotient*Divisor
// Following instructions are generated for both i32 and i64
// ; %quotient = udiv i32 %dividend, %divisor // ; %quotient = udiv i32 %dividend, %divisor
// ; %product = mul i32 %divisor, %quotient // ; %product = mul i32 %divisor, %quotient
// ; %remainder = sub i32 %dividend, %product // ; %remainder = sub i32 %dividend, %product
@ -88,9 +102,20 @@ static Value *generatedUnsignedRemainderCode(Value *Dividend, Value *Divisor,
/// present, i.e. not folded), ready to be expanded if the user wishes. /// present, i.e. not folded), ready to be expanded if the user wishes.
static Value *generateSignedDivisionCode(Value *Dividend, Value *Divisor, static Value *generateSignedDivisionCode(Value *Dividend, Value *Divisor,
IRBuilder<> &Builder) { IRBuilder<> &Builder) {
// Implementation taken from compiler-rt's __divsi3 // Implementation taken from compiler-rt's __divsi3 and __divdi3
ConstantInt *ThirtyOne = Builder.getInt32(31); unsigned BitWidth = Dividend->getType()->getIntegerBitWidth();
ConstantInt *Shift;
if (BitWidth == 64) {
Shift = Builder.getInt64(63);
} else {
assert(BitWidth == 32 && "Unexpected bit width");
Shift = Builder.getInt32(31);
}
// Following instructions are generated for both i32 (shift 31) and
// i64 (shift 63).
// ; %tmp = ashr i32 %dividend, 31 // ; %tmp = ashr i32 %dividend, 31
// ; %tmp1 = ashr i32 %divisor, 31 // ; %tmp1 = ashr i32 %divisor, 31
@ -102,8 +127,8 @@ static Value *generateSignedDivisionCode(Value *Dividend, Value *Divisor,
// ; %q_mag = udiv i32 %u_dvnd, %u_dvsr // ; %q_mag = udiv i32 %u_dvnd, %u_dvsr
// ; %tmp4 = xor i32 %q_mag, %q_sgn // ; %tmp4 = xor i32 %q_mag, %q_sgn
// ; %q = sub i32 %tmp4, %q_sgn // ; %q = sub i32 %tmp4, %q_sgn
Value *Tmp = Builder.CreateAShr(Dividend, ThirtyOne); Value *Tmp = Builder.CreateAShr(Dividend, Shift);
Value *Tmp1 = Builder.CreateAShr(Divisor, ThirtyOne); Value *Tmp1 = Builder.CreateAShr(Divisor, Shift);
Value *Tmp2 = Builder.CreateXor(Tmp, Dividend); Value *Tmp2 = Builder.CreateXor(Tmp, Dividend);
Value *U_Dvnd = Builder.CreateSub(Tmp2, Tmp); Value *U_Dvnd = Builder.CreateSub(Tmp2, Tmp);
Value *Tmp3 = Builder.CreateXor(Tmp1, Divisor); Value *Tmp3 = Builder.CreateXor(Tmp1, Divisor);
@ -119,9 +144,9 @@ static Value *generateSignedDivisionCode(Value *Dividend, Value *Divisor,
return Q; return Q;
} }
/// Generates code to divide two unsigned scalar 32-bit integers. Returns the /// Generates code to divide two unsigned scalar 32-bit or 64-bit integers.
/// quotient, rounded towards 0. Builder's insert point should be pointing where /// Returns the quotient, rounded towards 0. Builder's insert point should
/// the caller wants code generated, e.g. at the udiv instruction. /// point where the caller wants code generated, e.g. at the udiv instruction.
static Value *generateUnsignedDivisionCode(Value *Dividend, Value *Divisor, static Value *generateUnsignedDivisionCode(Value *Dividend, Value *Divisor,
IRBuilder<> &Builder) { IRBuilder<> &Builder) {
// The basic algorithm can be found in the compiler-rt project's // The basic algorithm can be found in the compiler-rt project's
@ -129,18 +154,33 @@ static Value *generateUnsignedDivisionCode(Value *Dividend, Value *Divisor,
// that's been hand-tuned to lessen the amount of control flow involved. // that's been hand-tuned to lessen the amount of control flow involved.
// Some helper values // Some helper values
IntegerType *I32Ty = Builder.getInt32Ty(); IntegerType *DivTy = cast<IntegerType>(Dividend->getType());
unsigned BitWidth = DivTy->getBitWidth();
ConstantInt *Zero;
ConstantInt *One;
ConstantInt *NegOne;
ConstantInt *MSB;
if (BitWidth == 64) {
Zero = Builder.getInt64(0);
One = Builder.getInt64(1);
NegOne = ConstantInt::getSigned(DivTy, -1);
MSB = Builder.getInt64(63);
} else {
assert(BitWidth == 32 && "Unexpected bit width");
Zero = Builder.getInt32(0);
One = Builder.getInt32(1);
NegOne = ConstantInt::getSigned(DivTy, -1);
MSB = Builder.getInt32(31);
}
ConstantInt *Zero = Builder.getInt32(0);
ConstantInt *One = Builder.getInt32(1);
ConstantInt *ThirtyOne = Builder.getInt32(31);
ConstantInt *NegOne = ConstantInt::getSigned(I32Ty, -1);
ConstantInt *True = Builder.getTrue(); ConstantInt *True = Builder.getTrue();
BasicBlock *IBB = Builder.GetInsertBlock(); BasicBlock *IBB = Builder.GetInsertBlock();
Function *F = IBB->getParent(); Function *F = IBB->getParent();
Function *CTLZi32 = Intrinsic::getDeclaration(F->getParent(), Intrinsic::ctlz, Function *CTLZ = Intrinsic::getDeclaration(F->getParent(), Intrinsic::ctlz,
I32Ty); DivTy);
// Our CFG is going to look like: // Our CFG is going to look like:
// +---------------------+ // +---------------------+
@ -190,6 +230,8 @@ static Value *generateUnsignedDivisionCode(Value *Dividend, Value *Divisor,
// We'll be overwriting the terminator to insert our extra blocks // We'll be overwriting the terminator to insert our extra blocks
SpecialCases->getTerminator()->eraseFromParent(); SpecialCases->getTerminator()->eraseFromParent();
// Same instructions are generated for both i32 (msb 31) and i64 (msb 63).
// First off, check for special cases: dividend or divisor is zero, divisor // First off, check for special cases: dividend or divisor is zero, divisor
// is greater than dividend, and divisor is 1. // is greater than dividend, and divisor is 1.
// ; special-cases: // ; special-cases:
@ -209,12 +251,12 @@ static Value *generateUnsignedDivisionCode(Value *Dividend, Value *Divisor,
Value *Ret0_1 = Builder.CreateICmpEQ(Divisor, Zero); Value *Ret0_1 = Builder.CreateICmpEQ(Divisor, Zero);
Value *Ret0_2 = Builder.CreateICmpEQ(Dividend, Zero); Value *Ret0_2 = Builder.CreateICmpEQ(Dividend, Zero);
Value *Ret0_3 = Builder.CreateOr(Ret0_1, Ret0_2); Value *Ret0_3 = Builder.CreateOr(Ret0_1, Ret0_2);
Value *Tmp0 = Builder.CreateCall2(CTLZi32, Divisor, True); Value *Tmp0 = Builder.CreateCall2(CTLZ, Divisor, True);
Value *Tmp1 = Builder.CreateCall2(CTLZi32, Dividend, True); Value *Tmp1 = Builder.CreateCall2(CTLZ, Dividend, True);
Value *SR = Builder.CreateSub(Tmp0, Tmp1); Value *SR = Builder.CreateSub(Tmp0, Tmp1);
Value *Ret0_4 = Builder.CreateICmpUGT(SR, ThirtyOne); Value *Ret0_4 = Builder.CreateICmpUGT(SR, MSB);
Value *Ret0 = Builder.CreateOr(Ret0_3, Ret0_4); Value *Ret0 = Builder.CreateOr(Ret0_3, Ret0_4);
Value *RetDividend = Builder.CreateICmpEQ(SR, ThirtyOne); Value *RetDividend = Builder.CreateICmpEQ(SR, MSB);
Value *RetVal = Builder.CreateSelect(Ret0, Zero, Dividend); Value *RetVal = Builder.CreateSelect(Ret0, Zero, Dividend);
Value *EarlyRet = Builder.CreateOr(Ret0, RetDividend); Value *EarlyRet = Builder.CreateOr(Ret0, RetDividend);
Builder.CreateCondBr(EarlyRet, End, BB1); Builder.CreateCondBr(EarlyRet, End, BB1);
@ -227,7 +269,7 @@ static Value *generateUnsignedDivisionCode(Value *Dividend, Value *Divisor,
// ; br i1 %skipLoop, label %loop-exit, label %preheader // ; br i1 %skipLoop, label %loop-exit, label %preheader
Builder.SetInsertPoint(BB1); Builder.SetInsertPoint(BB1);
Value *SR_1 = Builder.CreateAdd(SR, One); Value *SR_1 = Builder.CreateAdd(SR, One);
Value *Tmp2 = Builder.CreateSub(ThirtyOne, SR); Value *Tmp2 = Builder.CreateSub(MSB, SR);
Value *Q = Builder.CreateShl(Dividend, Tmp2); Value *Q = Builder.CreateShl(Dividend, Tmp2);
Value *SkipLoop = Builder.CreateICmpEQ(SR_1, Zero); Value *SkipLoop = Builder.CreateICmpEQ(SR_1, Zero);
Builder.CreateCondBr(SkipLoop, LoopExit, Preheader); Builder.CreateCondBr(SkipLoop, LoopExit, Preheader);
@ -260,17 +302,17 @@ static Value *generateUnsignedDivisionCode(Value *Dividend, Value *Divisor,
// ; %tmp12 = icmp eq i32 %sr_2, 0 // ; %tmp12 = icmp eq i32 %sr_2, 0
// ; br i1 %tmp12, label %loop-exit, label %do-while // ; br i1 %tmp12, label %loop-exit, label %do-while
Builder.SetInsertPoint(DoWhile); Builder.SetInsertPoint(DoWhile);
PHINode *Carry_1 = Builder.CreatePHI(I32Ty, 2); PHINode *Carry_1 = Builder.CreatePHI(DivTy, 2);
PHINode *SR_3 = Builder.CreatePHI(I32Ty, 2); PHINode *SR_3 = Builder.CreatePHI(DivTy, 2);
PHINode *R_1 = Builder.CreatePHI(I32Ty, 2); PHINode *R_1 = Builder.CreatePHI(DivTy, 2);
PHINode *Q_2 = Builder.CreatePHI(I32Ty, 2); PHINode *Q_2 = Builder.CreatePHI(DivTy, 2);
Value *Tmp5 = Builder.CreateShl(R_1, One); Value *Tmp5 = Builder.CreateShl(R_1, One);
Value *Tmp6 = Builder.CreateLShr(Q_2, ThirtyOne); Value *Tmp6 = Builder.CreateLShr(Q_2, MSB);
Value *Tmp7 = Builder.CreateOr(Tmp5, Tmp6); Value *Tmp7 = Builder.CreateOr(Tmp5, Tmp6);
Value *Tmp8 = Builder.CreateShl(Q_2, One); Value *Tmp8 = Builder.CreateShl(Q_2, One);
Value *Q_1 = Builder.CreateOr(Carry_1, Tmp8); Value *Q_1 = Builder.CreateOr(Carry_1, Tmp8);
Value *Tmp9 = Builder.CreateSub(Tmp4, Tmp7); Value *Tmp9 = Builder.CreateSub(Tmp4, Tmp7);
Value *Tmp10 = Builder.CreateAShr(Tmp9, 31); Value *Tmp10 = Builder.CreateAShr(Tmp9, MSB);
Value *Carry = Builder.CreateAnd(Tmp10, One); Value *Carry = Builder.CreateAnd(Tmp10, One);
Value *Tmp11 = Builder.CreateAnd(Tmp10, Divisor); Value *Tmp11 = Builder.CreateAnd(Tmp10, Divisor);
Value *R = Builder.CreateSub(Tmp7, Tmp11); Value *R = Builder.CreateSub(Tmp7, Tmp11);
@ -285,8 +327,8 @@ static Value *generateUnsignedDivisionCode(Value *Dividend, Value *Divisor,
// ; %q_4 = or i32 %carry_2, %tmp13 // ; %q_4 = or i32 %carry_2, %tmp13
// ; br label %end // ; br label %end
Builder.SetInsertPoint(LoopExit); Builder.SetInsertPoint(LoopExit);
PHINode *Carry_2 = Builder.CreatePHI(I32Ty, 2); PHINode *Carry_2 = Builder.CreatePHI(DivTy, 2);
PHINode *Q_3 = Builder.CreatePHI(I32Ty, 2); PHINode *Q_3 = Builder.CreatePHI(DivTy, 2);
Value *Tmp13 = Builder.CreateShl(Q_3, One); Value *Tmp13 = Builder.CreateShl(Q_3, One);
Value *Q_4 = Builder.CreateOr(Carry_2, Tmp13); Value *Q_4 = Builder.CreateOr(Carry_2, Tmp13);
Builder.CreateBr(End); Builder.CreateBr(End);
@ -295,7 +337,7 @@ static Value *generateUnsignedDivisionCode(Value *Dividend, Value *Divisor,
// ; %q_5 = phi i32 [ %q_4, %loop-exit ], [ %retVal, %special-cases ] // ; %q_5 = phi i32 [ %q_4, %loop-exit ], [ %retVal, %special-cases ]
// ; ret i32 %q_5 // ; ret i32 %q_5
Builder.SetInsertPoint(End, End->begin()); Builder.SetInsertPoint(End, End->begin());
PHINode *Q_5 = Builder.CreatePHI(I32Ty, 2); PHINode *Q_5 = Builder.CreatePHI(DivTy, 2);
// Populate the Phis, since all values have now been created. Our Phis were: // Populate the Phis, since all values have now been created. Our Phis were:
// ; %carry_1 = phi i32 [ 0, %preheader ], [ %carry, %do-while ] // ; %carry_1 = phi i32 [ 0, %preheader ], [ %carry, %do-while ]
@ -326,9 +368,8 @@ static Value *generateUnsignedDivisionCode(Value *Dividend, Value *Divisor,
/// Generate code to calculate the remainder of two integers, replacing Rem with /// Generate code to calculate the remainder of two integers, replacing Rem with
/// the generated code. This currently generates code using the udiv expansion, /// the generated code. This currently generates code using the udiv expansion,
/// but future work includes generating more specialized code, e.g. when more /// but future work includes generating more specialized code, e.g. when more
/// information about the operands are known. Currently only implements 32bit /// information about the operands are known. Implements both 32bit and 64bit
/// scalar division (due to udiv's limitation), but future work is removing this /// scalar division.
/// limitation.
/// ///
/// @brief Replace Rem with generated code. /// @brief Replace Rem with generated code.
bool llvm::expandRemainder(BinaryOperator *Rem) { bool llvm::expandRemainder(BinaryOperator *Rem) {
@ -338,6 +379,15 @@ bool llvm::expandRemainder(BinaryOperator *Rem) {
IRBuilder<> Builder(Rem); IRBuilder<> Builder(Rem);
Type *RemTy = Rem->getType();
if (RemTy->isVectorTy())
llvm_unreachable("Div over vectors not supported");
unsigned RemTyBitWidth = RemTy->getIntegerBitWidth();
if (RemTyBitWidth != 32 && RemTyBitWidth != 64)
llvm_unreachable("Div of bitwidth other than 32 or 64 not supported");
// First prepare the sign if it's a signed remainder // First prepare the sign if it's a signed remainder
if (Rem->getOpcode() == Instruction::SRem) { if (Rem->getOpcode() == Instruction::SRem) {
Value *Remainder = generateSignedRemainderCode(Rem->getOperand(0), Value *Remainder = generateSignedRemainderCode(Rem->getOperand(0),
@ -376,9 +426,8 @@ bool llvm::expandRemainder(BinaryOperator *Rem) {
/// Generate code to divide two integers, replacing Div with the generated /// Generate code to divide two integers, replacing Div with the generated
/// code. This currently generates code similarly to compiler-rt's /// code. This currently generates code similarly to compiler-rt's
/// implementations, but future work includes generating more specialized code /// implementations, but future work includes generating more specialized code
/// when more information about the operands are known. Currently only /// when more information about the operands are known. Implements both
/// implements 32bit scalar division, but future work is removing this /// 32bit and 64bit scalar division.
/// limitation.
/// ///
/// @brief Replace Div with generated code. /// @brief Replace Div with generated code.
bool llvm::expandDivision(BinaryOperator *Div) { bool llvm::expandDivision(BinaryOperator *Div) {
@ -388,9 +437,15 @@ bool llvm::expandDivision(BinaryOperator *Div) {
IRBuilder<> Builder(Div); IRBuilder<> Builder(Div);
if (Div->getType()->isVectorTy()) Type *DivTy = Div->getType();
if (DivTy->isVectorTy())
llvm_unreachable("Div over vectors not supported"); llvm_unreachable("Div over vectors not supported");
unsigned DivTyBitWidth = DivTy->getIntegerBitWidth();
if (DivTyBitWidth != 32 && DivTyBitWidth != 64)
llvm_unreachable("Div of bitwidth other than 32 or 64 not supported");
// First prepare the sign if it's a signed division // First prepare the sign if it's a signed division
if (Div->getOpcode() == Instruction::SDiv) { if (Div->getOpcode() == Instruction::SDiv) {
// Lower the code to unsigned division, and reset Div to point to the udiv. // Lower the code to unsigned division, and reset Div to point to the udiv.
@ -443,7 +498,7 @@ bool llvm::expandRemainderUpTo32Bits(BinaryOperator *Rem) {
if (RemTyBitWidth == 32) if (RemTyBitWidth == 32)
return expandRemainder(Rem); return expandRemainder(Rem);
// If bitwidth smaller than 32 extend inputs, truncate output and proceed // If bitwidth smaller than 32 extend inputs, extend output and proceed
// with 32 bit division. // with 32 bit division.
IRBuilder<> Builder(Rem); IRBuilder<> Builder(Rem);
@ -471,6 +526,55 @@ bool llvm::expandRemainderUpTo32Bits(BinaryOperator *Rem) {
return expandRemainder(cast<BinaryOperator>(ExtRem)); return expandRemainder(cast<BinaryOperator>(ExtRem));
} }
/// Generate code to compute the remainder of two integers of bitwidth up to
/// 64 bits. Uses the above routines and extends the inputs/truncates the
/// outputs to operate in 64 bits.
///
/// @brief Replace Rem with emulation code.
bool llvm::expandRemainderUpTo64Bits(BinaryOperator *Rem) {
assert((Rem->getOpcode() == Instruction::SRem ||
Rem->getOpcode() == Instruction::URem) &&
"Trying to expand remainder from a non-remainder function");
Type *RemTy = Rem->getType();
if (RemTy->isVectorTy())
llvm_unreachable("Div over vectors not supported");
unsigned RemTyBitWidth = RemTy->getIntegerBitWidth();
if (RemTyBitWidth > 64)
llvm_unreachable("Div of bitwidth greater than 64 not supported");
if (RemTyBitWidth == 64)
return expandRemainder(Rem);
// If bitwidth smaller than 64 extend inputs, extend output and proceed
// with 64 bit division.
IRBuilder<> Builder(Rem);
Value *ExtDividend;
Value *ExtDivisor;
Value *ExtRem;
Value *Trunc;
Type *Int64Ty = Builder.getInt64Ty();
if (Rem->getOpcode() == Instruction::SRem) {
ExtDividend = Builder.CreateSExt(Rem->getOperand(0), Int64Ty);
ExtDivisor = Builder.CreateSExt(Rem->getOperand(1), Int64Ty);
ExtRem = Builder.CreateSRem(ExtDividend, ExtDivisor);
} else {
ExtDividend = Builder.CreateZExt(Rem->getOperand(0), Int64Ty);
ExtDivisor = Builder.CreateZExt(Rem->getOperand(1), Int64Ty);
ExtRem = Builder.CreateURem(ExtDividend, ExtDivisor);
}
Trunc = Builder.CreateTrunc(ExtRem, RemTy);
Rem->replaceAllUsesWith(Trunc);
Rem->dropAllReferences();
Rem->eraseFromParent();
return expandRemainder(cast<BinaryOperator>(ExtRem));
}
/// Generate code to divide two integers of bitwidth up to 32 bits. Uses the /// Generate code to divide two integers of bitwidth up to 32 bits. Uses the
/// above routines and extends the inputs/truncates the outputs to operate /// above routines and extends the inputs/truncates the outputs to operate
@ -495,7 +599,7 @@ bool llvm::expandDivisionUpTo32Bits(BinaryOperator *Div) {
if (DivTyBitWidth == 32) if (DivTyBitWidth == 32)
return expandDivision(Div); return expandDivision(Div);
// If bitwidth smaller than 32 extend inputs, truncate output and proceed // If bitwidth smaller than 32 extend inputs, extend output and proceed
// with 32 bit division. // with 32 bit division.
IRBuilder<> Builder(Div); IRBuilder<> Builder(Div);
@ -522,3 +626,53 @@ bool llvm::expandDivisionUpTo32Bits(BinaryOperator *Div) {
return expandDivision(cast<BinaryOperator>(ExtDiv)); return expandDivision(cast<BinaryOperator>(ExtDiv));
} }
/// Generate code to divide two integers of bitwidth up to 64 bits. Uses the
/// above routines and extends the inputs/truncates the outputs to operate
/// in 64 bits.
///
/// @brief Replace Div with emulation code.
bool llvm::expandDivisionUpTo64Bits(BinaryOperator *Div) {
assert((Div->getOpcode() == Instruction::SDiv ||
Div->getOpcode() == Instruction::UDiv) &&
"Trying to expand division from a non-division function");
Type *DivTy = Div->getType();
if (DivTy->isVectorTy())
llvm_unreachable("Div over vectors not supported");
unsigned DivTyBitWidth = DivTy->getIntegerBitWidth();
if (DivTyBitWidth > 64)
llvm_unreachable("Div of bitwidth greater than 64 not supported");
if (DivTyBitWidth == 64)
return expandDivision(Div);
// If bitwidth smaller than 64 extend inputs, extend output and proceed
// with 64 bit division.
IRBuilder<> Builder(Div);
Value *ExtDividend;
Value *ExtDivisor;
Value *ExtDiv;
Value *Trunc;
Type *Int64Ty = Builder.getInt64Ty();
if (Div->getOpcode() == Instruction::SDiv) {
ExtDividend = Builder.CreateSExt(Div->getOperand(0), Int64Ty);
ExtDivisor = Builder.CreateSExt(Div->getOperand(1), Int64Ty);
ExtDiv = Builder.CreateSDiv(ExtDividend, ExtDivisor);
} else {
ExtDividend = Builder.CreateZExt(Div->getOperand(0), Int64Ty);
ExtDivisor = Builder.CreateZExt(Div->getOperand(1), Int64Ty);
ExtDiv = Builder.CreateUDiv(ExtDividend, ExtDivisor);
}
Trunc = Builder.CreateTrunc(ExtDiv, DivTy);
Div->replaceAllUsesWith(Trunc);
Div->dropAllReferences();
Div->eraseFromParent();
return expandDivision(cast<BinaryOperator>(ExtDiv));
}

View File

@ -19,6 +19,7 @@ using namespace llvm;
namespace { namespace {
TEST(IntegerDivision, SDiv) { TEST(IntegerDivision, SDiv) {
LLVMContext &C(getGlobalContext()); LLVMContext &C(getGlobalContext());
Module M("test division", C); Module M("test division", C);
@ -139,4 +140,125 @@ TEST(IntegerDivision, URem) {
EXPECT_TRUE(Remainder && Remainder->getOpcode() == Instruction::Sub); EXPECT_TRUE(Remainder && Remainder->getOpcode() == Instruction::Sub);
} }
TEST(IntegerDivision, SDiv64) {
LLVMContext &C(getGlobalContext());
Module M("test division", C);
IRBuilder<> Builder(C);
SmallVector<Type*, 2> ArgTys(2, Builder.getInt64Ty());
Function *F = Function::Create(FunctionType::get(Builder.getInt64Ty(),
ArgTys, false),
GlobalValue::ExternalLinkage, "F", &M);
assert(F->getArgumentList().size() == 2);
BasicBlock *BB = BasicBlock::Create(C, "", F);
Builder.SetInsertPoint(BB);
Function::arg_iterator AI = F->arg_begin();
Value *A = AI++;
Value *B = AI++;
Value *Div = Builder.CreateSDiv(A, B);
EXPECT_TRUE(BB->front().getOpcode() == Instruction::SDiv);
Value *Ret = Builder.CreateRet(Div);
expandDivision(cast<BinaryOperator>(Div));
EXPECT_TRUE(BB->front().getOpcode() == Instruction::AShr);
Instruction* Quotient = dyn_cast<Instruction>(cast<User>(Ret)->getOperand(0));
EXPECT_TRUE(Quotient && Quotient->getOpcode() == Instruction::Sub);
}
TEST(IntegerDivision, UDiv64) {
LLVMContext &C(getGlobalContext());
Module M("test division", C);
IRBuilder<> Builder(C);
SmallVector<Type*, 2> ArgTys(2, Builder.getInt64Ty());
Function *F = Function::Create(FunctionType::get(Builder.getInt64Ty(),
ArgTys, false),
GlobalValue::ExternalLinkage, "F", &M);
assert(F->getArgumentList().size() == 2);
BasicBlock *BB = BasicBlock::Create(C, "", F);
Builder.SetInsertPoint(BB);
Function::arg_iterator AI = F->arg_begin();
Value *A = AI++;
Value *B = AI++;
Value *Div = Builder.CreateUDiv(A, B);
EXPECT_TRUE(BB->front().getOpcode() == Instruction::UDiv);
Value *Ret = Builder.CreateRet(Div);
expandDivision(cast<BinaryOperator>(Div));
EXPECT_TRUE(BB->front().getOpcode() == Instruction::ICmp);
Instruction* Quotient = dyn_cast<Instruction>(cast<User>(Ret)->getOperand(0));
EXPECT_TRUE(Quotient && Quotient->getOpcode() == Instruction::PHI);
}
TEST(IntegerDivision, SRem64) {
LLVMContext &C(getGlobalContext());
Module M("test remainder", C);
IRBuilder<> Builder(C);
SmallVector<Type*, 2> ArgTys(2, Builder.getInt64Ty());
Function *F = Function::Create(FunctionType::get(Builder.getInt64Ty(),
ArgTys, false),
GlobalValue::ExternalLinkage, "F", &M);
assert(F->getArgumentList().size() == 2);
BasicBlock *BB = BasicBlock::Create(C, "", F);
Builder.SetInsertPoint(BB);
Function::arg_iterator AI = F->arg_begin();
Value *A = AI++;
Value *B = AI++;
Value *Rem = Builder.CreateSRem(A, B);
EXPECT_TRUE(BB->front().getOpcode() == Instruction::SRem);
Value *Ret = Builder.CreateRet(Rem);
expandRemainder(cast<BinaryOperator>(Rem));
EXPECT_TRUE(BB->front().getOpcode() == Instruction::AShr);
Instruction* Remainder = dyn_cast<Instruction>(cast<User>(Ret)->getOperand(0));
EXPECT_TRUE(Remainder && Remainder->getOpcode() == Instruction::Sub);
}
TEST(IntegerDivision, URem64) {
LLVMContext &C(getGlobalContext());
Module M("test remainder", C);
IRBuilder<> Builder(C);
SmallVector<Type*, 2> ArgTys(2, Builder.getInt64Ty());
Function *F = Function::Create(FunctionType::get(Builder.getInt64Ty(),
ArgTys, false),
GlobalValue::ExternalLinkage, "F", &M);
assert(F->getArgumentList().size() == 2);
BasicBlock *BB = BasicBlock::Create(C, "", F);
Builder.SetInsertPoint(BB);
Function::arg_iterator AI = F->arg_begin();
Value *A = AI++;
Value *B = AI++;
Value *Rem = Builder.CreateURem(A, B);
EXPECT_TRUE(BB->front().getOpcode() == Instruction::URem);
Value *Ret = Builder.CreateRet(Rem);
expandRemainder(cast<BinaryOperator>(Rem));
EXPECT_TRUE(BB->front().getOpcode() == Instruction::ICmp);
Instruction* Remainder = dyn_cast<Instruction>(cast<User>(Ret)->getOperand(0));
EXPECT_TRUE(Remainder && Remainder->getOpcode() == Instruction::Sub);
}
} }