Skip to content

Commit

Permalink
Add splat simplify opt for various ops (bytecodealliance#6851)
Browse files Browse the repository at this point in the history
* Add splat simplify opt for iadd, isub, imul, ineg & iabs

* Add splat simplify opt for smulhi & hmulhi

* Add splat simplify opt for band, bor & bxor

* Add splat simplify opt for a few more ops

namely, popcnt, smin, umin, smax, umax, sadd_sat, uadd_sat, ssub_sat & usub_sat

* Add splat simplify opt for bnot

* Add splat simplify opt for shift and rotate ops

and avg_round as well

* Remove splat simplify opt for certain ops

because they don't support scalars.

* Add lane_type to splat opts for shift/rotate

Some of the wasmtime spec tests were failing without this

* Remove splat simplify opt for avg_round

because it doesn't support scalars.
  • Loading branch information
gurry authored and eduardomourar committed Aug 18, 2023
1 parent 158d5c7 commit b32a9d8
Show file tree
Hide file tree
Showing 2 changed files with 293 additions and 2 deletions.
70 changes: 68 additions & 2 deletions cranelift/codegen/src/opts/vector.isle
Original file line number Diff line number Diff line change
@@ -1,8 +1,74 @@
;; Lift a splat outside of an int-to-float conversion to try to open up
;; For various ops lift a splat outside of the op to try to open up
;; optimization opportunities with scalars.
;;
;; NB: this is also required for correctness at this time due to #6562
;; NB: for int-to-float conversion op this simplification is also
;; required for correctness at this time due to #6562
(rule (simplify (fcvt_from_uint float_vector_ty (splat _ x)))
(splat float_vector_ty (fcvt_from_uint (lane_type float_vector_ty) x)))
(rule (simplify (fcvt_from_sint float_vector_ty (splat _ x)))
(splat float_vector_ty (fcvt_from_sint (lane_type float_vector_ty) x)))

(rule (simplify (band ty (splat ty x) (splat ty y)))
(splat ty (band (lane_type ty) x y)))

(rule (simplify (bor ty (splat ty x) (splat ty y)))
(splat ty (bor (lane_type ty) x y)))

(rule (simplify (bxor ty (splat ty x) (splat ty y)))
(splat ty (bxor (lane_type ty) x y)))

(rule (simplify (bnot ty (splat ty x)))
(splat ty (bnot (lane_type ty) x)))

(rule (simplify (iadd ty (splat ty x) (splat ty y)))
(splat ty (iadd (lane_type ty) x y)))

(rule (simplify (isub ty (splat ty x) (splat ty y)))
(splat ty (isub (lane_type ty) x y)))

(rule (simplify (imul ty (splat ty x) (splat ty y)))
(splat ty (imul (lane_type ty) x y)))

(rule (simplify (smulhi ty (splat ty x) (splat ty y)))
(splat ty (smulhi (lane_type ty) x y)))

(rule (simplify (umulhi ty (splat ty x) (splat ty y)))
(splat ty (umulhi (lane_type ty) x y)))

(rule (simplify (ineg ty (splat ty x)))
(splat ty (ineg (lane_type ty) x)))

(rule (simplify (iabs ty (splat ty x)))
(splat ty (iabs (lane_type ty) x)))

(rule (simplify (popcnt ty (splat ty x)))
(splat ty (popcnt (lane_type ty) x)))

(rule (simplify (smin ty (splat ty x) (splat ty y)))
(splat ty (smin (lane_type ty) x y)))

(rule (simplify (umin ty (splat ty x) (splat ty y)))
(splat ty (umin (lane_type ty) x y)))

(rule (simplify (smax ty (splat ty x) (splat ty y)))
(splat ty (smax (lane_type ty) x y)))

(rule (simplify (umax ty (splat ty x) (splat ty y)))
(splat ty (umax (lane_type ty) x y)))

;; The second operand of shift and rotate ops is
;; scalar so splat opt applies only to the first
(rule (simplify (rotl ty (splat ty x) y))
(splat ty (rotl (lane_type ty) x y)))

(rule (simplify (rotr ty (splat ty x) y))
(splat ty (rotr (lane_type ty) x y)))

(rule (simplify (ishl ty (splat ty x) y))
(splat ty (ishl (lane_type ty) x y)))

(rule (simplify (ushr ty (splat ty x) y))
(splat ty (ushr (lane_type ty) x y)))

(rule (simplify (sshr ty (splat ty x) y))
(splat ty (sshr (lane_type ty) x y)))
225 changes: 225 additions & 0 deletions cranelift/filetests/filetests/egraph/simd-splat-simplify.clif
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
test optimize
set opt_level=speed
target x86_64

function %band_splat_into_splat_band(i64, i64) -> i64x2 {
block0(v0: i64, v1: i64):
v2 = splat.i64x2 v0
v3 = splat.i64x2 v1
v4 = band.i64x2 v2, v3
return v4
; check: v5 = band v0, v1
; check: v6 = splat.i64x2 v5
; check: return v6
}

function %bor_splat_into_splat_bor(i64, i64) -> i64x2 {
block0(v0: i64, v1: i64):
v2 = splat.i64x2 v0
v3 = splat.i64x2 v1
v4 = bor.i64x2 v2, v3
return v4
; check: v5 = bor v0, v1
; check: v6 = splat.i64x2 v5
; check: return v6
}

function %bxor_splat_into_splat_bxor(i64, i64) -> i64x2 {
block0(v0: i64, v1: i64):
v2 = splat.i64x2 v0
v3 = splat.i64x2 v1
v4 = bxor.i64x2 v2, v3
return v4
; check: v5 = bxor v0, v1
; check: v6 = splat.i64x2 v5
; check: return v6
}

function %bnot_splat_into_splat_bnot(i64) -> i64x2 {
block0(v0: i64):
v1 = splat.i64x2 v0
v2 = bnot.i64x2 v1
return v2
; check: v3 = bnot v0
; check: v4 = splat.i64x2 v3
; check: return v4
}

function %iadd_splat_into_splat_iadd(i64, i64) -> i64x2 {
block0(v0: i64, v1: i64):
v2 = splat.i64x2 v0
v3 = splat.i64x2 v1
v4 = iadd.i64x2 v2, v3
return v4
; check: v5 = iadd v0, v1
; check: v6 = splat.i64x2 v5
; check: return v6
}

function %isub_splat_into_splat_isub(i64, i64) -> i64x2 {
block0(v0: i64, v1: i64):
v2 = splat.i64x2 v0
v3 = splat.i64x2 v1
v4 = isub.i64x2 v2, v3
return v4
; check: v5 = isub v0, v1
; check: v6 = splat.i64x2 v5
; check: return v6
}

function %imul_splat_into_splat_imul(i64, i64) -> i64x2 {
block0(v0: i64, v1: i64):
v2 = splat.i64x2 v0
v3 = splat.i64x2 v1
v4 = imul.i64x2 v2, v3
return v4
; check: v5 = imul v0, v1
; check: v6 = splat.i64x2 v5
; check: return v6
}

function %smulhi_splat_into_splat_smulhi(i64, i64) -> i64x2 {
block0(v0: i64, v1: i64):
v2 = splat.i64x2 v0
v3 = splat.i64x2 v1
v4 = smulhi.i64x2 v2, v3
return v4
; check: v5 = smulhi v0, v1
; check: v6 = splat.i64x2 v5
; check: return v6
}

function %umulhi_splat_into_splat_umulhi(i64, i64) -> i64x2 {
block0(v0: i64, v1: i64):
v2 = splat.i64x2 v0
v3 = splat.i64x2 v1
v4 = umulhi.i64x2 v2, v3
return v4
; check: v5 = umulhi v0, v1
; check: v6 = splat.i64x2 v5
; check: return v6
}

function %ineg_splat_into_splat_ineg(i64) -> i64x2 {
block0(v0: i64):
v1 = splat.i64x2 v0
v2 = ineg.i64x2 v1
return v2
; check: v3 = ineg v0
; check: v4 = splat.i64x2 v3
; check: return v4
}

function %iabs_splat_into_splat_iabs(i64) -> i64x2 {
block0(v0: i64):
v1 = splat.i64x2 v0
v2 = iabs.i64x2 v1
return v2
; check: v3 = iabs v0
; check: v4 = splat.i64x2 v3
; check: return v4
}

function %popcnt_splat_into_splat_popcnt(i64) -> i64x2 {
block0(v0: i64):
v1 = splat.i64x2 v0
v2 = popcnt.i64x2 v1
return v2
; check: v3 = popcnt v0
; check: v4 = splat.i64x2 v3
; check: return v4
}

function %smin_splat_into_splat_smin(i64, i64) -> i64x2 {
block0(v0: i64, v1: i64):
v2 = splat.i64x2 v0
v3 = splat.i64x2 v1
v4 = smin.i64x2 v2, v3
return v4
; check: v5 = smin v0, v1
; check: v6 = splat.i64x2 v5
; check: return v6
}

function %umin_splat_into_splat_umin(i64, i64) -> i64x2 {
block0(v0: i64, v1: i64):
v2 = splat.i64x2 v0
v3 = splat.i64x2 v1
v4 = umin.i64x2 v2, v3
return v4
; check: v5 = umin v0, v1
; check: v6 = splat.i64x2 v5
; check: return v6
}

function %smax_splat_into_splat_smax(i64, i64) -> i64x2 {
block0(v0: i64, v1: i64):
v2 = splat.i64x2 v0
v3 = splat.i64x2 v1
v4 = smax.i64x2 v2, v3
return v4
; check: v5 = smax v0, v1
; check: v6 = splat.i64x2 v5
; check: return v6
}

function %umax_splat_into_splat_umax(i64, i64) -> i64x2 {
block0(v0: i64, v1: i64):
v2 = splat.i64x2 v0
v3 = splat.i64x2 v1
v4 = umax.i64x2 v2, v3
return v4
; check: v5 = umax v0, v1
; check: v6 = splat.i64x2 v5
; check: return v6
}

function %rotl_splat_into_splat_rotl(i64, i64) -> i64x2 {
block0(v0: i64, v1: i64):
v2 = splat.i64x2 v0
v3 = rotl.i64x2 v2, v1
return v3
; check: v4 = rotl v0, v1
; check: v5 = splat.i64x2 v4
; check: return v5
}

function %rotr_splat_into_splat_rotr(i64, i64) -> i64x2 {
block0(v0: i64, v1: i64):
v2 = splat.i64x2 v0
v3 = rotr.i64x2 v2, v1
return v3
; check: v4 = rotr v0, v1
; check: v5 = splat.i64x2 v4
; check: return v5
}

function %ishl_splat_into_splat_ishl(i64, i64) -> i64x2 {
block0(v0: i64, v1: i64):
v2 = splat.i64x2 v0
v3 = ishl.i64x2 v2, v1
return v3
; check: v4 = ishl v0, v1
; check: v5 = splat.i64x2 v4
; check: return v5
}

function %ushr_splat_into_splat_ushr(i64, i64) -> i64x2 {
block0(v0: i64, v1: i64):
v2 = splat.i64x2 v0
v3 = ushr.i64x2 v2, v1
return v3
; check: v4 = ushr v0, v1
; check: v5 = splat.i64x2 v4
; check: return v5
}

function %sshr_splat_into_splat_sshr(i64, i64) -> i64x2 {
block0(v0: i64, v1: i64):
v2 = splat.i64x2 v0
v3 = sshr.i64x2 v2, v1
return v3
; check: v4 = sshr v0, v1
; check: v5 = splat.i64x2 v4
; check: return v5
}

0 comments on commit b32a9d8

Please sign in to comment.