-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Cranelift: Rewrite or(and(x, y), not(y)) => or(x, not(y))
#5676
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
Changes from all commits
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 |
|---|---|---|
|
|
@@ -138,6 +138,33 @@ | |
| (rule (simplify (bnot ty (band t x y))) | ||
| (bor ty (bnot ty x) (bnot ty y))) | ||
|
|
||
| ;; `or(and(x, y), not(y)) == or(x, not(y))` | ||
| (rule (simplify (bor ty | ||
| (band ty x y) | ||
| z @ (bnot ty y))) | ||
| (bor ty x z)) | ||
| ;; Duplicate the rule but swap the `bor` operands because `bor` is | ||
| ;; commutative. We could, of course, add a `simplify` rule to do the commutative | ||
| ;; swap for all `bor`s but this will bloat the e-graph with many e-nodes. It is | ||
| ;; cheaper to have additional rules, rather than additional e-nodes, because we | ||
| ;; amortize their cost via ISLE's smart codegen. | ||
| (rule (simplify (bor ty | ||
| z @ (bnot ty y) | ||
| (band ty x y))) | ||
| (bor ty x z)) | ||
|
|
||
| ;; `or(and(x, y), not(y)) == or(x, not(y))` specialized for constants, since | ||
| ;; otherwise we may not know that `z == not(y)` since we don't generally expand | ||
| ;; constants in the e-graph. | ||
| ;; | ||
| ;; (No need to duplicate for commutative `bor` for this constant version because | ||
| ;; we move constants to the right.) | ||
| (rule (simplify (bor ty | ||
| (band ty x (iconst ty (u64_from_imm64 y))) | ||
| z @ (iconst ty (u64_from_imm64 zk)))) | ||
| (if (u64_eq zk (u64_not y))) | ||
| (bor ty x z)) | ||
|
Member
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. Our verifier prototype finds the following counterexample for this rule (lightly edited for readability):
Member
Author
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. I believe that this is because the Anyways, the predicate needs to be rewritten as
Contributor
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. That's so cool! I don't understand it but it's awesome. 😆 Here's what's confusing me: The rule should only fire if Also, what type is this counterexample for? I'd be especially interested if you can find counterexamples for I64 specifically, because I think the rule as-written is wrong for any other width. That said, I'd expect other widths to just fail to match the rule most of the time, rather than ever rewriting incorrectly, so if you find a narrower counterexample it's probably a real issue.
Contributor
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. Ohhh, Nick's got it right. Although it's because We also need to mask both constants down to the appropriate width if we want to make the rule fire on <64-bit types.
Member
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. To restate what @fitzgen realized:
Right now, this counterexample is for BVs of width 64, and the verifier is complaining that the rule is infeasible (that is, doesn't match) for other widths (which, based on your comment, seems correct?). |
||
|
|
||
| ;; x*2 == 2*x == x+x. | ||
| (rule (simplify (imul ty x (iconst _ (simm32 2)))) | ||
| (iadd ty x x)) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| ;; Test the rewrite: `or(and(x, y), not(y)) => or(x, not(y))` | ||
|
|
||
| test interpret | ||
| test run | ||
| target aarch64 | ||
| target x86_64 | ||
| target riscv64 | ||
| target s390x | ||
|
|
||
| function %or_and_y_with_not_y(i8, i8) -> i8 { | ||
| block0(v0: i8, v1: i8): | ||
| v2 = band v0, v1 | ||
| v3 = bnot v1 | ||
| v4 = bor v2, v3 | ||
| return v4 | ||
| } | ||
| ; run: %or_and_y_with_not_y(0xff, 0x0a) == 0xff | ||
| ; run: %or_and_y_with_not_y(0xff, 0xb0) == 0xff | ||
| ; run: %or_and_y_with_not_y(0xaa, 0x0a) == 0xff | ||
| ; run: %or_and_y_with_not_y(0xaa, 0xb0) == 0xef | ||
| ; run: %or_and_y_with_not_y(0x00, 0x0a) == 0xf5 | ||
| ; run: %or_and_y_with_not_y(0x00, 0xb0) == 0x4f | ||
|
|
||
| function %or_and_constant_with_not_constant(i8) -> i8 { | ||
| block0(v0: i8): | ||
| v1 = iconst.i8 -4 | ||
| v2 = band v0, v1 | ||
| v3 = iconst.i8 3 | ||
| v4 = bor v2, v3 | ||
| return v4 | ||
| } | ||
| ; run: %or_and_constant_with_not_constant(0xff) == 0xff | ||
| ; run: %or_and_constant_with_not_constant(0xaa) == 0xab | ||
| ; run: %or_and_constant_with_not_constant(0x00) == 0x03 |
Uh oh!
There was an error while loading. Please reload this page.