cranelift_codegen/isa/x64/inst/
external.rs1use super::{
4 regs, Amode, Gpr, Inst, LabelUse, MachBuffer, MachLabel, OperandVisitor, OperandVisitorImpl,
5 SyntheticAmode, VCodeConstant, WritableGpr, WritableXmm, Xmm,
6};
7use crate::ir::TrapCode;
8use cranelift_assembler_x64 as asm;
9use std::string::String;
10
11#[derive(Clone, Debug)]
13pub struct CraneliftRegisters;
14impl asm::Registers for CraneliftRegisters {
15 type ReadGpr = Gpr;
16 type ReadWriteGpr = PairedGpr;
17 type ReadXmm = Xmm;
18 type ReadWriteXmm = PairedXmm;
19}
20
21#[derive(Clone, Copy, Debug)]
28pub struct PairedGpr {
29 pub(crate) read: Gpr,
30 pub(crate) write: WritableGpr,
31}
32
33impl asm::AsReg for PairedGpr {
34 fn enc(&self) -> u8 {
35 let PairedGpr { read, write } = self;
36 let read = enc_gpr(read);
37 let write = enc_gpr(&write.to_reg());
38 assert_eq!(read, write);
39 write
40 }
41
42 fn to_string(&self, size: Option<asm::Size>) -> String {
43 if self.read.is_real() {
44 asm::gpr::enc::to_string(self.enc(), size.unwrap()).into()
45 } else {
46 let read = self.read.to_reg();
47 let write = self.write.to_reg().to_reg();
48 format!("(%{write:?} <- %{read:?})")
49 }
50 }
51
52 fn new(_: u8) -> Self {
53 panic!("disallow creation of new assembler registers")
54 }
55}
56
57#[derive(Clone, Copy, Debug)]
59pub struct PairedXmm {
60 pub(crate) read: Xmm,
61 pub(crate) write: WritableXmm,
62}
63
64impl asm::AsReg for PairedXmm {
65 fn enc(&self) -> u8 {
66 let PairedXmm { read, write } = self;
67 let read = enc_xmm(read);
68 let write = enc_xmm(&write.to_reg());
69 assert_eq!(read, write);
70 write
71 }
72
73 fn to_string(&self, size: Option<asm::Size>) -> String {
74 assert!(size.is_none(), "XMM registers do not have size variants");
75 if self.read.is_real() {
76 asm::xmm::enc::to_string(self.enc()).into()
77 } else {
78 let read = self.read.to_reg();
79 let write = self.write.to_reg().to_reg();
80 format!("(%{write:?} <- %{read:?})")
81 }
82 }
83
84 fn new(_: u8) -> Self {
85 panic!("disallow creation of new assembler registers")
86 }
87}
88
89impl asm::AsReg for Gpr {
91 fn enc(&self) -> u8 {
92 enc_gpr(self)
93 }
94
95 fn to_string(&self, size: Option<asm::Size>) -> String {
96 if self.is_real() {
97 asm::gpr::enc::to_string(self.enc(), size.unwrap()).into()
98 } else {
99 format!("%{:?}", self.to_reg())
100 }
101 }
102
103 fn new(_: u8) -> Self {
104 panic!("disallow creation of new assembler registers")
105 }
106}
107
108impl asm::AsReg for Xmm {
110 fn enc(&self) -> u8 {
111 enc_xmm(self)
112 }
113
114 fn to_string(&self, size: Option<asm::Size>) -> String {
115 assert!(size.is_none(), "XMM registers do not have size variants");
116 if self.is_real() {
117 asm::xmm::enc::to_string(self.enc()).into()
118 } else {
119 format!("%{:?}", self.to_reg())
120 }
121 }
122
123 fn new(_: u8) -> Self {
124 panic!("disallow creation of new assembler registers")
125 }
126}
127
128#[inline]
130fn enc_gpr(gpr: &Gpr) -> u8 {
131 if let Some(real) = gpr.to_reg().to_real_reg() {
132 real.hw_enc()
133 } else {
134 unreachable!()
135 }
136}
137
138#[inline]
140fn enc_xmm(xmm: &Xmm) -> u8 {
141 if let Some(real) = xmm.to_reg().to_real_reg() {
142 real.hw_enc()
143 } else {
144 unreachable!()
145 }
146}
147
148pub(crate) struct RegallocVisitor<'a, T>
152where
153 T: OperandVisitorImpl,
154{
155 pub collector: &'a mut T,
156}
157
158impl<'a, T: OperandVisitor> asm::RegisterVisitor<CraneliftRegisters> for RegallocVisitor<'a, T> {
159 fn read(&mut self, reg: &mut Gpr) {
160 self.collector.reg_use(reg);
161 }
162
163 fn read_write(&mut self, reg: &mut PairedGpr) {
164 let PairedGpr { read, write } = reg;
165 self.collector.reg_use(read);
166 self.collector.reg_reuse_def(write, 0);
167 }
168
169 fn fixed_read(&mut self, _reg: &Gpr) {
170 todo!()
171 }
172
173 fn fixed_read_write(&mut self, _reg: &PairedGpr) {
174 todo!()
175 }
176
177 fn read_xmm(&mut self, reg: &mut Xmm) {
178 self.collector.reg_use(reg);
179 }
180
181 fn read_write_xmm(&mut self, reg: &mut PairedXmm) {
182 let PairedXmm { read, write } = reg;
183 self.collector.reg_use(read);
184 self.collector.reg_reuse_def(write, 0);
185 }
186
187 fn fixed_read_xmm(&mut self, _reg: &Xmm) {
188 todo!()
189 }
190
191 fn fixed_read_write_xmm(&mut self, _reg: &PairedXmm) {
192 todo!()
193 }
194}
195
196impl Into<asm::Amode<Gpr>> for SyntheticAmode {
197 fn into(self) -> asm::Amode<Gpr> {
198 match self {
199 SyntheticAmode::Real(amode) => amode.into(),
200 SyntheticAmode::IncomingArg { offset } => asm::Amode::ImmReg {
201 base: Gpr::unwrap_new(regs::rbp()),
202 simm32: asm::AmodeOffsetPlusKnownOffset {
203 simm32: (-i32::try_from(offset).unwrap()).into(),
204 offset: Some(offsets::KEY_INCOMING_ARG),
205 },
206 trap: None,
207 },
208 SyntheticAmode::SlotOffset { simm32 } => asm::Amode::ImmReg {
209 base: Gpr::unwrap_new(regs::rbp()),
210 simm32: asm::AmodeOffsetPlusKnownOffset {
211 simm32: simm32.into(),
212 offset: Some(offsets::KEY_SLOT_OFFSET),
213 },
214 trap: None,
215 },
216 SyntheticAmode::ConstantOffset(vcode_constant) => asm::Amode::RipRelative {
217 target: asm::DeferredTarget::Constant(asm::Constant(vcode_constant.as_u32())),
218 },
219 }
220 }
221}
222
223impl Into<asm::Amode<Gpr>> for Amode {
224 fn into(self) -> asm::Amode<Gpr> {
225 match self {
226 Amode::ImmReg {
227 simm32,
228 base,
229 flags,
230 } => asm::Amode::ImmReg {
231 simm32: asm::AmodeOffsetPlusKnownOffset {
232 simm32: simm32.into(),
233 offset: None,
234 },
235 base: Gpr::unwrap_new(base),
236 trap: flags.trap_code().map(Into::into),
237 },
238 Amode::ImmRegRegShift {
239 simm32,
240 base,
241 index,
242 shift,
243 flags,
244 } => asm::Amode::ImmRegRegShift {
245 base,
246 index: asm::NonRspGpr::new(index),
247 scale: asm::Scale::new(shift),
248 simm32: simm32.into(),
249 trap: flags.trap_code().map(Into::into),
250 },
251 Amode::RipRelative { target } => asm::Amode::RipRelative {
252 target: asm::DeferredTarget::Label(asm::Label(target.as_u32())),
253 },
254 }
255 }
256}
257
258pub mod offsets {
261 pub const KEY_INCOMING_ARG: usize = 0;
262 pub const KEY_SLOT_OFFSET: usize = 1;
263}
264
265impl asm::CodeSink for MachBuffer<Inst> {
266 fn put1(&mut self, value: u8) {
267 self.put1(value)
268 }
269
270 fn put2(&mut self, value: u16) {
271 self.put2(value)
272 }
273
274 fn put4(&mut self, value: u32) {
275 self.put4(value)
276 }
277
278 fn put8(&mut self, value: u64) {
279 self.put8(value)
280 }
281
282 fn current_offset(&self) -> u32 {
283 self.cur_offset()
284 }
285
286 fn use_label_at_offset(&mut self, offset: u32, label: asm::Label) {
287 self.use_label_at_offset(offset, label.into(), LabelUse::JmpRel32);
288 }
289
290 fn add_trap(&mut self, code: asm::TrapCode) {
291 self.add_trap(code.into());
292 }
293
294 fn get_label_for_constant(&mut self, c: asm::Constant) -> asm::Label {
295 self.get_label_for_constant(c.into()).into()
296 }
297}
298
299impl From<asm::TrapCode> for TrapCode {
300 fn from(value: asm::TrapCode) -> Self {
301 Self::from_raw(value.0)
302 }
303}
304
305impl From<TrapCode> for asm::TrapCode {
306 fn from(value: TrapCode) -> Self {
307 Self(value.as_raw())
308 }
309}
310
311impl From<asm::Label> for MachLabel {
312 fn from(value: asm::Label) -> Self {
313 Self::from_u32(value.0)
314 }
315}
316
317impl From<MachLabel> for asm::Label {
318 fn from(value: MachLabel) -> Self {
319 Self(value.as_u32())
320 }
321}
322
323impl From<asm::Constant> for VCodeConstant {
324 fn from(value: asm::Constant) -> Self {
325 Self::from_u32(value.0)
326 }
327}
328
329include!(concat!(env!("OUT_DIR"), "/assembler-isle-macro.rs"));
333pub(crate) use isle_assembler_methods;
334
335#[cfg(test)]
336mod tests {
337 use super::asm::{AsReg, Size};
338 use super::PairedGpr;
339 use crate::isa::x64::args::{FromWritableReg, Gpr, WritableGpr, WritableXmm, Xmm};
340 use crate::isa::x64::inst::external::PairedXmm;
341 use crate::{Reg, Writable};
342 use regalloc2::{RegClass, VReg};
343
344 #[test]
345 fn pretty_print_registers() {
346 let v200: Reg = VReg::new(200, RegClass::Int).into();
352 let gpr200 = Gpr::new(v200).unwrap();
353 assert_eq!(gpr200.to_string(Some(Size::Quadword)), "%v200");
354
355 let v300: Reg = VReg::new(300, RegClass::Int).into();
356 let wgpr300 = WritableGpr::from_writable_reg(Writable::from_reg(v300).into()).unwrap();
357 let pair = PairedGpr {
358 read: gpr200,
359 write: wgpr300,
360 };
361 assert_eq!(pair.to_string(Some(Size::Quadword)), "(%v300 <- %v200)");
362
363 let v400: Reg = VReg::new(400, RegClass::Float).into();
364 let xmm400 = Xmm::new(v400).unwrap();
365 assert_eq!(xmm400.to_string(None), "%v400");
366
367 let v500: Reg = VReg::new(500, RegClass::Float).into();
368 let wxmm500 = WritableXmm::from_writable_reg(Writable::from_reg(v500).into()).unwrap();
369 let pair = PairedXmm {
370 read: xmm400,
371 write: wxmm500,
372 };
373 assert_eq!(pair.to_string(None), "(%v500 <- %v400)");
374 }
375}