Skip to content

[Cranelift] (x * y) (==/!=) z --> x (==/!=) (y / z)#11994

Merged
cfallin merged 8 commits into
bytecodealliance:mainfrom
bongjunj:mul_ne_eqv_ne_div
Nov 8, 2025
Merged

[Cranelift] (x * y) (==/!=) z --> x (==/!=) (y / z)#11994
cfallin merged 8 commits into
bytecodealliance:mainfrom
bongjunj:mul_ne_eqv_ne_div

Conversation

@bongjunj

@bongjunj bongjunj commented Nov 7, 2025

Copy link
Copy Markdown
Contributor

This add the optimization of (x * y) (==/!=) z --> x (==/!=) (y / z).
y must be odd and divides z for the rule to be correct.

@bongjunj
bongjunj requested a review from a team as a code owner November 7, 2025 01:33
@bongjunj
bongjunj requested review from cfallin and removed request for a team November 7, 2025 01:33
(rule (simplify (isub ty (iadd ty x y) x)) y)
(rule (simplify (isub ty (iadd ty x y) y)) x)

;; (x * y) (==/!=) z --> x (==/!=) (y / z) when y is odd and divides z

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.

Could you add "and y and z are constant" to the description here? Otherwise this reads as a fairly odd optimization that is replacing a multiply with a divide, which would ordinarily reduce performance.

Also: why is it necessary that y is odd? Is that because we need it to be mutually prime with the ring's modulus (2^n) so the product doesn't collapse to zero?

@bongjunj bongjunj Nov 7, 2025

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've changed the description so that one can read that the division happens in compile time.
Also, the solution X for X * C = D is not unique when C is even in 2^n module arithmetic.
Therefore, it is not safe to say X = D / C

@github-actions github-actions Bot added cranelift Issues related to the Cranelift code generator isle Related to the ISLE domain-specific language labels Nov 7, 2025
@github-actions

github-actions Bot commented Nov 7, 2025

Copy link
Copy Markdown

Subscribe to Label Action

cc @cfallin, @fitzgen

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

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

  • cfallin: isle
  • fitzgen: isle

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

Learn more.

@bongjunj

bongjunj commented Nov 7, 2025

Copy link
Copy Markdown
Contributor Author

Could you add "and y and z are constant" to the description here? Otherwise this reads as a fairly odd optimization that is replacing a multiply with a divide, which would ordinarily reduce performance.

Also: why is it necessary that y is odd? Is that because we need it to be mutually prime with the ring's modulus (2^n) so the product doesn't collapse to zero?

To clarify, this is the counterexample obtained by Crocus, when y is relaxed to be any bitvector.
Here, y is even.

Verification failed for <unnamed rule>, width 8
(simplify (ne [cty|8] (imul [ty|32] [x|#x80000002] (iconst_u [ty|32] [y|#x0000000000448102])) (iconst_u [ty|32] [z|#x0000000000890204])))
(if-let ((0) (u64_rem [z|#x0000000000890204] [y|#x0000000000448102]))((true) (u64_ne [y|#x0000000000448102] (0))))=>
(ne [cty|8] [x|#x80000002] (iconst [ty|32] (imm64 (u64_div [z|#x0000000000890204] [y|#x0000000000448102]))))

Furthermore, there is a similar optimization in LLVM, and the optimization requires y to be odd as well.

When y is odd:

define i1 @src(i32 %x) {
#0:
  %mul = mul i32 %x, 7
  %eq = icmp eq i32 %mul, 42
  ret i1 %eq
}
=>
define i1 @src(i32 %x) nofree willreturn memory(none) {
#0:
  %eq = icmp eq i32 %x, 6
  ret i1 %eq
}
Transformation seems to be correct!

When y is even:

----------------------------------------
define i1 @src(i32 %x) {
#0:
  %mul = mul i32 %x, 6
  %eq = icmp eq i32 %mul, 42
  ret i1 %eq
}
=>
define i1 @tgt(i32 %x) {
#0:
  %eq = icmp eq i32 %x, 7
  ret i1 %eq
}
Transformation doesn't verify!

ERROR: Value mismatch

NOTE: The counterexample is unique.

Example:
i32 %x = #x80000007 (2147483655, -2147483641)

Source:
i32 %mul = #x0000002a (42)
i1 %eq = #x1 (1)

Target:
i1 %eq = #x0 (0)
Source value: #x1 (1)
Target value: #x0 (0)

This shows that the optimization violates the semantic equivalence (or refinement) when y is even.

Reference implementation in LLVM: https://github.com/llvm/llvm-project/blob/a257a063c6fdcbc1db897d360c3791d8c4f4e48d/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp#L2209-L2230

@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.

Yep, that makes sense -- just wanted to get it written down why. Thanks! Happy to merge once the merge conflicts are resolved.

Comment thread cranelift/codegen/src/opts/arithmetic.isle Outdated
@cfallin
cfallin added this pull request to the merge queue Nov 8, 2025
Merged via the queue into bytecodealliance:main with commit 53d3652 Nov 8, 2025
76 checks passed
alexcrichton added a commit to alexcrichton/wasmtime that referenced this pull request Nov 10, 2025
This commit fixes a minor regression from bytecodealliance#11994 where a divide-by-zero
was happening in a fuzz-generated input.
alexcrichton added a commit to alexcrichton/wasmtime that referenced this pull request Nov 10, 2025
This commit fixes a minor regression from bytecodealliance#11994 where a divide-by-zero
was happening in a fuzz-generated input.
github-merge-queue Bot pushed a commit that referenced this pull request Nov 10, 2025
This commit fixes a minor regression from #11994 where a divide-by-zero
was happening in a fuzz-generated input.
bongjunj added a commit to prosyslab/wasmtime that referenced this pull request Mar 9, 2026
bongjunj added a commit to prosyslab/wasmtime that referenced this pull request Mar 9, 2026
bongjunj added a commit to prosyslab/wasmtime that referenced this pull request Mar 9, 2026
bongjunj added a commit to prosyslab/wasmtime that referenced this pull request Mar 12, 2026
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