[llvm] r206732 - Implement builtins for safe division: safe.sdiv.iN, safe.udiv.iN, safe.srem.iN,
Michael Zolotukhin
mzolotukhin at apple.com
Tue Apr 22 08:07:06 PDT 2014
Hi,
Thanks, Andy! I have actually nothing to add to this detailed description, just chiming up to confirm this.
Best regards,
Michael
On Apr 22, 2014, at 1:05 AM, Andrew Trick <atrick at apple.com> wrote:
> HI Eric,
>
> This patch fills in some missing intrinsics in LLVM’s arithmetic and overflow intrinsics. I actually reviewed several iterations of this patch in its prototype stages. I obviously need to summarize those discussions on the list. Let me start by answering your questions.
>
> On Apr 21, 2014, at 1:20 PM, Eric Christopher <echristo at gmail.com> wrote:
>
>> Hi Michael,
>>
>> I don't think this is the right change for the IR level. I realize
>> Nadav stamped it pretty quickly so I assume there was some discussion
>> within your group about it, but it seems to be an odd change.
>
> One of Michael’s early implementations worked completely within the SelectionDAG. We could share that patch if it’s interesting. The goal was to mimic the rest of the llvm.arith.with.overflow intrinsics, including lowering them through the same codegen mechanism.
>
> The problem is that division is special and requires generating target-specific control flow. The SD implementation was full of CMOVs and was spread across legalization and other places. This made it hard to understand the semantics of the intrinsics and hard to grok the resulting SD. The IR implementation is just vastly simpler (much easier to review this way).
>
>> So I
>> have a few questions for you on the design for the intrinsics:
>>
>> Do we need brand new builtins for this? Could it not be solved as part
>> of a TTI using pass that could know how to inspect each normal div
>> instruction to see how it works?
>
> The goal here is to complete the implementation of LLVM’s existing arithmetic with overflow intrinsics. It was originally llvm.sdiv.with.overflow. I objected to that name because it is technically not checking overflow, so I thought that name would be misleading. To me overflow on division means taking a numerator composed of two 64-bit operands and expecting a single 64-bit result (as with x86).
>
> This intrinsic is about supporting safe division in high-level languages in a way that can be lowered to optimal machine code. It is not an accident that high-level languages and ARM64 semantics match nicely. But the goal here is not better ARM64 codegen. The goal is simply to support checked division either through an option to the C compiler or for non-C languages.
>
>> Is this only about lowering ARM64 idiv? Should it be a target builtin instead?
>
> This is not really about ARM64 at all. It’s just that ARM64 provides a great counter-example to how the intrinsic should be lowered on x86.
>
>> Could/should we have annotations similar to nsw/nuw on the idiv
>> instructions instead?
>
> These intrinsics are meant to be used with an option like -ftrapv (although I think we need a new flag for division). I think this feature has been requested multiple times on the dev list, but no one has managed to upstream the implementation work. I can probably dig up those discussions.
>
> nsw/nuw flags can be dropped by any IR pass, but we need these checks to be preserved.
>
> In that past, I’ve been in favor of representing control flow directly within the IR, as opposed to using intrinsics like llvm.arith.with.overflow. However, the precedent has been set, and I admit this makes it much easier to guarantee reasonable codegen on a given platform.
>
> -Andy
>
>> Since there didn't seem to be any discussion on it I thought I'd raise
>> a few starter questions here. I'm sure I'll have more once I think
>> about this more.
>>
>> (cc'ing Chris because IR level changes, and Jim because arm64).
>>
>> -eric
>>
>>
>> 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
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list