[llvm] r206732 - Implement builtins for safe division: safe.sdiv.iN, safe.udiv.iN, safe.srem.iN,
Chandler Carruth
chandlerc at google.com
Mon Apr 21 00:13:49 PDT 2014
This has broken roughly all of the build bots:
http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-debian-fast/builds/14859
I'm going to revert as they've been broken for an hour now.
On Sun, Apr 20, 2014 at 10:33 PM, Michael Zolotukhin
<mzolotukhin at apple.com>wrote:
> Author: mzolotukhin
> Date: Mon Apr 21 00:33:09 2014
> New Revision: 206732
>
> URL: http://llvm.org/viewvc/llvm-project?rev=206732&view=rev
> Log:
> Implement builtins for safe division: safe.sdiv.iN, safe.udiv.iN,
> safe.srem.iN,
> safe.urem.iN (iN = i8, i16, i32, or i64).
>
>
> Added:
> llvm/trunk/test/CodeGen/ARM64/SafeDivRemIntrinsics-Opts.ll
> llvm/trunk/test/CodeGen/ARM64/SafeDivRemIntrinsics.ll
> llvm/trunk/test/CodeGen/X86/SafeDivRemIntrinsics-Opts.ll
> llvm/trunk/test/CodeGen/X86/SafeDivRemIntrinsics.ll
> Modified:
> llvm/trunk/include/llvm/IR/Intrinsics.td
> llvm/trunk/include/llvm/Target/TargetLowering.h
> llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp
> llvm/trunk/lib/CodeGen/TargetLoweringBase.cpp
> llvm/trunk/lib/Target/ARM64/ARM64ISelLowering.cpp
>
> Modified: llvm/trunk/include/llvm/IR/Intrinsics.td
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Intrinsics.td?rev=206732&r1=206731&r2=206732&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/IR/Intrinsics.td (original)
> +++ llvm/trunk/include/llvm/IR/Intrinsics.td Mon Apr 21 00:33:09 2014
> @@ -444,6 +444,19 @@ def int_umul_with_overflow : Intrinsic<[
> [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<[],
>
> Modified: llvm/trunk/include/llvm/Target/TargetLowering.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/TargetLowering.h?rev=206732&r1=206731&r2=206732&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/Target/TargetLowering.h (original)
> +++ llvm/trunk/include/llvm/Target/TargetLowering.h Mon Apr 21 00:33:09
> 2014
> @@ -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.
>
> Modified: llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp?rev=206732&r1=206731&r2=206732&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp (original)
> +++ llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp Mon Apr 21 00:33:09 2014
> @@ -688,6 +688,293 @@ bool CodeGenPrepare::OptimizeCallInst(Ca
> }
> 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;
> + }
> +
> + // Check if the flag is used to jump out to a 'trap' block
> + // If it's the case, we want to use this block directly when we create
> + // branches after comparing with 0 and comparing with -1 (signed
> case).
> + // We can do it only iff we can track all the uses of the flag, i.e.
> the
> + // only users are EXTRACTVALUE-insns, and their users are conditional
> + // branches, targeting the same 'trap' basic block.
> + BasicBlock *TrapBB = nullptr;
> + bool DoRelinkTrap = true;
> + for (User *FlagU: ResultsUsers[1]) {
> + for (User *U: FlagU->users()) {
> + BranchInst *TrapBranch = dyn_cast<BranchInst>(U);
> + // If the user isn't a branch-insn, or it jumps to another BB,
> don't
> + // try to use TrapBB in the lowering.
> + if (!TrapBranch || (TrapBB && TrapBB !=
> TrapBranch->getSuccessor(0))) {
> + DoRelinkTrap = false;
> + break;
> + }
> + TrapBB = TrapBranch->getSuccessor(0);
> + }
> + }
> + if (!TrapBB)
> + DoRelinkTrap = false;
> + // We want to reuse TrapBB if possible, because in that case we can
> avoid
> + // creating new basic blocks and thus overcomplicating the IR.
> However, if
> + // DIV instruction isn't well defined, we still need those blocks to
> model
> + // well-defined behaviour. Thus, we can't reuse TrapBB in this case.
> + if (!DivWellDefined)
> + DoRelinkTrap = false;
> +
> + 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;
> + if (!DoRelinkTrap) {
> + 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);
> + if (!DoRelinkTrap) {
> + 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(DoRelinkTrap ? TrapBB : 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(DoRelinkTrap ? TrapBB : 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] && !DoRelinkTrap) {
> + 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);
> + if (DoRelinkTrap) {
> + // Replace
> + // %flag = extractvalue %intrinsic.res, 1
> + // br i1 %flag, label %trap.bb, label %other.bb
> + // With
> + // br label %other.bb
> + // We've already created checks that are pointing to %trap.bb,
> there
> + // is no need to have the same checks here.
> + for (User *U: FlagUInst->users()) {
> + BranchInst *TrapBranch = dyn_cast<BranchInst>(U);
> + BasicBlock *CurBB = TrapBranch->getParent();
> + BasicBlock *SuccessorBB = TrapBranch->getSuccessor(1);
> + CurBB->getTerminator()->eraseFromParent();
> + BranchInst::Create(SuccessorBB, CurBB);
> + }
> + } else {
> + FlagUInst->replaceAllUsesWith(FlagRes);
> + }
> + dyn_cast<Instruction>(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;
>
> Modified: llvm/trunk/lib/CodeGen/TargetLoweringBase.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/TargetLoweringBase.cpp?rev=206732&r1=206731&r2=206732&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/TargetLoweringBase.cpp (original)
> +++ llvm/trunk/lib/CodeGen/TargetLoweringBase.cpp Mon Apr 21 00:33:09 2014
> @@ -682,6 +682,7 @@ TargetLoweringBase::TargetLoweringBase(c
> HasMultipleConditionRegisters = false;
> IntDivIsCheap = false;
> Pow2DivIsCheap = false;
> + DivIsWellDefined = false;
> JumpIsExpensive = false;
> PredictableSelectIsExpensive = false;
> MaskAndBranchFoldingIsLegal = false;
>
> Modified: llvm/trunk/lib/Target/ARM64/ARM64ISelLowering.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM64/ARM64ISelLowering.cpp?rev=206732&r1=206731&r2=206732&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM64/ARM64ISelLowering.cpp (original)
> +++ llvm/trunk/lib/Target/ARM64/ARM64ISelLowering.cpp Mon Apr 21 00:33:09
> 2014
> @@ -435,6 +435,8 @@ ARM64TargetLowering::ARM64TargetLowering
>
> setMinFunctionAlignment(2);
>
> + setDivIsWellDefined(true);
> +
> RequireStrictAlign = StrictAlign;
> }
>
>
> Added: llvm/trunk/test/CodeGen/ARM64/SafeDivRemIntrinsics-Opts.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM64/SafeDivRemIntrinsics-Opts.ll?rev=206732&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/CodeGen/ARM64/SafeDivRemIntrinsics-Opts.ll (added)
> +++ llvm/trunk/test/CodeGen/ARM64/SafeDivRemIntrinsics-Opts.ll Mon Apr 21
> 00:33:09 2014
> @@ -0,0 +1,112 @@
> +; 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: sdiv32_trap_relinked
> +; CHECK-NOT: %div.divmin
> +; CHECK-NOT: %div.divz
> +define i32 @sdiv32_trap_relinked(i32 %x, i32 %y) {
> +entry:
> + %divr = call %divovf32 @llvm.safe.sdiv.i32(i32 %x, i32 %y)
> + %div = extractvalue %divovf32 %divr, 0
> + %bit = extractvalue %divovf32 %divr, 1
> + br i1 %bit, label %trap.bb, label %ok.bb
> +trap.bb:
> + ret i32 7
> +ok.bb:
> + ret i32 %div
> +}
> +
> +; 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
> +}
> +
> +; CHECK-LABEL: udiv32_trap_relinked
> +; CHECK-NOT: %div.divz
> +define i32 @udiv32_trap_relinked(i32 %x, i32 %y) {
> +entry:
> + %divr = call %divovf32 @llvm.safe.udiv.i32(i32 %x, i32 %y)
> + %div = extractvalue %divovf32 %divr, 0
> + %bit = extractvalue %divovf32 %divr, 1
> + br i1 %bit, label %trap.bb, label %ok.bb
> +trap.bb:
> + ret i32 7
> +ok.bb:
> + ret i32 %div
> +}
> +
> +!llvm.ident = !{!0}
> +
> +!0 = metadata !{metadata !"clang version 3.5.0 "}
>
> Added: llvm/trunk/test/CodeGen/ARM64/SafeDivRemIntrinsics.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM64/SafeDivRemIntrinsics.ll?rev=206732&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/CodeGen/ARM64/SafeDivRemIntrinsics.ll (added)
> +++ llvm/trunk/test/CodeGen/ARM64/SafeDivRemIntrinsics.ll Mon Apr 21
> 00:33:09 2014
> @@ -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 "}
>
> Added: llvm/trunk/test/CodeGen/X86/SafeDivRemIntrinsics-Opts.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/SafeDivRemIntrinsics-Opts.ll?rev=206732&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/CodeGen/X86/SafeDivRemIntrinsics-Opts.ll (added)
> +++ llvm/trunk/test/CodeGen/X86/SafeDivRemIntrinsics-Opts.ll Mon Apr 21
> 00:33:09 2014
> @@ -0,0 +1,110 @@
> +; RUN: llc < %s | 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: sdiv32_trap_relinked
> +; CHECK: %div.div{{min|z}}
> +define i32 @sdiv32_trap_relinked(i32 %x, i32 %y) {
> +entry:
> + %divr = call %divovf32 @llvm.safe.sdiv.i32(i32 %x, i32 %y)
> + %div = extractvalue %divovf32 %divr, 0
> + %bit = extractvalue %divovf32 %divr, 1
> + br i1 %bit, label %trap.bb, label %ok.bb
> +trap.bb:
> + ret i32 7
> +ok.bb:
> + ret i32 %div
> +}
> +
> +; 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
> +}
> +
> +; CHECK-LABEL: udiv32_trap_relinked
> +; CHECK: %div.divz
> +define i32 @udiv32_trap_relinked(i32 %x, i32 %y) {
> +entry:
> + %divr = call %divovf32 @llvm.safe.udiv.i32(i32 %x, i32 %y)
> + %div = extractvalue %divovf32 %divr, 0
> + %bit = extractvalue %divovf32 %divr, 1
> + br i1 %bit, label %trap.bb, label %ok.bb
> +trap.bb:
> + ret i32 7
> +ok.bb:
> + ret i32 %div
> +}
> +
> +!llvm.ident = !{!0}
> +
> +!0 = metadata !{metadata !"clang version 3.5.0 "}
>
> Added: llvm/trunk/test/CodeGen/X86/SafeDivRemIntrinsics.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/SafeDivRemIntrinsics.ll?rev=206732&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/CodeGen/X86/SafeDivRemIntrinsics.ll (added)
> +++ llvm/trunk/test/CodeGen/X86/SafeDivRemIntrinsics.ll Mon Apr 21
> 00:33:09 2014
> @@ -0,0 +1,144 @@
> +; RUN: llc < %s | 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 "}
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20140421/c5fd6fad/attachment.html>
More information about the llvm-commits
mailing list