return SinkCast(CI);
}
+static void replaceMathCmpWithIntrinsic(BinaryOperator *BO, CmpInst *Cmp,
+ Instruction *InsertPt,
+ Intrinsic::ID IID) {
+ IRBuilder<> Builder(InsertPt);
+ Value *MathOV = Builder.CreateBinaryIntrinsic(IID, BO->getOperand(0),
+ BO->getOperand(1));
+ Value *Math = Builder.CreateExtractValue(MathOV, 0, "math");
+ Value *OV = Builder.CreateExtractValue(MathOV, 1, "ov");
+ BO->replaceAllUsesWith(Math);
+ Cmp->replaceAllUsesWith(OV);
+ BO->eraseFromParent();
+ Cmp->eraseFromParent();
+}
+
/// Try to combine the compare into a call to the llvm.uadd.with.overflow
/// intrinsic. Return true if any changes were made.
static bool combineToUAddWithOverflow(CmpInst *Cmp, const TargetLowering &TLI,
const DataLayout &DL) {
Value *A, *B;
- Instruction *AddI;
- if (!match(Cmp,
- m_UAddWithOverflow(m_Value(A), m_Value(B), m_Instruction(AddI))))
+ BinaryOperator *Add;
+ if (!match(Cmp, m_UAddWithOverflow(m_Value(A), m_Value(B), m_BinOp(Add))))
return false;
// Allow the transform as long as we have an integer type that is not
// obviously illegal and unsupported.
- Type *Ty = AddI->getType();
+ Type *Ty = Add->getType();
if (!isa<IntegerType>(Ty))
return false;
EVT CodegenVT = TLI.getValueType(DL, Ty);
if (!CodegenVT.isSimple() && TLI.isOperationExpand(ISD::UADDO, CodegenVT))
return false;
- // We don't want to move around uses of condition values this late, so we we
+ // We don't want to move around uses of condition values this late, so we
// check if it is legal to create the call to the intrinsic in the basic
- // block containing the icmp:
- if (AddI->getParent() != Cmp->getParent() && !AddI->hasOneUse())
+ // block containing the icmp.
+ if (Add->getParent() != Cmp->getParent() && !Add->hasOneUse())
return false;
#ifndef NDEBUG
// Someday m_UAddWithOverflow may get smarter, but this is a safe assumption
// for now:
- if (AddI->hasOneUse())
- assert(*AddI->user_begin() == Cmp && "expected!");
+ if (Add->hasOneUse())
+ assert(*Add->user_begin() == Cmp && "expected!");
#endif
- Module *M = Cmp->getModule();
- Function *F = Intrinsic::getDeclaration(M, Intrinsic::uadd_with_overflow, Ty);
- Instruction *InsertPt = AddI->hasOneUse() ? Cmp : AddI;
- DebugLoc Loc = Cmp->getDebugLoc();
- Instruction *UAddWithOverflow = CallInst::Create(F, {A, B}, "uadd.overflow",
- InsertPt);
- UAddWithOverflow->setDebugLoc(Loc);
- Instruction *UAdd = ExtractValueInst::Create(UAddWithOverflow, 0, "uadd",
- InsertPt);
- UAdd->setDebugLoc(Loc);
- Instruction *Overflow = ExtractValueInst::Create(UAddWithOverflow, 1,
- "overflow", InsertPt);
- Overflow->setDebugLoc(Loc);
- Cmp->replaceAllUsesWith(Overflow);
- AddI->replaceAllUsesWith(UAdd);
- Cmp->eraseFromParent();
- AddI->eraseFromParent();
+ Instruction *InPt = Add->hasOneUse() ? cast<Instruction>(Cmp)
+ : cast<Instruction>(Add);
+ replaceMathCmpWithIntrinsic(Add, Cmp, InPt, Intrinsic::uadd_with_overflow);
return true;
}
define i64 @test1(i64 %a, i64 %b) nounwind ssp {
; CHECK-LABEL: @test1(
-; CHECK-NEXT: [[UADD_OVERFLOW:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[B:%.*]], i64 [[A:%.*]])
-; CHECK-NEXT: [[UADD:%.*]] = extractvalue { i64, i1 } [[UADD_OVERFLOW]], 0
-; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[UADD_OVERFLOW]], 1
-; CHECK-NEXT: [[Q:%.*]] = select i1 [[OVERFLOW]], i64 [[B]], i64 42
+; CHECK-NEXT: [[TMP1:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[B:%.*]], i64 [[A:%.*]])
+; CHECK-NEXT: [[MATH:%.*]] = extractvalue { i64, i1 } [[TMP1]], 0
+; CHECK-NEXT: [[OV:%.*]] = extractvalue { i64, i1 } [[TMP1]], 1
+; CHECK-NEXT: [[Q:%.*]] = select i1 [[OV]], i64 [[B]], i64 42
; CHECK-NEXT: ret i64 [[Q]]
;
%add = add i64 %b, %a
define i64 @test2(i64 %a, i64 %b) nounwind ssp {
; CHECK-LABEL: @test2(
-; CHECK-NEXT: [[UADD_OVERFLOW:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[B:%.*]], i64 [[A:%.*]])
-; CHECK-NEXT: [[UADD:%.*]] = extractvalue { i64, i1 } [[UADD_OVERFLOW]], 0
-; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[UADD_OVERFLOW]], 1
-; CHECK-NEXT: [[Q:%.*]] = select i1 [[OVERFLOW]], i64 [[B]], i64 42
+; CHECK-NEXT: [[TMP1:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[B:%.*]], i64 [[A:%.*]])
+; CHECK-NEXT: [[MATH:%.*]] = extractvalue { i64, i1 } [[TMP1]], 0
+; CHECK-NEXT: [[OV:%.*]] = extractvalue { i64, i1 } [[TMP1]], 1
+; CHECK-NEXT: [[Q:%.*]] = select i1 [[OV]], i64 [[B]], i64 42
; CHECK-NEXT: ret i64 [[Q]]
;
%add = add i64 %b, %a
define i64 @test3(i64 %a, i64 %b) nounwind ssp {
; CHECK-LABEL: @test3(
-; CHECK-NEXT: [[UADD_OVERFLOW:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[B:%.*]], i64 [[A:%.*]])
-; CHECK-NEXT: [[UADD:%.*]] = extractvalue { i64, i1 } [[UADD_OVERFLOW]], 0
-; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[UADD_OVERFLOW]], 1
-; CHECK-NEXT: [[Q:%.*]] = select i1 [[OVERFLOW]], i64 [[B]], i64 42
+; CHECK-NEXT: [[TMP1:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[B:%.*]], i64 [[A:%.*]])
+; CHECK-NEXT: [[MATH:%.*]] = extractvalue { i64, i1 } [[TMP1]], 0
+; CHECK-NEXT: [[OV:%.*]] = extractvalue { i64, i1 } [[TMP1]], 1
+; CHECK-NEXT: [[Q:%.*]] = select i1 [[OV]], i64 [[B]], i64 42
; CHECK-NEXT: ret i64 [[Q]]
;
%add = add i64 %b, %a
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[C:%.*]], label [[NEXT:%.*]], label [[EXIT:%.*]]
; CHECK: next:
-; CHECK-NEXT: [[UADD_OVERFLOW:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[B:%.*]], i64 [[A:%.*]])
-; CHECK-NEXT: [[UADD:%.*]] = extractvalue { i64, i1 } [[UADD_OVERFLOW]], 0
-; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[UADD_OVERFLOW]], 1
-; CHECK-NEXT: [[Q:%.*]] = select i1 [[OVERFLOW]], i64 [[B]], i64 42
+; CHECK-NEXT: [[TMP0:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[B:%.*]], i64 [[A:%.*]])
+; CHECK-NEXT: [[MATH:%.*]] = extractvalue { i64, i1 } [[TMP0]], 0
+; CHECK-NEXT: [[OV:%.*]] = extractvalue { i64, i1 } [[TMP0]], 1
+; CHECK-NEXT: [[Q:%.*]] = select i1 [[OV]], i64 [[B]], i64 42
; CHECK-NEXT: ret i64 [[Q]]
; CHECK: exit:
; CHECK-NEXT: ret i64 0
define i1 @uaddo_i64_increment(i64 %x, i64* %p) {
; CHECK-LABEL: @uaddo_i64_increment(
-; CHECK-NEXT: [[UADD_OVERFLOW:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[X:%.*]], i64 1)
-; CHECK-NEXT: [[UADD:%.*]] = extractvalue { i64, i1 } [[UADD_OVERFLOW]], 0
-; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[UADD_OVERFLOW]], 1
-; CHECK-NEXT: store i64 [[UADD]], i64* [[P:%.*]]
-; CHECK-NEXT: ret i1 [[OVERFLOW]]
+; CHECK-NEXT: [[TMP1:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[X:%.*]], i64 1)
+; CHECK-NEXT: [[MATH:%.*]] = extractvalue { i64, i1 } [[TMP1]], 0
+; CHECK-NEXT: [[OV1:%.*]] = extractvalue { i64, i1 } [[TMP1]], 1
+; CHECK-NEXT: store i64 [[MATH]], i64* [[P:%.*]]
+; CHECK-NEXT: ret i1 [[OV1]]
;
%a = add i64 %x, 1
%ov = icmp eq i64 %a, 0
define i1 @uaddo_i8_increment_noncanonical_1(i8 %x, i8* %p) {
; CHECK-LABEL: @uaddo_i8_increment_noncanonical_1(
-; CHECK-NEXT: [[UADD_OVERFLOW:%.*]] = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 1, i8 [[X:%.*]])
-; CHECK-NEXT: [[UADD:%.*]] = extractvalue { i8, i1 } [[UADD_OVERFLOW]], 0
-; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i8, i1 } [[UADD_OVERFLOW]], 1
-; CHECK-NEXT: store i8 [[UADD]], i8* [[P:%.*]]
-; CHECK-NEXT: ret i1 [[OVERFLOW]]
+; CHECK-NEXT: [[TMP1:%.*]] = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 1, i8 [[X:%.*]])
+; CHECK-NEXT: [[MATH:%.*]] = extractvalue { i8, i1 } [[TMP1]], 0
+; CHECK-NEXT: [[OV1:%.*]] = extractvalue { i8, i1 } [[TMP1]], 1
+; CHECK-NEXT: store i8 [[MATH]], i8* [[P:%.*]]
+; CHECK-NEXT: ret i1 [[OV1]]
;
%a = add i8 1, %x ; commute
%ov = icmp eq i8 %a, 0
define i1 @uaddo_i32_increment_noncanonical_2(i32 %x, i32* %p) {
; CHECK-LABEL: @uaddo_i32_increment_noncanonical_2(
-; CHECK-NEXT: [[UADD_OVERFLOW:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[X:%.*]], i32 1)
-; CHECK-NEXT: [[UADD:%.*]] = extractvalue { i32, i1 } [[UADD_OVERFLOW]], 0
-; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i32, i1 } [[UADD_OVERFLOW]], 1
-; CHECK-NEXT: store i32 [[UADD]], i32* [[P:%.*]]
-; CHECK-NEXT: ret i1 [[OVERFLOW]]
+; CHECK-NEXT: [[TMP1:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[X:%.*]], i32 1)
+; CHECK-NEXT: [[MATH:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0
+; CHECK-NEXT: [[OV1:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1
+; CHECK-NEXT: store i32 [[MATH]], i32* [[P:%.*]]
+; CHECK-NEXT: ret i1 [[OV1]]
;
%a = add i32 %x, 1
%ov = icmp eq i32 0, %a ; commute
define i1 @uaddo_i16_increment_noncanonical_3(i16 %x, i16* %p) {
; CHECK-LABEL: @uaddo_i16_increment_noncanonical_3(
-; CHECK-NEXT: [[UADD_OVERFLOW:%.*]] = call { i16, i1 } @llvm.uadd.with.overflow.i16(i16 1, i16 [[X:%.*]])
-; CHECK-NEXT: [[UADD:%.*]] = extractvalue { i16, i1 } [[UADD_OVERFLOW]], 0
-; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i16, i1 } [[UADD_OVERFLOW]], 1
-; CHECK-NEXT: store i16 [[UADD]], i16* [[P:%.*]]
-; CHECK-NEXT: ret i1 [[OVERFLOW]]
+; CHECK-NEXT: [[TMP1:%.*]] = call { i16, i1 } @llvm.uadd.with.overflow.i16(i16 1, i16 [[X:%.*]])
+; CHECK-NEXT: [[MATH:%.*]] = extractvalue { i16, i1 } [[TMP1]], 0
+; CHECK-NEXT: [[OV1:%.*]] = extractvalue { i16, i1 } [[TMP1]], 1
+; CHECK-NEXT: store i16 [[MATH]], i16* [[P:%.*]]
+; CHECK-NEXT: ret i1 [[OV1]]
;
%a = add i16 1, %x ; commute
%ov = icmp eq i16 0, %a ; commute