-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
ISLE: rewrite and
/or
of icmp
#6095
Conversation
and
/or
of icmp
and
/or
of icmp
5b7f8af
to
0bb6e69
Compare
I think we can factor these rules in a different way to reduce a bunch of the duplication. But I haven't figured out the details. I was fiddling with ideas like the following, though I'm not sure if this actually turns out any shorter: (decl pure partial eq_implies (Value Value Value) bool)
(rule (eq_implies x y (eq x y)) $true)
(rule (eq_implies x y (eq y x)) $true)
(rule (eq_implies x y (ule x y)) $true)
(rule (eq_implies x y (uge x y)) $true)
(rule (eq_implies x y (sle x y)) $true)
(rule (eq_implies x y (sge x y)) $true)
(rule (eq_implies x y (ne x y)) $false)
(rule (eq_implies x y (ne y x)) $false)
(rule (eq_implies x y (ult x y)) $false)
(rule (eq_implies x y (ugt x y)) $false)
(rule (eq_implies x y (slt x y)) $false)
(rule (eq_implies x y (sgt x y)) $false)
(decl pure partial ult_implies (Value Value Value) bool)
(rule (ult_implies x y (eq x y)) $false)
(rule (ult_implies x y (eq y x)) $false)
(rule (ult_implies x y (ne x y)) $true)
(rule (ult_implies x y (ne y x)) $true)
(rule (ult_implies x y (ult x y)) $true)
(rule (ult_implies x y (ule x y)) $true)
(rule (ult_implies x y (uge x y)) $false)
(rule (ult_implies x y (ugt x y)) $false)
(rule (simplify (band ty (eq x y) other))
(if-let $true (eq_implies x y other))
(subsume (iconst ty 1)))
(rule (simplify (band ty other (eq x y)))
(if-let $true (eq_implies x y other))
(subsume (iconst ty 1)))
(rule (simplify (band ty (eq x y) other))
(if-let $false (eq_implies x y other))
(subsume (iconst ty 0))) |
I think this would work out to being basically the same length. We could remove half the cases by adding rules to make |
I've been unable to let go of this and just enjoy my weekend, so: Can we do it this way? Decompose both condition codes into separate "less than", "equal to", and "greater than" booleans, then pairwise apply "and"/"or" to the booleans according to whether the comparisons were combined with (decl pure decompose_intcc (IntCC) u64)
(rule (decompose_intcc IntCC.Equal) 1)
(rule (decompose_intcc IntCC.UnsignedLessThan) 2)
(rule (decompose_intcc IntCC.UnsignedLessThanOrEqual) 3)
(rule (decompose_intcc IntCC.UnsignedGreaterThan) 4)
(rule (decompose_intcc IntCC.UnsignedGreaterThanOrEqual) 5)
(rule (decompose_intcc IntCC.NotEqual) 6)
(decl pure partial compose_intcc (u64) IntCC)
; inverse of `decompose_intcc`
(rule (simplify (band ty (icmp ty cc1 x y) (icmp ty cc2 x y)))
(if-let cc (compose_intcc (u64_and (decompose_intcc cc1) (decompose_intcc cc2))))
(icmp ty cc x y))
(rule (simplify (band ty (icmp ty cc1 x y) (icmp ty cc2 x y)))
(if-let 0 (u64_and (decompose_intcc cc1) (decompose_intcc cc2)))
(subsume (iconst ty (imm64 0))))
(rule (simplify (bor ty (icmp ty cc1 x y) (icmp ty cc2 x y)))
(if-let cc (compose_intcc (u64_or (decompose_intcc cc1) (decompose_intcc cc2))))
(icmp ty cc x y))
(rule (simplify (bor ty (icmp ty cc1 x y) (icmp ty cc2 x y)))
(if-let 7 (u64_or (decompose_intcc cc1) (decompose_intcc cc2)))
(subsume (iconst ty (imm64 1)))) That doesn't handle signedness but I think fixing that shouldn't be too much more involved. Adding the cases where one of the comparisons has its operands flipped ( Also I think this extends in the obvious way to |
The signedness condition can work in a similar way: (decl pure intcc_class (IntCC) u64)
(rule (intcc_class IntCC.UnsignedLessThan) 0b01)
(rule (intcc_class IntCC.UnsignedLessThanEqual) 0b01)
(rule (intcc_class IntCC.UnsignedGreaterThan) 0b01)
(rule (intcc_class IntCC.UnsignedGreaterThanEqual) 0b01)
(rule (intcc_class IntCC.SignedLessThan) 0b10)
(rule (intcc_class IntCC.SignedLessThanEqual) 0b10)
(rule (intcc_class IntCC.SignedGreaterThan) 0b10)
(rule (intcc_class IntCC.SignedGreaterThanEqual) 0b10)
(rule (intcc_class IntCC.Equal) 0b11)
(rule (intcc_class IntCC.NotEqual) 0b11)
(decl pure intcc_comparable (IntCC IntCC) Unit)
(rule (intcc_comparable x y)
(if-let (u64_nonzero _) (u64_and (intcc_class x) (intcc_class y)))
(unit)) Then add The |
That's a really incredibly neat way of seeing the rewrite! I was trying to work out for myself why it should work, since it's non-obvious (at least to me!) why AND of the bitfield representation should be AND of the
The above line of reasoning doesn't quite work directly for XOR (XOR does not distribute over OR in general) but I think given the disjointness property one could argue that it does in this case. |
That's a nice way to prove it! I was thinking about it differently, by conditioning on the actual relationship between the inputs. For example, assume that On further thought I think there are even more concise ways to factor this: (decl pure partial intcc_comparable (IntCC IntCC) bool)
(rule (intcc_comparable x y)
(if-let (u64_nonzero class) (u64_and (intcc_class x) (intcc_class y)))
(u64_eq 0b10 class))
(decl pure compose_icmp (Type u64 bool Value Value) Value)
(rule (compose_icmp ty 0 _ _ _) (subsume (iconst ty (imm64 0))))
(rule (compose_icmp ty 1 _ x y) (icmp ty IntCC.Equal x y))
(rule (compose_icmp ty 2 $false x y) (icmp ty IntCC.UnsignedLessThan x y))
(rule (compose_icmp ty 2 $true x y) (icmp ty IntCC.SignedLessThan x y))
; ...
(rule (compose_icmp ty 6 _ x y) (icmp ty IntCC.NotEqual x y))
(rule (compose_icmp ty 7 _ _ _) (subsume (iconst ty (imm64 1))))
(rule (simplify (band ty (icmp ty cc1 x y) (icmp ty cc2 x y)))
(if-let signed (intcc_comparable cc1 cc2))
(compose_icmp ty (u64_and (decompose_intcc cc1) (decompose_intcc cc2)) signed x y))
(rule (simplify (bor ty (icmp ty cc1 x y) (icmp ty cc2 x y)))
(if-let signed (intcc_comparable cc1 cc2))
(compose_icmp ty (u64_or (decompose_intcc cc1) (decompose_intcc cc2)) signed x y)) |
Thank you @jameysharp and @cfallin. I have updated the patch with your contributions |
Nice! This means the changes to I meant to ask before: could you commit the script you used to generate the tests too? We have precedent for that in Also, I guess now we need to either merge #6111 before finishing this PR, or decide we want these tests to not check the full output and back out the precise-output changes. I haven't thought about this enough to have an opinion on that question yet. |
Good point, I forgot to remove those
I used a rust program but I can convert it to a shell script
I would prefer to wait for #6111 |
You can remove the changes in And the changes in |
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.
Alright, let's merge this!
Here's some future work I'd like to see, but I'm not going to delay this PR further for any of this:
- Comments explaining why decompose/compose work the way they do, and what intcc_comparable is doing. Right now I know why this is correct but I'll probably be confused when I look at this in a month, even though it was my suggestion.
- Flipped versions of the rules for when
icmp x y
is combined withicmp y x
. That's now just one extra rule forband
plus one extra rule forbor
, to handle all possible commutative cases. - Rules for
bxor
, because we might as well. - Potentially, rules matching
ne
of twoicmp
s, which is equivalent tobxor
in this context; similarly foreq
.
Adds ISLE rewrites for logical combinations of
icmp
(band ty (icmp ty cc1 x y) (icmp ty cc2 x y))
:(bor ty (icmp ty cc1 x y) (icmp ty cc2 x y))
:Tests were generated by a script