Stream: cranelift

Topic: How ISLE variable matching works?


view this post on Zulip Bongjun Jang (May 20 2025 at 06:03):

Hi,

I'm trying to write this optimization rule with ISLE and I've noticed some interesting result.

(rule
  (simplify (icmp cty (IntCC.Equal) x (bxor bty x y)))
  (icmp cty (IntCC.Equal) y (iconst_u bty 0)))

This rewrites X == (X ^ Y) to Y == 0.
For example, a filetest passes:

;; This optimization simplifies `x == (x ^ y)` to `y == 0`.
function %simplify_icmp_eq_x_bxor_x_y(i32, i32) -> i8 fast {
block0(v0: i32, v1: i32):  ;; v0: x, v1: y
    v2 = bxor v0, v1       ;; v2 = x ^ y
    v3 = icmp eq v0, v2    ;; v3 = (x == (x ^ y))
    return v3
}

; function %simplify_icmp_eq_x_bxor_x_y(i32, i32) -> i8 fast {
; block0(v0: i32, v1: i32):
;     v4 = iconst.i32 0
;     v5 = icmp eq v1, v4  ; v4 = 0
;     return v5
; }

At first, I tried a more concise rule.
Please note that all the types are matched with a single variable ty.

(rule
  (simplify (icmp ty (IntCC.Equal) x (bxor ty x y)))
  (subsume (icmp ty (IntCC.Equal) y (iconst_u ty 0))))

But with this simplify rule, the optimization did not fire.
I expected all the type variable (ty) to be identical for all instructions.
However, it turned out that I have to relax the constraint and let icmp and bxor have different types.

Why is this happening?

view this post on Zulip Alex Crichton (May 20 2025 at 11:57):

I think this may be because the icmp is producing I8 while the bxor is I32in this case?

view this post on Zulip Bongjun Jang (May 20 2025 at 12:03):

oh icmp's type specifies the resulting type not that of operands?

view this post on Zulip Alex Crichton (May 20 2025 at 13:29):

correct yeah, I believe icmp always produces i8 for scalar types (but produces the input vector type if the inputs are vectors)

view this post on Zulip Chris Fallin (May 20 2025 at 16:02):

Yep, in general the first ty of every operator specifies that operator's result type

view this post on Zulip Chris Fallin (May 20 2025 at 16:03):

The reason that icmps produce an I8 in particular is an annoying historical wart that has to do with x86's SETcc instructions operating only on 8-bit-wide registers, and us wanting to avoid unnecessary widens. But I suspect with better matching rules we could make icmp produce a truthy/falsy i32 or arbitrary width. In any case, here you'll want the two types to be decoupled so the ty/cty form is correct

view this post on Zulip Bongjun Jang (May 21 2025 at 02:40):

Thanks for the reply! Coming from LLVM world, I though it was the type of operands :sweat_smile:


Last updated: Dec 06 2025 at 07:03 UTC