| ;; Chained `uextend` and `sextend`. |
| (rule (simplify (uextend ty (uextend _intermediate_ty x))) |
| (uextend ty x)) |
| (rule (simplify (sextend ty (sextend _intermediate_ty x))) |
| (sextend ty x)) |
| |
| ;; Once something has be `uextend`ed, further `sextend`ing is the same as `uextend` |
| (rule (simplify (sextend ty (uextend _intermediate_ty x))) |
| (uextend ty x)) |
| |
| ;; `icmp` is zero or one, so sign-extending is the same as zero-extending |
| (rule (simplify (sextend ty x@(icmp _ _ _ _))) |
| (uextend ty x)) |
| |
| ;; Masking out any of the top bits of the result of `uextend` is a no-op. (This |
| ;; is like a cheap version of known-bits analysis.) |
| (rule (simplify (band wide x @ (uextend _ (value_type narrow)) (iconst_u _ mask))) |
| ; Check that `narrow_mask` has a subset of the bits that `mask` does. |
| (if-let $true (let ((narrow_mask u64 (ty_mask narrow))) (u64_eq narrow_mask (u64_and mask narrow_mask)))) |
| x) |
| |
| ;; Masking out the sign-extended bits of an `sextend` turns it into a `uextend`. |
| (rule (simplify (band wide (sextend _ x @ (value_type narrow)) (iconst_u _ mask))) |
| (if-let $true (u64_eq mask (ty_mask narrow))) |
| (uextend wide x)) |
| |
| ;; 32-bit integers zero-extended to 64-bit integers are never negative |
| (rule (simplify |
| (slt ty |
| (uextend $I64 x @ (value_type $I32)) |
| (iconst_u _ 0))) |
| (iconst_u ty 0)) |
| (rule (simplify |
| (sge ty |
| (uextend $I64 x @ (value_type $I32)) |
| (iconst_u _ 0))) |
| (iconst_u ty 1)) |
| |
| ;; Sign-extending can't change whether a number is zero nor how it signed-compares to zero |
| (rule (simplify (eq _ (sextend _ x@(value_type ty)) (iconst_s _ 0))) |
| (eq ty x (iconst_s ty 0))) |
| (rule (simplify (ne _ (sextend _ x@(value_type ty)) (iconst_s _ 0))) |
| (ne ty x (iconst_s ty 0))) |
| (rule (simplify (icmp _ cc (sextend _ x@(value_type ty)) (iconst_s _ 0))) |
| (if (signed_cond_code cc)) |
| (icmp ty cc x (iconst_s ty 0))) |
| |
| ;; A reduction-of-an-extend back to the same original type is the same as not |
| ;; actually doing the extend in the first place. |
| (rule (simplify (ireduce ty (sextend _ x @ (value_type ty)))) (subsume x)) |
| (rule (simplify (ireduce ty (uextend _ x @ (value_type ty)))) (subsume x)) |
| |
| ;; A reduction-of-an-extend that's not just to the original type is either: |
| ;; a reduction of the original if the final type is smaller, or |
| (rule (simplify (ireduce (ty_int ty_final) (sextend _ inner@(value_type ty_initial)))) |
| (if-let $true (u64_lt (ty_bits_u64 ty_final) (ty_bits_u64 ty_initial))) |
| (ireduce ty_final inner)) |
| (rule (simplify (ireduce (ty_int ty_final) (uextend _ inner@(value_type ty_initial)))) |
| (if-let $true (u64_lt (ty_bits_u64 ty_final) (ty_bits_u64 ty_initial))) |
| (ireduce ty_final inner)) |
| ;; an extension of the original if the final type is larger. |
| (rule (simplify (ireduce (ty_int ty_final) (sextend _ inner@(value_type ty_initial)))) |
| (if-let $true (u64_lt (ty_bits_u64 ty_initial) (ty_bits_u64 ty_final))) |
| (sextend ty_final inner)) |
| (rule (simplify (ireduce (ty_int ty_final) (uextend _ inner@(value_type ty_initial)))) |
| (if-let $true (u64_lt (ty_bits_u64 ty_initial) (ty_bits_u64 ty_final))) |
| (uextend ty_final inner)) |
| |
| ;; `band`, `bor`, and `bxor` can't affect any bits that aren't set in the one of |
| ;; the inputs, so they can be pushed down inside `uextend`s |
| (rule (simplify (band bigty (uextend _ x@(value_type smallty)) (uextend _ y@(value_type smallty)))) |
| (uextend bigty (band smallty x y))) |
| (rule (simplify (bor bigty (uextend _ x@(value_type smallty)) (uextend _ y@(value_type smallty)))) |
| (uextend bigty (bor smallty x y))) |
| (rule (simplify (bxor bigty (uextend _ x@(value_type smallty)) (uextend _ y@(value_type smallty)))) |
| (uextend bigty (bxor smallty x y))) |
| |
| ;; Matches values where `ireducing` them will not actually introduce another |
| ;; instruction, since other rules will collapse them with the reduction. |
| (decl pure multi will_simplify_with_ireduce (Value) Value) |
| (rule (will_simplify_with_ireduce x@(uextend _ _)) x) |
| (rule (will_simplify_with_ireduce x@(sextend _ _)) x) |
| (rule (will_simplify_with_ireduce x@(iconst _ _)) x) |
| (rule (will_simplify_with_ireduce x@(unary_op _ _ a)) |
| (if-let _ (will_simplify_with_ireduce a)) |
| x) |
| (rule (will_simplify_with_ireduce x@(binary_op _ _ a b)) |
| (if-let _ (will_simplify_with_ireduce a)) |
| (if-let _ (will_simplify_with_ireduce b)) |
| x) |
| |
| ;; Matches values where the high bits of the input don't affect lower bits of |
| ;; the output, and thus the inputs can be reduced before the operation rather |
| ;; than doing the wide operation then reducing afterwards. |
| (decl pure multi reducible_modular_op (Value) Value) |
| (rule (reducible_modular_op x@(ineg _ _)) x) |
| (rule (reducible_modular_op x@(bnot _ _)) x) |
| (rule (reducible_modular_op x@(iadd _ _ _)) x) |
| (rule (reducible_modular_op x@(isub _ _ _)) x) |
| (rule (reducible_modular_op x@(imul _ _ _)) x) |
| (rule (reducible_modular_op x@(bor _ _ _)) x) |
| (rule (reducible_modular_op x@(bxor _ _ _)) x) |
| (rule (reducible_modular_op x@(band _ _ _)) x) |
| |
| ;; Replace `(small)(x OP y)` with `(small)x OP (small)y` in cases where that's |
| ;; legal and it reduces the total number of instructions since the reductions |
| ;; to the arguments simplify further. |
| (rule (simplify (ireduce smallty val@(unary_op _ op x))) |
| (if-let _ (reducible_modular_op val)) |
| (if-let _ (will_simplify_with_ireduce x)) |
| (unary_op smallty op (ireduce smallty x))) |
| (rule (simplify (ireduce smallty val@(binary_op _ op x y))) |
| (if-let _ (reducible_modular_op val)) |
| (if-let _ (will_simplify_with_ireduce x)) |
| (if-let _ (will_simplify_with_ireduce y)) |
| (binary_op smallty op (ireduce smallty x) (ireduce smallty y))) |