1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 19:23:23 +01:00

Reapply r206732. This time without optimization of branches.

llvm-svn: 206749
This commit is contained in:
Michael Zolotukhin 2014-04-21 12:01:33 +00:00
parent d8c4c53242
commit c7f992f9a3
9 changed files with 729 additions and 0 deletions

View File

@ -444,6 +444,19 @@ def int_umul_with_overflow : Intrinsic<[llvm_anyint_ty, llvm_i1_ty],
[LLVMMatchType<0>, LLVMMatchType<0>],
[IntrNoMem]>;
def int_safe_udiv : Intrinsic<[llvm_anyint_ty, llvm_i1_ty],
[LLVMMatchType<0>, LLVMMatchType<0>],
[IntrNoMem]>;
def int_safe_urem : Intrinsic<[llvm_anyint_ty, llvm_i1_ty],
[LLVMMatchType<0>, LLVMMatchType<0>],
[IntrNoMem]>;
def int_safe_sdiv : Intrinsic<[llvm_anyint_ty, llvm_i1_ty],
[LLVMMatchType<0>, LLVMMatchType<0>],
[IntrNoMem]>;
def int_safe_srem : Intrinsic<[llvm_anyint_ty, llvm_i1_ty],
[LLVMMatchType<0>, LLVMMatchType<0>],
[IntrNoMem]>;
//===------------------------- Memory Use Markers -------------------------===//
//
def int_lifetime_start : Intrinsic<[],

View File

@ -218,6 +218,10 @@ public:
/// Return true if pow2 div is cheaper than a chain of srl/add/sra.
bool isPow2DivCheap() const { return Pow2DivIsCheap; }
/// Return true if Div never traps, returns 0 when div by 0 and return TMin,
/// when sdiv TMin by -1.
bool isDivWellDefined() const { return DivIsWellDefined; }
/// Return true if Flow Control is an expensive operation that should be
/// avoided.
bool isJumpExpensive() const { return JumpIsExpensive; }
@ -1026,6 +1030,13 @@ protected:
/// signed divide by power of two, and let the target handle it.
void setPow2DivIsCheap(bool isCheap = true) { Pow2DivIsCheap = isCheap; }
/// Tells the code-generator that it is safe to execute sdiv/udiv/srem/urem
/// even when RHS is 0. It is also safe to execute sdiv/srem when LHS is
/// SignedMinValue and RHS is -1.
void setDivIsWellDefined (bool isWellDefined = true) {
DivIsWellDefined = isWellDefined;
}
/// Add the specified register class as an available regclass for the
/// specified value type. This indicates the selector can handle values of
/// that class natively.
@ -1441,6 +1452,11 @@ private:
/// signed divide by power of two, and let the target handle it.
bool Pow2DivIsCheap;
/// Tells the code-generator that it is safe to execute sdiv/udiv/srem/urem
/// even when RHS is 0. It is also safe to execute sdiv/srem when LHS is
/// SignedMinValue and RHS is -1.
bool DivIsWellDefined;
/// Tells the code generator that it shouldn't generate extra flow control
/// instructions and should attempt to combine flow control instructions via
/// predication.

View File

