Skip to content

Cranelift: add mid-end opt rules - #14896

Open
myunbin wants to merge 3 commits into
bytecodealliance:mainfrom
myunbin:add-rules-261021
Open

myunbin wants to merge 3 commits into
bytecodealliance:mainfrom
myunbin:add-rules-261021

Conversation

@myunbin

@myunbin myunbin commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

Add mid-end optimization rules:

  • (~x | y) ^ x --> ~(x & y)
  • (~x OP y) ^ (~y OP x) --> x ^ y, where OP = {&, |}
  • (~x | y) & (~y | x) --> ~(x ^ y)
  • max(x, y) OP min(x, y) --> x OP y, where OP = {&, |, ^}
  • max(~x, ~y) --> ~min(x, y)
  • min(~x, ~y) --> ~max(x, y)
  • ~max(~x, y) --> min(x, ~y)
  • ~min(~x, y) --> max(x, ~y)
  • -(x & y) + x --> x & ~y
  • (~x & y) + (~y & x) --> x ^ y
  • (-x) - (~x) --> 1
  • ~x + C --> (C - 1) - x
  • (x + C) ^ -1 --> (-(C + 1)) - x
  • (x | C) - C --> x & ~C
  • (x | C) ^ (y | C) --> (x ^ y) & ~C
  • (x | C) ^ (y ^ C) --> (x & ~C) ^ y
  • (x << 1) * C --> x * (2 * C)
  • ~rotl(~x, k) --> rotl(x, k)
  • ~rotr(~x, k) --> rotr(x, k)
  • (x << 1) == x --> x == 0
  • (x >>u 1) == x --> x == 0
  • (~x & y) == y --> (x & y) == 0
  • ~x == (~x | y) --> (x & y) == 0
  • umax(x, y) OP 0 --> (x | y) OP 0, where OP = {==, !=}
  • umax(x, y) OP umin(x, y) --> x OP y, where OP = {==, !=}
  • (x >=s y) & (y >=s x) --> x == y
  • (x >=u y) & (y >=u x) --> x == y
  • select(c, x, y) == select(c, y, x) --> x == y
  • select(x == 0, -x, x) --> x, and corresponding x != 0
  • select(x == 0, 0, x OP y) --> x OP y, where OP = {&, *}, and corresponding x != 0
  • ~select(c, C1, C2) --> select(c, ~C1, ~C2)
  • -select(c, C1, C2) --> select(c, -C1, -C2)

Thanks!

@myunbin
myunbin requested a review from a team as a code owner October 21, 2026 01:16
@myunbin
myunbin requested review from cfallin and removed request for a team October 21, 2026 01:16
@github-actions github-actions Bot added cranelift Issues related to the Cranelift code generator isle Related to the ISLE domain-specific language labels Oct 21, 2026
@github-actions

Copy link
Copy Markdown

Subscribe to Label Action

cc @avanhatt, @cfallin, @fitzgen, @mmcloughlin

Details This issue or pull request has been labeled: "cranelift", "isle"

Thus the following users have been cc'd because of the following labels:

  • avanhatt: isle
  • cfallin: isle
  • fitzgen: isle
  • mmcloughlin: isle

To subscribe or unsubscribe from this label, edit the .github/subscribe-to-label.json configuration file.

Learn more.

@cfallin cfallin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks! The new rules look good generally. Just one question below about a possible pessimization.

; check: return v4
; check: v5 = iconst.i32 0
; check: v6 = isub v5, v0
; check: return v6

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This seems like a regression -- we won't use the native negation instruction anymore but instead will load a zero-constant and do a subtract. Could you look into what's going on here (cost function discrepancies or something else)?

@myunbin myunbin Oct 23, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@cfallin

I believe it's because of the rule ~x + C → (C - 1) - x.

When C=1, both rules match:

The cost model assigns both candidates as 4: ineg(4) and iconst(1) + isub(3), therefore tie.
I think the tie breaker chooses 0 - x afterward.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Interesting. Probably we should adjust the cost of ineg: on all CPUs I'm aware of, a unary integer negation operator has the same cost as other ALU ops (1 cycle) so it should win against a const materialization plus an ALU op. Can you bundle that change in here and see if it fixes this regression?

@myunbin myunbin Oct 27, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I adjusted ineg to have same cost with other ALU ops(cost = 3). I guess all affected test cases now produce ineg.

@cfallin

cfallin commented Oct 28, 2026

Copy link
Copy Markdown
Member

@myunbin it looks like there is a verifier failure now -- could you take a look?

@myunbin

myunbin commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor Author

@cfallin I found two issues.

  1. iconst_u spec seems to treat the result as a single integer rather than a splat. For example, the verifier reports: iconst_u({bits: 32, lanes: 4}, 1) -> [1, 0, 0, 0]. A splat would produce [1, 1, 1, 1]. The spec seems to be missing the per-lane semantics for supported vector types. I can investigate more and open a separate PR.
log
isub({bits: 32, lanes: 4}, [#x00 #x00 #x00 #x00], [#xff #xff #xff #xff]) -> [#x01 #x01 #x01
#x01]
ineg({bits: 32, lanes: 4}, [#x00 #x00 #x00 #x00]) -> [#x00 #x00 #x00 #x00]
bnot({bits: 32, lanes: 4}, [#x00 #x00 #x00 #x00]) -> [#xff #xff #xff #xff]
iconst_u({bits: 32, lanes: 4}, #x0000000000000001) -> [#x01 #x00 #x00 #x00]
simplify([#x01 #x01 #x01 #x01]) -> [#x01 #x00 #x00 #x00]
violated: cranelift/codegen/src/spec/opt.isle line 71: e123
violated: cranelift/codegen/src/spec/opt.isle line 20: e167
  1. (rule (simplify (isub ty (ineg ty x) (bnot ty x))) (iconst_u ty 1)) crashes. Currently iconst_u only supports scalar and vec128, but this rule can also match other vector widths, causing a panic. I'll restrict the rule to the supported types for now. Is there a reason the helper's vector support is limited to 128 bits?

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cranelift Issues related to the Cranelift code generator isle Related to the ISLE domain-specific language

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants