1;; Chained `uextend` and `sextend`.
2(rule (simplify (uextend ty (uextend _intermediate_ty x)))
3      (uextend ty x))
4(rule (simplify (sextend ty (sextend _intermediate_ty x)))
5      (sextend ty x))
6
7;; Once something has be `uextend`ed, further `sextend`ing is the same as `uextend`
8(rule (simplify (sextend ty (uextend _intermediate_ty x)))
9      (uextend ty x))
10
11;; `icmp` is zero or one, so sign-extending is the same as zero-extending
12(rule (simplify (sextend ty x@(icmp _ _ _ _)))
13      (uextend ty x))
14
15;; Masking out any of the top bits of the result of `uextend` is a no-op. (This
16;; is like a cheap version of known-bits analysis.)
17(rule (simplify (band wide x @ (uextend _ (value_type narrow)) (iconst_u _ mask)))
18      ; Check that `narrow_mask` has a subset of the bits that `mask` does.
19      (if-let $true (let ((narrow_mask u64 (ty_mask narrow))) (u64_eq narrow_mask (u64_and mask narrow_mask))))
20      x)
21
22;; Masking out the sign-extended bits of an `sextend` turns it into a `uextend`.
23(rule (simplify (band wide (sextend _ x @ (value_type narrow)) (iconst_u _ mask)))
24      (if-let $true (u64_eq mask (ty_mask narrow)))
25      (uextend wide x))
26
27;; 32-bit integers zero-extended to 64-bit integers are never negative
28(rule (simplify
29       (slt ty
30             (uextend $I64 x @ (value_type $I32))
31             (iconst_u _ 0)))
32      (iconst_u ty 0))
33(rule (simplify
34       (sge ty
35             (uextend $I64 x @ (value_type $I32))
36             (iconst_u _ 0)))
37      (iconst_u ty 1))
38
39;; Sign-extending can't change whether a number is zero nor how it signed-compares to zero
40(rule (simplify (eq _ (sextend _ x@(value_type ty)) (iconst_s _ 0)))
41      (eq ty x (iconst_s ty 0)))
42(rule (simplify (ne _ (sextend _ x@(value_type ty)) (iconst_s _ 0)))
43      (ne ty x (iconst_s ty 0)))
44(rule (simplify (icmp _ cc (sextend _ x@(value_type ty)) (iconst_s _ 0)))
45      (if (signed_cond_code cc))
46      (icmp ty cc x (iconst_s ty 0)))
47
48;; A reduction-of-an-extend back to the same original type is the same as not
49;; actually doing the extend in the first place.
50(rule (simplify (ireduce ty (sextend _ x @ (value_type ty)))) x)
51(rule (simplify (ireduce ty (uextend _ x @ (value_type ty)))) x)
52
53;; `band`, `bor`, and `bxor` can't affect any bits that aren't set in the one of
54;; the inputs, so they can be pushed down inside `uextend`s
55(rule (simplify (band bigty (uextend _ x@(value_type smallty)) (uextend _ y@(value_type smallty))))
56      (uextend bigty (band smallty x y)))
57(rule (simplify (bor bigty (uextend _ x@(value_type smallty)) (uextend _ y@(value_type smallty))))
58      (uextend bigty (bor smallty x y)))
59(rule (simplify (bxor bigty (uextend _ x@(value_type smallty)) (uextend _ y@(value_type smallty))))
60      (uextend bigty (bxor smallty x y)))
61
62;; Matches values where `ireducing` them will not actually introduce another
63;; instruction, since other rules will collapse them with the reduction.
64(decl pure multi will_simplify_with_ireduce (Value) Value)
65(rule (will_simplify_with_ireduce x@(uextend _ _)) x)
66(rule (will_simplify_with_ireduce x@(sextend _ _)) x)
67(rule (will_simplify_with_ireduce x@(iconst _ _)) x)
68(rule (will_simplify_with_ireduce x@(unary_op _ _ a))
69      (if-let _ (will_simplify_with_ireduce a))
70      x)
71(rule (will_simplify_with_ireduce x@(binary_op _ _ a b))
72      (if-let _ (will_simplify_with_ireduce a))
73      (if-let _ (will_simplify_with_ireduce b))
74      x)
75
76;; Matches values where the high bits of the input don't affect lower bits of
77;; the output, and thus the inputs can be reduced before the operation rather
78;; than doing the wide operation then reducing afterwards.
79(decl pure multi reducible_modular_op (Value) Value)
80(rule (reducible_modular_op x@(ineg _ _)) x)
81(rule (reducible_modular_op x@(bnot _ _)) x)
82(rule (reducible_modular_op x@(iadd _ _ _)) x)
83(rule (reducible_modular_op x@(isub _ _ _)) x)
84(rule (reducible_modular_op x@(imul _ _ _)) x)
85(rule (reducible_modular_op x@(bor  _ _ _)) x)
86(rule (reducible_modular_op x@(bxor _ _ _)) x)
87(rule (reducible_modular_op x@(band _ _ _)) x)
88
89;; Replace `(small)(x OP y)` with `(small)x OP (small)y` in cases where that's
90;; legal and it reduces the total number of instructions since the reductions
91;; to the arguments simplify further.
92(rule (simplify (ireduce smallty val@(unary_op _ op x)))
93      (if-let _ (reducible_modular_op val))
94      (if-let _ (will_simplify_with_ireduce x))
95      (unary_op smallty op (ireduce smallty x)))
96(rule (simplify (ireduce smallty val@(binary_op _ op x y)))
97      (if-let _ (reducible_modular_op val))
98      (if-let _ (will_simplify_with_ireduce x))
99      (if-let _ (will_simplify_with_ireduce y))
100      (binary_op smallty op (ireduce smallty x) (ireduce smallty y)))
101