-
Notifications
You must be signed in to change notification settings - Fork 14.5k
[DemandedBits] Support non-constant shift amounts #148880
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
Open
karouzakisp
wants to merge
5
commits into
llvm:main
Choose a base branch
from
karouzakisp:demanded-bits-extra
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+584
−1
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
b802455
[LLVM] Enhance shift operators in the Demanded Bits Analysis
karouzakisp 289fb1c
[LLVM] created new tests for lshr and ashr, and updated the Range han…
karouzakisp 3a4d65e
removed comment
karouzakisp 4fbabd6
fixed or-->trunc->shl error, by updating the GetShiftedRange, needs m…
karouzakisp 23cea68
added more range tests
karouzakisp File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -76,6 +76,16 @@ void DemandedBits::determineLiveOperandBits( | |||||
computeKnownBits(V2, Known2, DL, &AC, UserI, &DT); | ||||||
} | ||||||
}; | ||||||
auto GetShiftedRange = [&](unsigned const Min, unsigned const Max, | ||||||
bool ShiftLeft) { | ||||||
using ShiftFn = APInt (APInt::*)(unsigned) const; | ||||||
auto Shift = ShiftLeft ? static_cast<ShiftFn>(&APInt::shl) | ||||||
: static_cast<ShiftFn>(&APInt::lshr); | ||||||
AB = APInt::getZero(BitWidth); | ||||||
for (unsigned ShiftAmount = Min; ShiftAmount <= Max; ++ShiftAmount) { | ||||||
AB |= (AOut.*Shift)(ShiftAmount); | ||||||
} | ||||||
}; | ||||||
|
||||||
switch (UserI->getOpcode()) { | ||||||
default: break; | ||||||
|
@@ -183,6 +193,17 @@ void DemandedBits::determineLiveOperandBits( | |||||
AB |= APInt::getHighBitsSet(BitWidth, ShiftAmt+1); | ||||||
else if (S->hasNoUnsignedWrap()) | ||||||
AB |= APInt::getHighBitsSet(BitWidth, ShiftAmt); | ||||||
} else { | ||||||
ComputeKnownBits(BitWidth, UserI->getOperand(1), nullptr); | ||||||
dtcxzyw marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
unsigned Min = Known.getMinValue().getLimitedValue(BitWidth - 1); | ||||||
unsigned Max = Known.getMaxValue().getLimitedValue(BitWidth - 1); | ||||||
// similar to Lshr case | ||||||
GetShiftedRange(Min, Max, /*ShiftLeft=*/false); | ||||||
const auto *S = cast<ShlOperator>(UserI); | ||||||
if (S->hasNoSignedWrap()) | ||||||
AB |= APInt::getHighBitsSet(BitWidth, Max + 1); | ||||||
else if (S->hasNoUnsignedWrap()) | ||||||
AB |= APInt::getHighBitsSet(BitWidth, Max); | ||||||
} | ||||||
} | ||||||
break; | ||||||
|
@@ -197,6 +218,20 @@ void DemandedBits::determineLiveOperandBits( | |||||
// (they must be zero). | ||||||
if (cast<LShrOperator>(UserI)->isExact()) | ||||||
AB |= APInt::getLowBitsSet(BitWidth, ShiftAmt); | ||||||
} else { | ||||||
ComputeKnownBits(BitWidth, UserI->getOperand(1), nullptr); | ||||||
unsigned Min = Known.getMinValue().getLimitedValue(BitWidth - 1); | ||||||
unsigned Max = Known.getMaxValue().getLimitedValue(BitWidth - 1); | ||||||
// Suppose AOut == 0b0000 1001 | ||||||
// [min, max] = [1, 3] | ||||||
// shift by 1 we get 0b0001 00100 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
// shift by 2 we get 0b0010 0100 | ||||||
// shift by 3 we get 0b0100 1000 | ||||||
// we take the or for every shift to cover all the positions. | ||||||
// | ||||||
GetShiftedRange(Min, Max, /*ShiftLeft=*/true); | ||||||
if (cast<LShrOperator>(UserI)->isExact()) | ||||||
AB |= APInt::getLowBitsSet(BitWidth, Max); | ||||||
} | ||||||
} | ||||||
break; | ||||||
|
@@ -217,6 +252,26 @@ void DemandedBits::determineLiveOperandBits( | |||||
// (they must be zero). | ||||||
if (cast<AShrOperator>(UserI)->isExact()) | ||||||
AB |= APInt::getLowBitsSet(BitWidth, ShiftAmt); | ||||||
} else { | ||||||
ComputeKnownBits(BitWidth, UserI->getOperand(1), nullptr); | ||||||
unsigned Min = Known.getMinValue().getLimitedValue(BitWidth - 1); | ||||||
unsigned Max = Known.getMaxValue().getLimitedValue(BitWidth - 1); | ||||||
GetShiftedRange(Min, Max, /*ShiftLeft=*/true); | ||||||
if (Max) { | ||||||
// Suppose AOut = 0011 1100 | ||||||
// [min, max] = [1, 3] | ||||||
// ShiftAmount = 1 : Mask is 1000 0000 | ||||||
// ShiftAmount = 2 : Mask is 1100 0000 | ||||||
// ShiftAmount = 3 : Mask is 1110 0000 | ||||||
// The Mask with Max covers every case in [min, max], | ||||||
// so we are done | ||||||
if ((AOut & APInt::getHighBitsSet(BitWidth, Max)).getBoolValue()) | ||||||
AB.setSignBit(); | ||||||
} | ||||||
// If the shift is exact, then the low bits are not dead | ||||||
// (they must be zero). | ||||||
if (cast<AShrOperator>(UserI)->isExact()) | ||||||
AB |= APInt::getLowBitsSet(BitWidth, Max); | ||||||
} | ||||||
} | ||||||
break; | ||||||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
; RUN: opt -S -disable-output -passes="print<demanded-bits>" < %s 2>&1 | FileCheck %s | ||
|
||
define i8 @test_ashr_const_amount_4(i32 %a) { | ||
; CHECK-LABEL: 'test_ashr_const_amount_4' | ||
; CHECK-DAG: DemandedBits: 0xff for %ashr = ashr i32 %a, 4 | ||
; CHECK-DAG: DemandedBits: 0xff0 for %a in %ashr = ashr i32 %a, 4 | ||
; CHECK-DAG: DemandedBits: 0xffffffff for 4 in %ashr = ashr i32 %a, 4 | ||
; CHECK-DAG: DemandedBits: 0xff for %ashr.t = trunc i32 %ashr to i8 | ||
; CHECK-DAG: DemandedBits: 0xff for %ashr in %ashr.t = trunc i32 %ashr to i8 | ||
; | ||
%ashr = ashr i32 %a, 4 | ||
%ashr.t = trunc i32 %ashr to i8 | ||
ret i8 %ashr.t | ||
} | ||
|
||
define i8 @test_ashr_const_amount_5(i32 %a) { | ||
; CHECK-LABEL: 'test_ashr_const_amount_5' | ||
; CHECK-DAG: DemandedBits: 0xff for %ashr = ashr i32 %a, 5 | ||
; CHECK-DAG: DemandedBits: 0x1fe0 for %a in %ashr = ashr i32 %a, 5 | ||
; CHECK-DAG: DemandedBits: 0xffffffff for 5 in %ashr = ashr i32 %a, 5 | ||
; CHECK-DAG: DemandedBits: 0xff for %ashr.t = trunc i32 %ashr to i8 | ||
; CHECK-DAG: DemandedBits: 0xff for %ashr in %ashr.t = trunc i32 %ashr to i8 | ||
; | ||
%ashr = ashr i32 %a, 5 | ||
%ashr.t = trunc i32 %ashr to i8 | ||
ret i8 %ashr.t | ||
} | ||
|
||
define i8 @test_ashr_const_amount_8(i32 %a) { | ||
; CHECK-LABEL: 'test_ashr_const_amount_8' | ||
; CHECK-DAG: DemandedBits: 0xff for %ashr = ashr i32 %a, 8 | ||
; CHECK-DAG: DemandedBits: 0xff00 for %a in %ashr = ashr i32 %a, 8 | ||
; CHECK-DAG: DemandedBits: 0xffffffff for 8 in %ashr = ashr i32 %a, 8 | ||
; CHECK-DAG: DemandedBits: 0xff for %ashr.t = trunc i32 %ashr to i8 | ||
; CHECK-DAG: DemandedBits: 0xff for %ashr in %ashr.t = trunc i32 %ashr to i8 | ||
; | ||
%ashr = ashr i32 %a, 8 | ||
%ashr.t = trunc i32 %ashr to i8 | ||
ret i8 %ashr.t | ||
} | ||
|
||
define i8 @test_ashr_const_amount_9(i32 %a) { | ||
|
||
; CHECK-LABEL: 'test_ashr_const_amount_9' | ||
; CHECK-DAG: DemandedBits: 0xff for %ashr.t = trunc i32 %ashr to i8 | ||
; CHECK-DAG: DemandedBits: 0xff for %ashr in %ashr.t = trunc i32 %ashr to i8 | ||
; CHECK-DAG: DemandedBits: 0xff for %ashr = ashr i32 %a, 8 | ||
; CHECK-DAG: DemandedBits: 0xff00 for %a in %ashr = ashr i32 %a, 8 | ||
; CHECK-DAG: DemandedBits: 0xffffffff for 8 in %ashr = ashr i32 %a, 8 | ||
; | ||
%ashr = ashr i32 %a, 8 | ||
%ashr.t = trunc i32 %ashr to i8 | ||
ret i8 %ashr.t | ||
} | ||
|
||
define i8 @test_ashr(i32 %a, i32 %b) { | ||
; CHECK-LABEL: 'test_ashr' | ||
; CHECK-DAG: DemandedBits: 0xff for %ashr = ashr i32 %a, %b | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %a in %ashr = ashr i32 %a, %b | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %b in %ashr = ashr i32 %a, %b | ||
; CHECK-DAG: DemandedBits: 0xff for %ashr.t = trunc i32 %ashr to i8 | ||
; CHECK-DAG: DemandedBits: 0xff for %ashr in %ashr.t = trunc i32 %ashr to i8 | ||
; | ||
%ashr = ashr i32 %a, %b | ||
%ashr.t = trunc i32 %ashr to i8 | ||
ret i8 %ashr.t | ||
} | ||
|
||
define i8 @test_ashr_range_1(i32 %a, i32 %b) { | ||
; CHECK-LABEL: 'test_ashr_range_1' | ||
; CHECK-DAG: DemandedBits: 0xff for %shl.t = trunc i32 %ashr to i8 | ||
; CHECK-DAG: DemandedBits: 0xff for %ashr in %shl.t = trunc i32 %ashr to i8 | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %b2 = and i32 %b, 3 | ||
; CHECK-DAG: DemandedBits: 0x3 for %b in %b2 = and i32 %b, 3 | ||
; CHECK-DAG: DemandedBits: 0xffffffff for 3 in %b2 = and i32 %b, 3 | ||
; CHECK-DAG: DemandedBits: 0xff for %ashr = ashr i32 %a, %b2 | ||
; CHECK-DAG: DemandedBits: 0x7ff for %a in %ashr = ashr i32 %a, %b2 | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %b2 in %ashr = ashr i32 %a, %b2 | ||
; | ||
%b2 = and i32 %b, 3 | ||
%ashr = ashr i32 %a, %b2 | ||
%shl.t = trunc i32 %ashr to i8 | ||
ret i8 %shl.t | ||
} | ||
|
||
define i32 @test_ashr_range_2(i32 %a, i32 %b) { | ||
; CHECK-LABEL: 'test_ashr_range_2' | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %b2 = and i32 %b, 3 | ||
; CHECK-DAG: DemandedBits: 0x3 for %b in %b2 = and i32 %b, 3 | ||
; CHECK-DAG: DemandedBits: 0xffffffff for 3 in %b2 = and i32 %b, 3 | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %ashr = ashr i32 %a, %b2 | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %a in %ashr = ashr i32 %a, %b2 | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %b2 in %ashr = ashr i32 %a, %b2 | ||
; | ||
%b2 = and i32 %b, 3 | ||
%ashr = ashr i32 %a, %b2 | ||
ret i32 %ashr | ||
} | ||
|
||
define i32 @test_ashr_range_3(i32 %a, i32 %b) { | ||
; CHECK-LABEL: 'test_ashr_range_3' | ||
; CHECK-DAG: DemandedBits: 0xffff for %ashr = ashr i32 %a, %b | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %a in %ashr = ashr i32 %a, %b | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %b in %ashr = ashr i32 %a, %b | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %shl = shl i32 %ashr, 16 | ||
; CHECK-DAG: DemandedBits: 0xffff for %ashr in %shl = shl i32 %ashr, 16 | ||
; CHECK-DAG: DemandedBits: 0xffffffff for 16 in %shl = shl i32 %ashr, 16 | ||
; | ||
%ashr = ashr i32 %a, %b | ||
%shl = shl i32 %ashr, 16 | ||
ret i32 %shl | ||
} | ||
define i32 @test_ashr_range_4(i32 %a, i32 %b) { | ||
; CHECK-LABEL: 'test_ashr_range_4' | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %shr = lshr i32 %ashr, 8 | ||
; CHECK-DAG: DemandedBits: 0xffffff00 for %ashr in %shr = lshr i32 %ashr, 8 | ||
; CHECK-DAG: DemandedBits: 0xffffffff for 8 in %shr = lshr i32 %ashr, 8 | ||
; CHECK-DAG: DemandedBits: 0xffffff00 for %ashr = ashr i32 %a, %b | ||
; CHECK-DAG: DemandedBits: 0xffffff00 for %a in %ashr = ashr i32 %a, %b | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %b in %ashr = ashr i32 %a, %b | ||
%ashr = ashr i32 %a, %b | ||
%shr = lshr i32 %ashr, 8 | ||
ret i32 %shr | ||
} | ||
|
||
define i32 @test_ashr_range_5(i32 %a, i32 %b) { | ||
; CHECK-LABEL: 'test_ashr_range_5' | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %2 = and i32 %1, 255 | ||
; CHECK-DAG: DemandedBits: 0xff for %1 in %2 = and i32 %1, 255 | ||
; CHECK-DAG: DemandedBits: 0xffffffff for 255 in %2 = and i32 %1, 255 | ||
; CHECK-DAG: DemandedBits: 0xff for %1 = ashr i32 %a, %b | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %a in %1 = ashr i32 %a, %b | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %b in %1 = ashr i32 %a, %b | ||
; | ||
%1 = ashr i32 %a, %b | ||
%2 = and i32 %1, 255 | ||
ret i32 %2 | ||
} | ||
|
||
define i32 @test_ashr_range_6(i32 %a, i32 %b) { | ||
; CHECK-LABEL: 'test_ashr_range_6' | ||
; CHECK-DAG: DemandedBits: 0xffff0000 for %lshr.1 = ashr i32 %a, %b | ||
; CHECK-DAG: DemandedBits: 0xffff0000 for %a in %lshr.1 = ashr i32 %a, %b | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %b in %lshr.1 = ashr i32 %a, %b | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %lshr.2 = ashr i32 %lshr.1, 16 | ||
; CHECK-DAG: DemandedBits: 0xffff0000 for %lshr.1 in %lshr.2 = ashr i32 %lshr.1, 16 | ||
; CHECK-DAG: DemandedBits: 0xffffffff for 16 in %lshr.2 = ashr i32 %lshr.1, 16 | ||
; | ||
%lshr.1 = ashr i32 %a, %b | ||
%lshr.2 = ashr i32 %lshr.1, 16 | ||
ret i32 %lshr.2 | ||
} | ||
|
||
define i8 @test_ashr_var_amount(i32 %a, i32 %b){ | ||
; CHECK-LABEL: 'test_ashr_var_amount' | ||
; CHECK-DAG: DemandedBits: 0xff for %4 = ashr i32 %1, %3 | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %1 in %4 = ashr i32 %1, %3 | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %3 in %4 = ashr i32 %1, %3 | ||
; CHECK-DAG: DemandedBits: 0xff for %2 = trunc i32 %1 to i8 | ||
; CHECK-DAG: DemandedBits: 0xff for %1 in %2 = trunc i32 %1 to i8 | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %1 = add nsw i32 %a, %b | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %a in %1 = add nsw i32 %a, %b | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %b in %1 = add nsw i32 %a, %b | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %3 = zext i8 %2 to i32 | ||
; CHECK-DAG: DemandedBits: 0xff for %2 in %3 = zext i8 %2 to i32 | ||
; CHECK-DAG: DemandedBits: 0xff for %5 = trunc i32 %4 to i8 | ||
; CHECK-DAG: DemandedBits: 0xff for %4 in %5 = trunc i32 %4 to i8 | ||
; | ||
%1 = add nsw i32 %a, %b | ||
%2 = trunc i32 %1 to i8 | ||
%3 = zext i8 %2 to i32 | ||
%4 = ashr i32 %1, %3 | ||
%5 = trunc i32 %4 to i8 | ||
ret i8 %5 | ||
} | ||
|
||
define i8 @test_ashr_var_amount_nsw(i32 %a, i32 %b){ | ||
; CHECK-LABEL 'test_ashr_var_amount_nsw' | ||
; CHECK-DAG: DemandedBits: 0xff for %5 = trunc i32 %4 to i8 | ||
; CHECK-DAG: DemandedBits: 0xff for %4 in %5 = trunc i32 %4 to i8 | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %1 = add nsw i32 %a, %b | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %a in %1 = add nsw i32 %a, %b | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %b in %1 = add nsw i32 %a, %b | ||
; CHECK-DAG: DemandedBits: 0xff for %2 = trunc i32 %1 to i8 | ||
; CHECK-DAG: DemandedBits: 0xff for %1 in %2 = trunc i32 %1 to i8 | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %3 = zext i8 %2 to i32 | ||
; CHECK-DAG: DemandedBits: 0xff for %2 in %3 = zext i8 %2 to i32 | ||
; CHECK-DAG: DemandedBits: 0xff for %4 = ashr exact i32 %1, %3 | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %1 in %4 = ashr exact i32 %1, %3 | ||
; CHECK-DAG: DemandedBits: 0xffffffff for %3 in %4 = ashr exact i32 %1, %3 | ||
; | ||
%1 = add nsw i32 %a, %b | ||
%2 = trunc i32 %1 to i8 | ||
%3 = zext i8 %2 to i32 | ||
%4 = ashr exact i32 %1, %3 | ||
%5 = trunc i32 %4 to i8 | ||
ret i8 %5 | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.