cranelift_codegen/isa/x64/inst/
external.rs

1//! Interface with the external assembler crate.
2
3use super::{
4    regs, Amode, Gpr, Inst, LabelUse, MachBuffer, MachLabel, OperandVisitor, OperandVisitorImpl,
5    SyntheticAmode, VCodeConstant, WritableGpr,
6};
7use crate::ir::TrapCode;
8use cranelift_assembler_x64 as asm;
9
10/// Define the types of registers Cranelift will use.
11#[derive(Clone, Debug)]
12pub struct CraneliftRegisters;
13impl asm::Registers for CraneliftRegisters {
14    type ReadGpr = Gpr;
15    type ReadWriteGpr = PairedGpr;
16}
17
18/// A pair of registers, one for reading and one for writing.
19///
20/// Due to how Cranelift's SSA form, we must track the read and write registers
21/// separately prior to register allocation. Once register allocation is
22/// complete, we expect the hardware encoding for both `read` and `write` to be
23/// the same.
24#[derive(Clone, Copy, Debug)]
25pub struct PairedGpr {
26    pub(crate) read: Gpr,
27    pub(crate) write: WritableGpr,
28}
29
30impl asm::AsReg for PairedGpr {
31    fn enc(&self) -> u8 {
32        let PairedGpr { read, write } = self;
33        let read = enc(read);
34        let write = enc(&write.to_reg());
35        assert_eq!(read, write);
36        write
37    }
38
39    fn new(_: u8) -> Self {
40        panic!("disallow creation of new assembler registers")
41    }
42}
43
44/// This bridges the gap between codegen and assembler register types.
45impl asm::AsReg for Gpr {
46    fn enc(&self) -> u8 {
47        enc(self)
48    }
49
50    fn new(_: u8) -> Self {
51        panic!("disallow creation of new assembler registers")
52    }
53}
54
55/// A helper method for extracting the hardware encoding of a register.
56#[inline]
57fn enc(gpr: &Gpr) -> u8 {
58    if let Some(real) = gpr.to_reg().to_real_reg() {
59        real.hw_enc()
60    } else {
61        unreachable!()
62    }
63}
64
65/// A wrapper to implement the `cranelift-assembler-x64` register allocation trait,
66/// `RegallocVisitor`, in terms of the trait used in Cranelift,
67/// `OperandVisitor`.
68pub(crate) struct RegallocVisitor<'a, T>
69where
70    T: OperandVisitorImpl,
71{
72    pub collector: &'a mut T,
73}
74
75impl<'a, T: OperandVisitor> asm::RegisterVisitor<CraneliftRegisters> for RegallocVisitor<'a, T> {
76    fn read(&mut self, reg: &mut Gpr) {
77        self.collector.reg_use(reg);
78    }
79
80    fn read_write(&mut self, reg: &mut PairedGpr) {
81        let PairedGpr { read, write } = reg;
82        self.collector.reg_use(read);
83        self.collector.reg_reuse_def(write, 0);
84    }
85
86    fn fixed_read(&mut self, _reg: &Gpr) {
87        todo!()
88    }
89
90    fn fixed_read_write(&mut self, _reg: &PairedGpr) {
91        todo!()
92    }
93}
94
95impl Into<asm::Amode<Gpr>> for SyntheticAmode {
96    fn into(self) -> asm::Amode<Gpr> {
97        match self {
98            SyntheticAmode::Real(amode) => match amode {
99                Amode::ImmReg {
100                    simm32,
101                    base,
102                    flags,
103                } => asm::Amode::ImmReg {
104                    simm32: asm::Simm32PlusKnownOffset {
105                        simm32: simm32.into(),
106                        offset: None,
107                    },
108                    base: Gpr::unwrap_new(base),
109                    trap: flags.trap_code().map(Into::into),
110                },
111                Amode::ImmRegRegShift {
112                    simm32,
113                    base,
114                    index,
115                    shift,
116                    flags,
117                } => asm::Amode::ImmRegRegShift {
118                    base,
119                    index: asm::NonRspGpr::new(index),
120                    scale: asm::Scale::new(shift),
121                    simm32: simm32.into(),
122                    trap: flags.trap_code().map(Into::into),
123                },
124                Amode::RipRelative { target } => asm::Amode::RipRelative {
125                    target: asm::DeferredTarget::Label(asm::Label(target.as_u32())),
126                },
127            },
128            SyntheticAmode::IncomingArg { offset } => asm::Amode::ImmReg {
129                base: Gpr::unwrap_new(regs::rbp()),
130                simm32: asm::Simm32PlusKnownOffset {
131                    simm32: (-i32::try_from(offset).unwrap()).into(),
132                    offset: Some(offsets::KEY_INCOMING_ARG),
133                },
134                trap: None,
135            },
136            SyntheticAmode::SlotOffset { simm32 } => asm::Amode::ImmReg {
137                base: Gpr::unwrap_new(regs::rbp()),
138                simm32: asm::Simm32PlusKnownOffset {
139                    simm32: simm32.into(),
140                    offset: Some(offsets::KEY_SLOT_OFFSET),
141                },
142                trap: None,
143            },
144            SyntheticAmode::ConstantOffset(vcode_constant) => asm::Amode::RipRelative {
145                target: asm::DeferredTarget::Constant(asm::Constant(vcode_constant.as_u32())),
146            },
147        }
148    }
149}
150
151/// Keep track of the offset slots to fill in during emission; see
152/// `KnownOffsetTable`.
153pub mod offsets {
154    pub const KEY_INCOMING_ARG: usize = 0;
155    pub const KEY_SLOT_OFFSET: usize = 1;
156}
157
158impl asm::CodeSink for MachBuffer<Inst> {
159    fn put1(&mut self, value: u8) {
160        self.put1(value)
161    }
162
163    fn put2(&mut self, value: u16) {
164        self.put2(value)
165    }
166
167    fn put4(&mut self, value: u32) {
168        self.put4(value)
169    }
170
171    fn put8(&mut self, value: u64) {
172        self.put8(value)
173    }
174
175    fn current_offset(&self) -> u32 {
176        self.cur_offset()
177    }
178
179    fn use_label_at_offset(&mut self, offset: u32, label: asm::Label) {
180        self.use_label_at_offset(offset, label.into(), LabelUse::JmpRel32);
181    }
182
183    fn add_trap(&mut self, code: asm::TrapCode) {
184        self.add_trap(code.into());
185    }
186
187    fn get_label_for_constant(&mut self, c: asm::Constant) -> asm::Label {
188        self.get_label_for_constant(c.into()).into()
189    }
190}
191
192impl From<asm::TrapCode> for TrapCode {
193    fn from(value: asm::TrapCode) -> Self {
194        Self::from_raw(value.0)
195    }
196}
197
198impl From<TrapCode> for asm::TrapCode {
199    fn from(value: TrapCode) -> Self {
200        Self(value.as_raw())
201    }
202}
203
204impl From<asm::Label> for MachLabel {
205    fn from(value: asm::Label) -> Self {
206        Self::from_u32(value.0)
207    }
208}
209
210impl From<MachLabel> for asm::Label {
211    fn from(value: MachLabel) -> Self {
212        Self(value.as_u32())
213    }
214}
215
216impl From<asm::Constant> for VCodeConstant {
217    fn from(value: asm::Constant) -> Self {
218        Self::from_u32(value.0)
219    }
220}