summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakub Kuderski <jakub.kuderski@arm.com>2015-09-10 11:31:20 +0000
committerJakub Kuderski <jakub.kuderski@arm.com>2015-09-10 11:31:20 +0000
commit58ea4eeb9e812d7d9828f757ebfe7e574f92560b (patch)
tree7149adf7f40e48655db85b4d18e50b73701b39fe
parent5852e42949f42f2dae3b15fe3d52e9b7f62167d8 (diff)
downloadbcm5719-llvm-58ea4eeb9e812d7d9828f757ebfe7e574f92560b.tar.gz
bcm5719-llvm-58ea4eeb9e812d7d9828f757ebfe7e574f92560b.zip
There is a trunc(lshr (zext A), Cst) optimization in InstCombineCasts that
removes cast by performing the lshr on smaller types. However, currently there is no trunc(lshr (sext A), Cst) variant. This patch add such optimization by transforming trunc(lshr (sext A), Cst) to ashr A, Cst. Differential Revision: http://reviews.llvm.org/D12520 llvm-svn: 247271
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp20
-rw-r--r--llvm/test/Transforms/InstCombine/cast.ll48
2 files changed, 68 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index 768616f4233..89fd3de0b79 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -498,6 +498,26 @@ Instruction *InstCombiner::visitTrunc(TruncInst &CI) {
return CastInst::CreateIntegerCast(Shift, CI.getType(), false);
}
+ // Transform trunc(lshr (sext A), Cst) to ashr A, Cst to eliminate type
+ // conversion.
+ // It works because bits coming from sign extension have the same value as
+ // sign bit of the original value; performing ashr instead of lshr
+ // generates bits of the same value as the sign bit.
+ if (Src->hasOneUse() &&
+ match(Src, m_LShr(m_SExt(m_Value(A)), m_ConstantInt(Cst))) &&
+ cast<Instruction>(Src)->getOperand(0)->hasOneUse()) {
+ const unsigned ASize = A->getType()->getPrimitiveSizeInBits();
+ // This optimization can be only performed when zero bits generated by
+ // the original lshr aren't pulled into the value after truncation, so we
+ // can only shift by values smaller then the size of destination type (in
+ // bits).
+ if (Cst->getValue().ult(ASize)) {
+ Value *Shift = Builder->CreateAShr(A, Cst->getZExtValue());
+ Shift->takeName(Src);
+ return CastInst::CreateIntegerCast(Shift, CI.getType(), true);
+ }
+ }
+
// Transform "trunc (and X, cst)" -> "and (trunc X), cst" so long as the dest
// type isn't non-native.
if (Src->hasOneUse() && isa<IntegerType>(Src->getType()) &&
diff --git a/llvm/test/Transforms/InstCombine/cast.ll b/llvm/test/Transforms/InstCombine/cast.ll
index 7fe54ef8469..ba426c4a1ca 100644
--- a/llvm/test/Transforms/InstCombine/cast.ll
+++ b/llvm/test/Transforms/InstCombine/cast.ll
@@ -1062,6 +1062,43 @@ define i8 @test85(i32 %a) {
; CHECK: [[CST:%.*]] = trunc i32 [[SHR]] to i8
}
+define i16 @test86(i16 %v) {
+ %a = sext i16 %v to i32
+ %s = ashr i32 %a, 4
+ %t = trunc i32 %s to i16
+ ret i16 %t
+
+; CHECK-LABEL: @test86(
+; CHECK: [[ASHR:%.*]] = ashr i16 %v, 4
+; CHECK-NEXT: ret i16 [[ASHR]]
+}
+
+define i16 @test87(i16 %v) {
+ %c = sext i16 %v to i32
+ %m = mul nsw i32 %c, 16
+ %a = ashr i32 %m, 16
+ %t = trunc i32 %a to i16
+ ret i16 %t
+
+; CHECK-LABEL: @test87(
+; CHECK: [[ASHR:%.*]] = ashr i16 %v, 12
+; CHECK-NEXT: ret i16 [[ASHR]]
+}
+
+define i16 @test88(i16 %v) {
+ %a = sext i16 %v to i32
+ %s = ashr i32 %a, 18
+ %t = trunc i32 %s to i16
+ ret i16 %t
+
+; Do not optimize to ashr i16 (shift by 18)
+; CHECK-LABEL: @test88(
+; CHECK: [[SEXT:%.*]] = sext i16 %v to i32
+; CHECK-NEXT: [[ASHR:%.*]] = ashr i32 [[SEXT]], 18
+; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 [[ASHR]] to i16
+; CHECK-NEXT: ret i16 [[TRUNC]]
+}
+
; Overflow on a float to int or int to float conversion is undefined (PR21130).
define i8 @overflow_fptosi() {
@@ -1137,3 +1174,14 @@ define i1 @PR23309v2(i32 %A, i32 %B) {
%trunc = trunc i32 %sub to i1
ret i1 %trunc
}
+
+define i16 @PR24763(i8 %V) {
+; CHECK-LABEL: @PR24763(
+; CHECK-NEXT: %[[sh:.*]] = ashr i8
+; CHECK-NEXT: %[[ext:.*]] = sext i8 %[[sh]] to i16
+; CHECK-NEXT: ret i16 %[[ext]]
+ %conv = sext i8 %V to i32
+ %l = lshr i32 %conv, 1
+ %t = trunc i32 %l to i16
+ ret i16 %t
+}
OpenPOWER on IntegriCloud