diff options
author | Sanjay Patel <spatel@rotateright.com> | 2017-08-15 18:25:52 +0000 |
---|---|---|
committer | Sanjay Patel <spatel@rotateright.com> | 2017-08-15 18:25:52 +0000 |
commit | d9d323f05677ccd05e8881df26ac0da6b3cf4ade (patch) | |
tree | 43ec4a2ecca62b044430af57dbbdf40bb9e8b740 | |
parent | c0f00a95161ed64a875fff62716aec60d2631ce8 (diff) |
[InstCombine] sink sext after ashr
Narrow ops are better for bit-tracking, and in the case of vectors,
may enable better codegen.
As the trunc test shows, this can allow follow-on simplifications.
There's a block of code in visitTrunc that deals with shifted ops
with FIXME comments. It may be possible to remove some of that now,
but I want to make sure there are no problems with this step first.
http://rise4fun.com/Alive/Y3a
Name: hoist_ashr_ahead_of_sext_1
%s = sext i8 %x to i32
%r = ashr i32 %s, 3 ; shift value is < than source bit width
=>
%a = ashr i8 %x, 3
%r = sext i8 %a to i32
Name: hoist_ashr_ahead_of_sext_2
%s = sext i8 %x to i32
%r = ashr i32 %s, 8 ; shift value is >= than source bit width
=>
%a = ashr i8 %x, 7 ; so clamp this shift value
%r = sext i8 %a to i32
Name: junc_the_trunc
%a = sext i16 %v to i32
%s = ashr i32 %a, 18
%t = trunc i32 %s to i16
=>
%t = ashr i16 %v, 15
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@310942 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Transforms/InstCombine/InstCombineShifts.cpp | 9 | ||||
-rw-r--r-- | test/Transforms/InstCombine/cast.ll | 7 | ||||
-rw-r--r-- | test/Transforms/InstCombine/shift-sra.ll | 20 |
3 files changed, 19 insertions, 17 deletions
diff --git a/lib/Transforms/InstCombine/InstCombineShifts.cpp b/lib/Transforms/InstCombine/InstCombineShifts.cpp index 098079abdf7..a19cdf7ef6d 100644 --- a/lib/Transforms/InstCombine/InstCombineShifts.cpp +++ b/lib/Transforms/InstCombine/InstCombineShifts.cpp @@ -803,6 +803,15 @@ Instruction *InstCombiner::visitAShr(BinaryOperator &I) { return BinaryOperator::CreateAShr(X, ConstantInt::get(Ty, AmtSum)); } + if (match(Op0, m_OneUse(m_SExt(m_Value(X)))) && + (Ty->isVectorTy() || shouldChangeType(Ty, X->getType()))) { + // ashr (sext X), C --> sext (ashr X, C') + Type *SrcTy = X->getType(); + ShAmt = std::min(ShAmt, SrcTy->getScalarSizeInBits() - 1); + Value *NewSh = Builder.CreateAShr(X, ConstantInt::get(SrcTy, ShAmt)); + return new SExtInst(NewSh, Ty); + } + // If the shifted-out value is known-zero, then this is an exact shift. if (!I.isExact() && MaskedValueIsZero(Op0, APInt::getLowBitsSet(BitWidth, ShAmt), 0, &I)) { diff --git a/test/Transforms/InstCombine/cast.ll b/test/Transforms/InstCombine/cast.ll index d121f62a55a..bc50f92056d 100644 --- a/test/Transforms/InstCombine/cast.ll +++ b/test/Transforms/InstCombine/cast.ll @@ -1302,13 +1302,10 @@ define i16 @test87(i16 %v) { ret i16 %t } -; Do not optimize to ashr i16 (shift by 18) define i16 @test88(i16 %v) { ; CHECK-LABEL: @test88( -; CHECK-NEXT: [[A:%.*]] = sext i16 %v to i32 -; CHECK-NEXT: [[S:%.*]] = ashr i32 [[A]], 18 -; CHECK-NEXT: [[T:%.*]] = trunc i32 [[S]] to i16 -; CHECK-NEXT: ret i16 [[T]] +; CHECK-NEXT: [[TMP1:%.*]] = ashr i16 %v, 15 +; CHECK-NEXT: ret i16 [[TMP1]] ; %a = sext i16 %v to i32 %s = ashr i32 %a, 18 diff --git a/test/Transforms/InstCombine/shift-sra.ll b/test/Transforms/InstCombine/shift-sra.ll index 8aaa1a5cb49..4c28e878bbe 100644 --- a/test/Transforms/InstCombine/shift-sra.ll +++ b/test/Transforms/InstCombine/shift-sra.ll @@ -163,13 +163,12 @@ define <2 x i32> @ashr_overshift_splat_vec(<2 x i32> %x) { ret <2 x i32> %sh2 } -; TODO: Prefer a narrow shift for better for bit-tracking. ; ashr (sext X), C --> sext (ashr X, C') define i32 @hoist_ashr_ahead_of_sext_1(i8 %x) { ; CHECK-LABEL: @hoist_ashr_ahead_of_sext_1( -; CHECK-NEXT: [[SEXT:%.*]] = sext i8 %x to i32 -; CHECK-NEXT: [[R:%.*]] = ashr i32 [[SEXT]], 3 +; CHECK-NEXT: [[TMP1:%.*]] = ashr i8 %x, 3 +; CHECK-NEXT: [[R:%.*]] = sext i8 [[TMP1]] to i32 ; CHECK-NEXT: ret i32 [[R]] ; %sext = sext i8 %x to i32 @@ -177,13 +176,12 @@ define i32 @hoist_ashr_ahead_of_sext_1(i8 %x) { ret i32 %r } -; TODO: Prefer a narrow shift for better for bit-tracking. ; ashr (sext X), C --> sext (ashr X, C') define <2 x i32> @hoist_ashr_ahead_of_sext_1_splat(<2 x i8> %x) { ; CHECK-LABEL: @hoist_ashr_ahead_of_sext_1_splat( -; CHECK-NEXT: [[SEXT:%.*]] = sext <2 x i8> %x to <2 x i32> -; CHECK-NEXT: [[R:%.*]] = ashr <2 x i32> [[SEXT]], <i32 3, i32 3> +; CHECK-NEXT: [[TMP1:%.*]] = ashr <2 x i8> %x, <i8 3, i8 3> +; CHECK-NEXT: [[R:%.*]] = sext <2 x i8> [[TMP1]] to <2 x i32> ; CHECK-NEXT: ret <2 x i32> [[R]] ; %sext = sext <2 x i8> %x to <2 x i32> @@ -191,13 +189,12 @@ define <2 x i32> @hoist_ashr_ahead_of_sext_1_splat(<2 x i8> %x) { ret <2 x i32> %r } -; TODO: Prefer a narrow shift for better for bit-tracking. ; ashr (sext X), C --> sext (ashr X, C') -- the shift amount must be clamped define i32 @hoist_ashr_ahead_of_sext_2(i8 %x) { ; CHECK-LABEL: @hoist_ashr_ahead_of_sext_2( -; CHECK-NEXT: [[SEXT:%.*]] = sext i8 %x to i32 -; CHECK-NEXT: [[R:%.*]] = ashr i32 [[SEXT]], 8 +; CHECK-NEXT: [[TMP1:%.*]] = ashr i8 %x, 7 +; CHECK-NEXT: [[R:%.*]] = sext i8 [[TMP1]] to i32 ; CHECK-NEXT: ret i32 [[R]] ; %sext = sext i8 %x to i32 @@ -205,13 +202,12 @@ define i32 @hoist_ashr_ahead_of_sext_2(i8 %x) { ret i32 %r } -; TODO: Prefer a narrow shift for better for bit-tracking. ; ashr (sext X), C --> sext (ashr X, C') -- the shift amount must be clamped define <2 x i32> @hoist_ashr_ahead_of_sext_2_splat(<2 x i8> %x) { ; CHECK-LABEL: @hoist_ashr_ahead_of_sext_2_splat( -; CHECK-NEXT: [[SEXT:%.*]] = sext <2 x i8> %x to <2 x i32> -; CHECK-NEXT: [[R:%.*]] = ashr <2 x i32> [[SEXT]], <i32 8, i32 8> +; CHECK-NEXT: [[TMP1:%.*]] = ashr <2 x i8> %x, <i8 7, i8 7> +; CHECK-NEXT: [[R:%.*]] = sext <2 x i8> [[TMP1]] to <2 x i32> ; CHECK-NEXT: ret <2 x i32> [[R]] ; %sext = sext <2 x i8> %x to <2 x i32> |