diff options
| -rw-r--r-- | llvm/lib/CodeGen/CodeGenPrepare.cpp | 51 | ||||
| -rw-r--r-- | llvm/test/Transforms/CodeGenPrepare/X86/overflow-intrinsics.ll | 72 |
2 files changed, 61 insertions, 62 deletions
diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp index bcb899a9e02..4792e810a85 100644 --- a/llvm/lib/CodeGen/CodeGenPrepare.cpp +++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp @@ -1147,55 +1147,54 @@ static bool OptimizeNoopCopyExpression(CastInst *CI, const TargetLowering &TLI, 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; } diff --git a/llvm/test/Transforms/CodeGenPrepare/X86/overflow-intrinsics.ll b/llvm/test/Transforms/CodeGenPrepare/X86/overflow-intrinsics.ll index 6be9661cc63..9b881866cef 100644 --- a/llvm/test/Transforms/CodeGenPrepare/X86/overflow-intrinsics.ll +++ b/llvm/test/Transforms/CodeGenPrepare/X86/overflow-intrinsics.ll @@ -7,10 +7,10 @@ target triple = "x86_64-apple-darwin10.0.0" 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 @@ -21,10 +21,10 @@ define i64 @test1(i64 %a, i64 %b) nounwind ssp { 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 @@ -35,10 +35,10 @@ define i64 @test2(i64 %a, i64 %b) nounwind ssp { 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 @@ -52,10 +52,10 @@ define i64 @test4(i64 %a, i64 %b, i1 %c) nounwind ssp { ; 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 @@ -105,11 +105,11 @@ exit: 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 @@ -119,11 +119,11 @@ define i1 @uaddo_i64_increment(i64 %x, i64* %p) { 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 @@ -133,11 +133,11 @@ define i1 @uaddo_i8_increment_noncanonical_1(i8 %x, i8* %p) { 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 @@ -147,11 +147,11 @@ define i1 @uaddo_i32_increment_noncanonical_2(i32 %x, i32* %p) { 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 |

