Skip to content

[ValueTracking] Add rotate idiom to haveNoCommonBitsSet special cases #122165

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions llvm/lib/Analysis/ValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,19 @@ static bool haveNoCommonBitsSetSpecialCases(const Value *LHS, const Value *RHS,
return true;
}

// Look for: (X << V) op (Y >> (BitWidth - V))
// or (X >> V) op (Y << (BitWidth - V))
{
const Value *V;
const APInt *R;
if (((match(RHS, m_Shl(m_Value(), m_Sub(m_APInt(R), m_Value(V)))) &&
match(LHS, m_LShr(m_Value(), m_Specific(V)))) ||
(match(RHS, m_LShr(m_Value(), m_Sub(m_APInt(R), m_Value(V)))) &&
match(LHS, m_Shl(m_Value(), m_Specific(V))))) &&
R->uge(LHS->getType()->getScalarSizeInBits()))
return true;
}

return false;
}

Expand Down
117 changes: 111 additions & 6 deletions llvm/test/Transforms/InstCombine/rotate.ll
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ define i32 @rotl_i32(i32 %x, i32 %y) {
; CHECK-NEXT: [[SUB:%.*]] = sub i32 32, [[Y:%.*]]
; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[X:%.*]], [[Y]]
; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[X]], [[SUB]]
; CHECK-NEXT: [[R:%.*]] = or i32 [[SHR]], [[SHL]]
; CHECK-NEXT: [[R:%.*]] = or disjoint i32 [[SHR]], [[SHL]]
; CHECK-NEXT: ret i32 [[R]]
;
%sub = sub i32 32, %y
Expand All @@ -208,7 +208,7 @@ define i37 @rotr_i37(i37 %x, i37 %y) {
; CHECK-NEXT: [[SUB:%.*]] = sub i37 37, [[Y:%.*]]
; CHECK-NEXT: [[SHL:%.*]] = shl i37 [[X:%.*]], [[SUB]]
; CHECK-NEXT: [[SHR:%.*]] = lshr i37 [[X]], [[Y]]
; CHECK-NEXT: [[R:%.*]] = or i37 [[SHR]], [[SHL]]
; CHECK-NEXT: [[R:%.*]] = or disjoint i37 [[SHR]], [[SHL]]
; CHECK-NEXT: ret i37 [[R]]
;
%sub = sub i37 37, %y
Expand All @@ -225,7 +225,7 @@ define i8 @rotr_i8_commute(i8 %x, i8 %y) {
; CHECK-NEXT: [[SUB:%.*]] = sub i8 8, [[Y:%.*]]
; CHECK-NEXT: [[SHL:%.*]] = shl i8 [[X:%.*]], [[SUB]]
; CHECK-NEXT: [[SHR:%.*]] = lshr i8 [[X]], [[Y]]
; CHECK-NEXT: [[R:%.*]] = or i8 [[SHL]], [[SHR]]
; CHECK-NEXT: [[R:%.*]] = or disjoint i8 [[SHL]], [[SHR]]
; CHECK-NEXT: ret i8 [[R]]
;
%sub = sub i8 8, %y
Expand All @@ -242,7 +242,7 @@ define <4 x i32> @rotl_v4i32(<4 x i32> %x, <4 x i32> %y) {
; CHECK-NEXT: [[SUB:%.*]] = sub <4 x i32> splat (i32 32), [[Y:%.*]]
; CHECK-NEXT: [[SHL:%.*]] = shl <4 x i32> [[X:%.*]], [[Y]]
; CHECK-NEXT: [[SHR:%.*]] = lshr <4 x i32> [[X]], [[SUB]]
; CHECK-NEXT: [[R:%.*]] = or <4 x i32> [[SHL]], [[SHR]]
; CHECK-NEXT: [[R:%.*]] = or disjoint <4 x i32> [[SHL]], [[SHR]]
; CHECK-NEXT: ret <4 x i32> [[R]]
;
%sub = sub <4 x i32> <i32 32, i32 32, i32 32, i32 32>, %y
Expand All @@ -259,7 +259,7 @@ define <3 x i42> @rotr_v3i42(<3 x i42> %x, <3 x i42> %y) {
; CHECK-NEXT: [[SUB:%.*]] = sub <3 x i42> splat (i42 42), [[Y:%.*]]
; CHECK-NEXT: [[SHL:%.*]] = shl <3 x i42> [[X:%.*]], [[SUB]]
; CHECK-NEXT: [[SHR:%.*]] = lshr <3 x i42> [[X]], [[Y]]
; CHECK-NEXT: [[R:%.*]] = or <3 x i42> [[SHR]], [[SHL]]
; CHECK-NEXT: [[R:%.*]] = or disjoint <3 x i42> [[SHR]], [[SHL]]
; CHECK-NEXT: ret <3 x i42> [[R]]
;
%sub = sub <3 x i42> <i42 42, i42 42, i42 42>, %y
Expand Down Expand Up @@ -838,7 +838,7 @@ define i24 @rotl_select_weird_type(i24 %x, i24 %shamt) {
; CHECK-NEXT: [[SUB:%.*]] = sub i24 24, [[SHAMT]]
; CHECK-NEXT: [[SHR:%.*]] = lshr i24 [[X:%.*]], [[SUB]]
; CHECK-NEXT: [[SHL:%.*]] = shl i24 [[X]], [[SHAMT]]
; CHECK-NEXT: [[OR:%.*]] = or i24 [[SHL]], [[SHR]]
; CHECK-NEXT: [[OR:%.*]] = or disjoint i24 [[SHL]], [[SHR]]
; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP]], i24 [[X]], i24 [[OR]]
; CHECK-NEXT: ret i24 [[R]]
;
Expand Down Expand Up @@ -981,3 +981,108 @@ define i16 @check_rotate_masked_16bit(i8 %shamt, i32 %cond) {
%trunc = trunc i32 %or to i16
ret i16 %trunc
}

define i32 @rotl_i32_add(i32 %x, i32 %y) {
; CHECK-LABEL: @rotl_i32_add(
; CHECK-NEXT: [[SUB:%.*]] = sub i32 32, [[Y:%.*]]
; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[X:%.*]], [[Y]]
; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[X]], [[SUB]]
; CHECK-NEXT: [[R:%.*]] = or disjoint i32 [[SHR]], [[SHL]]
; CHECK-NEXT: ret i32 [[R]]
;
%sub = sub i32 32, %y
%shl = shl i32 %x, %y
%shr = lshr i32 %x, %sub
%r = add i32 %shr, %shl
ret i32 %r
}

define i32 @rotr_i32_add(i32 %x, i32 %y) {
; CHECK-LABEL: @rotr_i32_add(
; CHECK-NEXT: [[SUB:%.*]] = sub i32 32, [[Y:%.*]]
; CHECK-NEXT: [[SHL:%.*]] = lshr i32 [[X:%.*]], [[Y]]
; CHECK-NEXT: [[SHR:%.*]] = shl i32 [[X]], [[SUB]]
; CHECK-NEXT: [[R:%.*]] = or disjoint i32 [[SHR]], [[SHL]]
; CHECK-NEXT: ret i32 [[R]]
;
%sub = sub i32 32, %y
%shl = lshr i32 %x, %y
%shr = shl i32 %x, %sub
%r = add i32 %shr, %shl
ret i32 %r
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please also add tests for the additional cases you handle, i.e. the shift LHS being different values, and the constant being > bitwidth?

We should also have a negative test where the constant is < bitwidth.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, I've added all these cases.


define i32 @fshr_i32_add(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @fshr_i32_add(
; CHECK-NEXT: [[SUB:%.*]] = sub i32 32, [[Z:%.*]]
; CHECK-NEXT: [[SHL:%.*]] = lshr i32 [[X:%.*]], [[Z]]
; CHECK-NEXT: [[SHR:%.*]] = shl i32 [[Y:%.*]], [[SUB]]
; CHECK-NEXT: [[R:%.*]] = or disjoint i32 [[SHR]], [[SHL]]
; CHECK-NEXT: ret i32 [[R]]
;
%sub = sub i32 32, %z
%shl = lshr i32 %x, %z
%shr = shl i32 %y, %sub
%r = add i32 %shr, %shl
ret i32 %r
}

define i32 @fshl_i32_add(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @fshl_i32_add(
; CHECK-NEXT: [[SUB:%.*]] = sub i32 32, [[Z:%.*]]
; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[Y:%.*]], [[Z]]
; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[X:%.*]], [[SUB]]
; CHECK-NEXT: [[R:%.*]] = or disjoint i32 [[SHR]], [[SHL]]
; CHECK-NEXT: ret i32 [[R]]
;
%sub = sub i32 32, %z
%shl = shl i32 %y, %z
%shr = lshr i32 %x, %sub
%r = add i32 %shr, %shl
ret i32 %r
}

define i32 @rotl_i32_add_greater(i32 %x, i32 %y) {
; CHECK-LABEL: @rotl_i32_add_greater(
; CHECK-NEXT: [[SUB:%.*]] = sub i32 33, [[Y:%.*]]
; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[X:%.*]], [[Y]]
; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[X]], [[SUB]]
; CHECK-NEXT: [[R:%.*]] = or disjoint i32 [[SHR]], [[SHL]]
; CHECK-NEXT: ret i32 [[R]]
;
%sub = sub i32 33, %y
%shl = shl i32 %x, %y
%shr = lshr i32 %x, %sub
%r = add i32 %shr, %shl
ret i32 %r
}

define i32 @rotr_i32_add_greater(i32 %x, i32 %y) {
; CHECK-LABEL: @rotr_i32_add_greater(
; CHECK-NEXT: [[SUB:%.*]] = sub i32 34, [[Y:%.*]]
; CHECK-NEXT: [[SHL:%.*]] = lshr i32 [[X:%.*]], [[Y]]
; CHECK-NEXT: [[SHR:%.*]] = shl i32 [[X]], [[SUB]]
; CHECK-NEXT: [[R:%.*]] = or disjoint i32 [[SHR]], [[SHL]]
; CHECK-NEXT: ret i32 [[R]]
;
%sub = sub i32 34, %y
%shl = lshr i32 %x, %y
%shr = shl i32 %x, %sub
%r = add i32 %shr, %shl
ret i32 %r
}

define i32 @not_rotl_i32_add_less(i32 %x, i32 %y) {
; CHECK-LABEL: @not_rotl_i32_add_less(
; CHECK-NEXT: [[SUB:%.*]] = sub i32 31, [[Y:%.*]]
; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[X:%.*]], [[Y]]
; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[X]], [[SUB]]
; CHECK-NEXT: [[R:%.*]] = add i32 [[SHR]], [[SHL]]
; CHECK-NEXT: ret i32 [[R]]
;
%sub = sub i32 31, %y
%shl = shl i32 %x, %y
%shr = lshr i32 %x, %sub
%r = add i32 %shr, %shl
ret i32 %r
}
Loading