1use cranelift_control::ControlPlane;
4
5use crate::ir::{self, types::*};
6use crate::isa::aarch64;
7use crate::isa::aarch64::inst::*;
8use crate::trace;
9
10pub fn mem_finalize(
15 sink: Option<&mut MachBuffer<Inst>>,
16 mem: &AMode,
17 access_ty: Type,
18 state: &EmitState,
19) -> (SmallVec<[Inst; 4]>, AMode) {
20 match mem {
21 &AMode::RegOffset { off, .. }
22 | &AMode::SPOffset { off }
23 | &AMode::FPOffset { off }
24 | &AMode::IncomingArg { off }
25 | &AMode::SlotOffset { off } => {
26 let basereg = match mem {
27 &AMode::RegOffset { rn, .. } => rn,
28 &AMode::SPOffset { .. }
29 | &AMode::SlotOffset { .. }
30 | &AMode::IncomingArg { .. } => stack_reg(),
31 &AMode::FPOffset { .. } => fp_reg(),
32 _ => unreachable!(),
33 };
34 let off = match mem {
35 &AMode::IncomingArg { .. } => {
36 let frame_layout = state.frame_layout();
37 i64::from(
38 frame_layout.setup_area_size
39 + frame_layout.tail_args_size
40 + frame_layout.clobber_size
41 + frame_layout.fixed_frame_storage_size
42 + frame_layout.outgoing_args_size,
43 ) - off
44 }
45 &AMode::SlotOffset { .. } => {
46 let adj = i64::from(state.frame_layout().outgoing_args_size);
47 trace!(
48 "mem_finalize: slot offset {} + adj {} -> {}",
49 off,
50 adj,
51 off + adj
52 );
53 off + adj
54 }
55 _ => off,
56 };
57
58 if let Some(simm9) = SImm9::maybe_from_i64(off) {
59 let mem = AMode::Unscaled { rn: basereg, simm9 };
60 (smallvec![], mem)
61 } else if let Some(uimm12) = UImm12Scaled::maybe_from_i64(off, access_ty) {
62 let mem = AMode::UnsignedOffset {
63 rn: basereg,
64 uimm12,
65 };
66 (smallvec![], mem)
67 } else {
68 let tmp = writable_spilltmp_reg();
69 (
70 Inst::load_constant(tmp, off as u64),
71 AMode::RegExtended {
72 rn: basereg,
73 rm: tmp.to_reg(),
74 extendop: ExtendOp::SXTX,
75 },
76 )
77 }
78 }
79
80 AMode::Const { addr } => {
81 let sink = match sink {
82 Some(sink) => sink,
83 None => return (smallvec![], mem.clone()),
84 };
85 let label = sink.get_label_for_constant(*addr);
86 let label = MemLabel::Mach(label);
87 (smallvec![], AMode::Label { label })
88 }
89
90 _ => (smallvec![], mem.clone()),
91 }
92}
93
94pub(crate) fn machreg_to_gpr(m: Reg) -> u32 {
98 assert_eq!(m.class(), RegClass::Int);
99 u32::from(m.to_real_reg().unwrap().hw_enc() & 31)
100}
101
102pub(crate) fn machreg_to_vec(m: Reg) -> u32 {
103 assert_eq!(m.class(), RegClass::Float);
104 u32::from(m.to_real_reg().unwrap().hw_enc())
105}
106
107fn machreg_to_gpr_or_vec(m: Reg) -> u32 {
108 u32::from(m.to_real_reg().unwrap().hw_enc() & 31)
109}
110
111pub fn enc_arith_rrr(bits_31_21: u32, bits_15_10: u32, rd: Writable<Reg>, rn: Reg, rm: Reg) -> u32 {
113 (bits_31_21 << 21)
114 | (bits_15_10 << 10)
115 | machreg_to_gpr(rd.to_reg())
116 | (machreg_to_gpr(rn) << 5)
117 | (machreg_to_gpr(rm) << 16)
118}
119
120fn enc_arith_rr_imm12(
121 bits_31_24: u32,
122 immshift: u32,
123 imm12: u32,
124 rn: Reg,
125 rd: Writable<Reg>,
126) -> u32 {
127 (bits_31_24 << 24)
128 | (immshift << 22)
129 | (imm12 << 10)
130 | (machreg_to_gpr(rn) << 5)
131 | machreg_to_gpr(rd.to_reg())
132}
133
134fn enc_arith_rr_imml(bits_31_23: u32, imm_bits: u32, rn: Reg, rd: Writable<Reg>) -> u32 {
135 (bits_31_23 << 23) | (imm_bits << 10) | (machreg_to_gpr(rn) << 5) | machreg_to_gpr(rd.to_reg())
136}
137
138fn enc_arith_rrrr(top11: u32, rm: Reg, bit15: u32, ra: Reg, rn: Reg, rd: Writable<Reg>) -> u32 {
139 (top11 << 21)
140 | (machreg_to_gpr(rm) << 16)
141 | (bit15 << 15)
142 | (machreg_to_gpr(ra) << 10)
143 | (machreg_to_gpr(rn) << 5)
144 | machreg_to_gpr(rd.to_reg())
145}
146
147fn enc_jump26(op_31_26: u32, off_26_0: u32) -> u32 {
148 assert!(off_26_0 < (1 << 26));
149 (op_31_26 << 26) | off_26_0
150}
151
152fn enc_cmpbr(op_31_24: u32, off_18_0: u32, reg: Reg) -> u32 {
153 assert!(off_18_0 < (1 << 19));
154 (op_31_24 << 24) | (off_18_0 << 5) | machreg_to_gpr(reg)
155}
156
157fn enc_cbr(op_31_24: u32, off_18_0: u32, op_4: u32, cond: u32) -> u32 {
158 assert!(off_18_0 < (1 << 19));
159 assert!(cond < (1 << 4));
160 (op_31_24 << 24) | (off_18_0 << 5) | (op_4 << 4) | cond
161}
162
163fn enc_op_size(op: u32, size: OperandSize) -> u32 {
165 (op & !(1 << 31)) | (size.sf_bit() << 31)
166}
167
168fn enc_conditional_br(taken: BranchTarget, kind: CondBrKind) -> u32 {
169 match kind {
170 CondBrKind::Zero(reg, size) => enc_op_size(
171 enc_cmpbr(0b0_011010_0, taken.as_offset19_or_zero(), reg),
172 size,
173 ),
174 CondBrKind::NotZero(reg, size) => enc_op_size(
175 enc_cmpbr(0b0_011010_1, taken.as_offset19_or_zero(), reg),
176 size,
177 ),
178 CondBrKind::Cond(c) => enc_cbr(0b01010100, taken.as_offset19_or_zero(), 0b0, c.bits()),
179 }
180}
181
182fn enc_test_bit_and_branch(
183 kind: TestBitAndBranchKind,
184 taken: BranchTarget,
185 reg: Reg,
186 bit: u8,
187) -> u32 {
188 assert!(bit < 64);
189 let op_31 = u32::from(bit >> 5);
190 let op_23_19 = u32::from(bit & 0b11111);
191 let op_30_24 = 0b0110110
192 | match kind {
193 TestBitAndBranchKind::Z => 0,
194 TestBitAndBranchKind::NZ => 1,
195 };
196 (op_31 << 31)
197 | (op_30_24 << 24)
198 | (op_23_19 << 19)
199 | (taken.as_offset14_or_zero() << 5)
200 | machreg_to_gpr(reg)
201}
202
203pub fn enc_move_wide(
205 op: MoveWideOp,
206 rd: Writable<Reg>,
207 imm: MoveWideConst,
208 size: OperandSize,
209) -> u32 {
210 assert!(imm.shift <= 0b11);
211 let op = match op {
212 MoveWideOp::MovN => 0b00,
213 MoveWideOp::MovZ => 0b10,
214 };
215 0x12800000
216 | size.sf_bit() << 31
217 | op << 29
218 | u32::from(imm.shift) << 21
219 | u32::from(imm.bits) << 5
220 | machreg_to_gpr(rd.to_reg())
221}
222
223pub fn enc_movk(rd: Writable<Reg>, imm: MoveWideConst, size: OperandSize) -> u32 {
225 assert!(imm.shift <= 0b11);
226 0x72800000
227 | size.sf_bit() << 31
228 | u32::from(imm.shift) << 21
229 | u32::from(imm.bits) << 5
230 | machreg_to_gpr(rd.to_reg())
231}
232
233fn enc_ldst_pair(op_31_22: u32, simm7: SImm7Scaled, rn: Reg, rt: Reg, rt2: Reg) -> u32 {
234 (op_31_22 << 22)
235 | (simm7.bits() << 15)
236 | (machreg_to_gpr(rt2) << 10)
237 | (machreg_to_gpr(rn) << 5)
238 | machreg_to_gpr(rt)
239}
240
241fn enc_ldst_simm9(op_31_22: u32, simm9: SImm9, op_11_10: u32, rn: Reg, rd: Reg) -> u32 {
242 (op_31_22 << 22)
243 | (simm9.bits() << 12)
244 | (op_11_10 << 10)
245 | (machreg_to_gpr(rn) << 5)
246 | machreg_to_gpr_or_vec(rd)
247}
248
249fn enc_ldst_uimm12(op_31_22: u32, uimm12: UImm12Scaled, rn: Reg, rd: Reg) -> u32 {
250 (op_31_22 << 22)
251 | (0b1 << 24)
252 | (uimm12.bits() << 10)
253 | (machreg_to_gpr(rn) << 5)
254 | machreg_to_gpr_or_vec(rd)
255}
256
257fn enc_ldst_reg(
258 op_31_22: u32,
259 rn: Reg,
260 rm: Reg,
261 s_bit: bool,
262 extendop: Option<ExtendOp>,
263 rd: Reg,
264) -> u32 {
265 let s_bit = if s_bit { 1 } else { 0 };
266 let extend_bits = match extendop {
267 Some(ExtendOp::UXTW) => 0b010,
268 Some(ExtendOp::SXTW) => 0b110,
269 Some(ExtendOp::SXTX) => 0b111,
270 None => 0b011, _ => panic!("bad extend mode for ld/st AMode"),
272 };
273 (op_31_22 << 22)
274 | (1 << 21)
275 | (machreg_to_gpr(rm) << 16)
276 | (extend_bits << 13)
277 | (s_bit << 12)
278 | (0b10 << 10)
279 | (machreg_to_gpr(rn) << 5)
280 | machreg_to_gpr_or_vec(rd)
281}
282
283pub(crate) fn enc_ldst_imm19(op_31_24: u32, imm19: u32, rd: Reg) -> u32 {
284 (op_31_24 << 24) | (imm19 << 5) | machreg_to_gpr_or_vec(rd)
285}
286
287fn enc_ldst_vec(q: u32, size: u32, rn: Reg, rt: Writable<Reg>) -> u32 {
288 debug_assert_eq!(q & 0b1, q);
289 debug_assert_eq!(size & 0b11, size);
290 0b0_0_0011010_10_00000_110_0_00_00000_00000
291 | q << 30
292 | size << 10
293 | machreg_to_gpr(rn) << 5
294 | machreg_to_vec(rt.to_reg())
295}
296
297fn enc_ldst_vec_pair(
298 opc: u32,
299 amode: u32,
300 is_load: bool,
301 simm7: SImm7Scaled,
302 rn: Reg,
303 rt: Reg,
304 rt2: Reg,
305) -> u32 {
306 debug_assert_eq!(opc & 0b11, opc);
307 debug_assert_eq!(amode & 0b11, amode);
308
309 0b00_10110_00_0_0000000_00000_00000_00000
310 | opc << 30
311 | amode << 23
312 | (is_load as u32) << 22
313 | simm7.bits() << 15
314 | machreg_to_vec(rt2) << 10
315 | machreg_to_gpr(rn) << 5
316 | machreg_to_vec(rt)
317}
318
319fn enc_vec_rrr(top11: u32, rm: Reg, bit15_10: u32, rn: Reg, rd: Writable<Reg>) -> u32 {
320 (top11 << 21)
321 | (machreg_to_vec(rm) << 16)
322 | (bit15_10 << 10)
323 | (machreg_to_vec(rn) << 5)
324 | machreg_to_vec(rd.to_reg())
325}
326
327fn enc_vec_rrr_long(
328 q: u32,
329 u: u32,
330 size: u32,
331 bit14: u32,
332 rm: Reg,
333 rn: Reg,
334 rd: Writable<Reg>,
335) -> u32 {
336 debug_assert_eq!(q & 0b1, q);
337 debug_assert_eq!(u & 0b1, u);
338 debug_assert_eq!(size & 0b11, size);
339 debug_assert_eq!(bit14 & 0b1, bit14);
340
341 0b0_0_0_01110_00_1_00000_100000_00000_00000
342 | q << 30
343 | u << 29
344 | size << 22
345 | bit14 << 14
346 | (machreg_to_vec(rm) << 16)
347 | (machreg_to_vec(rn) << 5)
348 | machreg_to_vec(rd.to_reg())
349}
350
351fn enc_bit_rr(size: u32, opcode2: u32, opcode1: u32, rn: Reg, rd: Writable<Reg>) -> u32 {
352 (0b01011010110 << 21)
353 | size << 31
354 | opcode2 << 16
355 | opcode1 << 10
356 | machreg_to_gpr(rn) << 5
357 | machreg_to_gpr(rd.to_reg())
358}
359
360pub(crate) fn enc_br(rn: Reg) -> u32 {
361 0b1101011_0000_11111_000000_00000_00000 | (machreg_to_gpr(rn) << 5)
362}
363
364pub(crate) fn enc_adr_inst(opcode: u32, off: i32, rd: Writable<Reg>) -> u32 {
365 let off = u32::try_from(off).unwrap();
366 let immlo = off & 3;
367 let immhi = (off >> 2) & ((1 << 19) - 1);
368 opcode | (immlo << 29) | (immhi << 5) | machreg_to_gpr(rd.to_reg())
369}
370
371pub(crate) fn enc_adr(off: i32, rd: Writable<Reg>) -> u32 {
372 let opcode = 0b00010000 << 24;
373 enc_adr_inst(opcode, off, rd)
374}
375
376pub(crate) fn enc_adrp(off: i32, rd: Writable<Reg>) -> u32 {
377 let opcode = 0b10010000 << 24;
378 enc_adr_inst(opcode, off, rd)
379}
380
381fn enc_csel(rd: Writable<Reg>, rn: Reg, rm: Reg, cond: Cond, op: u32, o2: u32) -> u32 {
382 debug_assert_eq!(op & 0b1, op);
383 debug_assert_eq!(o2 & 0b1, o2);
384 0b100_11010100_00000_0000_00_00000_00000
385 | (op << 30)
386 | (machreg_to_gpr(rm) << 16)
387 | (cond.bits() << 12)
388 | (o2 << 10)
389 | (machreg_to_gpr(rn) << 5)
390 | machreg_to_gpr(rd.to_reg())
391}
392
393fn enc_fcsel(rd: Writable<Reg>, rn: Reg, rm: Reg, cond: Cond, size: ScalarSize) -> u32 {
394 0b000_11110_00_1_00000_0000_11_00000_00000
395 | (size.ftype() << 22)
396 | (machreg_to_vec(rm) << 16)
397 | (machreg_to_vec(rn) << 5)
398 | machreg_to_vec(rd.to_reg())
399 | (cond.bits() << 12)
400}
401
402fn enc_ccmp(size: OperandSize, rn: Reg, rm: Reg, nzcv: NZCV, cond: Cond) -> u32 {
403 0b0_1_1_11010010_00000_0000_00_00000_0_0000
404 | size.sf_bit() << 31
405 | machreg_to_gpr(rm) << 16
406 | cond.bits() << 12
407 | machreg_to_gpr(rn) << 5
408 | nzcv.bits()
409}
410
411fn enc_ccmp_imm(size: OperandSize, rn: Reg, imm: UImm5, nzcv: NZCV, cond: Cond) -> u32 {
412 0b0_1_1_11010010_00000_0000_10_00000_0_0000
413 | size.sf_bit() << 31
414 | imm.bits() << 16
415 | cond.bits() << 12
416 | machreg_to_gpr(rn) << 5
417 | nzcv.bits()
418}
419
420impl BfmOp {
421 fn opc(self) -> u8 {
422 match self {
423 BfmOp::UBfm => 0b10,
424 BfmOp::SBfm => 0b00,
425 }
426 }
427}
428
429fn enc_bfm(opc: u8, size: OperandSize, rd: Writable<Reg>, rn: Reg, immr: u8, imms: u8) -> u32 {
430 match size {
431 OperandSize::Size64 => {
432 debug_assert!(immr <= 63);
433 debug_assert!(imms <= 63);
434 }
435 OperandSize::Size32 => {
436 debug_assert!(immr <= 31);
437 debug_assert!(imms <= 31);
438 }
439 }
440 debug_assert_eq!(opc & 0b11, opc);
441 let n_bit = size.sf_bit();
442 0b0_00_100110_0_000000_000000_00000_00000
443 | size.sf_bit() << 31
444 | u32::from(opc) << 29
445 | n_bit << 22
446 | u32::from(immr) << 16
447 | u32::from(imms) << 10
448 | machreg_to_gpr(rn) << 5
449 | machreg_to_gpr(rd.to_reg())
450}
451
452fn enc_vecmov(is_16b: bool, rd: Writable<Reg>, rn: Reg) -> u32 {
453 0b00001110_101_00000_00011_1_00000_00000
454 | ((is_16b as u32) << 30)
455 | machreg_to_vec(rd.to_reg())
456 | (machreg_to_vec(rn) << 16)
457 | (machreg_to_vec(rn) << 5)
458}
459
460fn enc_fpurr(top22: u32, rd: Writable<Reg>, rn: Reg) -> u32 {
461 (top22 << 10) | (machreg_to_vec(rn) << 5) | machreg_to_vec(rd.to_reg())
462}
463
464fn enc_fpurrr(top22: u32, rd: Writable<Reg>, rn: Reg, rm: Reg) -> u32 {
465 (top22 << 10)
466 | (machreg_to_vec(rm) << 16)
467 | (machreg_to_vec(rn) << 5)
468 | machreg_to_vec(rd.to_reg())
469}
470
471fn enc_fpurrrr(top17: u32, rd: Writable<Reg>, rn: Reg, rm: Reg, ra: Reg) -> u32 {
472 (top17 << 15)
473 | (machreg_to_vec(rm) << 16)
474 | (machreg_to_vec(ra) << 10)
475 | (machreg_to_vec(rn) << 5)
476 | machreg_to_vec(rd.to_reg())
477}
478
479fn enc_fcmp(size: ScalarSize, rn: Reg, rm: Reg) -> u32 {
480 0b000_11110_00_1_00000_00_1000_00000_00000
481 | (size.ftype() << 22)
482 | (machreg_to_vec(rm) << 16)
483 | (machreg_to_vec(rn) << 5)
484}
485
486fn enc_fputoint(top16: u32, rd: Writable<Reg>, rn: Reg) -> u32 {
487 (top16 << 16) | (machreg_to_vec(rn) << 5) | machreg_to_gpr(rd.to_reg())
488}
489
490fn enc_inttofpu(top16: u32, rd: Writable<Reg>, rn: Reg) -> u32 {
491 (top16 << 16) | (machreg_to_gpr(rn) << 5) | machreg_to_vec(rd.to_reg())
492}
493
494fn enc_fround(top22: u32, rd: Writable<Reg>, rn: Reg) -> u32 {
495 (top22 << 10) | (machreg_to_vec(rn) << 5) | machreg_to_vec(rd.to_reg())
496}
497
498fn enc_vec_rr_misc(qu: u32, size: u32, bits_12_16: u32, rd: Writable<Reg>, rn: Reg) -> u32 {
499 debug_assert_eq!(qu & 0b11, qu);
500 debug_assert_eq!(size & 0b11, size);
501 debug_assert_eq!(bits_12_16 & 0b11111, bits_12_16);
502 let bits = 0b0_00_01110_00_10000_00000_10_00000_00000;
503 bits | qu << 29
504 | size << 22
505 | bits_12_16 << 12
506 | machreg_to_vec(rn) << 5
507 | machreg_to_vec(rd.to_reg())
508}
509
510fn enc_vec_rr_pair(bits_12_16: u32, rd: Writable<Reg>, rn: Reg) -> u32 {
511 debug_assert_eq!(bits_12_16 & 0b11111, bits_12_16);
512
513 0b010_11110_11_11000_11011_10_00000_00000
514 | bits_12_16 << 12
515 | machreg_to_vec(rn) << 5
516 | machreg_to_vec(rd.to_reg())
517}
518
519fn enc_vec_rr_pair_long(u: u32, enc_size: u32, rd: Writable<Reg>, rn: Reg) -> u32 {
520 debug_assert_eq!(u & 0b1, u);
521 debug_assert_eq!(enc_size & 0b1, enc_size);
522
523 0b0_1_0_01110_00_10000_00_0_10_10_00000_00000
524 | u << 29
525 | enc_size << 22
526 | machreg_to_vec(rn) << 5
527 | machreg_to_vec(rd.to_reg())
528}
529
530fn enc_vec_lanes(q: u32, u: u32, size: u32, opcode: u32, rd: Writable<Reg>, rn: Reg) -> u32 {
531 debug_assert_eq!(q & 0b1, q);
532 debug_assert_eq!(u & 0b1, u);
533 debug_assert_eq!(size & 0b11, size);
534 debug_assert_eq!(opcode & 0b11111, opcode);
535 0b0_0_0_01110_00_11000_0_0000_10_00000_00000
536 | q << 30
537 | u << 29
538 | size << 22
539 | opcode << 12
540 | machreg_to_vec(rn) << 5
541 | machreg_to_vec(rd.to_reg())
542}
543
544fn enc_tbl(is_extension: bool, len: u32, rd: Writable<Reg>, rn: Reg, rm: Reg) -> u32 {
545 debug_assert_eq!(len & 0b11, len);
546 0b0_1_001110_000_00000_0_00_0_00_00000_00000
547 | (machreg_to_vec(rm) << 16)
548 | len << 13
549 | (is_extension as u32) << 12
550 | (machreg_to_vec(rn) << 5)
551 | machreg_to_vec(rd.to_reg())
552}
553
554fn enc_dmb_ish() -> u32 {
555 0xD5033BBF
556}
557
558fn enc_acq_rel(ty: Type, op: AtomicRMWOp, rs: Reg, rt: Writable<Reg>, rn: Reg) -> u32 {
559 assert!(machreg_to_gpr(rt.to_reg()) != 31);
560 let sz = match ty {
561 I64 => 0b11,
562 I32 => 0b10,
563 I16 => 0b01,
564 I8 => 0b00,
565 _ => unreachable!(),
566 };
567 let bit15 = match op {
568 AtomicRMWOp::Swp => 0b1,
569 _ => 0b0,
570 };
571 let op = match op {
572 AtomicRMWOp::Add => 0b000,
573 AtomicRMWOp::Clr => 0b001,
574 AtomicRMWOp::Eor => 0b010,
575 AtomicRMWOp::Set => 0b011,
576 AtomicRMWOp::Smax => 0b100,
577 AtomicRMWOp::Smin => 0b101,
578 AtomicRMWOp::Umax => 0b110,
579 AtomicRMWOp::Umin => 0b111,
580 AtomicRMWOp::Swp => 0b000,
581 };
582 0b00_111_000_111_00000_0_000_00_00000_00000
583 | (sz << 30)
584 | (machreg_to_gpr(rs) << 16)
585 | bit15 << 15
586 | (op << 12)
587 | (machreg_to_gpr(rn) << 5)
588 | machreg_to_gpr(rt.to_reg())
589}
590
591fn enc_ldar(ty: Type, rt: Writable<Reg>, rn: Reg) -> u32 {
592 let sz = match ty {
593 I64 => 0b11,
594 I32 => 0b10,
595 I16 => 0b01,
596 I8 => 0b00,
597 _ => unreachable!(),
598 };
599 0b00_001000_1_1_0_11111_1_11111_00000_00000
600 | (sz << 30)
601 | (machreg_to_gpr(rn) << 5)
602 | machreg_to_gpr(rt.to_reg())
603}
604
605fn enc_stlr(ty: Type, rt: Reg, rn: Reg) -> u32 {
606 let sz = match ty {
607 I64 => 0b11,
608 I32 => 0b10,
609 I16 => 0b01,
610 I8 => 0b00,
611 _ => unreachable!(),
612 };
613 0b00_001000_100_11111_1_11111_00000_00000
614 | (sz << 30)
615 | (machreg_to_gpr(rn) << 5)
616 | machreg_to_gpr(rt)
617}
618
619fn enc_ldaxr(ty: Type, rt: Writable<Reg>, rn: Reg) -> u32 {
620 let sz = match ty {
621 I64 => 0b11,
622 I32 => 0b10,
623 I16 => 0b01,
624 I8 => 0b00,
625 _ => unreachable!(),
626 };
627 0b00_001000_0_1_0_11111_1_11111_00000_00000
628 | (sz << 30)
629 | (machreg_to_gpr(rn) << 5)
630 | machreg_to_gpr(rt.to_reg())
631}
632
633fn enc_ldaxp(ty: Type, rt: Writable<Reg>, rt2: Writable<Reg>, rn: Reg) -> u32 {
634 let sz = match ty {
635 I64 => 0b1,
636 I32 => 0b0,
637 _ => unreachable!(),
638 };
639 0b10_0010000_1_1_11111_1_00000_00000_00000
640 | (sz << 30)
641 | (machreg_to_gpr(rt2.to_reg()) << 10)
642 | (machreg_to_gpr(rn) << 5)
643 | machreg_to_gpr(rt.to_reg())
644}
645
646fn enc_ldxp(ty: Type, rt: Writable<Reg>, rt2: Writable<Reg>, rn: Reg) -> u32 {
647 let sz = match ty {
648 I64 => 0b1,
649 I32 => 0b0,
650 _ => unreachable!(),
651 };
652 0b10_0010000_1_1_11111_0_00000_00000_00000
653 | (sz << 30)
654 | (machreg_to_gpr(rt2.to_reg()) << 10)
655 | (machreg_to_gpr(rn) << 5)
656 | machreg_to_gpr(rt.to_reg())
657}
658
659fn enc_stlxr(ty: Type, rs: Writable<Reg>, rt: Reg, rn: Reg) -> u32 {
660 let sz = match ty {
661 I64 => 0b11,
662 I32 => 0b10,
663 I16 => 0b01,
664 I8 => 0b00,
665 _ => unreachable!(),
666 };
667 0b00_001000_000_00000_1_11111_00000_00000
668 | (sz << 30)
669 | (machreg_to_gpr(rs.to_reg()) << 16)
670 | (machreg_to_gpr(rn) << 5)
671 | machreg_to_gpr(rt)
672}
673
674fn enc_stlxp(ty: Type, rs: Writable<Reg>, rt: Reg, rt2: Reg, rn: Reg) -> u32 {
675 let sz = match ty {
676 I64 => 0b1,
677 I32 => 0b0,
678 _ => unreachable!(),
679 };
680 0b10_0010000_0_1_00000_1_00000_00000_00000
681 | (sz << 30)
682 | (machreg_to_gpr(rs.to_reg()) << 16)
683 | (machreg_to_gpr(rt2) << 10)
684 | (machreg_to_gpr(rn) << 5)
685 | machreg_to_gpr(rt)
686}
687
688fn enc_stxp(ty: Type, rs: Writable<Reg>, rt: Reg, rt2: Reg, rn: Reg) -> u32 {
689 let sz = match ty {
690 I64 => 0b1,
691 I32 => 0b0,
692 _ => unreachable!(),
693 };
694 0b10_0010000_0_1_00000_0_00000_00000_00000
695 | (sz << 30)
696 | (machreg_to_gpr(rs.to_reg()) << 16)
697 | (machreg_to_gpr(rt2) << 10)
698 | (machreg_to_gpr(rn) << 5)
699 | machreg_to_gpr(rt)
700}
701
702fn enc_cas(size: u32, rs: Writable<Reg>, rt: Reg, rn: Reg) -> u32 {
703 debug_assert_eq!(size & 0b11, size);
704
705 0b00_0010001_1_1_00000_1_11111_00000_00000
706 | size << 30
707 | machreg_to_gpr(rs.to_reg()) << 16
708 | machreg_to_gpr(rn) << 5
709 | machreg_to_gpr(rt)
710}
711
712fn enc_casp(rs: Writable<Reg>, rt: Reg, rn: Reg) -> u32 {
713 debug_assert_eq!(machreg_to_gpr(rs.to_reg()) & 1, 0);
714 debug_assert_eq!(machreg_to_gpr(rt) & 1, 0);
715
716 0b0_1_0010000_1_1_00000_1_11111_00000_00000
717 | machreg_to_gpr(rs.to_reg()) << 16
718 | machreg_to_gpr(rn) << 5
719 | machreg_to_gpr(rt)
720}
721
722fn enc_asimd_mod_imm(rd: Writable<Reg>, q_op: u32, cmode: u32, imm: u8) -> u32 {
723 let abc = (imm >> 5) as u32;
724 let defgh = (imm & 0b11111) as u32;
725
726 debug_assert_eq!(cmode & 0b1111, cmode);
727 debug_assert_eq!(q_op & 0b11, q_op);
728
729 0b0_0_0_0111100000_000_0000_01_00000_00000
730 | (q_op << 29)
731 | (abc << 16)
732 | (cmode << 12)
733 | (defgh << 5)
734 | machreg_to_vec(rd.to_reg())
735}
736
737#[derive(Default, Clone, Debug)]
739pub struct EmitState {
740 user_stack_map: Option<ir::UserStackMap>,
743
744 ctrl_plane: ControlPlane,
747
748 frame_layout: FrameLayout,
749}
750
751impl MachInstEmitState<Inst> for EmitState {
752 fn new(abi: &Callee<AArch64MachineDeps>, ctrl_plane: ControlPlane) -> Self {
753 EmitState {
754 user_stack_map: None,
755 ctrl_plane,
756 frame_layout: abi.frame_layout().clone(),
757 }
758 }
759
760 fn pre_safepoint(&mut self, user_stack_map: Option<ir::UserStackMap>) {
761 self.user_stack_map = user_stack_map;
762 }
763
764 fn ctrl_plane_mut(&mut self) -> &mut ControlPlane {
765 &mut self.ctrl_plane
766 }
767
768 fn take_ctrl_plane(self) -> ControlPlane {
769 self.ctrl_plane
770 }
771
772 fn frame_layout(&self) -> &FrameLayout {
773 &self.frame_layout
774 }
775}
776
777impl EmitState {
778 fn take_stack_map(&mut self) -> Option<ir::UserStackMap> {
779 self.user_stack_map.take()
780 }
781
782 fn clear_post_insn(&mut self) {
783 self.user_stack_map = None;
784 }
785}
786
787pub struct EmitInfo {
789 flags: settings::Flags,
790 isa_flags: aarch64::settings::Flags,
791}
792
793impl EmitInfo {
794 pub fn new(flags: settings::Flags, isa_flags: aarch64::settings::Flags) -> Self {
796 Self { flags, isa_flags }
797 }
798}
799
800impl MachInstEmit for Inst {
801 type State = EmitState;
802 type Info = EmitInfo;
803
804 fn emit(&self, sink: &mut MachBuffer<Inst>, emit_info: &Self::Info, state: &mut EmitState) {
805 let mut start_off = sink.cur_offset();
811
812 match self {
813 &Inst::AluRRR {
814 alu_op,
815 size,
816 rd,
817 rn,
818 rm,
819 } => {
820 debug_assert!(match alu_op {
821 ALUOp::SMulH | ALUOp::UMulH => size == OperandSize::Size64,
822 _ => true,
823 });
824 let top11 = match alu_op {
825 ALUOp::Add => 0b00001011_000,
826 ALUOp::Adc => 0b00011010_000,
827 ALUOp::AdcS => 0b00111010_000,
828 ALUOp::Sub => 0b01001011_000,
829 ALUOp::Sbc => 0b01011010_000,
830 ALUOp::SbcS => 0b01111010_000,
831 ALUOp::Orr => 0b00101010_000,
832 ALUOp::And => 0b00001010_000,
833 ALUOp::AndS => 0b01101010_000,
834 ALUOp::Eor => 0b01001010_000,
835 ALUOp::OrrNot => 0b00101010_001,
836 ALUOp::AndNot => 0b00001010_001,
837 ALUOp::EorNot => 0b01001010_001,
838 ALUOp::AddS => 0b00101011_000,
839 ALUOp::SubS => 0b01101011_000,
840 ALUOp::SDiv | ALUOp::UDiv => 0b00011010_110,
841 ALUOp::Extr | ALUOp::Lsr | ALUOp::Asr | ALUOp::Lsl => 0b00011010_110,
842 ALUOp::SMulH => 0b10011011_010,
843 ALUOp::UMulH => 0b10011011_110,
844 };
845
846 let top11 = top11 | size.sf_bit() << 10;
847 let bit15_10 = match alu_op {
848 ALUOp::SDiv => 0b000011,
849 ALUOp::UDiv => 0b000010,
850 ALUOp::Extr => 0b001011,
851 ALUOp::Lsr => 0b001001,
852 ALUOp::Asr => 0b001010,
853 ALUOp::Lsl => 0b001000,
854 ALUOp::SMulH | ALUOp::UMulH => 0b011111,
855 _ => 0b000000,
856 };
857 debug_assert_ne!(writable_stack_reg(), rd);
858 debug_assert_ne!(stack_reg(), rn);
861 debug_assert_ne!(stack_reg(), rm);
862 sink.put4(enc_arith_rrr(top11, bit15_10, rd, rn, rm));
863 }
864 &Inst::AluRRRR {
865 alu_op,
866 size,
867 rd,
868 rm,
869 rn,
870 ra,
871 } => {
872 let (top11, bit15) = match alu_op {
873 ALUOp3::MAdd => (0b0_00_11011_000, 0),
874 ALUOp3::MSub => (0b0_00_11011_000, 1),
875 ALUOp3::UMAddL => {
876 debug_assert!(size == OperandSize::Size32);
877 (0b1_00_11011_1_01, 0)
878 }
879 ALUOp3::SMAddL => {
880 debug_assert!(size == OperandSize::Size32);
881 (0b1_00_11011_0_01, 0)
882 }
883 };
884 let top11 = top11 | size.sf_bit() << 10;
885 sink.put4(enc_arith_rrrr(top11, rm, bit15, ra, rn, rd));
886 }
887 &Inst::AluRRImm12 {
888 alu_op,
889 size,
890 rd,
891 rn,
892 ref imm12,
893 } => {
894 let top8 = match alu_op {
895 ALUOp::Add => 0b000_10001,
896 ALUOp::Sub => 0b010_10001,
897 ALUOp::AddS => 0b001_10001,
898 ALUOp::SubS => 0b011_10001,
899 _ => unimplemented!("{:?}", alu_op),
900 };
901 let top8 = top8 | size.sf_bit() << 7;
902 sink.put4(enc_arith_rr_imm12(
903 top8,
904 imm12.shift_bits(),
905 imm12.imm_bits(),
906 rn,
907 rd,
908 ));
909 }
910 &Inst::AluRRImmLogic {
911 alu_op,
912 size,
913 rd,
914 rn,
915 ref imml,
916 } => {
917 let (top9, inv) = match alu_op {
918 ALUOp::Orr => (0b001_100100, false),
919 ALUOp::And => (0b000_100100, false),
920 ALUOp::AndS => (0b011_100100, false),
921 ALUOp::Eor => (0b010_100100, false),
922 ALUOp::OrrNot => (0b001_100100, true),
923 ALUOp::AndNot => (0b000_100100, true),
924 ALUOp::EorNot => (0b010_100100, true),
925 _ => unimplemented!("{:?}", alu_op),
926 };
927 let top9 = top9 | size.sf_bit() << 8;
928 let imml = if inv { imml.invert() } else { *imml };
929 sink.put4(enc_arith_rr_imml(top9, imml.enc_bits(), rn, rd));
930 }
931
932 &Inst::AluRRImmShift {
933 alu_op,
934 size,
935 rd,
936 rn,
937 ref immshift,
938 } => {
939 let amt = immshift.value();
940 let (top10, immr, imms) = match alu_op {
941 ALUOp::Extr => (0b0001001110, machreg_to_gpr(rn), u32::from(amt)),
942 ALUOp::Lsr => (0b0101001100, u32::from(amt), 0b011111),
943 ALUOp::Asr => (0b0001001100, u32::from(amt), 0b011111),
944 ALUOp::Lsl => {
945 let bits = if size.is64() { 64 } else { 32 };
946 (
947 0b0101001100,
948 u32::from((bits - amt) % bits),
949 u32::from(bits - 1 - amt),
950 )
951 }
952 _ => unimplemented!("{:?}", alu_op),
953 };
954 let top10 = top10 | size.sf_bit() << 9 | size.sf_bit();
955 let imms = match alu_op {
956 ALUOp::Lsr | ALUOp::Asr => imms | size.sf_bit() << 5,
957 _ => imms,
958 };
959 sink.put4(
960 (top10 << 22)
961 | (immr << 16)
962 | (imms << 10)
963 | (machreg_to_gpr(rn) << 5)
964 | machreg_to_gpr(rd.to_reg()),
965 );
966 }
967
968 &Inst::AluRRRShift {
969 alu_op,
970 size,
971 rd,
972 rn,
973 rm,
974 ref shiftop,
975 } => {
976 let top11: u32 = match alu_op {
977 ALUOp::Add => 0b000_01011000,
978 ALUOp::AddS => 0b001_01011000,
979 ALUOp::Sub => 0b010_01011000,
980 ALUOp::SubS => 0b011_01011000,
981 ALUOp::Orr => 0b001_01010000,
982 ALUOp::And => 0b000_01010000,
983 ALUOp::AndS => 0b011_01010000,
984 ALUOp::Eor => 0b010_01010000,
985 ALUOp::OrrNot => 0b001_01010001,
986 ALUOp::EorNot => 0b010_01010001,
987 ALUOp::AndNot => 0b000_01010001,
988 ALUOp::Extr => 0b000_10011100,
989 _ => unimplemented!("{:?}", alu_op),
990 };
991 let top11 = top11 | size.sf_bit() << 10;
992 let top11 = top11 | (u32::from(shiftop.op().bits()) << 1);
993 let bits_15_10 = u32::from(shiftop.amt().value());
994 sink.put4(enc_arith_rrr(top11, bits_15_10, rd, rn, rm));
995 }
996
997 &Inst::AluRRRExtend {
998 alu_op,
999 size,
1000 rd,
1001 rn,
1002 rm,
1003 extendop,
1004 } => {
1005 let top11: u32 = match alu_op {
1006 ALUOp::Add => 0b00001011001,
1007 ALUOp::Sub => 0b01001011001,
1008 ALUOp::AddS => 0b00101011001,
1009 ALUOp::SubS => 0b01101011001,
1010 _ => unimplemented!("{:?}", alu_op),
1011 };
1012 let top11 = top11 | size.sf_bit() << 10;
1013 let bits_15_10 = u32::from(extendop.bits()) << 3;
1014 sink.put4(enc_arith_rrr(top11, bits_15_10, rd, rn, rm));
1015 }
1016
1017 &Inst::BitRR {
1018 op, size, rd, rn, ..
1019 } => {
1020 let (op1, op2) = match op {
1021 BitOp::RBit => (0b00000, 0b000000),
1022 BitOp::Clz => (0b00000, 0b000100),
1023 BitOp::Cls => (0b00000, 0b000101),
1024 BitOp::Rev16 => (0b00000, 0b000001),
1025 BitOp::Rev32 => (0b00000, 0b000010),
1026 BitOp::Rev64 => (0b00000, 0b000011),
1027 };
1028 sink.put4(enc_bit_rr(size.sf_bit(), op1, op2, rn, rd))
1029 }
1030
1031 &Inst::ULoad8 { rd, ref mem, flags }
1032 | &Inst::SLoad8 { rd, ref mem, flags }
1033 | &Inst::ULoad16 { rd, ref mem, flags }
1034 | &Inst::SLoad16 { rd, ref mem, flags }
1035 | &Inst::ULoad32 { rd, ref mem, flags }
1036 | &Inst::SLoad32 { rd, ref mem, flags }
1037 | &Inst::ULoad64 {
1038 rd, ref mem, flags, ..
1039 }
1040 | &Inst::FpuLoad16 { rd, ref mem, flags }
1041 | &Inst::FpuLoad32 { rd, ref mem, flags }
1042 | &Inst::FpuLoad64 { rd, ref mem, flags }
1043 | &Inst::FpuLoad128 { rd, ref mem, flags } => {
1044 let mem = mem.clone();
1045 let access_ty = self.mem_type().unwrap();
1046 let (mem_insts, mem) = mem_finalize(Some(sink), &mem, access_ty, state);
1047
1048 for inst in mem_insts.into_iter() {
1049 inst.emit(sink, emit_info, state);
1050 }
1051
1052 let rd = rd.to_reg();
1054
1055 let op = match self {
1059 Inst::ULoad8 { .. } => 0b0011100001,
1060 Inst::SLoad8 { .. } => 0b0011100010,
1061 Inst::ULoad16 { .. } => 0b0111100001,
1062 Inst::SLoad16 { .. } => 0b0111100010,
1063 Inst::ULoad32 { .. } => 0b1011100001,
1064 Inst::SLoad32 { .. } => 0b1011100010,
1065 Inst::ULoad64 { .. } => 0b1111100001,
1066 Inst::FpuLoad16 { .. } => 0b0111110001,
1067 Inst::FpuLoad32 { .. } => 0b1011110001,
1068 Inst::FpuLoad64 { .. } => 0b1111110001,
1069 Inst::FpuLoad128 { .. } => 0b0011110011,
1070 _ => unreachable!(),
1071 };
1072
1073 if let Some(trap_code) = flags.trap_code() {
1074 sink.add_trap(trap_code);
1076 }
1077
1078 match &mem {
1079 &AMode::Unscaled { rn, simm9 } => {
1080 let reg = rn;
1081 sink.put4(enc_ldst_simm9(op, simm9, 0b00, reg, rd));
1082 }
1083 &AMode::UnsignedOffset { rn, uimm12 } => {
1084 let reg = rn;
1085 sink.put4(enc_ldst_uimm12(op, uimm12, reg, rd));
1086 }
1087 &AMode::RegReg { rn, rm } => {
1088 let r1 = rn;
1089 let r2 = rm;
1090 sink.put4(enc_ldst_reg(
1091 op, r1, r2, false, None, rd,
1092 ));
1093 }
1094 &AMode::RegScaled { rn, rm } | &AMode::RegScaledExtended { rn, rm, .. } => {
1095 let r1 = rn;
1096 let r2 = rm;
1097 let extendop = match &mem {
1098 &AMode::RegScaled { .. } => None,
1099 &AMode::RegScaledExtended { extendop, .. } => Some(extendop),
1100 _ => unreachable!(),
1101 };
1102 sink.put4(enc_ldst_reg(
1103 op, r1, r2, true, extendop, rd,
1104 ));
1105 }
1106 &AMode::RegExtended { rn, rm, extendop } => {
1107 let r1 = rn;
1108 let r2 = rm;
1109 sink.put4(enc_ldst_reg(
1110 op,
1111 r1,
1112 r2,
1113 false,
1114 Some(extendop),
1115 rd,
1116 ));
1117 }
1118 &AMode::Label { ref label } => {
1119 let offset = match label {
1120 MemLabel::PCRel(off) => *off as u32,
1122 MemLabel::Mach(label) => {
1127 sink.use_label_at_offset(
1128 sink.cur_offset(),
1129 *label,
1130 LabelUse::Ldr19,
1131 );
1132 0
1133 }
1134 } / 4;
1135 assert!(offset < (1 << 19));
1136 match self {
1137 &Inst::ULoad32 { .. } => {
1138 sink.put4(enc_ldst_imm19(0b00011000, offset, rd));
1139 }
1140 &Inst::SLoad32 { .. } => {
1141 sink.put4(enc_ldst_imm19(0b10011000, offset, rd));
1142 }
1143 &Inst::FpuLoad32 { .. } => {
1144 sink.put4(enc_ldst_imm19(0b00011100, offset, rd));
1145 }
1146 &Inst::ULoad64 { .. } => {
1147 sink.put4(enc_ldst_imm19(0b01011000, offset, rd));
1148 }
1149 &Inst::FpuLoad64 { .. } => {
1150 sink.put4(enc_ldst_imm19(0b01011100, offset, rd));
1151 }
1152 &Inst::FpuLoad128 { .. } => {
1153 sink.put4(enc_ldst_imm19(0b10011100, offset, rd));
1154 }
1155 _ => panic!("Unsupported size for LDR from constant pool!"),
1156 }
1157 }
1158 &AMode::SPPreIndexed { simm9 } => {
1159 let reg = stack_reg();
1160 sink.put4(enc_ldst_simm9(op, simm9, 0b11, reg, rd));
1161 }
1162 &AMode::SPPostIndexed { simm9 } => {
1163 let reg = stack_reg();
1164 sink.put4(enc_ldst_simm9(op, simm9, 0b01, reg, rd));
1165 }
1166 &AMode::SPOffset { .. }
1168 | &AMode::FPOffset { .. }
1169 | &AMode::IncomingArg { .. }
1170 | &AMode::SlotOffset { .. }
1171 | &AMode::Const { .. }
1172 | &AMode::RegOffset { .. } => {
1173 panic!("Should not see {mem:?} here!")
1174 }
1175 }
1176 }
1177
1178 &Inst::Store8 { rd, ref mem, flags }
1179 | &Inst::Store16 { rd, ref mem, flags }
1180 | &Inst::Store32 { rd, ref mem, flags }
1181 | &Inst::Store64 { rd, ref mem, flags }
1182 | &Inst::FpuStore16 { rd, ref mem, flags }
1183 | &Inst::FpuStore32 { rd, ref mem, flags }
1184 | &Inst::FpuStore64 { rd, ref mem, flags }
1185 | &Inst::FpuStore128 { rd, ref mem, flags } => {
1186 let mem = mem.clone();
1187 let access_ty = self.mem_type().unwrap();
1188 let (mem_insts, mem) = mem_finalize(Some(sink), &mem, access_ty, state);
1189
1190 for inst in mem_insts.into_iter() {
1191 inst.emit(sink, emit_info, state);
1192 }
1193
1194 let op = match self {
1195 Inst::Store8 { .. } => 0b0011100000,
1196 Inst::Store16 { .. } => 0b0111100000,
1197 Inst::Store32 { .. } => 0b1011100000,
1198 Inst::Store64 { .. } => 0b1111100000,
1199 Inst::FpuStore16 { .. } => 0b0111110000,
1200 Inst::FpuStore32 { .. } => 0b1011110000,
1201 Inst::FpuStore64 { .. } => 0b1111110000,
1202 Inst::FpuStore128 { .. } => 0b0011110010,
1203 _ => unreachable!(),
1204 };
1205
1206 if let Some(trap_code) = flags.trap_code() {
1207 sink.add_trap(trap_code);
1209 }
1210
1211 match &mem {
1212 &AMode::Unscaled { rn, simm9 } => {
1213 let reg = rn;
1214 sink.put4(enc_ldst_simm9(op, simm9, 0b00, reg, rd));
1215 }
1216 &AMode::UnsignedOffset { rn, uimm12 } => {
1217 let reg = rn;
1218 sink.put4(enc_ldst_uimm12(op, uimm12, reg, rd));
1219 }
1220 &AMode::RegReg { rn, rm } => {
1221 let r1 = rn;
1222 let r2 = rm;
1223 sink.put4(enc_ldst_reg(
1224 op, r1, r2, false, None, rd,
1225 ));
1226 }
1227 &AMode::RegScaled { rn, rm } | &AMode::RegScaledExtended { rn, rm, .. } => {
1228 let r1 = rn;
1229 let r2 = rm;
1230 let extendop = match &mem {
1231 &AMode::RegScaled { .. } => None,
1232 &AMode::RegScaledExtended { extendop, .. } => Some(extendop),
1233 _ => unreachable!(),
1234 };
1235 sink.put4(enc_ldst_reg(
1236 op, r1, r2, true, extendop, rd,
1237 ));
1238 }
1239 &AMode::RegExtended { rn, rm, extendop } => {
1240 let r1 = rn;
1241 let r2 = rm;
1242 sink.put4(enc_ldst_reg(
1243 op,
1244 r1,
1245 r2,
1246 false,
1247 Some(extendop),
1248 rd,
1249 ));
1250 }
1251 &AMode::Label { .. } => {
1252 panic!("Store to a MemLabel not implemented!");
1253 }
1254 &AMode::SPPreIndexed { simm9 } => {
1255 let reg = stack_reg();
1256 sink.put4(enc_ldst_simm9(op, simm9, 0b11, reg, rd));
1257 }
1258 &AMode::SPPostIndexed { simm9 } => {
1259 let reg = stack_reg();
1260 sink.put4(enc_ldst_simm9(op, simm9, 0b01, reg, rd));
1261 }
1262 &AMode::SPOffset { .. }
1264 | &AMode::FPOffset { .. }
1265 | &AMode::IncomingArg { .. }
1266 | &AMode::SlotOffset { .. }
1267 | &AMode::Const { .. }
1268 | &AMode::RegOffset { .. } => {
1269 panic!("Should not see {mem:?} here!")
1270 }
1271 }
1272 }
1273
1274 &Inst::StoreP64 {
1275 rt,
1276 rt2,
1277 ref mem,
1278 flags,
1279 } => {
1280 let mem = mem.clone();
1281 if let Some(trap_code) = flags.trap_code() {
1282 sink.add_trap(trap_code);
1284 }
1285 match &mem {
1286 &PairAMode::SignedOffset { reg, simm7 } => {
1287 assert_eq!(simm7.scale_ty, I64);
1288 sink.put4(enc_ldst_pair(0b1010100100, simm7, reg, rt, rt2));
1289 }
1290 &PairAMode::SPPreIndexed { simm7 } => {
1291 assert_eq!(simm7.scale_ty, I64);
1292 let reg = stack_reg();
1293 sink.put4(enc_ldst_pair(0b1010100110, simm7, reg, rt, rt2));
1294 }
1295 &PairAMode::SPPostIndexed { simm7 } => {
1296 assert_eq!(simm7.scale_ty, I64);
1297 let reg = stack_reg();
1298 sink.put4(enc_ldst_pair(0b1010100010, simm7, reg, rt, rt2));
1299 }
1300 }
1301 }
1302 &Inst::LoadP64 {
1303 rt,
1304 rt2,
1305 ref mem,
1306 flags,
1307 } => {
1308 let rt = rt.to_reg();
1309 let rt2 = rt2.to_reg();
1310 let mem = mem.clone();
1311 if let Some(trap_code) = flags.trap_code() {
1312 sink.add_trap(trap_code);
1314 }
1315
1316 match &mem {
1317 &PairAMode::SignedOffset { reg, simm7 } => {
1318 assert_eq!(simm7.scale_ty, I64);
1319 sink.put4(enc_ldst_pair(0b1010100101, simm7, reg, rt, rt2));
1320 }
1321 &PairAMode::SPPreIndexed { simm7 } => {
1322 assert_eq!(simm7.scale_ty, I64);
1323 let reg = stack_reg();
1324 sink.put4(enc_ldst_pair(0b1010100111, simm7, reg, rt, rt2));
1325 }
1326 &PairAMode::SPPostIndexed { simm7 } => {
1327 assert_eq!(simm7.scale_ty, I64);
1328 let reg = stack_reg();
1329 sink.put4(enc_ldst_pair(0b1010100011, simm7, reg, rt, rt2));
1330 }
1331 }
1332 }
1333 &Inst::FpuLoadP64 {
1334 rt,
1335 rt2,
1336 ref mem,
1337 flags,
1338 }
1339 | &Inst::FpuLoadP128 {
1340 rt,
1341 rt2,
1342 ref mem,
1343 flags,
1344 } => {
1345 let rt = rt.to_reg();
1346 let rt2 = rt2.to_reg();
1347 let mem = mem.clone();
1348
1349 if let Some(trap_code) = flags.trap_code() {
1350 sink.add_trap(trap_code);
1352 }
1353
1354 let opc = match self {
1355 &Inst::FpuLoadP64 { .. } => 0b01,
1356 &Inst::FpuLoadP128 { .. } => 0b10,
1357 _ => unreachable!(),
1358 };
1359
1360 match &mem {
1361 &PairAMode::SignedOffset { reg, simm7 } => {
1362 assert!(simm7.scale_ty == F64 || simm7.scale_ty == I8X16);
1363 sink.put4(enc_ldst_vec_pair(opc, 0b10, true, simm7, reg, rt, rt2));
1364 }
1365 &PairAMode::SPPreIndexed { simm7 } => {
1366 assert!(simm7.scale_ty == F64 || simm7.scale_ty == I8X16);
1367 let reg = stack_reg();
1368 sink.put4(enc_ldst_vec_pair(opc, 0b11, true, simm7, reg, rt, rt2));
1369 }
1370 &PairAMode::SPPostIndexed { simm7 } => {
1371 assert!(simm7.scale_ty == F64 || simm7.scale_ty == I8X16);
1372 let reg = stack_reg();
1373 sink.put4(enc_ldst_vec_pair(opc, 0b01, true, simm7, reg, rt, rt2));
1374 }
1375 }
1376 }
1377 &Inst::FpuStoreP64 {
1378 rt,
1379 rt2,
1380 ref mem,
1381 flags,
1382 }
1383 | &Inst::FpuStoreP128 {
1384 rt,
1385 rt2,
1386 ref mem,
1387 flags,
1388 } => {
1389 let mem = mem.clone();
1390
1391 if let Some(trap_code) = flags.trap_code() {
1392 sink.add_trap(trap_code);
1394 }
1395
1396 let opc = match self {
1397 &Inst::FpuStoreP64 { .. } => 0b01,
1398 &Inst::FpuStoreP128 { .. } => 0b10,
1399 _ => unreachable!(),
1400 };
1401
1402 match &mem {
1403 &PairAMode::SignedOffset { reg, simm7 } => {
1404 assert!(simm7.scale_ty == F64 || simm7.scale_ty == I8X16);
1405 sink.put4(enc_ldst_vec_pair(opc, 0b10, false, simm7, reg, rt, rt2));
1406 }
1407 &PairAMode::SPPreIndexed { simm7 } => {
1408 assert!(simm7.scale_ty == F64 || simm7.scale_ty == I8X16);
1409 let reg = stack_reg();
1410 sink.put4(enc_ldst_vec_pair(opc, 0b11, false, simm7, reg, rt, rt2));
1411 }
1412 &PairAMode::SPPostIndexed { simm7 } => {
1413 assert!(simm7.scale_ty == F64 || simm7.scale_ty == I8X16);
1414 let reg = stack_reg();
1415 sink.put4(enc_ldst_vec_pair(opc, 0b01, false, simm7, reg, rt, rt2));
1416 }
1417 }
1418 }
1419 &Inst::Mov { size, rd, rm } => {
1420 assert!(rd.to_reg().class() == rm.class());
1421 assert!(rm.class() == RegClass::Int);
1422
1423 match size {
1424 OperandSize::Size64 => {
1425 assert!(rd.to_reg() != stack_reg());
1428
1429 if rm == stack_reg() {
1430 let imm12 = Imm12::maybe_from_u64(0).unwrap();
1432 sink.put4(enc_arith_rr_imm12(
1433 0b100_10001,
1434 imm12.shift_bits(),
1435 imm12.imm_bits(),
1436 rm,
1437 rd,
1438 ));
1439 } else {
1440 sink.put4(enc_arith_rrr(0b10101010_000, 0b000_000, rd, zero_reg(), rm));
1442 }
1443 }
1444 OperandSize::Size32 => {
1445 assert!(machreg_to_gpr(rd.to_reg()) != 31);
1448 sink.put4(enc_arith_rrr(0b00101010_000, 0b000_000, rd, zero_reg(), rm));
1450 }
1451 }
1452 }
1453 &Inst::MovFromPReg { rd, rm } => {
1454 let rm: Reg = rm.into();
1455 debug_assert!(
1456 [
1457 regs::fp_reg(),
1458 regs::stack_reg(),
1459 regs::link_reg(),
1460 regs::pinned_reg()
1461 ]
1462 .contains(&rm)
1463 );
1464 assert!(rm.class() == RegClass::Int);
1465 assert!(rd.to_reg().class() == rm.class());
1466 let size = OperandSize::Size64;
1467 Inst::Mov { size, rd, rm }.emit(sink, emit_info, state);
1468 }
1469 &Inst::MovToPReg { rd, rm } => {
1470 let rd: Writable<Reg> = Writable::from_reg(rd.into());
1471 debug_assert!(
1472 [
1473 regs::fp_reg(),
1474 regs::stack_reg(),
1475 regs::link_reg(),
1476 regs::pinned_reg()
1477 ]
1478 .contains(&rd.to_reg())
1479 );
1480 assert!(rd.to_reg().class() == RegClass::Int);
1481 assert!(rm.class() == rd.to_reg().class());
1482 let size = OperandSize::Size64;
1483 Inst::Mov { size, rd, rm }.emit(sink, emit_info, state);
1484 }
1485 &Inst::MovWide { op, rd, imm, size } => {
1486 sink.put4(enc_move_wide(op, rd, imm, size));
1487 }
1488 &Inst::MovK { rd, rn, imm, size } => {
1489 debug_assert_eq!(rn, rd.to_reg());
1490 sink.put4(enc_movk(rd, imm, size));
1491 }
1492 &Inst::CSel { rd, rn, rm, cond } => {
1493 sink.put4(enc_csel(rd, rn, rm, cond, 0, 0));
1494 }
1495 &Inst::CSNeg { rd, rn, rm, cond } => {
1496 sink.put4(enc_csel(rd, rn, rm, cond, 1, 1));
1497 }
1498 &Inst::CSet { rd, cond } => {
1499 sink.put4(enc_csel(rd, zero_reg(), zero_reg(), cond.invert(), 0, 1));
1500 }
1501 &Inst::CSetm { rd, cond } => {
1502 sink.put4(enc_csel(rd, zero_reg(), zero_reg(), cond.invert(), 1, 0));
1503 }
1504 &Inst::CCmp {
1505 size,
1506 rn,
1507 rm,
1508 nzcv,
1509 cond,
1510 } => {
1511 sink.put4(enc_ccmp(size, rn, rm, nzcv, cond));
1512 }
1513 &Inst::CCmpImm {
1514 size,
1515 rn,
1516 imm,
1517 nzcv,
1518 cond,
1519 } => {
1520 sink.put4(enc_ccmp_imm(size, rn, imm, nzcv, cond));
1521 }
1522 &Inst::AtomicRMW {
1523 ty,
1524 op,
1525 rs,
1526 rt,
1527 rn,
1528 flags,
1529 } => {
1530 if let Some(trap_code) = flags.trap_code() {
1531 sink.add_trap(trap_code);
1532 }
1533
1534 sink.put4(enc_acq_rel(ty, op, rs, rt, rn));
1535 }
1536 &Inst::AtomicRMWLoop { ty, op, flags, .. } => {
1537 let xzr = zero_reg();
1557 let x24 = xreg(24);
1558 let x25 = xreg(25);
1559 let x26 = xreg(26);
1560 let x27 = xreg(27);
1561 let x28 = xreg(28);
1562 let x24wr = writable_xreg(24);
1563 let x27wr = writable_xreg(27);
1564 let x28wr = writable_xreg(28);
1565 let again_label = sink.get_label();
1566
1567 sink.bind_label(again_label, &mut state.ctrl_plane);
1569
1570 if let Some(trap_code) = flags.trap_code() {
1571 sink.add_trap(trap_code);
1572 }
1573
1574 sink.put4(enc_ldaxr(ty, x27wr, x25)); let size = OperandSize::from_ty(ty);
1576 let sign_ext = match op {
1577 AtomicRMWLoopOp::Smin | AtomicRMWLoopOp::Smax => match ty {
1578 I16 => Some(ExtendOp::SXTH),
1579 I8 => Some(ExtendOp::SXTB),
1580 _ => None,
1581 },
1582 _ => None,
1583 };
1584 let zero_ext = match op {
1585 AtomicRMWLoopOp::Umin | AtomicRMWLoopOp::Umax => match ty {
1586 I16 => Some(ExtendOp::UXTH),
1587 I8 => Some(ExtendOp::UXTB),
1588 _ => None,
1589 },
1590 _ => None,
1591 };
1592 if let Some(op) = sign_ext {
1594 Inst::gen_extend(x27wr, x27, op, size).emit(sink, emit_info, state);
1595 }
1596
1597 match op {
1598 AtomicRMWLoopOp::Xchg => {} AtomicRMWLoopOp::Nand => {
1600 Inst::AluRRR {
1604 alu_op: ALUOp::And,
1605 size,
1606 rd: x28wr,
1607 rn: x27,
1608 rm: x26,
1609 }
1610 .emit(sink, emit_info, state);
1611
1612 Inst::AluRRR {
1613 alu_op: ALUOp::OrrNot,
1614 size,
1615 rd: x28wr,
1616 rn: xzr,
1617 rm: x28,
1618 }
1619 .emit(sink, emit_info, state);
1620 }
1621 AtomicRMWLoopOp::Umin
1622 | AtomicRMWLoopOp::Umax
1623 | AtomicRMWLoopOp::Smin
1624 | AtomicRMWLoopOp::Smax => {
1625 let cond = match op {
1629 AtomicRMWLoopOp::Umin => Cond::Lo,
1630 AtomicRMWLoopOp::Umax => Cond::Hi,
1631 AtomicRMWLoopOp::Smin => Cond::Lt,
1632 AtomicRMWLoopOp::Smax => Cond::Gt,
1633 _ => unreachable!(),
1634 };
1635
1636 if let Some(extendop) = sign_ext.or(zero_ext) {
1637 Inst::AluRRRExtend {
1638 alu_op: ALUOp::SubS,
1639 size,
1640 rd: writable_zero_reg(),
1641 rn: x27,
1642 rm: x26,
1643 extendop,
1644 }
1645 .emit(sink, emit_info, state);
1646 } else {
1647 Inst::AluRRR {
1648 alu_op: ALUOp::SubS,
1649 size,
1650 rd: writable_zero_reg(),
1651 rn: x27,
1652 rm: x26,
1653 }
1654 .emit(sink, emit_info, state);
1655 }
1656
1657 Inst::CSel {
1658 cond,
1659 rd: x28wr,
1660 rn: x27,
1661 rm: x26,
1662 }
1663 .emit(sink, emit_info, state);
1664 }
1665 _ => {
1666 let alu_op = match op {
1668 AtomicRMWLoopOp::Add => ALUOp::Add,
1669 AtomicRMWLoopOp::Sub => ALUOp::Sub,
1670 AtomicRMWLoopOp::And => ALUOp::And,
1671 AtomicRMWLoopOp::Orr => ALUOp::Orr,
1672 AtomicRMWLoopOp::Eor => ALUOp::Eor,
1673 AtomicRMWLoopOp::Nand
1674 | AtomicRMWLoopOp::Umin
1675 | AtomicRMWLoopOp::Umax
1676 | AtomicRMWLoopOp::Smin
1677 | AtomicRMWLoopOp::Smax
1678 | AtomicRMWLoopOp::Xchg => unreachable!(),
1679 };
1680
1681 Inst::AluRRR {
1682 alu_op,
1683 size,
1684 rd: x28wr,
1685 rn: x27,
1686 rm: x26,
1687 }
1688 .emit(sink, emit_info, state);
1689 }
1690 }
1691
1692 if let Some(trap_code) = flags.trap_code() {
1693 sink.add_trap(trap_code);
1694 }
1695 if op == AtomicRMWLoopOp::Xchg {
1696 sink.put4(enc_stlxr(ty, x24wr, x26, x25)); } else {
1698 sink.put4(enc_stlxr(ty, x24wr, x28, x25)); }
1700
1701 let br_offset = sink.cur_offset();
1705 sink.put4(enc_conditional_br(
1706 BranchTarget::Label(again_label),
1707 CondBrKind::NotZero(x24, OperandSize::Size64),
1708 ));
1709 sink.use_label_at_offset(br_offset, again_label, LabelUse::Branch19);
1710 }
1711 &Inst::AtomicRMW128Loop { op, flags, .. } => {
1712 let xzr = zero_reg();
1731 let x21 = xreg(21);
1732 let x22 = xreg(22);
1733 let x23 = xreg(23);
1734 let x24 = xreg(24);
1735 let x25 = xreg(25);
1736 let x26 = xreg(26);
1737 let x27 = xreg(27);
1738 let x28 = xreg(28);
1739 let x21wr = writable_xreg(21);
1740 let x23wr = writable_xreg(23);
1741 let x24wr = writable_xreg(24);
1742 let x27wr = writable_xreg(27);
1743 let x28wr = writable_xreg(28);
1744 let again_label = sink.get_label();
1745
1746 sink.bind_label(again_label, &mut state.ctrl_plane);
1748
1749 if let Some(trap_code) = flags.trap_code() {
1750 sink.add_trap(trap_code);
1751 }
1752
1753 sink.put4(enc_ldaxp(I64, x27wr, x23wr, x25)); match op {
1756 AtomicRMWLoopOp::Xchg => {} AtomicRMWLoopOp::Smax
1758 | AtomicRMWLoopOp::Umax
1759 | AtomicRMWLoopOp::Smin
1760 | AtomicRMWLoopOp::Umin => {
1761 let cond = match op {
1767 AtomicRMWLoopOp::Smax => Cond::Lt,
1768 AtomicRMWLoopOp::Umax => Cond::Lo,
1769 AtomicRMWLoopOp::Smin => Cond::Ge,
1770 AtomicRMWLoopOp::Umin => Cond::Hs,
1771 _ => unreachable!(),
1772 };
1773
1774 Inst::AluRRR {
1775 alu_op: ALUOp::SubS,
1776 size: OperandSize::Size64,
1777 rd: writable_zero_reg(),
1778 rn: x27,
1779 rm: x26,
1780 }
1781 .emit(sink, emit_info, state);
1782
1783 Inst::AluRRR {
1784 alu_op: ALUOp::SbcS,
1785 size: OperandSize::Size64,
1786 rd: writable_zero_reg(),
1787 rn: x23,
1788 rm: x22,
1789 }
1790 .emit(sink, emit_info, state);
1791
1792 Inst::CSel {
1793 cond,
1794 rd: x21wr,
1795 rn: x22,
1796 rm: x23,
1797 }
1798 .emit(sink, emit_info, state);
1799
1800 Inst::CSel {
1801 cond,
1802 rd: x28wr,
1803 rn: x26,
1804 rm: x27,
1805 }
1806 .emit(sink, emit_info, state);
1807 }
1808 _ => {
1809 let (op_lo, op_hi) = match op {
1810 AtomicRMWLoopOp::Add => (ALUOp::AddS, ALUOp::Adc),
1813 AtomicRMWLoopOp::Sub => (ALUOp::SubS, ALUOp::Sbc),
1816 AtomicRMWLoopOp::And | AtomicRMWLoopOp::Nand => {
1819 (ALUOp::And, ALUOp::And)
1820 }
1821 AtomicRMWLoopOp::Orr => (ALUOp::Orr, ALUOp::Orr),
1824 AtomicRMWLoopOp::Eor => (ALUOp::Eor, ALUOp::Eor),
1827 _ => unreachable!(),
1828 };
1829
1830 Inst::AluRRR {
1831 alu_op: op_lo,
1832 size: OperandSize::Size64,
1833 rd: x28wr,
1834 rn: x27,
1835 rm: x26,
1836 }
1837 .emit(sink, emit_info, state);
1838
1839 Inst::AluRRR {
1840 alu_op: op_hi,
1841 size: OperandSize::Size64,
1842 rd: x21wr,
1843 rn: x23,
1844 rm: x22,
1845 }
1846 .emit(sink, emit_info, state);
1847
1848 if op == AtomicRMWLoopOp::Nand {
1849 Inst::AluRRR {
1853 alu_op: ALUOp::OrrNot,
1854 size: OperandSize::Size64,
1855 rd: x28wr,
1856 rn: xzr,
1857 rm: x28,
1858 }
1859 .emit(sink, emit_info, state);
1860
1861 Inst::AluRRR {
1862 alu_op: ALUOp::OrrNot,
1863 size: OperandSize::Size64,
1864 rd: x21wr,
1865 rn: xzr,
1866 rm: x21,
1867 }
1868 .emit(sink, emit_info, state);
1869 }
1870 }
1871 }
1872
1873 if let Some(trap_code) = flags.trap_code() {
1874 sink.add_trap(trap_code);
1875 }
1876
1877 if op == AtomicRMWLoopOp::Xchg {
1878 sink.put4(enc_stlxp(I64, x24wr, x26, x22, x25)); } else {
1880 sink.put4(enc_stlxp(I64, x24wr, x28, x21, x25)); }
1882
1883 let br_offset = sink.cur_offset();
1887 sink.put4(enc_conditional_br(
1888 BranchTarget::Label(again_label),
1889 CondBrKind::NotZero(x24, OperandSize::Size64),
1890 ));
1891 sink.use_label_at_offset(br_offset, again_label, LabelUse::Branch19);
1892 }
1893 &Inst::AtomicCAS {
1894 rd,
1895 rs,
1896 rt,
1897 rn,
1898 ty,
1899 flags,
1900 } => {
1901 debug_assert_eq!(rd.to_reg(), rs);
1902 let size = match ty {
1903 I8 => 0b00,
1904 I16 => 0b01,
1905 I32 => 0b10,
1906 I64 => 0b11,
1907 _ => panic!("Unsupported type: {ty}"),
1908 };
1909
1910 if let Some(trap_code) = flags.trap_code() {
1911 sink.add_trap(trap_code);
1912 }
1913
1914 sink.put4(enc_cas(size, rd, rt, rn));
1915 }
1916 Inst::AtomicCAS128 { args } => {
1917 let &AtomicCAS128Args {
1918 rd_lo,
1919 rd_hi,
1920 rs_lo,
1921 rs_hi,
1922 rt_lo,
1923 rt_hi,
1924 rn,
1925 flags,
1926 } = &**args;
1927 debug_assert_eq!(rd_lo.to_reg(), rs_lo);
1928 debug_assert_eq!(rd_hi.to_reg(), rs_hi);
1929
1930 debug_assert_eq!(rs_hi, xreg(machreg_to_gpr(rs_lo) as u8 + 1));
1932 debug_assert_eq!(rt_hi, xreg(machreg_to_gpr(rt_lo) as u8 + 1));
1933
1934 if let Some(trap_code) = flags.trap_code() {
1935 sink.add_trap(trap_code);
1936 }
1937
1938 sink.put4(enc_casp(rd_lo, rt_lo, rn));
1939 }
1940 &Inst::AtomicCASLoop { ty, flags, .. } => {
1941 let x24 = xreg(24);
1955 let x25 = xreg(25);
1956 let x26 = xreg(26);
1957 let x27 = xreg(27);
1958 let x28 = xreg(28);
1959 let xzrwr = writable_zero_reg();
1960 let x24wr = writable_xreg(24);
1961 let x27wr = writable_xreg(27);
1962 let again_label = sink.get_label();
1963 let out_label = sink.get_label();
1964
1965 sink.bind_label(again_label, &mut state.ctrl_plane);
1967
1968 if let Some(trap_code) = flags.trap_code() {
1969 sink.add_trap(trap_code);
1970 }
1971
1972 sink.put4(enc_ldaxr(ty, x27wr, x25));
1974
1975 let (sf, bit21, extend_op) = match ty {
1983 I8 => (0b1, 0b1, 0b000000),
1984 I16 => (0b1, 0b1, 0b001000),
1985 I32 => (0b0, 0b0, 0b000000),
1986 _ => (0b1, 0b0, 0b000000),
1987 };
1988 let bits_31_21 = (sf << 10) | 0b011_01011_000 | bit21;
1989 sink.put4(enc_arith_rrr(bits_31_21, extend_op, xzrwr, x27, x26));
1991
1992 let br_out_offset = sink.cur_offset();
1994 sink.put4(enc_conditional_br(
1995 BranchTarget::Label(out_label),
1996 CondBrKind::Cond(Cond::Ne),
1997 ));
1998 sink.use_label_at_offset(br_out_offset, out_label, LabelUse::Branch19);
1999
2000 if let Some(trap_code) = flags.trap_code() {
2001 sink.add_trap(trap_code);
2002 }
2003
2004 sink.put4(enc_stlxr(ty, x24wr, x28, x25)); let br_again_offset = sink.cur_offset();
2010 sink.put4(enc_conditional_br(
2011 BranchTarget::Label(again_label),
2012 CondBrKind::NotZero(x24, OperandSize::Size64),
2013 ));
2014 sink.use_label_at_offset(br_again_offset, again_label, LabelUse::Branch19);
2015
2016 sink.bind_label(out_label, &mut state.ctrl_plane);
2018 }
2019 &Inst::AtomicCAS128Loop { flags, .. } => {
2020 let x21 = xreg(21);
2040 let x22 = xreg(22);
2041 let x23 = xreg(23);
2042 let x24 = xreg(24);
2043 let x25 = xreg(25);
2044 let x26 = xreg(26);
2045 let x27 = xreg(27);
2046 let x28 = xreg(28);
2047 let xzrwr = writable_zero_reg();
2048 let x21wr = writable_xreg(21);
2049 let x24wr = writable_xreg(24);
2050 let x27wr = writable_xreg(27);
2051 let again_label = sink.get_label();
2052 let keep_label = sink.get_label();
2053 let out_label = sink.get_label();
2054
2055 sink.bind_label(again_label, &mut state.ctrl_plane);
2057
2058 if let Some(trap_code) = flags.trap_code() {
2059 sink.add_trap(trap_code);
2060 }
2061
2062 sink.put4(enc_ldaxp(I64, x27wr, x21wr, x25));
2064
2065 Inst::AluRRR {
2067 alu_op: ALUOp::SubS,
2068 size: OperandSize::Size64,
2069 rd: xzrwr,
2070 rn: x27,
2071 rm: x26,
2072 }
2073 .emit(sink, emit_info, state);
2074
2075 let br_keep_offset = sink.cur_offset();
2077 sink.put4(enc_conditional_br(
2078 BranchTarget::Label(keep_label),
2079 CondBrKind::Cond(Cond::Ne),
2080 ));
2081 sink.use_label_at_offset(br_keep_offset, keep_label, LabelUse::Branch19);
2082
2083 Inst::AluRRR {
2085 alu_op: ALUOp::SubS,
2086 size: OperandSize::Size64,
2087 rd: xzrwr,
2088 rn: x21,
2089 rm: x23,
2090 }
2091 .emit(sink, emit_info, state);
2092
2093 let br_keep_offset = sink.cur_offset();
2095 sink.put4(enc_conditional_br(
2096 BranchTarget::Label(keep_label),
2097 CondBrKind::Cond(Cond::Ne),
2098 ));
2099 sink.use_label_at_offset(br_keep_offset, keep_label, LabelUse::Branch19);
2100
2101 if let Some(trap_code) = flags.trap_code() {
2102 sink.add_trap(trap_code);
2103 }
2104
2105 sink.put4(enc_stlxp(I64, x24wr, x28, x22, x25));
2107
2108 let br_again_offset = sink.cur_offset();
2110 sink.put4(enc_conditional_br(
2111 BranchTarget::Label(again_label),
2112 CondBrKind::NotZero(x24, OperandSize::Size64),
2113 ));
2114 sink.use_label_at_offset(br_again_offset, again_label, LabelUse::Branch19);
2115
2116 let b_out_offset = sink.cur_offset();
2118 sink.put4(enc_jump26(
2119 0b000101,
2120 BranchTarget::Label(out_label).as_offset26_or_zero(),
2121 ));
2122 sink.use_label_at_offset(b_out_offset, out_label, LabelUse::Branch26);
2123
2124 sink.bind_label(keep_label, &mut state.ctrl_plane);
2126
2127 if let Some(trap_code) = flags.trap_code() {
2128 sink.add_trap(trap_code);
2129 }
2130
2131 sink.put4(enc_stlxp(I64, x24wr, x27, x21, x25));
2133
2134 let br_again_offset = sink.cur_offset();
2136 sink.put4(enc_conditional_br(
2137 BranchTarget::Label(again_label),
2138 CondBrKind::NotZero(x24, OperandSize::Size64),
2139 ));
2140 sink.use_label_at_offset(br_again_offset, again_label, LabelUse::Branch19);
2141
2142 sink.bind_label(out_label, &mut state.ctrl_plane);
2144 }
2145 &Inst::LoadAcquire {
2146 access_ty,
2147 rt,
2148 rn,
2149 flags,
2150 } => {
2151 if let Some(trap_code) = flags.trap_code() {
2152 sink.add_trap(trap_code);
2153 }
2154
2155 sink.put4(enc_ldar(access_ty, rt, rn));
2156 }
2157 &Inst::LoadAcquire128 {
2158 rt1,
2159 rt2,
2160 rn,
2161 scratch,
2162 flags,
2163 } => {
2164 let again_label = sink.get_label();
2165
2166 sink.bind_label(again_label, &mut state.ctrl_plane);
2168
2169 if let Some(trap_code) = flags.trap_code() {
2170 sink.add_trap(trap_code);
2171 }
2172
2173 sink.put4(enc_ldaxp(I64, rt1, rt2, rn));
2175
2176 if let Some(trap_code) = flags.trap_code() {
2177 sink.add_trap(trap_code);
2178 }
2179
2180 sink.put4(enc_stxp(I64, scratch, rt1.to_reg(), rt2.to_reg(), rn));
2182
2183 let br_again_offset = sink.cur_offset();
2185 sink.put4(enc_conditional_br(
2186 BranchTarget::Label(again_label),
2187 CondBrKind::NotZero(scratch.to_reg(), OperandSize::Size64),
2188 ));
2189 sink.use_label_at_offset(br_again_offset, again_label, LabelUse::Branch19);
2190 }
2191 &Inst::StoreRelease {
2192 access_ty,
2193 rt,
2194 rn,
2195 flags,
2196 } => {
2197 if let Some(trap_code) = flags.trap_code() {
2198 sink.add_trap(trap_code);
2199 }
2200
2201 sink.put4(enc_stlr(access_ty, rt, rn));
2202 }
2203 &Inst::StoreRelease128 {
2204 rt1,
2205 rt2,
2206 rn,
2207 scratch,
2208 flags,
2209 } => {
2210 let again_label = sink.get_label();
2211
2212 sink.bind_label(again_label, &mut state.ctrl_plane);
2214
2215 if let Some(trap_code) = flags.trap_code() {
2216 sink.add_trap(trap_code);
2217 }
2218
2219 sink.put4(enc_ldxp(I64, writable_zero_reg(), scratch, rn));
2221
2222 if let Some(trap_code) = flags.trap_code() {
2223 sink.add_trap(trap_code);
2224 }
2225
2226 sink.put4(enc_stlxp(I64, scratch, rt1, rt2, rn));
2228
2229 let br_again_offset = sink.cur_offset();
2231 sink.put4(enc_conditional_br(
2232 BranchTarget::Label(again_label),
2233 CondBrKind::NotZero(scratch.to_reg(), OperandSize::Size64),
2234 ));
2235 sink.use_label_at_offset(br_again_offset, again_label, LabelUse::Branch19);
2236 }
2237 &Inst::Fence {} => {
2238 sink.put4(enc_dmb_ish()); }
2240 &Inst::Csdb {} => {
2241 sink.put4(0xd503229f);
2242 }
2243 &Inst::FpuMove32 { rd, rn } => {
2244 sink.put4(enc_fpurr(0b000_11110_00_1_000000_10000, rd, rn));
2245 }
2246 &Inst::FpuMove64 { rd, rn } => {
2247 sink.put4(enc_fpurr(0b000_11110_01_1_000000_10000, rd, rn));
2248 }
2249 &Inst::FpuMove128 { rd, rn } => {
2250 sink.put4(enc_vecmov(true, rd, rn));
2251 }
2252 &Inst::FpuMoveFromVec { rd, rn, idx, size } => {
2253 let (imm5, shift, mask) = match size.lane_size() {
2254 ScalarSize::Size32 => (0b00100, 3, 0b011),
2255 ScalarSize::Size64 => (0b01000, 4, 0b001),
2256 _ => unimplemented!(),
2257 };
2258 debug_assert_eq!(idx & mask, idx);
2259 let imm5 = imm5 | ((idx as u32) << shift);
2260 sink.put4(
2261 0b010_11110000_00000_000001_00000_00000
2262 | (imm5 << 16)
2263 | (machreg_to_vec(rn) << 5)
2264 | machreg_to_vec(rd.to_reg()),
2265 );
2266 }
2267 &Inst::FpuExtend { rd, rn, size } => {
2268 sink.put4(enc_fpurr(
2269 0b000_11110_00_1_000000_10000 | (size.ftype() << 12),
2270 rd,
2271 rn,
2272 ));
2273 }
2274 &Inst::FpuRR {
2275 fpu_op,
2276 size,
2277 rd,
2278 rn,
2279 } => {
2280 let top22 = match fpu_op {
2281 FPUOp1::Abs => 0b000_11110_00_1_000001_10000,
2282 FPUOp1::Neg => 0b000_11110_00_1_000010_10000,
2283 FPUOp1::Sqrt => 0b000_11110_00_1_000011_10000,
2284 FPUOp1::Cvt16To32 => {
2285 debug_assert_eq!(size, ScalarSize::Size16);
2286 0b000_11110_11_1_000100_10000
2287 }
2288 FPUOp1::Cvt32To64 => {
2289 debug_assert_eq!(size, ScalarSize::Size32);
2290 0b000_11110_00_1_000101_10000
2291 }
2292 FPUOp1::Cvt64To32 => {
2293 debug_assert_eq!(size, ScalarSize::Size64);
2294 0b000_11110_01_1_000100_10000
2295 }
2296 };
2297 let top22 = top22 | size.ftype() << 12;
2298 sink.put4(enc_fpurr(top22, rd, rn));
2299 }
2300 &Inst::FpuRRR {
2301 fpu_op,
2302 size,
2303 rd,
2304 rn,
2305 rm,
2306 } => {
2307 let top22 = match fpu_op {
2308 FPUOp2::Add => 0b000_11110_00_1_00000_001010,
2309 FPUOp2::Sub => 0b000_11110_00_1_00000_001110,
2310 FPUOp2::Mul => 0b000_11110_00_1_00000_000010,
2311 FPUOp2::Div => 0b000_11110_00_1_00000_000110,
2312 FPUOp2::Max => 0b000_11110_00_1_00000_010010,
2313 FPUOp2::Min => 0b000_11110_00_1_00000_010110,
2314 };
2315 let top22 = top22 | size.ftype() << 12;
2316 sink.put4(enc_fpurrr(top22, rd, rn, rm));
2317 }
2318 &Inst::FpuRRI { fpu_op, rd, rn } => match fpu_op {
2319 FPUOpRI::UShr32(imm) => {
2320 debug_assert_eq!(32, imm.lane_size_in_bits);
2321 sink.put4(
2322 0b0_0_1_011110_0000000_00_0_0_0_1_00000_00000
2323 | imm.enc() << 16
2324 | machreg_to_vec(rn) << 5
2325 | machreg_to_vec(rd.to_reg()),
2326 )
2327 }
2328 FPUOpRI::UShr64(imm) => {
2329 debug_assert_eq!(64, imm.lane_size_in_bits);
2330 sink.put4(
2331 0b01_1_111110_0000000_00_0_0_0_1_00000_00000
2332 | imm.enc() << 16
2333 | machreg_to_vec(rn) << 5
2334 | machreg_to_vec(rd.to_reg()),
2335 )
2336 }
2337 },
2338 &Inst::FpuRRIMod { fpu_op, rd, ri, rn } => {
2339 debug_assert_eq!(rd.to_reg(), ri);
2340 match fpu_op {
2341 FPUOpRIMod::Sli64(imm) => {
2342 debug_assert_eq!(64, imm.lane_size_in_bits);
2343 sink.put4(
2344 0b01_1_111110_0000000_010101_00000_00000
2345 | imm.enc() << 16
2346 | machreg_to_vec(rn) << 5
2347 | machreg_to_vec(rd.to_reg()),
2348 )
2349 }
2350 FPUOpRIMod::Sli32(imm) => {
2351 debug_assert_eq!(32, imm.lane_size_in_bits);
2352 sink.put4(
2353 0b0_0_1_011110_0000000_010101_00000_00000
2354 | imm.enc() << 16
2355 | machreg_to_vec(rn) << 5
2356 | machreg_to_vec(rd.to_reg()),
2357 )
2358 }
2359 }
2360 }
2361 &Inst::FpuRRRR {
2362 fpu_op,
2363 size,
2364 rd,
2365 rn,
2366 rm,
2367 ra,
2368 } => {
2369 let top17 = match fpu_op {
2370 FPUOp3::MAdd => 0b000_11111_00_0_00000_0,
2371 FPUOp3::MSub => 0b000_11111_00_0_00000_1,
2372 FPUOp3::NMAdd => 0b000_11111_00_1_00000_0,
2373 FPUOp3::NMSub => 0b000_11111_00_1_00000_1,
2374 };
2375 let top17 = top17 | size.ftype() << 7;
2376 sink.put4(enc_fpurrrr(top17, rd, rn, rm, ra));
2377 }
2378 &Inst::VecMisc { op, rd, rn, size } => {
2379 let (q, enc_size) = size.enc_size();
2380 let (u, bits_12_16, size) = match op {
2381 VecMisc2::Not => (0b1, 0b00101, 0b00),
2382 VecMisc2::Neg => (0b1, 0b01011, enc_size),
2383 VecMisc2::Abs => (0b0, 0b01011, enc_size),
2384 VecMisc2::Fabs => {
2385 debug_assert!(
2386 size == VectorSize::Size32x2
2387 || size == VectorSize::Size32x4
2388 || size == VectorSize::Size64x2
2389 );
2390 (0b0, 0b01111, enc_size)
2391 }
2392 VecMisc2::Fneg => {
2393 debug_assert!(
2394 size == VectorSize::Size32x2
2395 || size == VectorSize::Size32x4
2396 || size == VectorSize::Size64x2
2397 );
2398 (0b1, 0b01111, enc_size)
2399 }
2400 VecMisc2::Fsqrt => {
2401 debug_assert!(
2402 size == VectorSize::Size32x2
2403 || size == VectorSize::Size32x4
2404 || size == VectorSize::Size64x2
2405 );
2406 (0b1, 0b11111, enc_size)
2407 }
2408 VecMisc2::Rev16 => {
2409 debug_assert_eq!(size, VectorSize::Size8x16);
2410 (0b0, 0b00001, enc_size)
2411 }
2412 VecMisc2::Rev32 => {
2413 debug_assert!(size == VectorSize::Size8x16 || size == VectorSize::Size16x8);
2414 (0b1, 0b00000, enc_size)
2415 }
2416 VecMisc2::Rev64 => {
2417 debug_assert!(
2418 size == VectorSize::Size8x16
2419 || size == VectorSize::Size16x8
2420 || size == VectorSize::Size32x4
2421 );
2422 (0b0, 0b00000, enc_size)
2423 }
2424 VecMisc2::Fcvtzs => {
2425 debug_assert!(
2426 size == VectorSize::Size32x2
2427 || size == VectorSize::Size32x4
2428 || size == VectorSize::Size64x2
2429 );
2430 (0b0, 0b11011, enc_size)
2431 }
2432 VecMisc2::Fcvtzu => {
2433 debug_assert!(
2434 size == VectorSize::Size32x2
2435 || size == VectorSize::Size32x4
2436 || size == VectorSize::Size64x2
2437 );
2438 (0b1, 0b11011, enc_size)
2439 }
2440 VecMisc2::Scvtf => {
2441 debug_assert!(size == VectorSize::Size32x4 || size == VectorSize::Size64x2);
2442 (0b0, 0b11101, enc_size & 0b1)
2443 }
2444 VecMisc2::Ucvtf => {
2445 debug_assert!(size == VectorSize::Size32x4 || size == VectorSize::Size64x2);
2446 (0b1, 0b11101, enc_size & 0b1)
2447 }
2448 VecMisc2::Frintn => {
2449 debug_assert!(
2450 size == VectorSize::Size32x2
2451 || size == VectorSize::Size32x4
2452 || size == VectorSize::Size64x2
2453 );
2454 (0b0, 0b11000, enc_size & 0b01)
2455 }
2456 VecMisc2::Frintz => {
2457 debug_assert!(
2458 size == VectorSize::Size32x2
2459 || size == VectorSize::Size32x4
2460 || size == VectorSize::Size64x2
2461 );
2462 (0b0, 0b11001, enc_size)
2463 }
2464 VecMisc2::Frintm => {
2465 debug_assert!(
2466 size == VectorSize::Size32x2
2467 || size == VectorSize::Size32x4
2468 || size == VectorSize::Size64x2
2469 );
2470 (0b0, 0b11001, enc_size & 0b01)
2471 }
2472 VecMisc2::Frintp => {
2473 debug_assert!(
2474 size == VectorSize::Size32x2
2475 || size == VectorSize::Size32x4
2476 || size == VectorSize::Size64x2
2477 );
2478 (0b0, 0b11000, enc_size)
2479 }
2480 VecMisc2::Cnt => {
2481 debug_assert!(size == VectorSize::Size8x8 || size == VectorSize::Size8x16);
2482 (0b0, 0b00101, enc_size)
2483 }
2484 VecMisc2::Cmeq0 => (0b0, 0b01001, enc_size),
2485 VecMisc2::Cmge0 => (0b1, 0b01000, enc_size),
2486 VecMisc2::Cmgt0 => (0b0, 0b01000, enc_size),
2487 VecMisc2::Cmle0 => (0b1, 0b01001, enc_size),
2488 VecMisc2::Cmlt0 => (0b0, 0b01010, enc_size),
2489 VecMisc2::Fcmeq0 => {
2490 debug_assert!(
2491 size == VectorSize::Size32x2
2492 || size == VectorSize::Size32x4
2493 || size == VectorSize::Size64x2
2494 );
2495 (0b0, 0b01101, enc_size)
2496 }
2497 VecMisc2::Fcmge0 => {
2498 debug_assert!(
2499 size == VectorSize::Size32x2
2500 || size == VectorSize::Size32x4
2501 || size == VectorSize::Size64x2
2502 );
2503 (0b1, 0b01100, enc_size)
2504 }
2505 VecMisc2::Fcmgt0 => {
2506 debug_assert!(
2507 size == VectorSize::Size32x2
2508 || size == VectorSize::Size32x4
2509 || size == VectorSize::Size64x2
2510 );
2511 (0b0, 0b01100, enc_size)
2512 }
2513 VecMisc2::Fcmle0 => {
2514 debug_assert!(
2515 size == VectorSize::Size32x2
2516 || size == VectorSize::Size32x4
2517 || size == VectorSize::Size64x2
2518 );
2519 (0b1, 0b01101, enc_size)
2520 }
2521 VecMisc2::Fcmlt0 => {
2522 debug_assert!(
2523 size == VectorSize::Size32x2
2524 || size == VectorSize::Size32x4
2525 || size == VectorSize::Size64x2
2526 );
2527 (0b0, 0b01110, enc_size)
2528 }
2529 };
2530 sink.put4(enc_vec_rr_misc((q << 1) | u, size, bits_12_16, rd, rn));
2531 }
2532 &Inst::VecLanes { op, rd, rn, size } => {
2533 let (q, size) = match size {
2534 VectorSize::Size8x8 => (0b0, 0b00),
2535 VectorSize::Size8x16 => (0b1, 0b00),
2536 VectorSize::Size16x4 => (0b0, 0b01),
2537 VectorSize::Size16x8 => (0b1, 0b01),
2538 VectorSize::Size32x4 => (0b1, 0b10),
2539 _ => unreachable!(),
2540 };
2541 let (u, opcode) = match op {
2542 VecLanesOp::Uminv => (0b1, 0b11010),
2543 VecLanesOp::Addv => (0b0, 0b11011),
2544 };
2545 sink.put4(enc_vec_lanes(q, u, size, opcode, rd, rn));
2546 }
2547 &Inst::VecShiftImm {
2548 op,
2549 rd,
2550 rn,
2551 size,
2552 imm,
2553 } => {
2554 let (is_shr, mut template) = match op {
2555 VecShiftImmOp::Ushr => (true, 0b_001_011110_0000_000_000001_00000_00000_u32),
2556 VecShiftImmOp::Sshr => (true, 0b_000_011110_0000_000_000001_00000_00000_u32),
2557 VecShiftImmOp::Shl => (false, 0b_000_011110_0000_000_010101_00000_00000_u32),
2558 };
2559 if size.is_128bits() {
2560 template |= 0b1 << 30;
2561 }
2562 let imm = imm as u32;
2563 let immh_immb = match (size.lane_size(), is_shr) {
2566 (ScalarSize::Size64, true) if imm >= 1 && imm <= 64 => {
2567 0b_1000_000_u32 | (64 - imm)
2568 }
2569 (ScalarSize::Size32, true) if imm >= 1 && imm <= 32 => {
2570 0b_0100_000_u32 | (32 - imm)
2571 }
2572 (ScalarSize::Size16, true) if imm >= 1 && imm <= 16 => {
2573 0b_0010_000_u32 | (16 - imm)
2574 }
2575 (ScalarSize::Size8, true) if imm >= 1 && imm <= 8 => {
2576 0b_0001_000_u32 | (8 - imm)
2577 }
2578 (ScalarSize::Size64, false) if imm <= 63 => 0b_1000_000_u32 | imm,
2579 (ScalarSize::Size32, false) if imm <= 31 => 0b_0100_000_u32 | imm,
2580 (ScalarSize::Size16, false) if imm <= 15 => 0b_0010_000_u32 | imm,
2581 (ScalarSize::Size8, false) if imm <= 7 => 0b_0001_000_u32 | imm,
2582 _ => panic!(
2583 "aarch64: Inst::VecShiftImm: emit: invalid op/size/imm {op:?}, {size:?}, {imm:?}"
2584 ),
2585 };
2586 let rn_enc = machreg_to_vec(rn);
2587 let rd_enc = machreg_to_vec(rd.to_reg());
2588 sink.put4(template | (immh_immb << 16) | (rn_enc << 5) | rd_enc);
2589 }
2590 &Inst::VecShiftImmMod {
2591 op,
2592 rd,
2593 ri,
2594 rn,
2595 size,
2596 imm,
2597 } => {
2598 debug_assert_eq!(rd.to_reg(), ri);
2599 let (is_shr, mut template) = match op {
2600 VecShiftImmModOp::Sli => (false, 0b_001_011110_0000_000_010101_00000_00000_u32),
2601 };
2602 if size.is_128bits() {
2603 template |= 0b1 << 30;
2604 }
2605 let imm = imm as u32;
2606 let immh_immb = match (size.lane_size(), is_shr) {
2609 (ScalarSize::Size64, true) if imm >= 1 && imm <= 64 => {
2610 0b_1000_000_u32 | (64 - imm)
2611 }
2612 (ScalarSize::Size32, true) if imm >= 1 && imm <= 32 => {
2613 0b_0100_000_u32 | (32 - imm)
2614 }
2615 (ScalarSize::Size16, true) if imm >= 1 && imm <= 16 => {
2616 0b_0010_000_u32 | (16 - imm)
2617 }
2618 (ScalarSize::Size8, true) if imm >= 1 && imm <= 8 => {
2619 0b_0001_000_u32 | (8 - imm)
2620 }
2621 (ScalarSize::Size64, false) if imm <= 63 => 0b_1000_000_u32 | imm,
2622 (ScalarSize::Size32, false) if imm <= 31 => 0b_0100_000_u32 | imm,
2623 (ScalarSize::Size16, false) if imm <= 15 => 0b_0010_000_u32 | imm,
2624 (ScalarSize::Size8, false) if imm <= 7 => 0b_0001_000_u32 | imm,
2625 _ => panic!(
2626 "aarch64: Inst::VecShiftImmMod: emit: invalid op/size/imm {op:?}, {size:?}, {imm:?}"
2627 ),
2628 };
2629 let rn_enc = machreg_to_vec(rn);
2630 let rd_enc = machreg_to_vec(rd.to_reg());
2631 sink.put4(template | (immh_immb << 16) | (rn_enc << 5) | rd_enc);
2632 }
2633 &Inst::VecExtract { rd, rn, rm, imm4 } => {
2634 if imm4 < 16 {
2635 let template = 0b_01_101110_000_00000_0_0000_0_00000_00000_u32;
2636 let rm_enc = machreg_to_vec(rm);
2637 let rn_enc = machreg_to_vec(rn);
2638 let rd_enc = machreg_to_vec(rd.to_reg());
2639 sink.put4(
2640 template | (rm_enc << 16) | ((imm4 as u32) << 11) | (rn_enc << 5) | rd_enc,
2641 );
2642 } else {
2643 panic!("aarch64: Inst::VecExtract: emit: invalid extract index {imm4}");
2644 }
2645 }
2646 &Inst::VecTbl { rd, rn, rm } => {
2647 sink.put4(enc_tbl(false, 0b00, rd, rn, rm));
2648 }
2649 &Inst::VecTblExt { rd, ri, rn, rm } => {
2650 debug_assert_eq!(rd.to_reg(), ri);
2651 sink.put4(enc_tbl(true, 0b00, rd, rn, rm));
2652 }
2653 &Inst::VecTbl2 { rd, rn, rn2, rm } => {
2654 assert_eq!(machreg_to_vec(rn2), (machreg_to_vec(rn) + 1) % 32);
2655 sink.put4(enc_tbl(false, 0b01, rd, rn, rm));
2656 }
2657 &Inst::VecTbl2Ext {
2658 rd,
2659 ri,
2660 rn,
2661 rn2,
2662 rm,
2663 } => {
2664 debug_assert_eq!(rd.to_reg(), ri);
2665 assert_eq!(machreg_to_vec(rn2), (machreg_to_vec(rn) + 1) % 32);
2666 sink.put4(enc_tbl(true, 0b01, rd, rn, rm));
2667 }
2668 &Inst::FpuCmp { size, rn, rm } => {
2669 sink.put4(enc_fcmp(size, rn, rm));
2670 }
2671 &Inst::FpuToInt { op, rd, rn } => {
2672 let top16 = match op {
2673 FpuToIntOp::F32ToI32 => 0b000_11110_00_1_11_000,
2675 FpuToIntOp::F32ToU32 => 0b000_11110_00_1_11_001,
2677 FpuToIntOp::F32ToI64 => 0b100_11110_00_1_11_000,
2679 FpuToIntOp::F32ToU64 => 0b100_11110_00_1_11_001,
2681 FpuToIntOp::F64ToI32 => 0b000_11110_01_1_11_000,
2683 FpuToIntOp::F64ToU32 => 0b000_11110_01_1_11_001,
2685 FpuToIntOp::F64ToI64 => 0b100_11110_01_1_11_000,
2687 FpuToIntOp::F64ToU64 => 0b100_11110_01_1_11_001,
2689 };
2690 sink.put4(enc_fputoint(top16, rd, rn));
2691 }
2692 &Inst::IntToFpu { op, rd, rn } => {
2693 let top16 = match op {
2694 IntToFpuOp::I32ToF32 => 0b000_11110_00_1_00_010,
2696 IntToFpuOp::U32ToF32 => 0b000_11110_00_1_00_011,
2698 IntToFpuOp::I64ToF32 => 0b100_11110_00_1_00_010,
2700 IntToFpuOp::U64ToF32 => 0b100_11110_00_1_00_011,
2702 IntToFpuOp::I32ToF64 => 0b000_11110_01_1_00_010,
2704 IntToFpuOp::U32ToF64 => 0b000_11110_01_1_00_011,
2706 IntToFpuOp::I64ToF64 => 0b100_11110_01_1_00_010,
2708 IntToFpuOp::U64ToF64 => 0b100_11110_01_1_00_011,
2710 };
2711 sink.put4(enc_inttofpu(top16, rd, rn));
2712 }
2713 &Inst::FpuCSel16 { rd, rn, rm, cond } => {
2714 sink.put4(enc_fcsel(rd, rn, rm, cond, ScalarSize::Size16));
2715 }
2716 &Inst::FpuCSel32 { rd, rn, rm, cond } => {
2717 sink.put4(enc_fcsel(rd, rn, rm, cond, ScalarSize::Size32));
2718 }
2719 &Inst::FpuCSel64 { rd, rn, rm, cond } => {
2720 sink.put4(enc_fcsel(rd, rn, rm, cond, ScalarSize::Size64));
2721 }
2722 &Inst::FpuRound { op, rd, rn } => {
2723 let top22 = match op {
2724 FpuRoundMode::Minus32 => 0b000_11110_00_1_001_010_10000,
2725 FpuRoundMode::Minus64 => 0b000_11110_01_1_001_010_10000,
2726 FpuRoundMode::Plus32 => 0b000_11110_00_1_001_001_10000,
2727 FpuRoundMode::Plus64 => 0b000_11110_01_1_001_001_10000,
2728 FpuRoundMode::Zero32 => 0b000_11110_00_1_001_011_10000,
2729 FpuRoundMode::Zero64 => 0b000_11110_01_1_001_011_10000,
2730 FpuRoundMode::Nearest32 => 0b000_11110_00_1_001_000_10000,
2731 FpuRoundMode::Nearest64 => 0b000_11110_01_1_001_000_10000,
2732 };
2733 sink.put4(enc_fround(top22, rd, rn));
2734 }
2735 &Inst::MovToFpu { rd, rn, size } => {
2736 let template = match size {
2737 ScalarSize::Size16 => 0b000_11110_11_1_00_111_000000_00000_00000,
2738 ScalarSize::Size32 => 0b000_11110_00_1_00_111_000000_00000_00000,
2739 ScalarSize::Size64 => 0b100_11110_01_1_00_111_000000_00000_00000,
2740 _ => unreachable!(),
2741 };
2742 sink.put4(template | (machreg_to_gpr(rn) << 5) | machreg_to_vec(rd.to_reg()));
2743 }
2744 &Inst::FpuMoveFPImm { rd, imm, size } => {
2745 sink.put4(
2746 0b000_11110_00_1_00_000_000100_00000_00000
2747 | size.ftype() << 22
2748 | ((imm.enc_bits() as u32) << 13)
2749 | machreg_to_vec(rd.to_reg()),
2750 );
2751 }
2752 &Inst::MovToVec {
2753 rd,
2754 ri,
2755 rn,
2756 idx,
2757 size,
2758 } => {
2759 debug_assert_eq!(rd.to_reg(), ri);
2760 let (imm5, shift) = match size.lane_size() {
2761 ScalarSize::Size8 => (0b00001, 1),
2762 ScalarSize::Size16 => (0b00010, 2),
2763 ScalarSize::Size32 => (0b00100, 3),
2764 ScalarSize::Size64 => (0b01000, 4),
2765 _ => unreachable!(),
2766 };
2767 debug_assert_eq!(idx & (0b11111 >> shift), idx);
2768 let imm5 = imm5 | ((idx as u32) << shift);
2769 sink.put4(
2770 0b010_01110000_00000_0_0011_1_00000_00000
2771 | (imm5 << 16)
2772 | (machreg_to_gpr(rn) << 5)
2773 | machreg_to_vec(rd.to_reg()),
2774 );
2775 }
2776 &Inst::MovFromVec { rd, rn, idx, size } => {
2777 let (q, imm5, shift, mask) = match size {
2778 ScalarSize::Size8 => (0b0, 0b00001, 1, 0b1111),
2779 ScalarSize::Size16 => (0b0, 0b00010, 2, 0b0111),
2780 ScalarSize::Size32 => (0b0, 0b00100, 3, 0b0011),
2781 ScalarSize::Size64 => (0b1, 0b01000, 4, 0b0001),
2782 _ => panic!("Unexpected scalar FP operand size: {size:?}"),
2783 };
2784 debug_assert_eq!(idx & mask, idx);
2785 let imm5 = imm5 | ((idx as u32) << shift);
2786 sink.put4(
2787 0b000_01110000_00000_0_0111_1_00000_00000
2788 | (q << 30)
2789 | (imm5 << 16)
2790 | (machreg_to_vec(rn) << 5)
2791 | machreg_to_gpr(rd.to_reg()),
2792 );
2793 }
2794 &Inst::MovFromVecSigned {
2795 rd,
2796 rn,
2797 idx,
2798 size,
2799 scalar_size,
2800 } => {
2801 let (imm5, shift, half) = match size {
2802 VectorSize::Size8x8 => (0b00001, 1, true),
2803 VectorSize::Size8x16 => (0b00001, 1, false),
2804 VectorSize::Size16x4 => (0b00010, 2, true),
2805 VectorSize::Size16x8 => (0b00010, 2, false),
2806 VectorSize::Size32x2 => {
2807 debug_assert_ne!(scalar_size, OperandSize::Size32);
2808 (0b00100, 3, true)
2809 }
2810 VectorSize::Size32x4 => {
2811 debug_assert_ne!(scalar_size, OperandSize::Size32);
2812 (0b00100, 3, false)
2813 }
2814 _ => panic!("Unexpected vector operand size"),
2815 };
2816 debug_assert_eq!(idx & (0b11111 >> (half as u32 + shift)), idx);
2817 let imm5 = imm5 | ((idx as u32) << shift);
2818 sink.put4(
2819 0b000_01110000_00000_0_0101_1_00000_00000
2820 | (scalar_size.is64() as u32) << 30
2821 | (imm5 << 16)
2822 | (machreg_to_vec(rn) << 5)
2823 | machreg_to_gpr(rd.to_reg()),
2824 );
2825 }
2826 &Inst::VecDup { rd, rn, size } => {
2827 let q = size.is_128bits() as u32;
2828 let imm5 = match size.lane_size() {
2829 ScalarSize::Size8 => 0b00001,
2830 ScalarSize::Size16 => 0b00010,
2831 ScalarSize::Size32 => 0b00100,
2832 ScalarSize::Size64 => 0b01000,
2833 _ => unreachable!(),
2834 };
2835 sink.put4(
2836 0b0_0_0_01110000_00000_000011_00000_00000
2837 | (q << 30)
2838 | (imm5 << 16)
2839 | (machreg_to_gpr(rn) << 5)
2840 | machreg_to_vec(rd.to_reg()),
2841 );
2842 }
2843 &Inst::VecDupFromFpu { rd, rn, size, lane } => {
2844 let q = size.is_128bits() as u32;
2845 let imm5 = match size.lane_size() {
2846 ScalarSize::Size8 => {
2847 assert!(lane < 16);
2848 0b00001 | (u32::from(lane) << 1)
2849 }
2850 ScalarSize::Size16 => {
2851 assert!(lane < 8);
2852 0b00010 | (u32::from(lane) << 2)
2853 }
2854 ScalarSize::Size32 => {
2855 assert!(lane < 4);
2856 0b00100 | (u32::from(lane) << 3)
2857 }
2858 ScalarSize::Size64 => {
2859 assert!(lane < 2);
2860 0b01000 | (u32::from(lane) << 4)
2861 }
2862 _ => unimplemented!(),
2863 };
2864 sink.put4(
2865 0b000_01110000_00000_000001_00000_00000
2866 | (q << 30)
2867 | (imm5 << 16)
2868 | (machreg_to_vec(rn) << 5)
2869 | machreg_to_vec(rd.to_reg()),
2870 );
2871 }
2872 &Inst::VecDupFPImm { rd, imm, size } => {
2873 let imm = imm.enc_bits();
2874 let op = match size.lane_size() {
2875 ScalarSize::Size32 => 0,
2876 ScalarSize::Size64 => 1,
2877 _ => unimplemented!(),
2878 };
2879 let q_op = op | ((size.is_128bits() as u32) << 1);
2880
2881 sink.put4(enc_asimd_mod_imm(rd, q_op, 0b1111, imm));
2882 }
2883 &Inst::VecDupImm {
2884 rd,
2885 imm,
2886 invert,
2887 size,
2888 } => {
2889 let (imm, shift, shift_ones) = imm.value();
2890 let (op, cmode) = match size.lane_size() {
2891 ScalarSize::Size8 => {
2892 assert!(!invert);
2893 assert_eq!(shift, 0);
2894
2895 (0, 0b1110)
2896 }
2897 ScalarSize::Size16 => {
2898 let s = shift & 8;
2899
2900 assert!(!shift_ones);
2901 assert_eq!(s, shift);
2902
2903 (invert as u32, 0b1000 | (s >> 2))
2904 }
2905 ScalarSize::Size32 => {
2906 if shift_ones {
2907 assert!(shift == 8 || shift == 16);
2908
2909 (invert as u32, 0b1100 | (shift >> 4))
2910 } else {
2911 let s = shift & 24;
2912
2913 assert_eq!(s, shift);
2914
2915 (invert as u32, 0b0000 | (s >> 2))
2916 }
2917 }
2918 ScalarSize::Size64 => {
2919 assert!(!invert);
2920 assert_eq!(shift, 0);
2921
2922 (1, 0b1110)
2923 }
2924 _ => unreachable!(),
2925 };
2926 let q_op = op | ((size.is_128bits() as u32) << 1);
2927
2928 sink.put4(enc_asimd_mod_imm(rd, q_op, cmode, imm));
2929 }
2930 &Inst::VecExtend {
2931 t,
2932 rd,
2933 rn,
2934 high_half,
2935 lane_size,
2936 } => {
2937 let immh = match lane_size {
2938 ScalarSize::Size16 => 0b001,
2939 ScalarSize::Size32 => 0b010,
2940 ScalarSize::Size64 => 0b100,
2941 _ => panic!("Unexpected VecExtend to lane size of {lane_size:?}"),
2942 };
2943 let u = match t {
2944 VecExtendOp::Sxtl => 0b0,
2945 VecExtendOp::Uxtl => 0b1,
2946 };
2947 sink.put4(
2948 0b000_011110_0000_000_101001_00000_00000
2949 | ((high_half as u32) << 30)
2950 | (u << 29)
2951 | (immh << 19)
2952 | (machreg_to_vec(rn) << 5)
2953 | machreg_to_vec(rd.to_reg()),
2954 );
2955 }
2956 &Inst::VecRRLong {
2957 op,
2958 rd,
2959 rn,
2960 high_half,
2961 } => {
2962 let (u, size, bits_12_16) = match op {
2963 VecRRLongOp::Fcvtl16 => (0b0, 0b00, 0b10111),
2964 VecRRLongOp::Fcvtl32 => (0b0, 0b01, 0b10111),
2965 VecRRLongOp::Shll8 => (0b1, 0b00, 0b10011),
2966 VecRRLongOp::Shll16 => (0b1, 0b01, 0b10011),
2967 VecRRLongOp::Shll32 => (0b1, 0b10, 0b10011),
2968 };
2969
2970 sink.put4(enc_vec_rr_misc(
2971 ((high_half as u32) << 1) | u,
2972 size,
2973 bits_12_16,
2974 rd,
2975 rn,
2976 ));
2977 }
2978 &Inst::VecRRNarrowLow {
2979 op,
2980 rd,
2981 rn,
2982 lane_size,
2983 }
2984 | &Inst::VecRRNarrowHigh {
2985 op,
2986 rd,
2987 rn,
2988 lane_size,
2989 ..
2990 } => {
2991 let high_half = match self {
2992 &Inst::VecRRNarrowLow { .. } => false,
2993 &Inst::VecRRNarrowHigh { .. } => true,
2994 _ => unreachable!(),
2995 };
2996
2997 let size = match lane_size {
2998 ScalarSize::Size8 => 0b00,
2999 ScalarSize::Size16 => 0b01,
3000 ScalarSize::Size32 => 0b10,
3001 _ => panic!("unsupported size: {lane_size:?}"),
3002 };
3003
3004 let size = match op {
3006 VecRRNarrowOp::Fcvtn => size >> 1,
3007 _ => size,
3008 };
3009
3010 let (u, bits_12_16) = match op {
3011 VecRRNarrowOp::Xtn => (0b0, 0b10010),
3012 VecRRNarrowOp::Sqxtn => (0b0, 0b10100),
3013 VecRRNarrowOp::Sqxtun => (0b1, 0b10010),
3014 VecRRNarrowOp::Uqxtn => (0b1, 0b10100),
3015 VecRRNarrowOp::Fcvtn => (0b0, 0b10110),
3016 };
3017
3018 sink.put4(enc_vec_rr_misc(
3019 ((high_half as u32) << 1) | u,
3020 size,
3021 bits_12_16,
3022 rd,
3023 rn,
3024 ));
3025 }
3026 &Inst::VecMovElement {
3027 rd,
3028 ri,
3029 rn,
3030 dest_idx,
3031 src_idx,
3032 size,
3033 } => {
3034 debug_assert_eq!(rd.to_reg(), ri);
3035 let (imm5, shift) = match size.lane_size() {
3036 ScalarSize::Size8 => (0b00001, 1),
3037 ScalarSize::Size16 => (0b00010, 2),
3038 ScalarSize::Size32 => (0b00100, 3),
3039 ScalarSize::Size64 => (0b01000, 4),
3040 _ => unreachable!(),
3041 };
3042 let mask = 0b11111 >> shift;
3043 debug_assert_eq!(dest_idx & mask, dest_idx);
3044 debug_assert_eq!(src_idx & mask, src_idx);
3045 let imm4 = (src_idx as u32) << (shift - 1);
3046 let imm5 = imm5 | ((dest_idx as u32) << shift);
3047 sink.put4(
3048 0b011_01110000_00000_0_0000_1_00000_00000
3049 | (imm5 << 16)
3050 | (imm4 << 11)
3051 | (machreg_to_vec(rn) << 5)
3052 | machreg_to_vec(rd.to_reg()),
3053 );
3054 }
3055 &Inst::VecRRPair { op, rd, rn } => {
3056 let bits_12_16 = match op {
3057 VecPairOp::Addp => 0b11011,
3058 };
3059
3060 sink.put4(enc_vec_rr_pair(bits_12_16, rd, rn));
3061 }
3062 &Inst::VecRRRLong {
3063 rd,
3064 rn,
3065 rm,
3066 alu_op,
3067 high_half,
3068 } => {
3069 let (u, size, bit14) = match alu_op {
3070 VecRRRLongOp::Smull8 => (0b0, 0b00, 0b1),
3071 VecRRRLongOp::Smull16 => (0b0, 0b01, 0b1),
3072 VecRRRLongOp::Smull32 => (0b0, 0b10, 0b1),
3073 VecRRRLongOp::Umull8 => (0b1, 0b00, 0b1),
3074 VecRRRLongOp::Umull16 => (0b1, 0b01, 0b1),
3075 VecRRRLongOp::Umull32 => (0b1, 0b10, 0b1),
3076 };
3077 sink.put4(enc_vec_rrr_long(
3078 high_half as u32,
3079 u,
3080 size,
3081 bit14,
3082 rm,
3083 rn,
3084 rd,
3085 ));
3086 }
3087 &Inst::VecRRRLongMod {
3088 rd,
3089 ri,
3090 rn,
3091 rm,
3092 alu_op,
3093 high_half,
3094 } => {
3095 debug_assert_eq!(rd.to_reg(), ri);
3096 let (u, size, bit14) = match alu_op {
3097 VecRRRLongModOp::Umlal8 => (0b1, 0b00, 0b0),
3098 VecRRRLongModOp::Umlal16 => (0b1, 0b01, 0b0),
3099 VecRRRLongModOp::Umlal32 => (0b1, 0b10, 0b0),
3100 };
3101 sink.put4(enc_vec_rrr_long(
3102 high_half as u32,
3103 u,
3104 size,
3105 bit14,
3106 rm,
3107 rn,
3108 rd,
3109 ));
3110 }
3111 &Inst::VecRRPairLong { op, rd, rn } => {
3112 let (u, size) = match op {
3113 VecRRPairLongOp::Saddlp8 => (0b0, 0b0),
3114 VecRRPairLongOp::Uaddlp8 => (0b1, 0b0),
3115 VecRRPairLongOp::Saddlp16 => (0b0, 0b1),
3116 VecRRPairLongOp::Uaddlp16 => (0b1, 0b1),
3117 };
3118
3119 sink.put4(enc_vec_rr_pair_long(u, size, rd, rn));
3120 }
3121 &Inst::VecRRR {
3122 rd,
3123 rn,
3124 rm,
3125 alu_op,
3126 size,
3127 } => {
3128 let (q, enc_size) = size.enc_size();
3129 let is_float = match alu_op {
3130 VecALUOp::Fcmeq
3131 | VecALUOp::Fcmgt
3132 | VecALUOp::Fcmge
3133 | VecALUOp::Fadd
3134 | VecALUOp::Fsub
3135 | VecALUOp::Fdiv
3136 | VecALUOp::Fmax
3137 | VecALUOp::Fmin
3138 | VecALUOp::Fmul => true,
3139 _ => false,
3140 };
3141
3142 let (top11, bit15_10) = match alu_op {
3143 VecALUOp::Sqadd => (0b000_01110_00_1 | enc_size << 1, 0b000011),
3144 VecALUOp::Sqsub => (0b000_01110_00_1 | enc_size << 1, 0b001011),
3145 VecALUOp::Uqadd => (0b001_01110_00_1 | enc_size << 1, 0b000011),
3146 VecALUOp::Uqsub => (0b001_01110_00_1 | enc_size << 1, 0b001011),
3147 VecALUOp::Cmeq => (0b001_01110_00_1 | enc_size << 1, 0b100011),
3148 VecALUOp::Cmge => (0b000_01110_00_1 | enc_size << 1, 0b001111),
3149 VecALUOp::Cmgt => (0b000_01110_00_1 | enc_size << 1, 0b001101),
3150 VecALUOp::Cmhi => (0b001_01110_00_1 | enc_size << 1, 0b001101),
3151 VecALUOp::Cmhs => (0b001_01110_00_1 | enc_size << 1, 0b001111),
3152 VecALUOp::Fcmeq => (0b000_01110_00_1, 0b111001),
3153 VecALUOp::Fcmgt => (0b001_01110_10_1, 0b111001),
3154 VecALUOp::Fcmge => (0b001_01110_00_1, 0b111001),
3155 VecALUOp::And => (0b000_01110_00_1, 0b000111),
3158 VecALUOp::Bic => (0b000_01110_01_1, 0b000111),
3159 VecALUOp::Orr => (0b000_01110_10_1, 0b000111),
3160 VecALUOp::Orn => (0b000_01110_11_1, 0b000111),
3161 VecALUOp::Eor => (0b001_01110_00_1, 0b000111),
3162 VecALUOp::Umaxp => {
3163 debug_assert_ne!(size, VectorSize::Size64x2);
3164
3165 (0b001_01110_00_1 | enc_size << 1, 0b101001)
3166 }
3167 VecALUOp::Add => (0b000_01110_00_1 | enc_size << 1, 0b100001),
3168 VecALUOp::Sub => (0b001_01110_00_1 | enc_size << 1, 0b100001),
3169 VecALUOp::Mul => {
3170 debug_assert_ne!(size, VectorSize::Size64x2);
3171 (0b000_01110_00_1 | enc_size << 1, 0b100111)
3172 }
3173 VecALUOp::Sshl => (0b000_01110_00_1 | enc_size << 1, 0b010001),
3174 VecALUOp::Ushl => (0b001_01110_00_1 | enc_size << 1, 0b010001),
3175 VecALUOp::Umin => {
3176 debug_assert_ne!(size, VectorSize::Size64x2);
3177
3178 (0b001_01110_00_1 | enc_size << 1, 0b011011)
3179 }
3180 VecALUOp::Smin => {
3181 debug_assert_ne!(size, VectorSize::Size64x2);
3182
3183 (0b000_01110_00_1 | enc_size << 1, 0b011011)
3184 }
3185 VecALUOp::Umax => {
3186 debug_assert_ne!(size, VectorSize::Size64x2);
3187
3188 (0b001_01110_00_1 | enc_size << 1, 0b011001)
3189 }
3190 VecALUOp::Smax => {
3191 debug_assert_ne!(size, VectorSize::Size64x2);
3192
3193 (0b000_01110_00_1 | enc_size << 1, 0b011001)
3194 }
3195 VecALUOp::Urhadd => {
3196 debug_assert_ne!(size, VectorSize::Size64x2);
3197
3198 (0b001_01110_00_1 | enc_size << 1, 0b000101)
3199 }
3200 VecALUOp::Fadd => (0b000_01110_00_1, 0b110101),
3201 VecALUOp::Fsub => (0b000_01110_10_1, 0b110101),
3202 VecALUOp::Fdiv => (0b001_01110_00_1, 0b111111),
3203 VecALUOp::Fmax => (0b000_01110_00_1, 0b111101),
3204 VecALUOp::Fmin => (0b000_01110_10_1, 0b111101),
3205 VecALUOp::Fmul => (0b001_01110_00_1, 0b110111),
3206 VecALUOp::Addp => (0b000_01110_00_1 | enc_size << 1, 0b101111),
3207 VecALUOp::Zip1 => (0b01001110_00_0 | enc_size << 1, 0b001110),
3208 VecALUOp::Zip2 => (0b01001110_00_0 | enc_size << 1, 0b011110),
3209 VecALUOp::Sqrdmulh => {
3210 debug_assert!(
3211 size.lane_size() == ScalarSize::Size16
3212 || size.lane_size() == ScalarSize::Size32
3213 );
3214
3215 (0b001_01110_00_1 | enc_size << 1, 0b101101)
3216 }
3217 VecALUOp::Uzp1 => (0b01001110_00_0 | enc_size << 1, 0b000110),
3218 VecALUOp::Uzp2 => (0b01001110_00_0 | enc_size << 1, 0b010110),
3219 VecALUOp::Trn1 => (0b01001110_00_0 | enc_size << 1, 0b001010),
3220 VecALUOp::Trn2 => (0b01001110_00_0 | enc_size << 1, 0b011010),
3221 };
3222 let top11 = if is_float {
3223 top11 | size.enc_float_size() << 1
3224 } else {
3225 top11
3226 };
3227 sink.put4(enc_vec_rrr(top11 | q << 9, rm, bit15_10, rn, rd));
3228 }
3229 &Inst::VecRRRMod {
3230 rd,
3231 ri,
3232 rn,
3233 rm,
3234 alu_op,
3235 size,
3236 } => {
3237 debug_assert_eq!(rd.to_reg(), ri);
3238 let (q, _enc_size) = size.enc_size();
3239
3240 let (top11, bit15_10) = match alu_op {
3241 VecALUModOp::Bsl => (0b001_01110_01_1, 0b000111),
3242 VecALUModOp::Fmla => {
3243 (0b000_01110_00_1 | (size.enc_float_size() << 1), 0b110011)
3244 }
3245 VecALUModOp::Fmls => {
3246 (0b000_01110_10_1 | (size.enc_float_size() << 1), 0b110011)
3247 }
3248 VecALUModOp::Sdot => (0b000_01110_10_0, 0b100101),
3253 VecALUModOp::Usdot => (0b000_01110_10_0, 0b100111),
3256 };
3257 sink.put4(enc_vec_rrr(top11 | q << 9, rm, bit15_10, rn, rd));
3258 }
3259 &Inst::VecFmlaElem {
3260 rd,
3261 ri,
3262 rn,
3263 rm,
3264 alu_op,
3265 size,
3266 idx,
3267 } => {
3268 debug_assert_eq!(rd.to_reg(), ri);
3269 let idx = u32::from(idx);
3270
3271 let (q, _size) = size.enc_size();
3272 let o2 = match alu_op {
3273 VecALUModOp::Fmla => 0b0,
3274 VecALUModOp::Fmls => 0b1,
3275 _ => unreachable!(),
3276 };
3277
3278 let (h, l) = match size {
3279 VectorSize::Size32x4 => {
3280 assert!(idx < 4);
3281 (idx >> 1, idx & 1)
3282 }
3283 VectorSize::Size64x2 => {
3284 assert!(idx < 2);
3285 (idx, 0)
3286 }
3287 _ => unreachable!(),
3288 };
3289
3290 let top11 = 0b000_011111_00 | (q << 9) | (size.enc_float_size() << 1) | l;
3291 let bit15_10 = 0b000100 | (o2 << 4) | (h << 1);
3292 sink.put4(enc_vec_rrr(top11, rm, bit15_10, rn, rd));
3293 }
3294 &Inst::VecLoadReplicate {
3295 rd,
3296 rn,
3297 size,
3298 flags,
3299 } => {
3300 let (q, size) = size.enc_size();
3301
3302 if let Some(trap_code) = flags.trap_code() {
3303 sink.add_trap(trap_code);
3305 }
3306
3307 sink.put4(enc_ldst_vec(q, size, rn, rd));
3308 }
3309 &Inst::VecCSel { rd, rn, rm, cond } => {
3310 let else_label = sink.get_label();
3321 let out_label = sink.get_label();
3322
3323 let br_else_offset = sink.cur_offset();
3325 sink.put4(enc_conditional_br(
3326 BranchTarget::Label(else_label),
3327 CondBrKind::Cond(cond),
3328 ));
3329 sink.use_label_at_offset(br_else_offset, else_label, LabelUse::Branch19);
3330
3331 sink.put4(enc_vecmov(true, rd, rm));
3333
3334 let b_out_offset = sink.cur_offset();
3336 sink.use_label_at_offset(b_out_offset, out_label, LabelUse::Branch26);
3337 sink.add_uncond_branch(b_out_offset, b_out_offset + 4, out_label);
3338 sink.put4(enc_jump26(0b000101, 0 ));
3339
3340 sink.bind_label(else_label, &mut state.ctrl_plane);
3342
3343 sink.put4(enc_vecmov(true, rd, rn));
3345
3346 sink.bind_label(out_label, &mut state.ctrl_plane);
3348 }
3349 &Inst::MovToNZCV { rn } => {
3350 sink.put4(0xd51b4200 | machreg_to_gpr(rn));
3351 }
3352 &Inst::MovFromNZCV { rd } => {
3353 sink.put4(0xd53b4200 | machreg_to_gpr(rd.to_reg()));
3354 }
3355 &Inst::BitfieldMove {
3356 size,
3357 bfm_op,
3358 rd,
3359 rn,
3360 immr,
3361 imms,
3362 } => {
3363 let opc = bfm_op.opc();
3364 sink.put4(enc_bfm(opc, size, rd, rn, immr.value(), imms.value()));
3365 }
3366 &Inst::BitfieldMoveMod {
3367 size,
3368 rd,
3369 ri,
3370 rn,
3371 immr,
3372 imms,
3373 } => {
3374 debug_assert_eq!(rd.to_reg(), ri);
3375 sink.put4(enc_bfm(0b01, size, rd, rn, immr.value(), imms.value()));
3376 }
3377 &Inst::Jump { ref dest } => {
3378 let off = sink.cur_offset();
3379 if let Some(l) = dest.as_label() {
3381 sink.use_label_at_offset(off, l, LabelUse::Branch26);
3382 sink.add_uncond_branch(off, off + 4, l);
3383 }
3384 sink.put4(enc_jump26(0b000101, dest.as_offset26_or_zero()));
3386 }
3387 &Inst::Args { .. } | &Inst::Rets { .. } => {
3388 }
3391 &Inst::Ret {} => {
3392 sink.put4(0xd65f03c0);
3393 }
3394 &Inst::AuthenticatedRet { key, is_hint } => {
3395 let (op2, is_hint) = match key {
3396 APIKey::AZ => (0b100, true),
3397 APIKey::ASP => (0b101, is_hint),
3398 APIKey::BZ => (0b110, true),
3399 APIKey::BSP => (0b111, is_hint),
3400 };
3401
3402 if is_hint {
3403 sink.put4(key.enc_auti_hint());
3404 Inst::Ret {}.emit(sink, emit_info, state);
3405 } else {
3406 sink.put4(0xd65f0bff | (op2 << 9)); }
3408 }
3409 &Inst::Call { ref info } => {
3410 let start = sink.cur_offset();
3411 let user_stack_map = state.take_stack_map();
3412 sink.add_reloc(Reloc::Arm64Call, &info.dest, 0);
3413 sink.put4(enc_jump26(0b100101, 0));
3414 if let Some(s) = user_stack_map {
3415 let offset = sink.cur_offset();
3416 sink.push_user_stack_map(state, offset, s);
3417 }
3418
3419 if let Some(try_call) = info.try_call_info.as_ref() {
3420 sink.add_try_call_site(
3421 Some(state.frame_layout.sp_to_fp()),
3422 try_call.exception_handlers(&state.frame_layout),
3423 );
3424 } else {
3425 sink.add_call_site();
3426 }
3427
3428 if info.callee_pop_size > 0 {
3429 let callee_pop_size =
3430 i32::try_from(info.callee_pop_size).expect("callee popped more than 2GB");
3431 for inst in AArch64MachineDeps::gen_sp_reg_adjust(-callee_pop_size) {
3432 inst.emit(sink, emit_info, state);
3433 }
3434 }
3435
3436 if info.patchable {
3437 sink.add_patchable_call_site(sink.cur_offset() - start);
3438 } else {
3439 info.emit_retval_loads::<AArch64MachineDeps, _, _>(
3441 state.frame_layout().stackslots_size,
3442 |inst| inst.emit(sink, emit_info, state),
3443 |needed_space| Some(Inst::EmitIsland { needed_space }),
3444 );
3445 }
3446
3447 if let Some(try_call) = info.try_call_info.as_ref() {
3450 let jmp = Inst::Jump {
3451 dest: BranchTarget::Label(try_call.continuation),
3452 };
3453 jmp.emit(sink, emit_info, state);
3454 }
3455
3456 start_off = sink.cur_offset();
3459 }
3460 &Inst::CallInd { ref info } => {
3461 let user_stack_map = state.take_stack_map();
3462 sink.put4(
3463 0b1101011_0001_11111_000000_00000_00000 | (machreg_to_gpr(info.dest) << 5),
3464 );
3465 if let Some(s) = user_stack_map {
3466 let offset = sink.cur_offset();
3467 sink.push_user_stack_map(state, offset, s);
3468 }
3469
3470 if let Some(try_call) = info.try_call_info.as_ref() {
3471 sink.add_try_call_site(
3472 Some(state.frame_layout.sp_to_fp()),
3473 try_call.exception_handlers(&state.frame_layout),
3474 );
3475 } else {
3476 sink.add_call_site();
3477 }
3478
3479 if info.callee_pop_size > 0 {
3480 let callee_pop_size =
3481 i32::try_from(info.callee_pop_size).expect("callee popped more than 2GB");
3482 for inst in AArch64MachineDeps::gen_sp_reg_adjust(-callee_pop_size) {
3483 inst.emit(sink, emit_info, state);
3484 }
3485 }
3486
3487 info.emit_retval_loads::<AArch64MachineDeps, _, _>(
3489 state.frame_layout().stackslots_size,
3490 |inst| inst.emit(sink, emit_info, state),
3491 |needed_space| Some(Inst::EmitIsland { needed_space }),
3492 );
3493
3494 if let Some(try_call) = info.try_call_info.as_ref() {
3497 let jmp = Inst::Jump {
3498 dest: BranchTarget::Label(try_call.continuation),
3499 };
3500 jmp.emit(sink, emit_info, state);
3501 }
3502
3503 start_off = sink.cur_offset();
3506 }
3507 &Inst::ReturnCall { ref info } => {
3508 emit_return_call_common_sequence(sink, emit_info, state, info);
3509
3510 sink.add_reloc(Reloc::Arm64Call, &info.dest, 0);
3514 sink.put4(enc_jump26(0b000101, 0));
3515 sink.add_call_site();
3516
3517 start_off = sink.cur_offset();
3521 }
3522 &Inst::ReturnCallInd { ref info } => {
3523 emit_return_call_common_sequence(sink, emit_info, state, info);
3524
3525 let dest = if emit_info.isa_flags.use_bti() {
3534 let dest = xreg(16);
3535 if info.dest != dest {
3536 Inst::Mov {
3537 size: OperandSize::Size64,
3538 rd: writable_xreg(16),
3539 rm: info.dest,
3540 }
3541 .emit(sink, emit_info, state);
3542 }
3543 dest
3544 } else {
3545 info.dest
3546 };
3547
3548 Inst::IndirectBr {
3549 rn: dest,
3550 targets: vec![],
3551 }
3552 .emit(sink, emit_info, state);
3553 sink.add_call_site();
3554
3555 start_off = sink.cur_offset();
3559 }
3560 &Inst::CondBr {
3561 taken,
3562 not_taken,
3563 kind,
3564 } => {
3565 let cond_off = sink.cur_offset();
3567 if let Some(l) = taken.as_label() {
3568 sink.use_label_at_offset(cond_off, l, LabelUse::Branch19);
3569 let inverted = enc_conditional_br(taken, kind.invert()).to_le_bytes();
3570 sink.add_cond_branch(cond_off, cond_off + 4, l, &inverted[..]);
3571 }
3572 sink.put4(enc_conditional_br(taken, kind));
3573
3574 let uncond_off = sink.cur_offset();
3576 if let Some(l) = not_taken.as_label() {
3577 sink.use_label_at_offset(uncond_off, l, LabelUse::Branch26);
3578 sink.add_uncond_branch(uncond_off, uncond_off + 4, l);
3579 }
3580 sink.put4(enc_jump26(0b000101, not_taken.as_offset26_or_zero()));
3581 }
3582 &Inst::TestBitAndBranch {
3583 taken,
3584 not_taken,
3585 kind,
3586 rn,
3587 bit,
3588 } => {
3589 let cond_off = sink.cur_offset();
3591 if let Some(l) = taken.as_label() {
3592 sink.use_label_at_offset(cond_off, l, LabelUse::Branch14);
3593 let inverted =
3594 enc_test_bit_and_branch(kind.complement(), taken, rn, bit).to_le_bytes();
3595 sink.add_cond_branch(cond_off, cond_off + 4, l, &inverted[..]);
3596 }
3597 sink.put4(enc_test_bit_and_branch(kind, taken, rn, bit));
3598
3599 let uncond_off = sink.cur_offset();
3601 if let Some(l) = not_taken.as_label() {
3602 sink.use_label_at_offset(uncond_off, l, LabelUse::Branch26);
3603 sink.add_uncond_branch(uncond_off, uncond_off + 4, l);
3604 }
3605 sink.put4(enc_jump26(0b000101, not_taken.as_offset26_or_zero()));
3606 }
3607 &Inst::TrapIf { kind, trap_code } => {
3608 let label = sink.defer_trap(trap_code);
3609 let off = sink.cur_offset();
3611 sink.put4(enc_conditional_br(BranchTarget::Label(label), kind));
3612 sink.use_label_at_offset(off, label, LabelUse::Branch19);
3613 }
3614 &Inst::IndirectBr { rn, .. } => {
3615 sink.put4(enc_br(rn));
3616 }
3617 &Inst::Nop0 => {}
3618 &Inst::Nop4 => {
3619 sink.put4(0xd503201f);
3620 }
3621 &Inst::Brk => {
3622 sink.put4(0xd43e0000);
3623 }
3624 &Inst::Udf { trap_code } => {
3625 sink.add_trap(trap_code);
3626 sink.put_data(Inst::TRAP_OPCODE);
3627 }
3628 &Inst::Adr { rd, off } => {
3629 assert!(off > -(1 << 20));
3630 assert!(off < (1 << 20));
3631 sink.put4(enc_adr(off, rd));
3632 }
3633 &Inst::Adrp { rd, off } => {
3634 assert!(off > -(1 << 20));
3635 assert!(off < (1 << 20));
3636 sink.put4(enc_adrp(off, rd));
3637 }
3638 &Inst::Word4 { data } => {
3639 sink.put4(data);
3640 }
3641 &Inst::Word8 { data } => {
3642 sink.put8(data);
3643 }
3644 &Inst::JTSequence {
3645 ridx,
3646 rtmp1,
3647 rtmp2,
3648 default,
3649 ref targets,
3650 ..
3651 } => {
3652 let default_index = u64::try_from(targets.len()).unwrap();
3666 for inst in Inst::load_constant(rtmp2, default_index) {
3667 inst.emit(sink, emit_info, state);
3668 }
3669 let inst = Inst::CSel {
3674 rd: rtmp2,
3675 cond: Cond::Lo,
3676 rn: ridx,
3677 rm: rtmp2.to_reg(),
3678 };
3679 inst.emit(sink, emit_info, state);
3680 if emit_info.flags.enable_table_access_spectre_mitigation()
3683 && emit_info.isa_flags.use_csdb()
3684 {
3685 Inst::Csdb.emit(sink, emit_info, state);
3686 }
3687
3688 let inst = Inst::Adr { rd: rtmp1, off: 16 };
3690 inst.emit(sink, emit_info, state);
3691 let inst = Inst::SLoad32 {
3693 rd: rtmp2,
3694 mem: AMode::reg_plus_reg_scaled_extended(
3695 rtmp1.to_reg(),
3696 rtmp2.to_reg(),
3697 ExtendOp::UXTW,
3698 ),
3699 flags: MemFlagsData::trusted(),
3700 };
3701 inst.emit(sink, emit_info, state);
3702 let inst = Inst::AluRRR {
3704 alu_op: ALUOp::Add,
3705 size: OperandSize::Size64,
3706 rd: rtmp1,
3707 rn: rtmp1.to_reg(),
3708 rm: rtmp2.to_reg(),
3709 };
3710 inst.emit(sink, emit_info, state);
3711 let inst = Inst::IndirectBr {
3714 rn: rtmp1.to_reg(),
3715 targets: vec![],
3716 };
3717 inst.emit(sink, emit_info, state);
3718 let jt_off = sink.cur_offset();
3721 for &target in targets.iter().chain(core::iter::once(&default)) {
3722 let word_off = sink.cur_offset();
3723 let off_into_table = word_off - jt_off;
3728 sink.use_label_at_offset(word_off, target, LabelUse::PCRel32);
3729 sink.put4(off_into_table);
3730 }
3731
3732 start_off = sink.cur_offset();
3735 }
3736 &Inst::LoadExtNameGot { rd, ref name } => {
3737 sink.add_reloc(Reloc::Aarch64AdrGotPage21, &**name, 0);
3746 let inst = Inst::Adrp { rd, off: 0 };
3747 inst.emit(sink, emit_info, state);
3748
3749 sink.add_reloc(Reloc::Aarch64Ld64GotLo12Nc, &**name, 0);
3751 let inst = Inst::ULoad64 {
3752 rd,
3753 mem: AMode::reg(rd.to_reg()),
3754 flags: MemFlagsData::trusted(),
3755 };
3756 inst.emit(sink, emit_info, state);
3757 }
3758 &Inst::LoadExtNameNear {
3759 rd,
3760 ref name,
3761 offset,
3762 } => {
3763 sink.add_reloc(Reloc::Aarch64AdrPrelPgHi21, &**name, offset);
3771 let inst = Inst::Adrp { rd, off: 0 };
3772 inst.emit(sink, emit_info, state);
3773
3774 sink.add_reloc(Reloc::Aarch64AddAbsLo12Nc, &**name, offset);
3776 let inst = Inst::AluRRImm12 {
3777 alu_op: ALUOp::Add,
3778 size: OperandSize::Size64,
3779 rd,
3780 rn: rd.to_reg(),
3781 imm12: Imm12::ZERO,
3782 };
3783 inst.emit(sink, emit_info, state);
3784 }
3785 &Inst::LoadExtNameFar {
3786 rd,
3787 ref name,
3788 offset,
3789 } => {
3790 let inst = Inst::ULoad64 {
3799 rd,
3800 mem: AMode::Label {
3801 label: MemLabel::PCRel(8),
3802 },
3803 flags: MemFlagsData::trusted(),
3804 };
3805 inst.emit(sink, emit_info, state);
3806 let inst = Inst::Jump {
3807 dest: BranchTarget::ResolvedOffset(12),
3808 };
3809 inst.emit(sink, emit_info, state);
3810 sink.add_reloc(Reloc::Abs8, &**name, offset);
3811 sink.put8(0);
3812 }
3813 &Inst::LoadAddr { rd, ref mem } => {
3814 let mem = mem.clone();
3815 let (mem_insts, mem) = mem_finalize(Some(sink), &mem, I8, state);
3816 for inst in mem_insts.into_iter() {
3817 inst.emit(sink, emit_info, state);
3818 }
3819
3820 let (reg, index_reg, offset) = match mem {
3821 AMode::RegExtended { rn, rm, extendop } => {
3822 let r = rn;
3823 (r, Some((rm, extendop)), 0)
3824 }
3825 AMode::Unscaled { rn, simm9 } => {
3826 let r = rn;
3827 (r, None, simm9.value())
3828 }
3829 AMode::UnsignedOffset { rn, uimm12 } => {
3830 let r = rn;
3831 (r, None, uimm12.value() as i32)
3832 }
3833 _ => panic!("Unsupported case for LoadAddr: {mem:?}"),
3834 };
3835 let abs_offset = if offset < 0 {
3836 -offset as u64
3837 } else {
3838 offset as u64
3839 };
3840 let alu_op = if offset < 0 { ALUOp::Sub } else { ALUOp::Add };
3841
3842 if let Some((idx, extendop)) = index_reg {
3843 let add = Inst::AluRRRExtend {
3844 alu_op: ALUOp::Add,
3845 size: OperandSize::Size64,
3846 rd,
3847 rn: reg,
3848 rm: idx,
3849 extendop,
3850 };
3851
3852 add.emit(sink, emit_info, state);
3853 } else if offset == 0 {
3854 if reg != rd.to_reg() {
3855 let mov = Inst::Mov {
3856 size: OperandSize::Size64,
3857 rd,
3858 rm: reg,
3859 };
3860
3861 mov.emit(sink, emit_info, state);
3862 }
3863 } else if let Some(imm12) = Imm12::maybe_from_u64(abs_offset) {
3864 let add = Inst::AluRRImm12 {
3865 alu_op,
3866 size: OperandSize::Size64,
3867 rd,
3868 rn: reg,
3869 imm12,
3870 };
3871 add.emit(sink, emit_info, state);
3872 } else {
3873 debug_assert!(rd.to_reg() != tmp2_reg());
3879 debug_assert!(reg != tmp2_reg());
3880 let tmp = writable_tmp2_reg();
3881 for insn in Inst::load_constant(tmp, abs_offset).into_iter() {
3882 insn.emit(sink, emit_info, state);
3883 }
3884 let add = Inst::AluRRR {
3885 alu_op,
3886 size: OperandSize::Size64,
3887 rd,
3888 rn: reg,
3889 rm: tmp.to_reg(),
3890 };
3891 add.emit(sink, emit_info, state);
3892 }
3893 }
3894 &Inst::Paci { key } => {
3895 let (crm, op2) = match key {
3896 APIKey::AZ => (0b0011, 0b000),
3897 APIKey::ASP => (0b0011, 0b001),
3898 APIKey::BZ => (0b0011, 0b010),
3899 APIKey::BSP => (0b0011, 0b011),
3900 };
3901
3902 sink.put4(0xd503211f | (crm << 8) | (op2 << 5));
3903 }
3904 &Inst::Xpaclri => sink.put4(0xd50320ff),
3905 &Inst::Bti { targets } => {
3906 let targets = match targets {
3907 BranchTargetType::None => 0b00,
3908 BranchTargetType::C => 0b01,
3909 BranchTargetType::J => 0b10,
3910 BranchTargetType::JC => 0b11,
3911 };
3912
3913 sink.put4(0xd503241f | targets << 6);
3914 }
3915 &Inst::EmitIsland { needed_space } => {
3916 if sink.island_needed(needed_space + 4) {
3917 let jump_around_label = sink.get_label();
3918 let jmp = Inst::Jump {
3919 dest: BranchTarget::Label(jump_around_label),
3920 };
3921 jmp.emit(sink, emit_info, state);
3922 sink.emit_island(needed_space + 4, &mut state.ctrl_plane);
3923 sink.bind_label(jump_around_label, &mut state.ctrl_plane);
3924 }
3925 }
3926
3927 &Inst::ElfTlsGetAddr {
3928 ref symbol,
3929 rd,
3930 tmp,
3931 } => {
3932 assert_eq!(xreg(0), rd.to_reg());
3933
3934 sink.add_reloc(Reloc::Aarch64TlsDescAdrPage21, &**symbol, 0);
3950 Inst::Adrp { rd, off: 0 }.emit(sink, emit_info, state);
3951
3952 sink.add_reloc(Reloc::Aarch64TlsDescLd64Lo12, &**symbol, 0);
3954 Inst::ULoad64 {
3955 rd: tmp,
3956 mem: AMode::reg(rd.to_reg()),
3957 flags: MemFlagsData::trusted(),
3958 }
3959 .emit(sink, emit_info, state);
3960
3961 sink.add_reloc(Reloc::Aarch64TlsDescAddLo12, &**symbol, 0);
3963 Inst::AluRRImm12 {
3964 alu_op: ALUOp::Add,
3965 size: OperandSize::Size64,
3966 rd,
3967 rn: rd.to_reg(),
3968 imm12: Imm12::maybe_from_u64(0).unwrap(),
3969 }
3970 .emit(sink, emit_info, state);
3971
3972 sink.add_reloc(Reloc::Aarch64TlsDescCall, &**symbol, 0);
3974 Inst::CallInd {
3975 info: crate::isa::Box::new(CallInfo::empty(tmp.to_reg(), CallConv::SystemV)),
3976 }
3977 .emit(sink, emit_info, state);
3978
3979 sink.put4(0xd53bd040 | machreg_to_gpr(tmp.to_reg()));
3981
3982 Inst::AluRRR {
3984 alu_op: ALUOp::Add,
3985 size: OperandSize::Size64,
3986 rd,
3987 rn: rd.to_reg(),
3988 rm: tmp.to_reg(),
3989 }
3990 .emit(sink, emit_info, state);
3991 }
3992
3993 &Inst::MachOTlsGetAddr { ref symbol, rd } => {
3994 assert_eq!(xreg(0), rd.to_reg());
4007 let rtmp = writable_xreg(1);
4008
4009 sink.add_reloc(Reloc::MachOAarch64TlsAdrPage21, symbol, 0);
4011 sink.put4(0x90000000);
4012
4013 sink.add_reloc(Reloc::MachOAarch64TlsAdrPageOff12, symbol, 0);
4015 sink.put4(0xf9400000);
4016
4017 Inst::ULoad64 {
4019 rd: rtmp,
4020 mem: AMode::reg(rd.to_reg()),
4021 flags: MemFlagsData::trusted(),
4022 }
4023 .emit(sink, emit_info, state);
4024
4025 Inst::CallInd {
4027 info: crate::isa::Box::new(CallInfo::empty(
4028 rtmp.to_reg(),
4029 CallConv::AppleAarch64,
4030 )),
4031 }
4032 .emit(sink, emit_info, state);
4033 }
4034
4035 &Inst::Unwind { ref inst } => {
4036 sink.add_unwind(inst.clone());
4037 }
4038
4039 &Inst::DummyUse { .. } => {}
4040
4041 &Inst::LabelAddress { dst, label } => {
4042 let inst = Inst::Adr { rd: dst, off: 0 };
4047 let offset = sink.cur_offset();
4048 inst.emit(sink, emit_info, state);
4049 sink.use_label_at_offset(offset, label, LabelUse::Adr21);
4050 }
4051
4052 &Inst::SequencePoint { .. } => {
4053 }
4055
4056 &Inst::StackProbeLoop { start, end, step } => {
4057 assert!(emit_info.flags.enable_probestack());
4058
4059 let loop_start = sink.get_label();
4082 sink.bind_label(loop_start, &mut state.ctrl_plane);
4083
4084 Inst::AluRRImm12 {
4085 alu_op: ALUOp::Sub,
4086 size: OperandSize::Size64,
4087 rd: start,
4088 rn: start.to_reg(),
4089 imm12: step,
4090 }
4091 .emit(sink, emit_info, state);
4092 Inst::Store32 {
4093 rd: regs::zero_reg(),
4094 mem: AMode::RegReg {
4095 rn: regs::stack_reg(),
4096 rm: start.to_reg(),
4097 },
4098 flags: MemFlagsData::trusted(),
4099 }
4100 .emit(sink, emit_info, state);
4101 Inst::AluRRR {
4102 alu_op: ALUOp::AddS,
4103 size: OperandSize::Size64,
4104 rd: regs::writable_zero_reg(),
4105 rn: start.to_reg(),
4106 rm: end,
4107 }
4108 .emit(sink, emit_info, state);
4109
4110 let loop_end = sink.get_label();
4111 Inst::CondBr {
4112 taken: BranchTarget::Label(loop_start),
4113 not_taken: BranchTarget::Label(loop_end),
4114 kind: CondBrKind::Cond(Cond::Gt),
4115 }
4116 .emit(sink, emit_info, state);
4117 sink.bind_label(loop_end, &mut state.ctrl_plane);
4118 }
4119
4120 &Inst::InterruptPoll {
4121 dst,
4122 load_ptr,
4123 trap_code,
4124 ..
4125 } => {
4126 sink.add_trap(trap_code);
4130
4131 Inst::ULoad64 {
4135 rd: dst,
4136 mem: AMode::UnsignedOffset {
4137 rn: load_ptr,
4138 uimm12: UImm12Scaled::zero(I64),
4139 },
4140 flags: MemFlagsData::trusted(),
4141 }
4142 .emit(sink, emit_info, state);
4143 }
4144 }
4145
4146 let end_off = sink.cur_offset();
4147 debug_assert!(
4148 (end_off - start_off) <= Inst::worst_case_size()
4149 || matches!(self, Inst::EmitIsland { .. }),
4150 "Worst case size exceed for {:?}: {}",
4151 self,
4152 end_off - start_off
4153 );
4154
4155 state.clear_post_insn();
4156 }
4157
4158 fn pretty_print_inst(&self, state: &mut Self::State) -> String {
4159 self.print_with_state(state)
4160 }
4161}
4162
4163fn emit_return_call_common_sequence<T>(
4164 sink: &mut MachBuffer<Inst>,
4165 emit_info: &EmitInfo,
4166 state: &mut EmitState,
4167 info: &ReturnCallInfo<T>,
4168) {
4169 for inst in AArch64MachineDeps::gen_clobber_restore(
4170 CallConv::Tail,
4171 &emit_info.flags,
4172 state.frame_layout(),
4173 ) {
4174 inst.emit(sink, emit_info, state);
4175 }
4176
4177 let setup_area_size = state.frame_layout().setup_area_size;
4178 if setup_area_size > 0 {
4179 Inst::LoadP64 {
4185 rt: writable_fp_reg(),
4186 rt2: writable_link_reg(),
4187 mem: PairAMode::SPPostIndexed {
4188 simm7: SImm7Scaled::maybe_from_i64(i64::from(setup_area_size), types::I64).unwrap(),
4192 },
4193 flags: MemFlagsData::trusted(),
4194 }
4195 .emit(sink, emit_info, state);
4196 }
4197
4198 let incoming_args_diff = state.frame_layout().tail_args_size - info.new_stack_arg_size;
4200 if incoming_args_diff > 0 {
4201 for inst in
4202 AArch64MachineDeps::gen_sp_reg_adjust(i32::try_from(incoming_args_diff).unwrap())
4203 {
4204 inst.emit(sink, emit_info, state);
4205 }
4206 }
4207
4208 if (setup_area_size > 0 || info.sign_return_address_all)
4209 && let Some(key) = info.key
4210 {
4211 sink.put4(key.enc_auti_hint());
4212 }
4213}