aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2010-12-19 18:35:09 +0000
committerChris Lattner <sabre@nondot.org>2010-12-19 18:35:09 +0000
commit0a62474830f50b423329470caeb9a4e4da14a607 (patch)
treeff08ba86ca2158565d9c438e174ba0d1239d9d54
parentdd7e83737491b14ebf98e09fa6cb9b515f9f2e3e (diff)
generalize the sadd creation code to not require that the
sadd formed is half the size of the original type. We can now compile this into a sadd.i8: unsigned char X(char a, char b) { int res = a+b; if ((unsigned )(res+128) > 255U) abort(); return res; } git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@122178 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Transforms/InstCombine/InstCombineCompares.cpp55
-rw-r--r--test/Transforms/InstCombine/overflow.ll31
2 files changed, 43 insertions, 43 deletions
diff --git a/lib/Transforms/InstCombine/InstCombineCompares.cpp b/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 11426863f6..9f0fa3e740 100644
--- a/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -1635,54 +1635,31 @@ static Instruction *ProcessUGT_ADDCST_ADD(ICmpInst &I, Value *A, Value *B,
TI->getType()->getPrimitiveSizeInBits() > NewWidth) return 0;
}
- const IntegerType *WideType = cast<IntegerType>(CI1->getType());
- unsigned WideWidth = WideType->getBitWidth();
- unsigned NarrowWidth = WideWidth / 2;
- const IntegerType *NarrowType =
- IntegerType::get(CI1->getContext(), NarrowWidth);
-
- // NarrowAllOnes and NarrowSignBit are the magic constants used to
- // perform an overflow check in the wider type: 0x00..00FF..FF and
- // 0x00..0010..00 respectively, where the highest set bit in each is
- // what would be the sign bit in the narrower type.
- ConstantInt *NarrowAllOnes = cast<ConstantInt>(ConstantInt::get(WideType,
- APInt::getAllOnesValue(NarrowWidth).zext(WideWidth)));
- APInt SignBit(WideWidth, 0);
- SignBit.setBit(NarrowWidth-1);
- ConstantInt *NarrowSignBit =
- cast<ConstantInt>(ConstantInt::get(WideType, SignBit));
-
- if (CI1 != NarrowAllOnes || CI2 != NarrowSignBit)
- return 0;
-
- Module *M = I.getParent()->getParent()->getParent();
-
- const Type *IntrinsicType = NarrowType;
- Value *F = Intrinsic::getDeclaration(M, Intrinsic::sadd_with_overflow,
- &IntrinsicType, 1);
-
- BasicBlock *InitialBlock = Builder->GetInsertBlock();
- BasicBlock::iterator InitialInsert = Builder->GetInsertPoint();
-
// If the pattern matches, truncate the inputs to the narrower type and
// use the sadd_with_overflow intrinsic to efficiently compute both the
// result and the overflow bit.
- Builder->SetInsertPoint(OrigAdd->getParent(),
- BasicBlock::iterator(OrigAdd));
+ Module *M = I.getParent()->getParent()->getParent();
+
+ const Type *NewType = IntegerType::get(OrigAdd->getContext(), NewWidth);
+ Value *F = Intrinsic::getDeclaration(M, Intrinsic::sadd_with_overflow,
+ &NewType, 1);
+
+ // Put the new code above the original add, in case there are any uses of the
+ // add between the add and the compare.
+ Builder->SetInsertPoint(OrigAdd->getParent(), BasicBlock::iterator(OrigAdd));
- Value *TruncA = Builder->CreateTrunc(A, NarrowType, A->getName());
- Value *TruncB = Builder->CreateTrunc(B, NarrowType, B->getName());
- CallInst *Call = Builder->CreateCall2(F, TruncA, TruncB);
- Value *Add = Builder->CreateExtractValue(Call, 0);
- Value *ZExt = Builder->CreateZExt(Add, WideType);
+ Value *TruncA = Builder->CreateTrunc(A, NewType, A->getName()+".trunc");
+ Value *TruncB = Builder->CreateTrunc(B, NewType, B->getName()+".trunc");
+ CallInst *Call = Builder->CreateCall2(F, TruncA, TruncB, "sadd");
+ Value *Add = Builder->CreateExtractValue(Call, 0, "sadd.result");
+ Value *ZExt = Builder->CreateZExt(Add, OrigAdd->getType());
// The inner add was the result of the narrow add, zero extended to the
// wider type. Replace it with the result computed by the intrinsic.
OrigAdd->replaceAllUsesWith(ZExt);
- Builder->SetInsertPoint(InitialBlock, InitialInsert);
-
- return ExtractValueInst::Create(Call, 1);
+ // The original icmp gets replaced with the overflow value.
+ return ExtractValueInst::Create(Call, 1, "sadd.overflow");
}
diff --git a/test/Transforms/InstCombine/overflow.ll b/test/Transforms/InstCombine/overflow.ll
index da20e2c983..6a53d27749 100644
--- a/test/Transforms/InstCombine/overflow.ll
+++ b/test/Transforms/InstCombine/overflow.ll
@@ -1,7 +1,7 @@
; RUN: opt -S -instcombine < %s | FileCheck %s
; <rdar://problem/8558713>
-declare i32 @throwAnExceptionOrWhatever(...)
+declare void @throwAnExceptionOrWhatever()
; CHECK: @test1
define i32 @test1(i32 %a, i32 %b) nounwind ssp {
@@ -16,7 +16,7 @@ entry:
br i1 %0, label %if.then, label %if.end
if.then:
- %call = tail call i32 (...)* @throwAnExceptionOrWhatever() nounwind
+ tail call void @throwAnExceptionOrWhatever() nounwind
br label %if.end
if.end:
@@ -44,7 +44,7 @@ entry:
br i1 %0, label %if.then, label %if.end
if.then:
- %call = tail call i32 (...)* @throwAnExceptionOrWhatever() nounwind
+ tail call void @throwAnExceptionOrWhatever() nounwind
br label %if.end
if.end:
@@ -54,6 +54,7 @@ if.end:
}
; CHECK: test3
+; PR8816
; This is illegal to transform because the high bits of the original add are
; live out.
define i64 @test3(i32 %a, i32 %b) nounwind ssp {
@@ -67,10 +68,32 @@ entry:
br i1 %0, label %if.then, label %if.end
if.then:
- %call = tail call i32 (...)* @throwAnExceptionOrWhatever() nounwind
+ tail call void @throwAnExceptionOrWhatever() nounwind
br label %if.end
if.end:
ret i64 %add
; CHECK: ret i64
}
+
+; CHECK: @test4
+; Should be able to form an i8 sadd computed in an i32.
+define zeroext i8 @test4(i8 signext %a, i8 signext %b) nounwind ssp {
+entry:
+ %conv = sext i8 %a to i32
+ %conv2 = sext i8 %b to i32
+ %add = add nsw i32 %conv2, %conv
+ %add4 = add nsw i32 %add, 128
+ %cmp = icmp ugt i32 %add4, 255
+ br i1 %cmp, label %if.then, label %if.end
+; CHECK: llvm.sadd.with.overflow.i8
+if.then: ; preds = %entry
+ tail call void @throwAnExceptionOrWhatever() nounwind
+ unreachable
+
+if.end: ; preds = %entry
+ %conv7 = trunc i32 %add to i8
+ ret i8 %conv7
+; CHECK: ret i8
+}
+