1;; Prelude definitions specific to the mid-end.
2
3;; Any `extern` definitions here are generally implemented in `src/opts.rs`.
4
5;;;;; eclass and enode access ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
6
7;; Extract any node(s) for the given eclass ID.
8(decl multi inst_data (Type InstructionData) Value)
9(extern extractor inst_data inst_data_etor)
10
11;; Identical to `inst_data`, just with a different ISLE type.
12;; This is basically a manual version of `curry`/`uncurry` in Haskell:
13;; to compose extractors the outer one needs to be single-parameter,
14;; so this combines the two parameters of `inst_data` into one.
15(type TypeAndInstructionData (primitive TypeAndInstructionData))
16(decl multi inst_data_tupled (TypeAndInstructionData) Value)
17(extern extractor inst_data_tupled inst_data_tupled_etor)
18
19;; Construct a pure node, returning a new (or deduplicated
20;; already-existing) eclass ID.
21(decl make_inst (Type InstructionData) Value)
22(extern constructor make_inst make_inst_ctor)
23
24;; Constructors for value arrays.
25(decl value_array_2_ctor (Value Value) ValueArray2)
26(extern constructor value_array_2_ctor value_array_2_ctor)
27(decl value_array_3_ctor (Value Value Value) ValueArray3)
28(extern constructor value_array_3_ctor value_array_3_ctor)
29
30(rule (eq ty x y) (icmp ty (IntCC.Equal) x y))
31(rule (ne ty x y) (icmp ty (IntCC.NotEqual) x y))
32(rule (ult ty x y) (icmp ty (IntCC.UnsignedLessThan) x y))
33(rule (ule ty x y) (icmp ty (IntCC.UnsignedLessThanOrEqual) x y))
34(rule (ugt ty x y) (icmp ty (IntCC.UnsignedGreaterThan) x y))
35(rule (uge ty x y) (icmp ty (IntCC.UnsignedGreaterThanOrEqual) x y))
36(rule (slt ty x y) (icmp ty (IntCC.SignedLessThan) x y))
37(rule (sle ty x y) (icmp ty (IntCC.SignedLessThanOrEqual) x y))
38(rule (sgt ty x y) (icmp ty (IntCC.SignedGreaterThan) x y))
39(rule (sge ty x y) (icmp ty (IntCC.SignedGreaterThanOrEqual) x y))
40
41;; 3-way comparison, returning -1/0/+1 in I8
42(decl spaceship_s (Type Value Value) Value)
43(rule (spaceship_s ty x y) (isub $I8 (sgt ty x y) (slt ty x y)))
44(extractor (spaceship_s ty x y) (isub $I8 (sgt ty x y) (slt ty x y)))
45(decl spaceship_u (Type Value Value) Value)
46(rule (spaceship_u ty x y) (isub $I8 (ugt ty x y) (ult ty x y)))
47(extractor (spaceship_u ty x y) (isub $I8 (ugt ty x y) (ult ty x y)))
48
49;;;;; optimization toplevel ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
50
51;; The main matcher rule invoked by the toplevel driver.
52(decl multi simplify (Value) Value)
53
54;; Mark a node as requiring remat when used in a different block.
55(decl remat (Value) Value)
56(extern constructor remat remat)
57
58;; Mark a node as subsuming whatever else it's rewritten from -- this
59;; is definitely preferable, not just a possible option. Useful for,
60;; e.g., constant propagation where we arrive at a definite "final
61;; answer".
62(decl subsume (Value) Value)
63(extern constructor subsume subsume)
64
65;;;;; constructors ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
66
67(decl iconst_sextend_etor (Type i64) TypeAndInstructionData)
68(extern extractor iconst_sextend_etor iconst_sextend_etor)
69
70;; Construct an `iconst` from an `i64` or Extract an `i64` from an `iconst`
71;; by treating the constant as signed.
72;; When extracting, smaller types get their value sign-extended to 64-bits,
73;; so that `iconst.i8 255` will give you a `-1_i64`.
74;; When constructing, the rule will fail if the value cannot be represented in
75;; the target type.  If it fits, it'll be masked accordingly in the constant.
76(decl iconst_s (Type i64) Value)
77(extractor (iconst_s ty c) (inst_data_tupled (iconst_sextend_etor ty c)))
78(rule 0 (iconst_s ty c)
79	(if-let c_masked (u64_and (i64_as_u64 c) (ty_umax ty)))
80	(if-let c_reextended (i64_sextend_u64 ty c_masked))
81	(if-let $true (u64_eq (i64_as_u64 c) (i64_as_u64 c_reextended)))
82	(iconst ty (imm64 c_masked)))
83(rule 1 (iconst_s $I128 c) (sextend $I128 (iconst_s $I64 c)))
84
85;; Construct an `iconst` from a `u64` or Extract a `u64` from an `iconst`
86;; by treating the constant as unsigned.
87;; When extracting, smaller types get their value zero-extended to 64-bits,
88;; so that `iconst.i8 255` will give you a `255_u64`.
89;; When constructing, the rule will fail if the value cannot be represented in
90;; the target type.
91(decl iconst_u (Type u64) Value)
92(extractor (iconst_u ty c) (iconst ty (u64_from_imm64 c)))
93(rule 0 (iconst_u ty c)
94	(if-let $true (u64_le c (ty_umax ty)))
95    (iconst ty (imm64 c)))
96(rule 1 (iconst_u $I128 c) (uextend $I128 (iconst_u $I64 c)))
97
98;; These take `Value`, rather than going through `inst_data_tupled`, because
99;; most of the time they want to return the original `Value`, and it would be
100;; a waste to need to re-GVN the instruction data in those cases.
101(decl multi sextend_maybe_etor (Type Value) Value)
102(extern extractor infallible sextend_maybe_etor sextend_maybe_etor)
103(decl multi uextend_maybe_etor (Type Value) Value)
104(extern extractor infallible uextend_maybe_etor uextend_maybe_etor)
105
106;; Match or Construct a possibly-`uextend`ed value.
107;; Gives the extended-to type and inner value when matching something that was
108;; extended, or the input value and its type when the value isn't an extension.
109;; Useful to write a single pattern that can match things that may or may not
110;; have undergone C's "usual arithmetic conversions".
111;; When generating values, extending to the same type is invalid CLIF,
112;; so this avoids doing that where there's no extension actually needed.
113(decl uextend_maybe (Type Value) Value)
114(extractor (uextend_maybe ty val) (uextend_maybe_etor ty val))
115(rule 0 (uextend_maybe ty val) (uextend ty val))
116(rule 1 (uextend_maybe ty val@(value_type ty)) val)
117
118;; Same as `uextend_maybe` above, just for `sextend`.
119(decl sextend_maybe (Type Value) Value)
120(extractor (sextend_maybe ty val) (sextend_maybe_etor ty val))
121(rule 0 (sextend_maybe ty val) (sextend ty val))
122(rule 1 (sextend_maybe ty val@(value_type ty)) val)
123