Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/isa/pulley_shared/inst/args.rs
1693 views
1
//! Pulley instruction arguments.
2
3
use super::*;
4
use crate::ir::ExternalName;
5
use crate::machinst::abi::StackAMode;
6
use pulley_interpreter::encode;
7
use pulley_interpreter::regs::Reg as _;
8
use std::fmt;
9
10
/// A macro for defining a newtype of `Reg` that enforces some invariant about
11
/// the wrapped `Reg` (such as that it is of a particular register class).
12
macro_rules! newtype_of_reg {
13
(
14
$newtype_reg:ident,
15
$newtype_writable_reg:ident,
16
$class:expr
17
) => {
18
/// A newtype wrapper around `Reg`.
19
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
20
pub struct $newtype_reg(Reg);
21
22
impl PartialEq<Reg> for $newtype_reg {
23
fn eq(&self, other: &Reg) -> bool {
24
self.0 == *other
25
}
26
}
27
28
impl From<$newtype_reg> for Reg {
29
fn from(r: $newtype_reg) -> Self {
30
r.0
31
}
32
}
33
34
impl TryFrom<Reg> for $newtype_reg {
35
type Error = ();
36
fn try_from(r: Reg) -> Result<Self, Self::Error> {
37
Self::new(r).ok_or(())
38
}
39
}
40
41
impl $newtype_reg {
42
/// Create this newtype from the given register, or return `None` if the register
43
/// is not a valid instance of this newtype.
44
pub fn new(reg: Reg) -> Option<Self> {
45
if reg.class() == $class {
46
Some(Self(reg))
47
} else {
48
None
49
}
50
}
51
52
/// Get this newtype's underlying `Reg`.
53
pub fn to_reg(self) -> Reg {
54
self.0
55
}
56
}
57
58
// Convenience impl so that people working with this newtype can use it
59
// "just like" a plain `Reg`.
60
//
61
// NB: We cannot implement `DerefMut` because that would let people do
62
// nasty stuff like `*my_xreg.deref_mut() = some_freg`, breaking the
63
// invariants that `XReg` provides.
64
impl std::ops::Deref for $newtype_reg {
65
type Target = Reg;
66
67
fn deref(&self) -> &Reg {
68
&self.0
69
}
70
}
71
72
/// If you know what you're doing, you can explicitly mutably borrow the
73
/// underlying `Reg`. Don't make it point to the wrong type of register
74
/// please.
75
impl AsMut<Reg> for $newtype_reg {
76
fn as_mut(&mut self) -> &mut Reg {
77
&mut self.0
78
}
79
}
80
81
/// Writable Reg.
82
pub type $newtype_writable_reg = Writable<$newtype_reg>;
83
84
impl From<pulley_interpreter::regs::$newtype_reg> for $newtype_reg {
85
fn from(r: pulley_interpreter::regs::$newtype_reg) -> Self {
86
Self::new(regalloc2::PReg::new(usize::from(r as u8), $class).into()).unwrap()
87
}
88
}
89
impl From<$newtype_reg> for pulley_interpreter::regs::$newtype_reg {
90
fn from(r: $newtype_reg) -> Self {
91
Self::new(r.to_real_reg().unwrap().hw_enc()).unwrap()
92
}
93
}
94
impl<'a> From<&'a $newtype_reg> for pulley_interpreter::regs::$newtype_reg {
95
fn from(r: &'a $newtype_reg) -> Self {
96
Self::new(r.to_real_reg().unwrap().hw_enc()).unwrap()
97
}
98
}
99
impl From<$newtype_writable_reg> for pulley_interpreter::regs::$newtype_reg {
100
fn from(r: $newtype_writable_reg) -> Self {
101
Self::new(r.to_reg().to_real_reg().unwrap().hw_enc()).unwrap()
102
}
103
}
104
impl<'a> From<&'a $newtype_writable_reg> for pulley_interpreter::regs::$newtype_reg {
105
fn from(r: &'a $newtype_writable_reg) -> Self {
106
Self::new(r.to_reg().to_real_reg().unwrap().hw_enc()).unwrap()
107
}
108
}
109
110
impl TryFrom<Writable<Reg>> for $newtype_writable_reg {
111
type Error = ();
112
fn try_from(r: Writable<Reg>) -> Result<Self, Self::Error> {
113
let r = r.to_reg();
114
match $newtype_reg::new(r) {
115
Some(r) => Ok(Writable::from_reg(r)),
116
None => Err(()),
117
}
118
}
119
}
120
};
121
}
122
123
// Newtypes for registers classes.
124
newtype_of_reg!(XReg, WritableXReg, RegClass::Int);
125
newtype_of_reg!(FReg, WritableFReg, RegClass::Float);
126
newtype_of_reg!(VReg, WritableVReg, RegClass::Vector);
127
128
impl XReg {
129
/// Index of the first "special" register, or the end of which registers
130
/// regalloc is allowed to use.
131
pub const SPECIAL_START: u8 = pulley_interpreter::regs::XReg::SPECIAL_START;
132
133
/// Returns whether this is a "special" physical register for pulley.
134
pub fn is_special(&self) -> bool {
135
match self.as_pulley() {
136
Some(reg) => reg.is_special(),
137
None => false,
138
}
139
}
140
141
/// Returns the pulley-typed register, if this is a physical register.
142
pub fn as_pulley(&self) -> Option<pulley_interpreter::XReg> {
143
let enc = self.to_real_reg()?.hw_enc();
144
Some(pulley_interpreter::XReg::new(enc).unwrap())
145
}
146
}
147
148
pub use super::super::lower::isle::generated_code::Amode;
149
150
impl Amode {
151
/// Add the registers referenced by this Amode to `collector`.
152
pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
153
match self {
154
Amode::RegOffset { base, offset: _ } => collector.reg_use(base),
155
// Registers used in these modes aren't allocatable.
156
Amode::SpOffset { .. } | Amode::Stack { .. } => {}
157
}
158
}
159
160
pub(crate) fn get_base_register(&self) -> Option<XReg> {
161
match self {
162
Amode::RegOffset { base, offset: _ } => Some(*base),
163
Amode::SpOffset { .. } | Amode::Stack { .. } => Some(XReg::new(stack_reg()).unwrap()),
164
}
165
}
166
167
pub(crate) fn get_offset_with_state<P>(&self, state: &EmitState<P>) -> i32
168
where
169
P: PulleyTargetKind,
170
{
171
match self {
172
Amode::RegOffset { base: _, offset } | Amode::SpOffset { offset } => *offset,
173
Amode::Stack { amode } => {
174
let offset64 = match amode {
175
StackAMode::IncomingArg(offset, stack_args_size) => {
176
let offset = i64::from(*stack_args_size) - *offset;
177
let frame_layout = state.frame_layout();
178
let sp_offset = frame_layout.tail_args_size
179
+ frame_layout.setup_area_size
180
+ frame_layout.clobber_size
181
+ frame_layout.fixed_frame_storage_size
182
+ frame_layout.outgoing_args_size;
183
i64::from(sp_offset) - offset
184
}
185
StackAMode::Slot(offset) => {
186
offset + i64::from(state.frame_layout().outgoing_args_size)
187
}
188
StackAMode::OutgoingArg(offset) => *offset,
189
};
190
i32::try_from(offset64).unwrap()
191
}
192
}
193
}
194
}
195
196
impl core::fmt::Display for Amode {
197
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
198
match self {
199
Amode::SpOffset { offset } => {
200
if *offset >= 0 {
201
write!(f, "sp+{offset}")
202
} else {
203
write!(f, "sp{offset}")
204
}
205
}
206
Amode::RegOffset { base, offset } => {
207
let name = reg_name(**base);
208
if *offset >= 0 {
209
write!(f, "{name}+{offset}")
210
} else {
211
write!(f, "{name}{offset}")
212
}
213
}
214
Amode::Stack { amode } => core::fmt::Debug::fmt(amode, f),
215
}
216
}
217
}
218
219
impl From<StackAMode> for Amode {
220
fn from(amode: StackAMode) -> Self {
221
Amode::Stack { amode }
222
}
223
}
224
225
/// The size of an operand or operation.
226
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
227
pub enum OperandSize {
228
/// 32 bits.
229
Size32,
230
/// 64 bits.
231
Size64,
232
}
233
234
pub use crate::isa::pulley_shared::lower::isle::generated_code::Cond;
235
236
impl Cond {
237
/// Collect register operands within `collector` for register allocation.
238
pub fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
239
match self {
240
Cond::If32 { reg } | Cond::IfNot32 { reg } => collector.reg_use(reg),
241
242
Cond::IfXeq32 { src1, src2 }
243
| Cond::IfXneq32 { src1, src2 }
244
| Cond::IfXslt32 { src1, src2 }
245
| Cond::IfXslteq32 { src1, src2 }
246
| Cond::IfXult32 { src1, src2 }
247
| Cond::IfXulteq32 { src1, src2 }
248
| Cond::IfXeq64 { src1, src2 }
249
| Cond::IfXneq64 { src1, src2 }
250
| Cond::IfXslt64 { src1, src2 }
251
| Cond::IfXslteq64 { src1, src2 }
252
| Cond::IfXult64 { src1, src2 }
253
| Cond::IfXulteq64 { src1, src2 } => {
254
collector.reg_use(src1);
255
collector.reg_use(src2);
256
}
257
258
Cond::IfXeq32I32 { src1, src2 }
259
| Cond::IfXneq32I32 { src1, src2 }
260
| Cond::IfXslt32I32 { src1, src2 }
261
| Cond::IfXslteq32I32 { src1, src2 }
262
| Cond::IfXsgt32I32 { src1, src2 }
263
| Cond::IfXsgteq32I32 { src1, src2 }
264
| Cond::IfXeq64I32 { src1, src2 }
265
| Cond::IfXneq64I32 { src1, src2 }
266
| Cond::IfXslt64I32 { src1, src2 }
267
| Cond::IfXslteq64I32 { src1, src2 }
268
| Cond::IfXsgt64I32 { src1, src2 }
269
| Cond::IfXsgteq64I32 { src1, src2 } => {
270
collector.reg_use(src1);
271
let _: &mut i32 = src2;
272
}
273
274
Cond::IfXult32I32 { src1, src2 }
275
| Cond::IfXulteq32I32 { src1, src2 }
276
| Cond::IfXugt32I32 { src1, src2 }
277
| Cond::IfXugteq32I32 { src1, src2 }
278
| Cond::IfXult64I32 { src1, src2 }
279
| Cond::IfXulteq64I32 { src1, src2 }
280
| Cond::IfXugt64I32 { src1, src2 }
281
| Cond::IfXugteq64I32 { src1, src2 } => {
282
collector.reg_use(src1);
283
let _: &mut u32 = src2;
284
}
285
}
286
}
287
288
/// Encode this condition as a branch into `sink`.
289
///
290
/// Note that the offset encoded to jump by is filled in as 0 and it's
291
/// assumed `MachBuffer` will come back and clean it up.
292
pub fn encode(&self, sink: &mut impl Extend<u8>, rel: i32) {
293
match *self {
294
Cond::If32 { reg } => encode::br_if32(sink, reg, rel),
295
Cond::IfNot32 { reg } => encode::br_if_not32(sink, reg, rel),
296
Cond::IfXeq32 { src1, src2 } => encode::br_if_xeq32(sink, src1, src2, rel),
297
Cond::IfXneq32 { src1, src2 } => encode::br_if_xneq32(sink, src1, src2, rel),
298
Cond::IfXslt32 { src1, src2 } => encode::br_if_xslt32(sink, src1, src2, rel),
299
Cond::IfXslteq32 { src1, src2 } => encode::br_if_xslteq32(sink, src1, src2, rel),
300
Cond::IfXult32 { src1, src2 } => encode::br_if_xult32(sink, src1, src2, rel),
301
Cond::IfXulteq32 { src1, src2 } => encode::br_if_xulteq32(sink, src1, src2, rel),
302
Cond::IfXeq64 { src1, src2 } => encode::br_if_xeq64(sink, src1, src2, rel),
303
Cond::IfXneq64 { src1, src2 } => encode::br_if_xneq64(sink, src1, src2, rel),
304
Cond::IfXslt64 { src1, src2 } => encode::br_if_xslt64(sink, src1, src2, rel),
305
Cond::IfXslteq64 { src1, src2 } => encode::br_if_xslteq64(sink, src1, src2, rel),
306
Cond::IfXult64 { src1, src2 } => encode::br_if_xult64(sink, src1, src2, rel),
307
Cond::IfXulteq64 { src1, src2 } => encode::br_if_xulteq64(sink, src1, src2, rel),
308
309
Cond::IfXeq32I32 { src1, src2 } => match i8::try_from(src2) {
310
Ok(src2) => encode::br_if_xeq32_i8(sink, src1, src2, rel),
311
Err(_) => encode::br_if_xeq32_i32(sink, src1, src2, rel),
312
},
313
Cond::IfXneq32I32 { src1, src2 } => match i8::try_from(src2) {
314
Ok(src2) => encode::br_if_xneq32_i8(sink, src1, src2, rel),
315
Err(_) => encode::br_if_xneq32_i32(sink, src1, src2, rel),
316
},
317
Cond::IfXslt32I32 { src1, src2 } => match i8::try_from(src2) {
318
Ok(src2) => encode::br_if_xslt32_i8(sink, src1, src2, rel),
319
Err(_) => encode::br_if_xslt32_i32(sink, src1, src2, rel),
320
},
321
Cond::IfXslteq32I32 { src1, src2 } => match i8::try_from(src2) {
322
Ok(src2) => encode::br_if_xslteq32_i8(sink, src1, src2, rel),
323
Err(_) => encode::br_if_xslteq32_i32(sink, src1, src2, rel),
324
},
325
Cond::IfXsgt32I32 { src1, src2 } => match i8::try_from(src2) {
326
Ok(src2) => encode::br_if_xsgt32_i8(sink, src1, src2, rel),
327
Err(_) => encode::br_if_xsgt32_i32(sink, src1, src2, rel),
328
},
329
Cond::IfXsgteq32I32 { src1, src2 } => match i8::try_from(src2) {
330
Ok(src2) => encode::br_if_xsgteq32_i8(sink, src1, src2, rel),
331
Err(_) => encode::br_if_xsgteq32_i32(sink, src1, src2, rel),
332
},
333
Cond::IfXult32I32 { src1, src2 } => match u8::try_from(src2) {
334
Ok(src2) => encode::br_if_xult32_u8(sink, src1, src2, rel),
335
Err(_) => encode::br_if_xult32_u32(sink, src1, src2, rel),
336
},
337
Cond::IfXulteq32I32 { src1, src2 } => match u8::try_from(src2) {
338
Ok(src2) => encode::br_if_xulteq32_u8(sink, src1, src2, rel),
339
Err(_) => encode::br_if_xulteq32_u32(sink, src1, src2, rel),
340
},
341
Cond::IfXugt32I32 { src1, src2 } => match u8::try_from(src2) {
342
Ok(src2) => encode::br_if_xugt32_u8(sink, src1, src2, rel),
343
Err(_) => encode::br_if_xugt32_u32(sink, src1, src2, rel),
344
},
345
Cond::IfXugteq32I32 { src1, src2 } => match u8::try_from(src2) {
346
Ok(src2) => encode::br_if_xugteq32_u8(sink, src1, src2, rel),
347
Err(_) => encode::br_if_xugteq32_u32(sink, src1, src2, rel),
348
},
349
350
Cond::IfXeq64I32 { src1, src2 } => match i8::try_from(src2) {
351
Ok(src2) => encode::br_if_xeq64_i8(sink, src1, src2, rel),
352
Err(_) => encode::br_if_xeq64_i32(sink, src1, src2, rel),
353
},
354
Cond::IfXneq64I32 { src1, src2 } => match i8::try_from(src2) {
355
Ok(src2) => encode::br_if_xneq64_i8(sink, src1, src2, rel),
356
Err(_) => encode::br_if_xneq64_i32(sink, src1, src2, rel),
357
},
358
Cond::IfXslt64I32 { src1, src2 } => match i8::try_from(src2) {
359
Ok(src2) => encode::br_if_xslt64_i8(sink, src1, src2, rel),
360
Err(_) => encode::br_if_xslt64_i32(sink, src1, src2, rel),
361
},
362
Cond::IfXslteq64I32 { src1, src2 } => match i8::try_from(src2) {
363
Ok(src2) => encode::br_if_xslteq64_i8(sink, src1, src2, rel),
364
Err(_) => encode::br_if_xslteq64_i32(sink, src1, src2, rel),
365
},
366
Cond::IfXsgt64I32 { src1, src2 } => match i8::try_from(src2) {
367
Ok(src2) => encode::br_if_xsgt64_i8(sink, src1, src2, rel),
368
Err(_) => encode::br_if_xsgt64_i32(sink, src1, src2, rel),
369
},
370
Cond::IfXsgteq64I32 { src1, src2 } => match i8::try_from(src2) {
371
Ok(src2) => encode::br_if_xsgteq64_i8(sink, src1, src2, rel),
372
Err(_) => encode::br_if_xsgteq64_i32(sink, src1, src2, rel),
373
},
374
Cond::IfXult64I32 { src1, src2 } => match u8::try_from(src2) {
375
Ok(src2) => encode::br_if_xult64_u8(sink, src1, src2, rel),
376
Err(_) => encode::br_if_xult64_u32(sink, src1, src2, rel),
377
},
378
Cond::IfXulteq64I32 { src1, src2 } => match u8::try_from(src2) {
379
Ok(src2) => encode::br_if_xulteq64_u8(sink, src1, src2, rel),
380
Err(_) => encode::br_if_xulteq64_u32(sink, src1, src2, rel),
381
},
382
Cond::IfXugt64I32 { src1, src2 } => match u8::try_from(src2) {
383
Ok(src2) => encode::br_if_xugt64_u8(sink, src1, src2, rel),
384
Err(_) => encode::br_if_xugt64_u32(sink, src1, src2, rel),
385
},
386
Cond::IfXugteq64I32 { src1, src2 } => match u8::try_from(src2) {
387
Ok(src2) => encode::br_if_xugteq64_u8(sink, src1, src2, rel),
388
Err(_) => encode::br_if_xugteq64_u32(sink, src1, src2, rel),
389
},
390
}
391
}
392
393
/// Inverts this conditional.
394
pub fn invert(&self) -> Cond {
395
match *self {
396
Cond::If32 { reg } => Cond::IfNot32 { reg },
397
Cond::IfNot32 { reg } => Cond::If32 { reg },
398
Cond::IfXeq32 { src1, src2 } => Cond::IfXneq32 { src1, src2 },
399
Cond::IfXneq32 { src1, src2 } => Cond::IfXeq32 { src1, src2 },
400
Cond::IfXeq64 { src1, src2 } => Cond::IfXneq64 { src1, src2 },
401
Cond::IfXneq64 { src1, src2 } => Cond::IfXeq64 { src1, src2 },
402
403
// Note that for below the condition changes but the operands are
404
// also swapped.
405
Cond::IfXslt32 { src1, src2 } => Cond::IfXslteq32 {
406
src1: src2,
407
src2: src1,
408
},
409
Cond::IfXslteq32 { src1, src2 } => Cond::IfXslt32 {
410
src1: src2,
411
src2: src1,
412
},
413
Cond::IfXult32 { src1, src2 } => Cond::IfXulteq32 {
414
src1: src2,
415
src2: src1,
416
},
417
Cond::IfXulteq32 { src1, src2 } => Cond::IfXult32 {
418
src1: src2,
419
src2: src1,
420
},
421
Cond::IfXslt64 { src1, src2 } => Cond::IfXslteq64 {
422
src1: src2,
423
src2: src1,
424
},
425
Cond::IfXslteq64 { src1, src2 } => Cond::IfXslt64 {
426
src1: src2,
427
src2: src1,
428
},
429
Cond::IfXult64 { src1, src2 } => Cond::IfXulteq64 {
430
src1: src2,
431
src2: src1,
432
},
433
Cond::IfXulteq64 { src1, src2 } => Cond::IfXult64 {
434
src1: src2,
435
src2: src1,
436
},
437
438
Cond::IfXeq32I32 { src1, src2 } => Cond::IfXneq32I32 { src1, src2 },
439
Cond::IfXneq32I32 { src1, src2 } => Cond::IfXeq32I32 { src1, src2 },
440
Cond::IfXslt32I32 { src1, src2 } => Cond::IfXsgteq32I32 { src1, src2 },
441
Cond::IfXslteq32I32 { src1, src2 } => Cond::IfXsgt32I32 { src1, src2 },
442
Cond::IfXult32I32 { src1, src2 } => Cond::IfXugteq32I32 { src1, src2 },
443
Cond::IfXulteq32I32 { src1, src2 } => Cond::IfXugt32I32 { src1, src2 },
444
Cond::IfXsgt32I32 { src1, src2 } => Cond::IfXslteq32I32 { src1, src2 },
445
Cond::IfXsgteq32I32 { src1, src2 } => Cond::IfXslt32I32 { src1, src2 },
446
Cond::IfXugt32I32 { src1, src2 } => Cond::IfXulteq32I32 { src1, src2 },
447
Cond::IfXugteq32I32 { src1, src2 } => Cond::IfXult32I32 { src1, src2 },
448
449
Cond::IfXeq64I32 { src1, src2 } => Cond::IfXneq64I32 { src1, src2 },
450
Cond::IfXneq64I32 { src1, src2 } => Cond::IfXeq64I32 { src1, src2 },
451
Cond::IfXslt64I32 { src1, src2 } => Cond::IfXsgteq64I32 { src1, src2 },
452
Cond::IfXslteq64I32 { src1, src2 } => Cond::IfXsgt64I32 { src1, src2 },
453
Cond::IfXult64I32 { src1, src2 } => Cond::IfXugteq64I32 { src1, src2 },
454
Cond::IfXulteq64I32 { src1, src2 } => Cond::IfXugt64I32 { src1, src2 },
455
Cond::IfXsgt64I32 { src1, src2 } => Cond::IfXslteq64I32 { src1, src2 },
456
Cond::IfXsgteq64I32 { src1, src2 } => Cond::IfXslt64I32 { src1, src2 },
457
Cond::IfXugt64I32 { src1, src2 } => Cond::IfXulteq64I32 { src1, src2 },
458
Cond::IfXugteq64I32 { src1, src2 } => Cond::IfXult64I32 { src1, src2 },
459
}
460
}
461
}
462
463
impl fmt::Display for Cond {
464
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
465
match self {
466
Cond::If32 { reg } => write!(f, "if32 {}", reg_name(**reg)),
467
Cond::IfNot32 { reg } => write!(f, "if_not32 {}", reg_name(**reg)),
468
Cond::IfXeq32 { src1, src2 } => {
469
write!(f, "if_xeq32 {}, {}", reg_name(**src1), reg_name(**src2))
470
}
471
Cond::IfXneq32 { src1, src2 } => {
472
write!(f, "if_xneq32 {}, {}", reg_name(**src1), reg_name(**src2))
473
}
474
Cond::IfXslt32 { src1, src2 } => {
475
write!(f, "if_xslt32 {}, {}", reg_name(**src1), reg_name(**src2))
476
}
477
Cond::IfXslteq32 { src1, src2 } => {
478
write!(f, "if_xslteq32 {}, {}", reg_name(**src1), reg_name(**src2))
479
}
480
Cond::IfXult32 { src1, src2 } => {
481
write!(f, "if_xult32 {}, {}", reg_name(**src1), reg_name(**src2))
482
}
483
Cond::IfXulteq32 { src1, src2 } => {
484
write!(f, "if_xulteq32 {}, {}", reg_name(**src1), reg_name(**src2))
485
}
486
Cond::IfXeq64 { src1, src2 } => {
487
write!(f, "if_xeq64 {}, {}", reg_name(**src1), reg_name(**src2))
488
}
489
Cond::IfXneq64 { src1, src2 } => {
490
write!(f, "if_xneq64 {}, {}", reg_name(**src1), reg_name(**src2))
491
}
492
Cond::IfXslt64 { src1, src2 } => {
493
write!(f, "if_xslt64 {}, {}", reg_name(**src1), reg_name(**src2))
494
}
495
Cond::IfXslteq64 { src1, src2 } => {
496
write!(f, "if_xslteq64 {}, {}", reg_name(**src1), reg_name(**src2))
497
}
498
Cond::IfXult64 { src1, src2 } => {
499
write!(f, "if_xult64 {}, {}", reg_name(**src1), reg_name(**src2))
500
}
501
Cond::IfXulteq64 { src1, src2 } => {
502
write!(f, "if_xulteq64 {}, {}", reg_name(**src1), reg_name(**src2))
503
}
504
Cond::IfXeq32I32 { src1, src2 } => {
505
write!(f, "if_xeq32_i32 {}, {src2}", reg_name(**src1))
506
}
507
Cond::IfXneq32I32 { src1, src2 } => {
508
write!(f, "if_xneq32_i32 {}, {src2}", reg_name(**src1))
509
}
510
Cond::IfXslt32I32 { src1, src2 } => {
511
write!(f, "if_xslt32_i32 {}, {src2}", reg_name(**src1))
512
}
513
Cond::IfXslteq32I32 { src1, src2 } => {
514
write!(f, "if_xslteq32_i32 {}, {src2}", reg_name(**src1))
515
}
516
Cond::IfXsgt32I32 { src1, src2 } => {
517
write!(f, "if_xsgt32_i32 {}, {src2}", reg_name(**src1))
518
}
519
Cond::IfXsgteq32I32 { src1, src2 } => {
520
write!(f, "if_xsgteq32_i32 {}, {src2}", reg_name(**src1))
521
}
522
Cond::IfXult32I32 { src1, src2 } => {
523
write!(f, "if_xult32_i32 {}, {src2}", reg_name(**src1))
524
}
525
Cond::IfXulteq32I32 { src1, src2 } => {
526
write!(f, "if_xulteq32_i32 {}, {src2}", reg_name(**src1))
527
}
528
Cond::IfXugt32I32 { src1, src2 } => {
529
write!(f, "if_xugt32_i32 {}, {src2}", reg_name(**src1))
530
}
531
Cond::IfXugteq32I32 { src1, src2 } => {
532
write!(f, "if_xugteq32_i32 {}, {src2}", reg_name(**src1))
533
}
534
Cond::IfXeq64I32 { src1, src2 } => {
535
write!(f, "if_xeq64_i32 {}, {src2}", reg_name(**src1))
536
}
537
Cond::IfXneq64I32 { src1, src2 } => {
538
write!(f, "if_xneq64_i32 {}, {src2}", reg_name(**src1))
539
}
540
Cond::IfXslt64I32 { src1, src2 } => {
541
write!(f, "if_xslt64_i32 {}, {src2}", reg_name(**src1))
542
}
543
Cond::IfXslteq64I32 { src1, src2 } => {
544
write!(f, "if_xslteq64_i32 {}, {src2}", reg_name(**src1))
545
}
546
Cond::IfXsgt64I32 { src1, src2 } => {
547
write!(f, "if_xsgt64_i32 {}, {src2}", reg_name(**src1))
548
}
549
Cond::IfXsgteq64I32 { src1, src2 } => {
550
write!(f, "if_xsgteq64_i32 {}, {src2}", reg_name(**src1))
551
}
552
Cond::IfXult64I32 { src1, src2 } => {
553
write!(f, "if_xult64_i32 {}, {src2}", reg_name(**src1))
554
}
555
Cond::IfXulteq64I32 { src1, src2 } => {
556
write!(f, "if_xulteq64_i32 {}, {src2}", reg_name(**src1))
557
}
558
Cond::IfXugt64I32 { src1, src2 } => {
559
write!(f, "if_xugt64_i32 {}, {src2}", reg_name(**src1))
560
}
561
Cond::IfXugteq64I32 { src1, src2 } => {
562
write!(f, "if_xugteq64_i32 {}, {src2}", reg_name(**src1))
563
}
564
}
565
}
566
}
567
568
/// Payload of `CallInfo` for call instructions
569
#[derive(Clone, Debug)]
570
pub struct PulleyCall {
571
/// The external name that's being called, or the Cranelift-generated
572
/// function that's being invoked.
573
pub name: ExternalName,
574
/// Arguments tracked in this call invocation which aren't assigned fixed
575
/// registers. This tracks up to 4 registers and all remaining registers
576
/// will be present and tracked in `CallInfo<T>` fields.
577
pub args: SmallVec<[XReg; 4]>,
578
}
579
580
pub use super::super::lower::isle::generated_code::AddrO32;
581
582
impl Copy for AddrO32 {}
583
584
impl AddrO32 {
585
/// Implementation of regalloc for this addressing mode.
586
pub fn collect_operands(&mut self, collector: &mut impl OperandVisitor) {
587
match self {
588
AddrO32::Base { addr, offset: _ } => {
589
collector.reg_use(addr);
590
}
591
}
592
}
593
}
594
595
impl From<AddrO32> for pulley_interpreter::AddrO32 {
596
fn from(addr: AddrO32) -> Self {
597
match addr {
598
AddrO32::Base { addr, offset } => Self {
599
addr: addr.into(),
600
offset,
601
},
602
}
603
}
604
}
605
606
impl fmt::Display for AddrO32 {
607
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
608
match self {
609
AddrO32::Base { addr, offset } => {
610
let addr = reg_name(**addr);
611
write!(f, "{addr}, {offset}")
612
}
613
}
614
}
615
}
616
617
pub use super::super::lower::isle::generated_code::AddrZ;
618
619
impl Copy for AddrZ {}
620
621
impl AddrZ {
622
/// Implementation of regalloc for this addressing mode.
623
pub fn collect_operands(&mut self, collector: &mut impl OperandVisitor) {
624
match self {
625
AddrZ::Base { addr, offset: _ } => {
626
collector.reg_use(addr);
627
}
628
}
629
}
630
}
631
632
impl From<AddrZ> for pulley_interpreter::AddrZ {
633
fn from(addr: AddrZ) -> Self {
634
match addr {
635
AddrZ::Base { addr, offset } => Self {
636
addr: addr.into(),
637
offset,
638
},
639
}
640
}
641
}
642
643
impl fmt::Display for AddrZ {
644
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
645
match self {
646
AddrZ::Base { addr, offset } => {
647
let addr = reg_name(**addr);
648
write!(f, "{addr}, {offset}")
649
}
650
}
651
}
652
}
653
654
pub use super::super::lower::isle::generated_code::AddrG32;
655
656
impl Copy for AddrG32 {}
657
658
impl AddrG32 {
659
/// Implementation of regalloc for this addressing mode.
660
pub fn collect_operands(&mut self, collector: &mut impl OperandVisitor) {
661
match self {
662
AddrG32::RegisterBound {
663
host_heap_base,
664
host_heap_bound,
665
wasm_addr,
666
offset: _,
667
} => {
668
collector.reg_use(host_heap_base);
669
collector.reg_use(host_heap_bound);
670
collector.reg_use(wasm_addr);
671
}
672
}
673
}
674
}
675
676
impl From<AddrG32> for pulley_interpreter::AddrG32 {
677
fn from(addr: AddrG32) -> Self {
678
match addr {
679
AddrG32::RegisterBound {
680
host_heap_base,
681
host_heap_bound,
682
wasm_addr,
683
offset,
684
} => Self {
685
host_heap_base: host_heap_base.into(),
686
host_heap_bound: host_heap_bound.into(),
687
wasm_addr: wasm_addr.into(),
688
offset,
689
},
690
}
691
}
692
}
693
694
impl fmt::Display for AddrG32 {
695
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
696
match self {
697
AddrG32::RegisterBound {
698
host_heap_base,
699
host_heap_bound,
700
wasm_addr,
701
offset,
702
} => {
703
let host_heap_base = reg_name(**host_heap_base);
704
let host_heap_bound = reg_name(**host_heap_bound);
705
let wasm_addr = reg_name(**wasm_addr);
706
write!(
707
f,
708
"{host_heap_base}, {host_heap_bound}, {wasm_addr}, {offset}",
709
)
710
}
711
}
712
}
713
}
714
715
pub use super::super::lower::isle::generated_code::AddrG32Bne;
716
717
impl Copy for AddrG32Bne {}
718
719
impl AddrG32Bne {
720
/// Implementation of regalloc for this addressing mode.
721
pub fn collect_operands(&mut self, collector: &mut impl OperandVisitor) {
722
match self {
723
AddrG32Bne::BoundNe {
724
host_heap_base,
725
host_heap_bound_addr,
726
host_heap_bound_offset: _,
727
wasm_addr,
728
offset: _,
729
} => {
730
collector.reg_use(host_heap_base);
731
collector.reg_use(host_heap_bound_addr);
732
collector.reg_use(wasm_addr);
733
}
734
}
735
}
736
}
737
738
impl From<AddrG32Bne> for pulley_interpreter::AddrG32Bne {
739
fn from(addr: AddrG32Bne) -> Self {
740
match addr {
741
AddrG32Bne::BoundNe {
742
host_heap_base,
743
host_heap_bound_addr,
744
host_heap_bound_offset,
745
wasm_addr,
746
offset,
747
} => Self {
748
host_heap_base: host_heap_base.into(),
749
host_heap_bound_addr: host_heap_bound_addr.into(),
750
host_heap_bound_offset,
751
wasm_addr: wasm_addr.into(),
752
offset,
753
},
754
}
755
}
756
}
757
758
impl fmt::Display for AddrG32Bne {
759
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
760
match self {
761
AddrG32Bne::BoundNe {
762
host_heap_base,
763
host_heap_bound_addr,
764
host_heap_bound_offset,
765
wasm_addr,
766
offset,
767
} => {
768
let host_heap_base = reg_name(**host_heap_base);
769
let host_heap_bound_addr = reg_name(**host_heap_bound_addr);
770
let wasm_addr = reg_name(**wasm_addr);
771
write!(
772
f,
773
"{host_heap_base}, \
774
*[{host_heap_bound_addr} + {host_heap_bound_offset}], \
775
{wasm_addr}, \
776
{offset}",
777
)
778
}
779
}
780
}
781
}
782
783