Implement builtins for safe division: safe.sdiv.iN, safe.udiv.iN, safe.srem.iN,
authorMichael Zolotukhin <mzolotukhin@apple.com>
Mon, 21 Apr 2014 05:33:09 +0000 (05:33 +0000)
committerMichael Zolotukhin <mzolotukhin@apple.com>
Mon, 21 Apr 2014 05:33:09 +0000 (05:33 +0000)
safe.urem.iN (iN = i8, i16, i32, or i64).

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@206732 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/IR/Intrinsics.td
include/llvm/Target/TargetLowering.h
lib/CodeGen/CodeGenPrepare.cpp
lib/CodeGen/TargetLoweringBase.cpp
lib/Target/ARM64/ARM64ISelLowering.cpp
test/CodeGen/ARM64/SafeDivRemIntrinsics-Opts.ll [new file with mode: 0644]
test/CodeGen/ARM64/SafeDivRemIntrinsics.ll [new file with mode: 0644]
test/CodeGen/X86/SafeDivRemIntrinsics-Opts.ll [new file with mode: 0644]
test/CodeGen/X86/SafeDivRemIntrinsics.ll [new file with mode: 0644]

index 6a48f173935f77bc746cb4b7cba6ee5d2345fe93..c65b86f5b709970a178389fc7df1fb88aafd9a46 100644 (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<[],
index 5afcd80a280640323571a2938faedd5a5c7be566..2e4956f16d0251832105d657509aa0c169fc8bb8 100644 (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.
index 1ab24162dc8137c23facdb2b73af93a679da6591..642fbad1cdf5e9ea0325e579a30e764fd0dc752c 100644 (file)
@@ -688,6 +688,293 @@ 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;
+    }
+
+    // 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;
index c1a47751eb883726192aebc46c46cba5fa953214..4ed20d02703efce334754a2c33f7c42d2f0d450a 100644 (file)
@@ -682,6 +682,7 @@ TargetLoweringBase::TargetLoweringBase(const TargetMachine &tm,
   HasMultipleConditionRegisters = false;
   IntDivIsCheap = false;
   Pow2DivIsCheap = false;
+  DivIsWellDefined = false;
   JumpIsExpensive = false;
   PredictableSelectIsExpensive = false;
   MaskAndBranchFoldingIsLegal = false;
index 6df2122abecb33e57f2dd0240bd2487c8342ad98..7fee5646d1ce997e07a4038d3653084a9ef04264 100644 (file)
@@ -435,6 +435,8 @@ ARM64TargetLowering::ARM64TargetLowering(ARM64TargetMachine &TM)
 
   setMinFunctionAlignment(2);
 
+  setDivIsWellDefined(true);
+
   RequireStrictAlign = StrictAlign;
 }
 
diff --git a/test/CodeGen/ARM64/SafeDivRemIntrinsics-Opts.ll b/test/CodeGen/ARM64/SafeDivRemIntrinsics-Opts.ll
new file mode 100644 (file)
index 0000000..d722818
--- /dev/null
@@ -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 "}
diff --git a/test/CodeGen/ARM64/SafeDivRemIntrinsics.ll b/test/CodeGen/ARM64/SafeDivRemIntrinsics.ll
new file mode 100644 (file)
index 0000000..5c4e58b
--- /dev/null
@@ -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 "}
diff --git a/test/CodeGen/X86/SafeDivRemIntrinsics-Opts.ll b/test/CodeGen/X86/SafeDivRemIntrinsics-Opts.ll
new file mode 100644 (file)
index 0000000..9076316
--- /dev/null
@@ -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 "}
diff --git a/test/CodeGen/X86/SafeDivRemIntrinsics.ll b/test/CodeGen/X86/SafeDivRemIntrinsics.ll
new file mode 100644 (file)
index 0000000..7480343
--- /dev/null
@@ -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 "}