Skip to content

Commit f2807a1

Browse files
authored
Support vector types in iconst_{u,s} (#13063)
This commit updates the `iconst_{u,s}` helpers to support vector types where previously they did not support them. The meaning of `iconst_*` with a vector type is to insert the specified constant value into all lanes of the vector type. This gets a large number of optimization rules that currently panic on vector types to "just work" and my hope is that these sorts of bugs will be less common as vector ops will be both optimizable and applicable to existing rules.
1 parent ebc9f64 commit f2807a1

4 files changed

Lines changed: 337 additions & 38 deletions

File tree

cranelift/codegen/src/opts/arithmetic.isle

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
(subsume inner))
4848

4949
;; x-x == 0.
50-
(rule (simplify (isub (ty_int ty) x x)) (subsume (iconst_u ty 0)))
50+
(rule (simplify (isub ty x x)) (subsume (iconst_u ty 0)))
5151

5252
;; x*1 == x.
5353
(rule (simplify (imul ty
@@ -318,12 +318,8 @@
318318
(rule (simplify (isub ty (bor ty y x) (bxor ty y x))) (band ty x y))
319319

320320
;; (~x) + x == -1
321-
;; Keep the generic fold for <=64-bit types, and handle i128 explicitly.
322-
(rule (simplify (iadd (fits_in_64 ty) (bnot ty x) x)) (iconst_s ty -1))
323-
(rule (simplify (iadd (fits_in_64 ty) x (bnot ty x))) (iconst_s ty -1))
324-
325-
(rule (simplify (iadd $I128 (bnot $I128 x) x)) (sextend $I128 (iconst_s $I64 -1)))
326-
(rule (simplify (iadd $I128 x (bnot $I128 x))) (sextend $I128 (iconst_s $I64 -1)))
321+
(rule (simplify (iadd ty (bnot ty x) x)) (iconst_s ty -1))
322+
(rule (simplify (iadd ty x (bnot ty x))) (iconst_s ty -1))
327323

328324
;; ((x + y) - (x + z)) --> (y - z)
329325
(rule (simplify (isub ty (iadd ty x y) (iadd ty x z))) (isub ty y z))
@@ -379,11 +375,18 @@
379375
(rule (simplify (iadd ty x (iadd ty (isub ty z x) y))) (iadd ty y z))
380376
(rule (simplify (iadd ty (iadd ty (isub ty z x) y) x)) (iadd ty y z))
381377

378+
;; Helper to create a "true" value for a comparison. For scalar integers this is
379+
;; a value of 1 but for vectors this is -1 since each lane is filled with all
380+
;; 1s.
381+
(decl cmp_true (Type) Value)
382+
(rule 0 (cmp_true (ty_int ty)) (iconst_u ty 1))
383+
(rule 1 (cmp_true (ty_vec128 ty)) (iconst_s ty -1))
384+
382385
;; (x + y) == (y + x) --> true
383-
(rule (simplify (eq (ty_int ty) (iadd cty x y) (iadd cty y x))) (iconst_u ty 1))
384-
(rule (simplify (eq (ty_int ty) (iadd cty y x) (iadd cty x y))) (iconst_u ty 1))
385-
(rule (simplify (eq (ty_int ty) (iadd cty x y) (iadd cty x y))) (iconst_u ty 1))
386-
(rule (simplify (eq (ty_int ty) (iadd cty y x) (iadd cty y x))) (iconst_u ty 1))
386+
(rule (simplify (eq ty (iadd cty x y) (iadd cty y x))) (cmp_true ty))
387+
(rule (simplify (eq ty (iadd cty y x) (iadd cty x y))) (cmp_true ty))
388+
(rule (simplify (eq ty (iadd cty x y) (iadd cty x y))) (cmp_true ty))
389+
(rule (simplify (eq ty (iadd cty y x) (iadd cty y x))) (cmp_true ty))
387390

388391
;; (x - y) != x --> y != 0
389392
(rule (simplify (ne cty (isub ty x y) x)) (ne cty y (iconst_u ty 0)))
@@ -407,24 +410,24 @@
407410
(rule (simplify (ineg ty (imul ty x (ineg ty y)))) (imul ty x y))
408411

409412
;; max(x, y) >= x
410-
(rule (simplify (sge ty (smax ty x y) x)) (iconst_u ty 1))
411-
(rule (simplify (sge ty (smax ty y x) x)) (iconst_u ty 1))
412-
(rule (simplify (sle ty x (smax ty x y))) (iconst_u ty 1))
413-
(rule (simplify (sle ty x (smax ty y x))) (iconst_u ty 1))
414-
(rule (simplify (uge ty (umax ty x y) x)) (iconst_u ty 1))
415-
(rule (simplify (uge ty (umax ty y x) x)) (iconst_u ty 1))
416-
(rule (simplify (ule ty x (umax ty x y))) (iconst_u ty 1))
417-
(rule (simplify (ule ty x (umax ty y x))) (iconst_u ty 1))
413+
(rule (simplify (sge ty (smax ty x y) x)) (cmp_true ty))
414+
(rule (simplify (sge ty (smax ty y x) x)) (cmp_true ty))
415+
(rule (simplify (sle ty x (smax ty x y))) (cmp_true ty))
416+
(rule (simplify (sle ty x (smax ty y x))) (cmp_true ty))
417+
(rule (simplify (uge ty (umax ty x y) x)) (cmp_true ty))
418+
(rule (simplify (uge ty (umax ty y x) x)) (cmp_true ty))
419+
(rule (simplify (ule ty x (umax ty x y))) (cmp_true ty))
420+
(rule (simplify (ule ty x (umax ty y x))) (cmp_true ty))
418421

419422
;; x >= min(x, y)
420-
(rule (simplify (sge ty x (smin ty x y))) (iconst_u ty 1))
421-
(rule (simplify (sge ty x (smin ty y x))) (iconst_u ty 1))
422-
(rule (simplify (sle ty (smin ty x y) x)) (iconst_u ty 1))
423-
(rule (simplify (sle ty (smin ty y x) x)) (iconst_u ty 1))
424-
(rule (simplify (uge ty x (umin ty x y))) (iconst_u ty 1))
425-
(rule (simplify (uge ty x (umin ty y x))) (iconst_u ty 1))
426-
(rule (simplify (ule ty (umin ty x y) x)) (iconst_u ty 1))
427-
(rule (simplify (ule ty (umin ty y x) x)) (iconst_u ty 1))
423+
(rule (simplify (sge ty x (smin ty x y))) (cmp_true ty))
424+
(rule (simplify (sge ty x (smin ty y x))) (cmp_true ty))
425+
(rule (simplify (sle ty (smin ty x y) x)) (cmp_true ty))
426+
(rule (simplify (sle ty (smin ty y x) x)) (cmp_true ty))
427+
(rule (simplify (uge ty x (umin ty x y))) (cmp_true ty))
428+
(rule (simplify (uge ty x (umin ty y x))) (cmp_true ty))
429+
(rule (simplify (ule ty (umin ty x y) x)) (cmp_true ty))
430+
(rule (simplify (ule ty (umin ty y x) x)) (cmp_true ty))
428431

429432
;; min/max(x,x) --> x
430433
(rule (simplify (umin ty x x)) x)
@@ -560,4 +563,4 @@
560563
(rule (simplify (ugt ty x (umax ty x y))) (iconst_u ty 0))
561564
(rule (simplify (ugt ty x (umax ty y x))) (iconst_u ty 0))
562565
(rule (simplify (ult ty (umax ty x y) x)) (iconst_u ty 0))
563-
(rule (simplify (ult ty (umax ty y x) x)) (iconst_u ty 0))
566+
(rule (simplify (ult ty (umax ty y x) x)) (iconst_u ty 0))

cranelift/codegen/src/prelude_opt.isle

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,38 +125,51 @@
125125
(decl iconst_sextend_etor (Type i64) TypeAndInstructionData)
126126
(extern extractor iconst_sextend_etor iconst_sextend_etor)
127127

128-
;; Construct an `iconst` from an `i64` or Extract an `i64` from an `iconst`
129-
;; by treating the constant as signed.
128+
;; Create a constant value represented by the `i64` provided which has the
129+
;; `Type` provided.
130+
;;
131+
;; For 8 to 64-bit scalar integers this will construct an `iconst` from an `i64`
132+
;; or Extract an `i64` from an `iconst` by treating the constant as signed.
130133
;; When extracting, smaller types get their value sign-extended to 64-bits,
131134
;; so that `iconst.i8 255` will give you a `-1_i64`.
135+
;;
136+
;; For 128-bit integer types this rule will create a 64-bit `iconst` and then
137+
;; `sextend` it to 128-bit bits.
138+
;;
139+
;; For vector types this will create a constant for the lane type and then splat
140+
;; that to all lanes of the vector type.
141+
;;
132142
;; When constructing, the rule will fail if the value cannot be represented in
133143
;; the target type. If it fits, it'll be masked accordingly in the constant.
134144
;;
135-
;; Recursion: may recurse at most once to reduce reduce 128-bit to 64-bit.
145+
;; Recursion: may recurse at most once to reduce reduce 128-bit to 64-bit or
146+
;; to create a scalar constant to splat into a vector type.
136147
(decl rec iconst_s (Type i64) Value)
137148
(extractor (iconst_s ty c) (inst_data_value_tupled (iconst_sextend_etor ty c)))
138-
(rule 0 (iconst_s ty c)
149+
(rule 0 (iconst_s (ty_int (fits_in_64 ty)) c)
139150
(if-let c_masked (u64_and (i64_cast_unsigned c)
140151
(ty_umax ty)))
141152
(if-let c_reextended (i64_sextend_u64 ty c_masked))
142153
(if-let true (i64_eq c c_reextended))
143154
(iconst ty (imm64 c_masked)))
144155
(rule 1 (iconst_s $I128 c) (sextend $I128 (iconst_s $I64 c)))
156+
(rule 2 (iconst_s (ty_vec128 ty) c) (splat ty (iconst_s (lane_type ty) c)))
145157

146-
;; Construct an `iconst` from a `u64` or Extract a `u64` from an `iconst`
147-
;; by treating the constant as unsigned.
158+
;; Same as `iconst_s`, but used for zero-extending constant values.
159+
;;
148160
;; When extracting, smaller types get their value zero-extended to 64-bits,
149161
;; so that `iconst.i8 255` will give you a `255_u64`.
150162
;; When constructing, the rule will fail if the value cannot be represented in
151163
;; the target type.
152164
;;
153-
;; Recursion: may recurse at most once to reduce reduce 128-bit to 64-bit.
165+
;; Recursion: same as `iconst_s`, once for 128-bit integers or vectors.
154166
(decl rec iconst_u (Type u64) Value)
155167
(extractor (iconst_u ty c) (iconst ty (u64_from_imm64 c)))
156-
(rule 0 (iconst_u ty c)
168+
(rule 0 (iconst_u (ty_int (fits_in_64 ty)) c)
157169
(if-let true (u64_lt_eq c (ty_umax ty)))
158170
(iconst ty (imm64 c)))
159171
(rule 1 (iconst_u $I128 c) (uextend $I128 (iconst_u $I64 c)))
172+
(rule 2 (iconst_u (ty_vec128 ty) c) (splat ty (iconst_u (lane_type ty) c)))
160173

161174
;; These take `Value`, rather than going through `inst_data_value_tupled`,
162175
;; because most of the time they want to return the original `Value`, and it

cranelift/filetests/filetests/egraph/arithmetic-precise.clif

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,11 @@ block0(v0: i32x4, v1: i32x4):
244244
}
245245

246246
; function %simplify_vector_icmp_eq_iadd_commute(i32x4, i32x4) -> i32x4 fast {
247+
; const0 = 0xffffffffffffffffffffffffffffffff
248+
;
247249
; block0(v0: i32x4, v1: i32x4):
248-
; v5 = icmp eq v0, v0
249-
; return v5
250+
; v9 = icmp eq v0, v0
251+
; return v9
250252
; }
251253

252254
;; (x - y) != x --> y != 0

0 commit comments

Comments
 (0)