-
Notifications
You must be signed in to change notification settings - Fork 74
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
dialects: (builtin) add IntegerAttr truncation and use in individual rewrite #3585
base: main
Are you sure you want to change the base?
Changes from all commits
1f3bd5c
e08a833
0996e35
cae1259
2a8f874
123638a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// RUN:xdsl-opt %s --split-input-file -p 'apply-individual-rewrite{matched_operation_index=2 operation_name="arith.addi" pattern_name="AdditionOfSameVariablesToMultiplyByTwo"}'| filecheck %s | ||
|
||
|
||
// CHECK: %v = "test.op"() : () -> i32 | ||
// CHECK-NEXT: %[[#two:]] = arith.constant 2 : i32 | ||
// CHECK-NEXT: %{{.*}} = arith.muli %v, %[[#two]] : i32 | ||
|
||
%v = "test.op"() : () -> (i32) | ||
%1 = arith.addi %v, %v : i32 | ||
|
||
// ----- | ||
|
||
// CHECK: %v = "test.op"() : () -> i1 | ||
// CHECK-NEXT: %[[#zero:]] = arith.constant false | ||
// CHECK-NEXT: %{{.*}} = arith.muli %v, %[[#zero]] : i1 | ||
|
||
%v = "test.op"() : () -> (i1) | ||
%1 = arith.addi %v, %v : i1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -397,21 +397,26 @@ def verify_value(self, value: int): | |
f"values in the range [{min_value}, {max_value})" | ||
) | ||
|
||
def normalized_value(self, value: IntAttr) -> IntAttr | None: | ||
def normalized_value( | ||
self, value: IntAttr, *, truncate_bits: bool = False | ||
) -> IntAttr | None: | ||
""" | ||
Signless values can represent integers from both the signed and unsigned ranges | ||
for a given bitwidth. | ||
We choose to normalize values that are not in the intersection of the two ranges | ||
to the signed version (meaning ambiguous values will always be negative). | ||
For example, the bitpattern of all ones will always be represented as `-1` at | ||
runtime. | ||
If the input value is outside of the valid range, return `None`. | ||
If the input value is outside of the valid range, return `None` if `truncate_bits` | ||
is false, otherwise returns a value in range by truncating the bits of the input. | ||
""" | ||
min_value, max_value = self.value_range() | ||
if not (min_value <= value.data < max_value): | ||
return None | ||
if not truncate_bits: | ||
return None | ||
value = IntAttr(value.data % (2**self.bitwidth)) | ||
|
||
if self.signedness.data == Signedness.SIGNLESS: | ||
if self.signedness.data != Signedness.UNSIGNED: | ||
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. why this change? 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. Doing the bitwise and seems to wrap everything into the range [0,2**bitwidth), so for the signed case we need to normalise it back to the correct range. This seemed like the easiest way to do this but it could be refactored |
||
signed_ub = signed_upper_bound(self.bitwidth) | ||
unsigned_ub = unsigned_upper_bound(self.bitwidth) | ||
if signed_ub <= value.data: | ||
|
@@ -509,22 +514,34 @@ def __init__( | |
self, | ||
value: int | IntAttr, | ||
value_type: _IntegerAttrType, | ||
*, | ||
truncate_bits: bool = False, | ||
) -> None: ... | ||
|
||
@overload | ||
def __init__( | ||
self: IntegerAttr[IntegerType], value: int | IntAttr, value_type: int | ||
self: IntegerAttr[IntegerType], | ||
value: int | IntAttr, | ||
value_type: int, | ||
*, | ||
truncate_bits: bool = False, | ||
) -> None: ... | ||
|
||
def __init__( | ||
self, value: int | IntAttr, value_type: int | IntegerType | IndexType | ||
self, | ||
value: int | IntAttr, | ||
value_type: int | IntegerType | IndexType, | ||
*, | ||
truncate_bits: bool = False, | ||
) -> None: | ||
if isinstance(value_type, int): | ||
value_type = IntegerType(value_type) | ||
if isinstance(value, int): | ||
value = IntAttr(value) | ||
if not isinstance(value_type, IndexType): | ||
normalized_value = value_type.normalized_value(value) | ||
normalized_value = value_type.normalized_value( | ||
value, truncate_bits=truncate_bits | ||
) | ||
if normalized_value is not None: | ||
value = normalized_value | ||
super().__init__([value, value_type]) | ||
|
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.
I think a name like
wrapping
would be clearer thantruncate_bits
.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.
Hmm, what's it wrapping?
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.
Wrapping the int into the range. For what it's worth the overflow flags use the word wrap
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.
Yes, and truncating has already a meaning in LLVM/arith, which is to go from let's say i32 to i16, which is not really what we are doing here
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.
But wrapping is a feature of the operation, not of a value normalization step. I'm happy for an addition to be wrapping, but it seems a bit out of context here.
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.
Here's the relevant API that I have most experience with https://developer.apple.com/documentation/swift/int/init(truncating:)
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.
Did we come to a conclusion?
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.
We can hash it out on the zulip if you want, I'm happy to be outvoted if you both think wrapping is more intuitive here