@ -688,6 +688,242 @@ bool CodeGenPrepare::OptimizeCallInst(CallInst *CI) {
}
return true;
}
// Lower all uses of llvm.safe.[us]{div|rem}...
if (II &&
(II->getIntrinsicID() == Intrinsic::safe_sdiv ||
II->getIntrinsicID() == Intrinsic::safe_udiv ||
II->getIntrinsicID() == Intrinsic::safe_srem ||
II->getIntrinsicID() == Intrinsic::safe_urem)) {
// Given
// result_struct = type {iN, i1}
// %R = call result_struct llvm.safe.sdiv.iN(iN %x, iN %y)
// Expand it to actual IR, which produces result to the same variable %R.
// First element of the result %R.1 is the result of division, second
// element shows whether the division was correct or not.
// If %y is 0, %R.1 is 0, %R.2 is 1. (1)
// If %x is minSignedValue and %y is -1, %R.1 is %x, %R.2 is 1. (2)
// In other cases %R.1 is (sdiv %x, %y), %R.2 is 0. (3)
//
// Similar applies to srem, udiv, and urem builtins, except that in unsigned
// variants we don't check condition (2).
bool IsSigned;
BinaryOperator::BinaryOps Op;
switch (II->getIntrinsicID()) {
case Intrinsic::safe_sdiv:
IsSigned = true;
Op = Instruction::SDiv;
break;
case Intrinsic::safe_udiv:
IsSigned = false;
Op = Instruction::UDiv;
break;
case Intrinsic::safe_srem:
IsSigned = true;
Op = Instruction::SRem;
break;
case Intrinsic::safe_urem:
IsSigned = false;
Op = Instruction::URem;
break;
default:
llvm_unreachable("Only Div/Rem intrinsics are handled here.");
}
Value *LHS = II->getOperand(0), *RHS = II->getOperand(1);
bool DivWellDefined = TLI && TLI->isDivWellDefined();
bool ResultNeeded[2] = {false, false};
SmallVector<User*, 1> ResultsUsers[2];
bool BadCase = false;
for (User *U: II->users()) {
ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(U);
if (!EVI || EVI->getNumIndices() > 1 || EVI->getIndices()[0] > 1) {
BadCase = true;
break;
}
ResultNeeded[EVI->getIndices()[0]] = true;
ResultsUsers[EVI->getIndices()[0]].push_back(U);
}
// Behave conservatively, if there is an unusual user of the results.
if (BadCase)
ResultNeeded[0] = ResultNeeded[1] = true;
// Early exit if non of the results is ever used.
if (!ResultNeeded[0] && !ResultNeeded[1]) {
II->eraseFromParent();
return true;
}
// Early exit if the second result (flag) isn't used and target
// div-instruction computes exactly what we want to get as the first result
// and never traps.
if (ResultNeeded[0] && !ResultNeeded[1] && DivWellDefined) {
BinaryOperator *Div = BinaryOperator::Create(Op, LHS, RHS);
Div->insertAfter(II);
for (User *U: ResultsUsers[0]) {
Instruction *UserInst = dyn_cast<Instruction>(U);
assert(UserInst && "Unexpected null-instruction");
UserInst->replaceAllUsesWith(Div);
UserInst->eraseFromParent();
}
II->eraseFromParent();
CurInstIterator = Div;
ModifiedDT = true;
return true;
}
Value *MinusOne = Constant::getAllOnesValue(LHS->getType());
Value *Zero = Constant::getNullValue(LHS->getType());
// Split the original BB and create other basic blocks that will be used
// for checks.
BasicBlock *StartBB = II->getParent();
BasicBlock::iterator SplitPt = ++(BasicBlock::iterator(II));
BasicBlock *NextBB = StartBB->splitBasicBlock(SplitPt, "div.end");
BasicBlock *DivByZeroBB;
DivByZeroBB = BasicBlock::Create(II->getContext(), "div.divz",
NextBB->getParent(), NextBB);
BranchInst::Create(NextBB, DivByZeroBB);
BasicBlock *DivBB = BasicBlock::Create(II->getContext(), "div.div",
NextBB->getParent(), NextBB);
BranchInst::Create(NextBB, DivBB);
// For signed variants, check the condition (2):
// LHS == SignedMinValue, RHS == -1.
Value *CmpMinusOne;
Value *CmpMinValue;
BasicBlock *ChkDivMinBB;
BasicBlock *DivMinBB;
Value *MinValue;
if (IsSigned) {
APInt SignedMinValue =
APInt::getSignedMinValue(LHS->getType()->getPrimitiveSizeInBits());
MinValue = Constant::getIntegerValue(LHS->getType(), SignedMinValue);
ChkDivMinBB = BasicBlock::Create(II->getContext(), "div.chkdivmin",
NextBB->getParent(), NextBB);
BranchInst::Create(NextBB, ChkDivMinBB);
DivMinBB = BasicBlock::Create(II->getContext(), "div.divmin",
NextBB->getParent(), NextBB);
BranchInst::Create(NextBB, DivMinBB);
CmpMinusOne = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ,
RHS, MinusOne, "cmp.rhs.minus.one",
ChkDivMinBB->getTerminator());
CmpMinValue = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ,
LHS, MinValue, "cmp.lhs.signed.min",
ChkDivMinBB->getTerminator());
BinaryOperator *CmpSignedOvf = BinaryOperator::Create(Instruction::And,
CmpMinusOne,
CmpMinValue);
// Here we're interested in the case when both %x is TMin and %y is -1.
// In this case the result will overflow.
// If that's not the case, we can perform usual division. These blocks
// will be inserted after DivByZero, so the division will be safe.
CmpSignedOvf->insertBefore(ChkDivMinBB->getTerminator());
BranchInst::Create(DivMinBB, DivBB, CmpSignedOvf,
ChkDivMinBB->getTerminator());
ChkDivMinBB->getTerminator()->eraseFromParent();
}
// Check the condition (1):
// RHS == 0.
Value *CmpDivZero = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ,
RHS, Zero, "cmp.rhs.zero",
StartBB->getTerminator());
// If RHS != 0, we want to check condition (2) in signed case, or proceed
// to usual division in unsigned case.
BranchInst::Create(DivByZeroBB, IsSigned ? ChkDivMinBB : DivBB, CmpDivZero,
StartBB->getTerminator());
StartBB->getTerminator()->eraseFromParent();
// At the moment we have all the control flow created. We just need to
// insert DIV and PHI (if needed) to get the result value.
Instruction *DivRes, *FlagRes;
Instruction *InsPoint = nullptr;
if (ResultNeeded[0]) {
BinaryOperator *Div = BinaryOperator::Create(Op, LHS, RHS);
if (DivWellDefined) {
// The result value is the result of DIV operation placed right at the
// original place of the intrinsic.
Div->insertAfter(II);
DivRes = Div;
} else {
// The result is a PHI-node.
Div->insertBefore(DivBB->getTerminator());
PHINode *DivResPN =
PHINode::Create(LHS->getType(), IsSigned ? 3 : 2, "div.res.phi",
NextBB->begin());
DivResPN->addIncoming(Div, DivBB);
DivResPN->addIncoming(Zero, DivByZeroBB);
if (IsSigned)
DivResPN->addIncoming(MinValue, DivMinBB);
DivRes = DivResPN;
InsPoint = DivResPN;
}
}
// Prepare a value for the second result (flag) if it is needed.
if (ResultNeeded[1]) {
Type *FlagTy = II->getType()->getStructElementType(1);
PHINode *FlagResPN =
PHINode::Create(FlagTy, IsSigned ? 3 : 2, "div.flag.phi",
NextBB->begin());
FlagResPN->addIncoming(Constant::getNullValue(FlagTy), DivBB);
FlagResPN->addIncoming(Constant::getAllOnesValue(FlagTy), DivByZeroBB);
if (IsSigned)
FlagResPN->addIncoming(Constant::getAllOnesValue(FlagTy), DivMinBB);
FlagRes = FlagResPN;
if (!InsPoint)
InsPoint = FlagRes;
}
// If possible, propagate the results to the user. Otherwise, create alloca,
// and create a struct with the results on stack.
if (!BadCase) {
if (ResultNeeded[0]) {
for (User *U: ResultsUsers[0]) {
Instruction *UserInst = dyn_cast<Instruction>(U);
assert(UserInst && "Unexpected null-instruction");
UserInst->replaceAllUsesWith(DivRes);
UserInst->eraseFromParent();
}
}
if (ResultNeeded[1]) {
for (User *FlagU: ResultsUsers[1]) {
Instruction *FlagUInst = dyn_cast<Instruction>(FlagU);
FlagUInst->replaceAllUsesWith(FlagRes);
FlagUInst->eraseFromParent();
}
}
} else {
// Create alloca, store our new values to it, and then load the final
// result from it.
Constant *Idx0 = ConstantInt::get(Type::getInt32Ty(II->getContext()), 0);
Constant *Idx1 = ConstantInt::get(Type::getInt32Ty(II->getContext()), 1);
Value *Idxs_DivRes[2] = {Idx0, Idx0};
Value *Idxs_FlagRes[2] = {Idx0, Idx1};
Value *NewRes = new llvm::AllocaInst(II->getType(), 0, "div.res.ptr", II);
Instruction *ResDivAddr = GetElementPtrInst::Create(NewRes, Idxs_DivRes);
Instruction *ResFlagAddr =
GetElementPtrInst::Create(NewRes, Idxs_FlagRes);
ResDivAddr->insertAfter(InsPoint);
ResFlagAddr->insertAfter(ResDivAddr);
StoreInst *StoreResDiv = new StoreInst(DivRes, ResDivAddr);
StoreInst *StoreResFlag = new StoreInst(FlagRes, ResFlagAddr);
StoreResDiv->insertAfter(ResFlagAddr);
StoreResFlag->insertAfter(StoreResDiv);
LoadInst *LoadRes = new LoadInst(NewRes, "div.res");
LoadRes->insertAfter(StoreResFlag);
II->replaceAllUsesWith(LoadRes);
}
II->eraseFromParent();
CurInstIterator = StartBB->end();
ModifiedDT = true;
return true;
}
if (II && TLI) {
SmallVector<Value*, 2> PtrOps;

View File

@ -682,6 +682,7 @@ TargetLoweringBase::TargetLoweringBase(const TargetMachine &tm,
HasMultipleConditionRegisters = false;
IntDivIsCheap = false;
Pow2DivIsCheap = false;
DivIsWellDefined = false;
JumpIsExpensive = false;
PredictableSelectIsExpensive = false;
MaskAndBranchFoldingIsLegal = false;

View File

@ -435,6 +435,8 @@ ARM64TargetLowering::ARM64TargetLowering(ARM64TargetMachine &TM)
setMinFunctionAlignment(2);
setDivIsWellDefined(true);
RequireStrictAlign = StrictAlign;
}

View File

@ -0,0 +1,83 @@
; RUN: llc < %s -march=arm64 | FileCheck %s
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
%divovf32 = type { i32, i1 }
declare %divovf32 @llvm.safe.sdiv.i32(i32, i32) nounwind readnone
declare %divovf32 @llvm.safe.udiv.i32(i32, i32) nounwind readnone
; CHECK-LABEL: sdiv32_results_unused
; CHECK: entry
; CHECK-NEXT: ret
define void @sdiv32_results_unused(i32 %x, i32 %y) {
entry:
%divr = call %divovf32 @llvm.safe.sdiv.i32(i32 %x, i32 %y)
ret void
}
; CHECK-LABEL: sdiv32_div_result_unused
; CHECK-NOT: sdiv{{[ ]}}
define i1 @sdiv32_div_result_unused(i32 %x, i32 %y) {
entry:
%divr = call %divovf32 @llvm.safe.sdiv.i32(i32 %x, i32 %y)
%bit = extractvalue %divovf32 %divr, 1
ret i1 %bit
}
; CHECK-LABEL: sdiv32_flag_result_unused
; CHECK-NOT: cb
; CHECK: sdiv{{[ ]}}
define i32 @sdiv32_flag_result_unused(i32 %x, i32 %y) {
entry:
%divr = call %divovf32 @llvm.safe.sdiv.i32(i32 %x, i32 %y)
%div = extractvalue %divovf32 %divr, 0
ret i32 %div
}
; CHECK-LABEL: sdiv32_result_returned
; CHECK: sdiv{{[ ]}}
define %divovf32 @sdiv32_result_returned(i32 %x, i32 %y) {
entry:
%divr = call %divovf32 @llvm.safe.sdiv.i32(i32 %x, i32 %y)
ret %divovf32 %divr
}
; CHECK-LABEL: udiv32_results_unused
; CHECK: entry
; CHECK-NEXT: ret
define void @udiv32_results_unused(i32 %x, i32 %y) {
entry:
%divr = call %divovf32 @llvm.safe.udiv.i32(i32 %x, i32 %y)
ret void
}
; CHECK-LABEL: udiv32_div_result_unused
; CHECK-NOT: udiv{{[ ]}}
define i1 @udiv32_div_result_unused(i32 %x, i32 %y) {
entry:
%divr = call %divovf32 @llvm.safe.udiv.i32(i32 %x, i32 %y)
%bit = extractvalue %divovf32 %divr, 1
ret i1 %bit
}
; CHECK-LABEL: udiv32_flag_result_unused
; CHECK-NOT: cb
; CHECK: udiv{{[ ]}}
define i32 @udiv32_flag_result_unused(i32 %x, i32 %y) {
entry:
%divr = call %divovf32 @llvm.safe.udiv.i32(i32 %x, i32 %y)
%div = extractvalue %divovf32 %divr, 0
ret i32 %div
}
; CHECK-LABEL: udiv32_result_returned
; CHECK: udiv{{[ ]}}
define %divovf32 @udiv32_result_returned(i32 %x, i32 %y) {
entry:
%divr = call %divovf32 @llvm.safe.udiv.i32(i32 %x, i32 %y)
ret %divovf32 %divr
}
!llvm.ident = !{!0}
!0 = metadata !{metadata !"clang version 3.5.0 "}

View File

@ -0,0 +1,152 @@
; RUN: llc < %s -march=arm64 | FileCheck %s
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
%divovf8 = type { i8, i1 }
%divovf16 = type { i16, i1 }
%divovf32 = type { i32, i1 }
%divovf64 = type { i64, i1 }
declare %divovf8 @llvm.safe.sdiv.i8(i8, i8) nounwind readnone
declare %divovf16 @llvm.safe.sdiv.i16(i16, i16) nounwind readnone
declare %divovf32 @llvm.safe.sdiv.i32(i32, i32) nounwind readnone
declare %divovf64 @llvm.safe.sdiv.i64(i64, i64) nounwind readnone
declare %divovf8 @llvm.safe.srem.i8(i8, i8) nounwind readnone
declare %divovf16 @llvm.safe.srem.i16(i16, i16) nounwind readnone
declare %divovf32 @llvm.safe.srem.i32(i32, i32) nounwind readnone
declare %divovf64 @llvm.safe.srem.i64(i64, i64) nounwind readnone
declare %divovf8 @llvm.safe.udiv.i8(i8, i8) nounwind readnone
declare %divovf16 @llvm.safe.udiv.i16(i16, i16) nounwind readnone
declare %divovf32 @llvm.safe.udiv.i32(i32, i32) nounwind readnone
declare %divovf64 @llvm.safe.udiv.i64(i64, i64) nounwind readnone
declare %divovf8 @llvm.safe.urem.i8(i8, i8) nounwind readnone
declare %divovf16 @llvm.safe.urem.i16(i16, i16) nounwind readnone
declare %divovf32 @llvm.safe.urem.i32(i32, i32) nounwind readnone
declare %divovf64 @llvm.safe.urem.i64(i64, i64) nounwind readnone
; CHECK-LABEL: sdiv8
; CHECK: sdiv{{[ ]}}
define %divovf8 @sdiv8(i8 %x, i8 %y) {
entry:
%divr = call %divovf8 @llvm.safe.sdiv.i8(i8 %x, i8 %y)
ret %divovf8 %divr
}
; CHECK-LABEL: sdiv16
; CHECK: sdiv{{[ ]}}
define %divovf16 @sdiv16(i16 %x, i16 %y) {
entry:
%divr = call %divovf16 @llvm.safe.sdiv.i16(i16 %x, i16 %y)
ret %divovf16 %divr
}
; CHECK-LABEL: sdiv32
; CHECK: sdiv{{[ ]}}
define %divovf32 @sdiv32(i32 %x, i32 %y) {
entry:
%divr = call %divovf32 @llvm.safe.sdiv.i32(i32 %x, i32 %y)
ret %divovf32 %divr
}
; CHECK-LABEL: sdiv64
; CHECK: sdiv{{[ ]}}
define %divovf64 @sdiv64(i64 %x, i64 %y) {
entry:
%divr = call %divovf64 @llvm.safe.sdiv.i64(i64 %x, i64 %y)
ret %divovf64 %divr
}
; CHECK-LABEL: udiv8
; CHECK: udiv{{[ ]}}
define %divovf8 @udiv8(i8 %x, i8 %y) {
entry:
%divr = call %divovf8 @llvm.safe.udiv.i8(i8 %x, i8 %y)
ret %divovf8 %divr
}
; CHECK-LABEL: udiv16
; CHECK: udiv{{[ ]}}
define %divovf16 @udiv16(i16 %x, i16 %y) {
entry:
%divr = call %divovf16 @llvm.safe.udiv.i16(i16 %x, i16 %y)
ret %divovf16 %divr
}
; CHECK-LABEL: udiv32
; CHECK: udiv{{[ ]}}
define %divovf32 @udiv32(i32 %x, i32 %y) {
entry:
%divr = call %divovf32 @llvm.safe.udiv.i32(i32 %x, i32 %y)
ret %divovf32 %divr
}
; CHECK-LABEL: udiv64
; CHECK: udiv{{[ ]}}
define %divovf64 @udiv64(i64 %x, i64 %y) {
entry:
%divr = call %divovf64 @llvm.safe.udiv.i64(i64 %x, i64 %y)
ret %divovf64 %divr
}
; CHECK-LABEL: srem8
; CHECK: sdiv{{[ ]}}
; CHECK: msub{{[ ]}}
define %divovf8 @srem8(i8 %x, i8 %y) {
entry:
%remr = call %divovf8 @llvm.safe.srem.i8(i8 %x, i8 %y)
ret %divovf8 %remr
}
; CHECK-LABEL: srem16
; CHECK: sdiv{{[ ]}}
; CHECK: msub{{[ ]}}
define %divovf16 @srem16(i16 %x, i16 %y) {
entry:
%remr = call %divovf16 @llvm.safe.srem.i16(i16 %x, i16 %y)
ret %divovf16 %remr
}
; CHECK-LABEL: srem32
; CHECK: sdiv{{[ ]}}
; CHECK: msub{{[ ]}}
define %divovf32 @srem32(i32 %x, i32 %y) {
entry:
%remr = call %divovf32 @llvm.safe.srem.i32(i32 %x, i32 %y)
ret %divovf32 %remr
}
; CHECK-LABEL: srem64
; CHECK: sdiv{{[ ]}}
; CHECK: msub{{[ ]}}
define %divovf64 @srem64(i64 %x, i64 %y) {
entry:
%remr = call %divovf64 @llvm.safe.srem.i64(i64 %x, i64 %y)
ret %divovf64 %remr
}
; CHECK-LABEL: urem8
; CHECK: udiv{{[ ]}}
; CHECK: msub{{[ ]}}
define %divovf8 @urem8(i8 %x, i8 %y) {
entry:
%remr = call %divovf8 @llvm.safe.urem.i8(i8 %x, i8 %y)
ret %divovf8 %remr
}
; CHECK-LABEL: urem16
; CHECK: udiv{{[ ]}}
; CHECK: msub{{[ ]}}
define %divovf16 @urem16(i16 %x, i16 %y) {
entry:
%remr = call %divovf16 @llvm.safe.urem.i16(i16 %x, i16 %y)
ret %divovf16 %remr
}
; CHECK-LABEL: urem32
; CHECK: udiv{{[ ]}}
; CHECK: msub{{[ ]}}
define %divovf32 @urem32(i32 %x, i32 %y) {
entry:
%remr = call %divovf32 @llvm.safe.urem.i32(i32 %x, i32 %y)
ret %divovf32 %remr
}
; CHECK-LABEL: urem64
; CHECK: udiv{{[ ]}}
; CHECK: msub{{[ ]}}
define %divovf64 @urem64(i64 %x, i64 %y) {
entry:
%remr = call %divovf64 @llvm.safe.urem.i64(i64 %x, i64 %y)
ret %divovf64 %remr
}
!llvm.ident = !{!0}
!0 = metadata !{metadata !"clang version 3.5.0 "}

View File

@ -0,0 +1,82 @@
; RUN: llc < %s -march=x86-64 | FileCheck %s
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
%divovf32 = type { i32, i1 }
declare %divovf32 @llvm.safe.sdiv.i32(i32, i32) nounwind readnone
declare %divovf32 @llvm.safe.udiv.i32(i32, i32) nounwind readnone
; CHECK-LABEL: sdiv32_results_unused
; CHECK: entry
; CHECK-NEXT: ret
define void @sdiv32_results_unused(i32 %x, i32 %y) {
entry:
%divr = call %divovf32 @llvm.safe.sdiv.i32(i32 %x, i32 %y)
ret void
}
; CHECK-LABEL: sdiv32_div_result_unused
; CHECK-NOT: idiv
define i1 @sdiv32_div_result_unused(i32 %x, i32 %y) {
entry:
%divr = call %divovf32 @llvm.safe.sdiv.i32(i32 %x, i32 %y)
%bit = extractvalue %divovf32 %divr, 1
ret i1 %bit
}
; CHECK-LABEL: sdiv32_flag_result_unused
; CHECK: idiv
define i32 @sdiv32_flag_result_unused(i32 %x, i32 %y) {
entry:
%divr = call %divovf32 @llvm.safe.sdiv.i32(i32 %x, i32 %y)
%div = extractvalue %divovf32 %divr, 0
ret i32 %div
}
; CHECK-LABEL: sdiv32_result_returned
; CHECK: idiv
define %divovf32 @sdiv32_result_returned(i32 %x, i32 %y) {
entry:
%divr = call %divovf32 @llvm.safe.sdiv.i32(i32 %x, i32 %y)
ret %divovf32 %divr
}
; CHECK-LABEL: udiv32_results_unused
; CHECK: entry
; CHECK-NEXT: ret
define void @udiv32_results_unused(i32 %x, i32 %y) {
entry:
%divr = call %divovf32 @llvm.safe.udiv.i32(i32 %x, i32 %y)
ret void
}
; CHECK-LABEL: udiv32_div_result_unused
; CHECK-NOT: udiv{{[ ]}}
define i1 @udiv32_div_result_unused(i32 %x, i32 %y) {
entry:
%divr = call %divovf32 @llvm.safe.udiv.i32(i32 %x, i32 %y)
%bit = extractvalue %divovf32 %divr, 1
ret i1 %bit
}
; CHECK-LABEL: udiv32_flag_result_unused
; CHECK-NOT: cb
; CHECK: {{[ ]}}div
define i32 @udiv32_flag_result_unused(i32 %x, i32 %y) {
entry:
%divr = call %divovf32 @llvm.safe.udiv.i32(i32 %x, i32 %y)
%div = extractvalue %divovf32 %divr, 0
ret i32 %div
}
; CHECK-LABEL: udiv32_result_returned
; CHECK: {{[ ]}}div
define %divovf32 @udiv32_result_returned(i32 %x, i32 %y) {
entry:
%divr = call %divovf32 @llvm.safe.udiv.i32(i32 %x, i32 %y)
ret %divovf32 %divr
}
!llvm.ident = !{!0}
!0 = metadata !{metadata !"clang version 3.5.0 "}

View File

@ -0,0 +1,144 @@
; RUN: llc < %s -march=x86-64 | FileCheck %s
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
%divovf8 = type { i8, i1 }
%divovf16 = type { i16, i1 }
%divovf32 = type { i32, i1 }
%divovf64 = type { i64, i1 }
declare %divovf8 @llvm.safe.sdiv.i8(i8, i8) nounwind readnone
declare %divovf16 @llvm.safe.sdiv.i16(i16, i16) nounwind readnone
declare %divovf32 @llvm.safe.sdiv.i32(i32, i32) nounwind readnone
declare %divovf64 @llvm.safe.sdiv.i64(i64, i64) nounwind readnone
declare %divovf8 @llvm.safe.srem.i8(i8, i8) nounwind readnone
declare %divovf16 @llvm.safe.srem.i16(i16, i16) nounwind readnone
declare %divovf32 @llvm.safe.srem.i32(i32, i32) nounwind readnone
declare %divovf64 @llvm.safe.srem.i64(i64, i64) nounwind readnone
declare %divovf8 @llvm.safe.udiv.i8(i8, i8) nounwind readnone
declare %divovf16 @llvm.safe.udiv.i16(i16, i16) nounwind readnone
declare %divovf32 @llvm.safe.udiv.i32(i32, i32) nounwind readnone
declare %divovf64 @llvm.safe.udiv.i64(i64, i64) nounwind readnone
declare %divovf8 @llvm.safe.urem.i8(i8, i8) nounwind readnone
declare %divovf16 @llvm.safe.urem.i16(i16, i16) nounwind readnone
declare %divovf32 @llvm.safe.urem.i32(i32, i32) nounwind readnone
declare %divovf64 @llvm.safe.urem.i64(i64, i64) nounwind readnone
; CHECK-LABEL: sdiv8
; CHECK: idivb{{[ ]}}
define %divovf8 @sdiv8(i8 %x, i8 %y) {
entry:
%divr = call %divovf8 @llvm.safe.sdiv.i8(i8 %x, i8 %y)
ret %divovf8 %divr
}
; CHECK-LABEL: sdiv16
; CHECK: idivw{{[ ]}}
define %divovf16 @sdiv16(i16 %x, i16 %y) {
entry:
%divr = call %divovf16 @llvm.safe.sdiv.i16(i16 %x, i16 %y)
ret %divovf16 %divr
}
; CHECK-LABEL: sdiv32
; CHECK: idivl{{[ ]}}
define %divovf32 @sdiv32(i32 %x, i32 %y) {
entry:
%divr = call %divovf32 @llvm.safe.sdiv.i32(i32 %x, i32 %y)
ret %divovf32 %divr
}
; CHECK-LABEL: sdiv64
; CHECK: idivq{{[ ]}}
define %divovf64 @sdiv64(i64 %x, i64 %y) {
entry:
%divr = call %divovf64 @llvm.safe.sdiv.i64(i64 %x, i64 %y)
ret %divovf64 %divr
}
; CHECK-LABEL: udiv8
; CHECK: {{[ ]}}divb{{[ ]}}
define %divovf8 @udiv8(i8 %x, i8 %y) {
entry:
%divr = call %divovf8 @llvm.safe.udiv.i8(i8 %x, i8 %y)
ret %divovf8 %divr
}
; CHECK-LABEL: udiv16
; CHECK: {{[ ]}}divw{{[ ]}}
define %divovf16 @udiv16(i16 %x, i16 %y) {
entry:
%divr = call %divovf16 @llvm.safe.udiv.i16(i16 %x, i16 %y)
ret %divovf16 %divr
}
; CHECK-LABEL: udiv32
; CHECK: {{[ ]}}divl{{[ ]}}
define %divovf32 @udiv32(i32 %x, i32 %y) {
entry:
%divr = call %divovf32 @llvm.safe.udiv.i32(i32 %x, i32 %y)
ret %divovf32 %divr
}
; CHECK-LABEL: udiv64
; CHECK: {{[ ]}}divq{{[ ]}}
define %divovf64 @udiv64(i64 %x, i64 %y) {
entry:
%divr = call %divovf64 @llvm.safe.udiv.i64(i64 %x, i64 %y)
ret %divovf64 %divr
}
; CHECK-LABEL: srem8
; CHECK: idivb{{[ ]}}
define %divovf8 @srem8(i8 %x, i8 %y) {
entry:
%remr = call %divovf8 @llvm.safe.srem.i8(i8 %x, i8 %y)
ret %divovf8 %remr
}
; CHECK-LABEL: srem16
; CHECK: idivw{{[ ]}}
define %divovf16 @srem16(i16 %x, i16 %y) {
entry:
%remr = call %divovf16 @llvm.safe.srem.i16(i16 %x, i16 %y)
ret %divovf16 %remr
}
; CHECK-LABEL: srem32
; CHECK: idivl{{[ ]}}
define %divovf32 @srem32(i32 %x, i32 %y) {
entry:
%remr = call %divovf32 @llvm.safe.srem.i32(i32 %x, i32 %y)
ret %divovf32 %remr
}
; CHECK-LABEL: srem64
; CHECK: idivq{{[ ]}}
define %divovf64 @srem64(i64 %x, i64 %y) {
entry:
%remr = call %divovf64 @llvm.safe.srem.i64(i64 %x, i64 %y)
ret %divovf64 %remr
}
; CHECK-LABEL: urem8
; CHECK: {{[ ]}}divb{{[ ]}}
define %divovf8 @urem8(i8 %x, i8 %y) {
entry:
%remr = call %divovf8 @llvm.safe.urem.i8(i8 %x, i8 %y)
ret %divovf8 %remr
}
; CHECK-LABEL: urem16
; CHECK: {{[ ]}}divw{{[ ]}}
define %divovf16 @urem16(i16 %x, i16 %y) {
entry:
%remr = call %divovf16 @llvm.safe.urem.i16(i16 %x, i16 %y)
ret %divovf16 %remr
}
; CHECK-LABEL: urem32
; CHECK: {{[ ]}}divl{{[ ]}}
define %divovf32 @urem32(i32 %x, i32 %y) {
entry:
%remr = call %divovf32 @llvm.safe.urem.i32(i32 %x, i32 %y)
ret %divovf32 %remr
}
; CHECK-LABEL: urem64
; CHECK: {{[ ]}}divq{{[ ]}}
define %divovf64 @urem64(i64 %x, i64 %y) {
entry:
%remr = call %divovf64 @llvm.safe.urem.i64(i64 %x, i64 %y)
ret %divovf64 %remr
}
!llvm.ident = !{!0}
!0 = metadata !{metadata !"clang version 3.5.0 "}