Skip to content

Commit

Permalink
[InstCombine] try to fold low-mask of ashr to lshr
Browse files Browse the repository at this point in the history
With one-use, we handle this via demanded-bits.
But We need to handle extra uses to improve issue #54750.

https://alive2.llvm.org/ce/z/aDYkPv
(cherry picked from commit 7783db5)
  • Loading branch information
rotateright authored and tstellar committed Apr 14, 2022
1 parent 5ea5e3c commit 43ee392
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 4 deletions.
6 changes: 6 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1961,6 +1961,12 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
}
}

// If this 'and' clears the sign-bits added by ashr, replace with lshr:
// and (ashr X, ShiftC), C --> lshr X, ShiftC
if (match(Op0, m_AShr(m_Value(X), m_APInt(ShiftC))) && ShiftC->ult(Width) &&
C->isMask(Width - ShiftC->getZExtValue()))
return BinaryOperator::CreateLShr(X, ConstantInt::get(Ty, *ShiftC));

const APInt *AddC;
if (match(Op0, m_Add(m_Value(X), m_APInt(AddC)))) {
// If we add zeros to every bit below a mask, the add has no effect:
Expand Down
14 changes: 10 additions & 4 deletions llvm/test/Transforms/InstCombine/and.ll
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ define i32 @ashr_lowmask_use(i32 %x) {
; CHECK-LABEL: @ashr_lowmask_use(
; CHECK-NEXT: [[A:%.*]] = ashr i32 [[X:%.*]], 1
; CHECK-NEXT: call void @use32(i32 [[A]])
; CHECK-NEXT: [[R:%.*]] = and i32 [[A]], 2147483647
; CHECK-NEXT: [[R:%.*]] = lshr i32 [[X]], 1
; CHECK-NEXT: ret i32 [[R]]
;
%a = ashr i32 %x, 1
Expand All @@ -419,7 +419,7 @@ define <2 x i8> @ashr_lowmask_use_splat(<2 x i8> %x, <2 x i8>* %p) {
; CHECK-LABEL: @ashr_lowmask_use_splat(
; CHECK-NEXT: [[A:%.*]] = ashr <2 x i8> [[X:%.*]], <i8 7, i8 7>
; CHECK-NEXT: store <2 x i8> [[A]], <2 x i8>* [[P:%.*]], align 2
; CHECK-NEXT: [[R:%.*]] = and <2 x i8> [[A]], <i8 1, i8 1>
; CHECK-NEXT: [[R:%.*]] = lshr <2 x i8> [[X]], <i8 7, i8 7>
; CHECK-NEXT: ret <2 x i8> [[R]]
;
%a = ashr <2 x i8> %x, <i8 7, i8 7>
Expand All @@ -428,6 +428,8 @@ define <2 x i8> @ashr_lowmask_use_splat(<2 x i8> %x, <2 x i8>* %p) {
ret <2 x i8> %r
}

; negative test - must keep all low bits

define i32 @ashr_not_lowmask1_use(i32 %x) {
; CHECK-LABEL: @ashr_not_lowmask1_use(
; CHECK-NEXT: [[A:%.*]] = ashr i32 [[X:%.*]], 24
Expand All @@ -441,6 +443,8 @@ define i32 @ashr_not_lowmask1_use(i32 %x) {
ret i32 %r
}

; negative test - must keep all low bits

define i32 @ashr_not_lowmask2_use(i32 %x) {
; CHECK-LABEL: @ashr_not_lowmask2_use(
; CHECK-NEXT: [[A:%.*]] = ashr i32 [[X:%.*]], 24
Expand All @@ -454,6 +458,8 @@ define i32 @ashr_not_lowmask2_use(i32 %x) {
ret i32 %r
}

; negative test - must keep only low bits

define i32 @ashr_not_lowmask3_use(i32 %x) {
; CHECK-LABEL: @ashr_not_lowmask3_use(
; CHECK-NEXT: [[A:%.*]] = ashr i32 [[X:%.*]], 24
Expand Down Expand Up @@ -1231,14 +1237,14 @@ define i32 @lowmask_sext_in_reg(i32 %x) {
ret i32 %and
}

; Negative test - mismatched shift amounts
; Mismatched shift amounts, but the mask op can be replaced by a shift.

define i32 @lowmask_not_sext_in_reg(i32 %x) {
; CHECK-LABEL: @lowmask_not_sext_in_reg(
; CHECK-NEXT: [[L:%.*]] = shl i32 [[X:%.*]], 19
; CHECK-NEXT: [[R:%.*]] = ashr i32 [[L]], 20
; CHECK-NEXT: call void @use32(i32 [[R]])
; CHECK-NEXT: [[AND:%.*]] = and i32 [[R]], 4095
; CHECK-NEXT: [[AND:%.*]] = lshr i32 [[L]], 20
; CHECK-NEXT: ret i32 [[AND]]
;
%l = shl i32 %x, 19
Expand Down

0 comments on commit 43ee392

Please sign in to comment.