1use crate::egraph::{NewOrExistingInst, OptimizeCtx};
4pub use crate::ir::condcodes::{FloatCC, IntCC};
5use crate::ir::dfg::ValueDef;
6pub use crate::ir::immediates::{Ieee128, Ieee16, Ieee32, Ieee64, Imm64, Offset32, Uimm8, V128Imm};
7use crate::ir::instructions::InstructionFormat;
8pub use crate::ir::types::*;
9pub use crate::ir::{
10 AtomicRmwOp, BlockCall, Constant, DynamicStackSlot, FuncRef, GlobalValue, Immediate,
11 InstructionData, MemFlags, Opcode, StackSlot, TrapCode, Type, Value,
12};
13use crate::isle_common_prelude_methods;
14use crate::machinst::isle::*;
15use crate::trace;
16use cranelift_entity::packed_option::ReservedValue;
17use smallvec::{smallvec, SmallVec};
18use std::marker::PhantomData;
19
20#[allow(dead_code)]
21pub type Unit = ();
22pub type Range = (usize, usize);
23pub type ValueArray2 = [Value; 2];
24pub type ValueArray3 = [Value; 3];
25
26const MAX_ISLE_RETURNS: usize = 8;
27
28pub type ConstructorVec<T> = SmallVec<[T; MAX_ISLE_RETURNS]>;
29
30type TypeAndInstructionData = (Type, InstructionData);
31
32impl<T: smallvec::Array> generated_code::Length for SmallVec<T> {
33 #[inline]
34 fn len(&self) -> usize {
35 SmallVec::len(self)
36 }
37}
38
39pub(crate) mod generated_code;
40use generated_code::{ContextIter, IntoContextIter};
41
42pub(crate) struct IsleContext<'a, 'b, 'c> {
43 pub(crate) ctx: &'a mut OptimizeCtx<'b, 'c>,
44}
45
46pub(crate) struct InstDataEtorIter<'a, 'b, 'c> {
47 stack: SmallVec<[Value; 8]>,
48 _phantom1: PhantomData<&'a ()>,
49 _phantom2: PhantomData<&'b ()>,
50 _phantom3: PhantomData<&'c ()>,
51}
52
53impl Default for InstDataEtorIter<'_, '_, '_> {
54 fn default() -> Self {
55 InstDataEtorIter {
56 stack: SmallVec::default(),
57 _phantom1: PhantomData,
58 _phantom2: PhantomData,
59 _phantom3: PhantomData,
60 }
61 }
62}
63
64impl<'a, 'b, 'c> InstDataEtorIter<'a, 'b, 'c> {
65 fn new(root: Value) -> Self {
66 debug_assert_ne!(root, Value::reserved_value());
67 Self {
68 stack: smallvec![root],
69 _phantom1: PhantomData,
70 _phantom2: PhantomData,
71 _phantom3: PhantomData,
72 }
73 }
74}
75
76impl<'a, 'b, 'c> ContextIter for InstDataEtorIter<'a, 'b, 'c>
77where
78 'b: 'a,
79 'c: 'b,
80{
81 type Context = IsleContext<'a, 'b, 'c>;
82 type Output = (Type, InstructionData);
83
84 fn next(&mut self, ctx: &mut IsleContext<'a, 'b, 'c>) -> Option<Self::Output> {
85 while let Some(value) = self.stack.pop() {
86 debug_assert!(ctx.ctx.func.dfg.value_is_real(value));
87 trace!("iter: value {:?}", value);
88 match ctx.ctx.func.dfg.value_def(value) {
89 ValueDef::Union(x, y) => {
90 debug_assert_ne!(x, Value::reserved_value());
91 debug_assert_ne!(y, Value::reserved_value());
92 trace!(" -> {}, {}", x, y);
93 self.stack.push(x);
94 self.stack.push(y);
95 continue;
96 }
97 ValueDef::Result(inst, _) if ctx.ctx.func.dfg.inst_results(inst).len() == 1 => {
98 let ty = ctx.ctx.func.dfg.value_type(value);
99 trace!(" -> value of type {}", ty);
100 return Some((ty, ctx.ctx.func.dfg.insts[inst]));
101 }
102 _ => {}
103 }
104 }
105 None
106 }
107}
108
109impl<'a, 'b, 'c> IntoContextIter for InstDataEtorIter<'a, 'b, 'c>
110where
111 'b: 'a,
112 'c: 'b,
113{
114 type Context = IsleContext<'a, 'b, 'c>;
115 type Output = (Type, InstructionData);
116 type IntoIter = Self;
117
118 fn into_context_iter(self) -> Self {
119 self
120 }
121}
122
123#[derive(Default)]
124pub(crate) struct MaybeUnaryEtorIter<'a, 'b, 'c> {
125 opcode: Option<Opcode>,
126 inner: InstDataEtorIter<'a, 'b, 'c>,
127 fallback: Option<Value>,
128}
129
130impl MaybeUnaryEtorIter<'_, '_, '_> {
131 fn new(opcode: Opcode, value: Value) -> Self {
132 debug_assert_eq!(opcode.format(), InstructionFormat::Unary);
133 Self {
134 opcode: Some(opcode),
135 inner: InstDataEtorIter::new(value),
136 fallback: Some(value),
137 }
138 }
139}
140
141impl<'a, 'b, 'c> ContextIter for MaybeUnaryEtorIter<'a, 'b, 'c>
142where
143 'b: 'a,
144 'c: 'b,
145{
146 type Context = IsleContext<'a, 'b, 'c>;
147 type Output = (Type, Value);
148
149 fn next(&mut self, ctx: &mut IsleContext<'a, 'b, 'c>) -> Option<Self::Output> {
150 debug_assert_ne!(self.opcode, None);
151 while let Some((ty, inst_def)) = self.inner.next(ctx) {
152 let InstructionData::Unary { opcode, arg } = inst_def else {
153 continue;
154 };
155 if Some(opcode) == self.opcode {
156 self.fallback = None;
157 return Some((ty, arg));
158 }
159 }
160
161 self.fallback.take().map(|value| {
162 let ty = generated_code::Context::value_type(ctx, value);
163 (ty, value)
164 })
165 }
166}
167
168impl<'a, 'b, 'c> IntoContextIter for MaybeUnaryEtorIter<'a, 'b, 'c>
169where
170 'b: 'a,
171 'c: 'b,
172{
173 type Context = IsleContext<'a, 'b, 'c>;
174 type Output = (Type, Value);
175 type IntoIter = Self;
176
177 fn into_context_iter(self) -> Self {
178 self
179 }
180}
181
182impl<'a, 'b, 'c> generated_code::Context for IsleContext<'a, 'b, 'c> {
183 isle_common_prelude_methods!();
184
185 type inst_data_etor_returns = InstDataEtorIter<'a, 'b, 'c>;
186
187 fn inst_data_etor(&mut self, eclass: Value, returns: &mut InstDataEtorIter<'a, 'b, 'c>) {
188 *returns = InstDataEtorIter::new(eclass);
189 }
190
191 type inst_data_tupled_etor_returns = InstDataEtorIter<'a, 'b, 'c>;
192
193 fn inst_data_tupled_etor(&mut self, eclass: Value, returns: &mut InstDataEtorIter<'a, 'b, 'c>) {
194 self.inst_data_etor(eclass, returns);
196 }
197
198 fn make_inst_ctor(&mut self, ty: Type, op: &InstructionData) -> Value {
199 let value = self.ctx.insert_pure_enode(NewOrExistingInst::New(*op, ty));
200 trace!("make_inst_ctor: {:?} -> {}", op, value);
201 value
202 }
203
204 fn value_array_2_ctor(&mut self, arg0: Value, arg1: Value) -> ValueArray2 {
205 [arg0, arg1]
206 }
207
208 fn value_array_3_ctor(&mut self, arg0: Value, arg1: Value, arg2: Value) -> ValueArray3 {
209 [arg0, arg1, arg2]
210 }
211
212 #[inline]
213 fn value_type(&mut self, val: Value) -> Type {
214 self.ctx.func.dfg.value_type(val)
215 }
216
217 fn iconst_sextend_etor(
218 &mut self,
219 (ty, inst_data): (Type, InstructionData),
220 ) -> Option<(Type, i64)> {
221 if let InstructionData::UnaryImm {
222 opcode: Opcode::Iconst,
223 imm,
224 } = inst_data
225 {
226 Some((ty, self.i64_sextend_imm64(ty, imm)))
227 } else {
228 None
229 }
230 }
231
232 fn remat(&mut self, value: Value) -> Value {
233 trace!("remat: {}", value);
234 self.ctx.remat_values.insert(value);
235 self.ctx.stats.remat += 1;
236 value
237 }
238
239 fn subsume(&mut self, value: Value) -> Value {
240 trace!("subsume: {}", value);
241 self.ctx.subsume_values.insert(value);
242 self.ctx.stats.subsume += 1;
243 value
244 }
245
246 fn splat64(&mut self, val: u64) -> Constant {
247 let val = u128::from(val);
248 let val = val | (val << 64);
249 let imm = V128Imm(val.to_le_bytes());
250 self.ctx.func.dfg.constants.insert(imm.into())
251 }
252
253 type sextend_maybe_etor_returns = MaybeUnaryEtorIter<'a, 'b, 'c>;
254 fn sextend_maybe_etor(&mut self, value: Value, returns: &mut Self::sextend_maybe_etor_returns) {
255 *returns = MaybeUnaryEtorIter::new(Opcode::Sextend, value);
256 }
257
258 type uextend_maybe_etor_returns = MaybeUnaryEtorIter<'a, 'b, 'c>;
259 fn uextend_maybe_etor(&mut self, value: Value, returns: &mut Self::uextend_maybe_etor_returns) {
260 *returns = MaybeUnaryEtorIter::new(Opcode::Uextend, value);
261 }
262
263 fn f32_from_uint(&mut self, n: u64) -> Ieee32 {
267 Ieee32::with_float(n as f32)
268 }
269
270 fn f64_from_uint(&mut self, n: u64) -> Ieee64 {
271 Ieee64::with_float(n as f64)
272 }
273
274 fn f32_from_sint(&mut self, n: i64) -> Ieee32 {
275 Ieee32::with_float(n as f32)
276 }
277
278 fn f64_from_sint(&mut self, n: i64) -> Ieee64 {
279 Ieee64::with_float(n as f64)
280 }
281
282 fn u64_bswap16(&mut self, n: u64) -> u64 {
283 (n as u16).swap_bytes() as u64
284 }
285
286 fn u64_bswap32(&mut self, n: u64) -> u64 {
287 (n as u32).swap_bytes() as u64
288 }
289
290 fn u64_bswap64(&mut self, n: u64) -> u64 {
291 n.swap_bytes()
292 }
293
294 fn ieee128_constant_extractor(&mut self, n: Constant) -> Option<Ieee128> {
295 self.ctx.func.dfg.constants.get(n).try_into().ok()
296 }
297
298 fn ieee128_constant(&mut self, n: Ieee128) -> Constant {
299 self.ctx.func.dfg.constants.insert(n.into())
300 }
301}