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, 16)),
1579 I8 => Some((ExtendOp::SXTB, 8)),
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 sign_ext.is_some() {
1594 let (_, from_bits) = sign_ext.unwrap();
1595 Inst::Extend {
1596 rd: x27wr,
1597 rn: x27,
1598 signed: true,
1599 from_bits,
1600 to_bits: size.bits(),
1601 }
1602 .emit(sink, emit_info, state);
1603 }
1604
1605 match op {
1606 AtomicRMWLoopOp::Xchg => {} AtomicRMWLoopOp::Nand => {
1608 Inst::AluRRR {
1612 alu_op: ALUOp::And,
1613 size,
1614 rd: x28wr,
1615 rn: x27,
1616 rm: x26,
1617 }
1618 .emit(sink, emit_info, state);
1619
1620 Inst::AluRRR {
1621 alu_op: ALUOp::OrrNot,
1622 size,
1623 rd: x28wr,
1624 rn: xzr,
1625 rm: x28,
1626 }
1627 .emit(sink, emit_info, state);
1628 }
1629 AtomicRMWLoopOp::Umin
1630 | AtomicRMWLoopOp::Umax
1631 | AtomicRMWLoopOp::Smin
1632 | AtomicRMWLoopOp::Smax => {
1633 let cond = match op {
1637 AtomicRMWLoopOp::Umin => Cond::Lo,
1638 AtomicRMWLoopOp::Umax => Cond::Hi,
1639 AtomicRMWLoopOp::Smin => Cond::Lt,
1640 AtomicRMWLoopOp::Smax => Cond::Gt,
1641 _ => unreachable!(),
1642 };
1643
1644 if let Some(extendop) = sign_ext.map(|(op, _)| op).or(zero_ext) {
1645 Inst::AluRRRExtend {
1646 alu_op: ALUOp::SubS,
1647 size,
1648 rd: writable_zero_reg(),
1649 rn: x27,
1650 rm: x26,
1651 extendop,
1652 }
1653 .emit(sink, emit_info, state);
1654 } else {
1655 Inst::AluRRR {
1656 alu_op: ALUOp::SubS,
1657 size,
1658 rd: writable_zero_reg(),
1659 rn: x27,
1660 rm: x26,
1661 }
1662 .emit(sink, emit_info, state);
1663 }
1664
1665 Inst::CSel {
1666 cond,
1667 rd: x28wr,
1668 rn: x27,
1669 rm: x26,
1670 }
1671 .emit(sink, emit_info, state);
1672 }
1673 _ => {
1674 let alu_op = match op {
1676 AtomicRMWLoopOp::Add => ALUOp::Add,
1677 AtomicRMWLoopOp::Sub => ALUOp::Sub,
1678 AtomicRMWLoopOp::And => ALUOp::And,
1679 AtomicRMWLoopOp::Orr => ALUOp::Orr,
1680 AtomicRMWLoopOp::Eor => ALUOp::Eor,
1681 AtomicRMWLoopOp::Nand
1682 | AtomicRMWLoopOp::Umin
1683 | AtomicRMWLoopOp::Umax
1684 | AtomicRMWLoopOp::Smin
1685 | AtomicRMWLoopOp::Smax
1686 | AtomicRMWLoopOp::Xchg => unreachable!(),
1687 };
1688
1689 Inst::AluRRR {
1690 alu_op,
1691 size,
1692 rd: x28wr,
1693 rn: x27,
1694 rm: x26,
1695 }
1696 .emit(sink, emit_info, state);
1697 }
1698 }
1699
1700 if let Some(trap_code) = flags.trap_code() {
1701 sink.add_trap(trap_code);
1702 }
1703 if op == AtomicRMWLoopOp::Xchg {
1704 sink.put4(enc_stlxr(ty, x24wr, x26, x25)); } else {
1706 sink.put4(enc_stlxr(ty, x24wr, x28, x25)); }
1708
1709 let br_offset = sink.cur_offset();
1713 sink.put4(enc_conditional_br(
1714 BranchTarget::Label(again_label),
1715 CondBrKind::NotZero(x24, OperandSize::Size64),
1716 ));
1717 sink.use_label_at_offset(br_offset, again_label, LabelUse::Branch19);
1718 }
1719 &Inst::AtomicRMW128Loop { op, flags, .. } => {
1720 let xzr = zero_reg();
1739 let x21 = xreg(21);
1740 let x22 = xreg(22);
1741 let x23 = xreg(23);
1742 let x24 = xreg(24);
1743 let x25 = xreg(25);
1744 let x26 = xreg(26);
1745 let x27 = xreg(27);
1746 let x28 = xreg(28);
1747 let x21wr = writable_xreg(21);
1748 let x23wr = writable_xreg(23);
1749 let x24wr = writable_xreg(24);
1750 let x27wr = writable_xreg(27);
1751 let x28wr = writable_xreg(28);
1752 let again_label = sink.get_label();
1753
1754 sink.bind_label(again_label, &mut state.ctrl_plane);
1756
1757 if let Some(trap_code) = flags.trap_code() {
1758 sink.add_trap(trap_code);
1759 }
1760
1761 sink.put4(enc_ldaxp(I64, x27wr, x23wr, x25)); match op {
1764 AtomicRMWLoopOp::Xchg => {} AtomicRMWLoopOp::Smax
1766 | AtomicRMWLoopOp::Umax
1767 | AtomicRMWLoopOp::Smin
1768 | AtomicRMWLoopOp::Umin => {
1769 let cond = match op {
1775 AtomicRMWLoopOp::Smax => Cond::Lt,
1776 AtomicRMWLoopOp::Umax => Cond::Lo,
1777 AtomicRMWLoopOp::Smin => Cond::Ge,
1778 AtomicRMWLoopOp::Umin => Cond::Hs,
1779 _ => unreachable!(),
1780 };
1781
1782 Inst::AluRRR {
1783 alu_op: ALUOp::SubS,
1784 size: OperandSize::Size64,
1785 rd: writable_zero_reg(),
1786 rn: x27,
1787 rm: x26,
1788 }
1789 .emit(sink, emit_info, state);
1790
1791 Inst::AluRRR {
1792 alu_op: ALUOp::SbcS,
1793 size: OperandSize::Size64,
1794 rd: writable_zero_reg(),
1795 rn: x23,
1796 rm: x22,
1797 }
1798 .emit(sink, emit_info, state);
1799
1800 Inst::CSel {
1801 cond,
1802 rd: x21wr,
1803 rn: x22,
1804 rm: x23,
1805 }
1806 .emit(sink, emit_info, state);
1807
1808 Inst::CSel {
1809 cond,
1810 rd: x28wr,
1811 rn: x26,
1812 rm: x27,
1813 }
1814 .emit(sink, emit_info, state);
1815 }
1816 _ => {
1817 let (op_lo, op_hi) = match op {
1818 AtomicRMWLoopOp::Add => (ALUOp::AddS, ALUOp::Adc),
1821 AtomicRMWLoopOp::Sub => (ALUOp::SubS, ALUOp::Sbc),
1824 AtomicRMWLoopOp::And | AtomicRMWLoopOp::Nand => {
1827 (ALUOp::And, ALUOp::And)
1828 }
1829 AtomicRMWLoopOp::Orr => (ALUOp::Orr, ALUOp::Orr),
1832 AtomicRMWLoopOp::Eor => (ALUOp::Eor, ALUOp::Eor),
1835 _ => unreachable!(),
1836 };
1837
1838 Inst::AluRRR {
1839 alu_op: op_lo,
1840 size: OperandSize::Size64,
1841 rd: x28wr,
1842 rn: x27,
1843 rm: x26,
1844 }
1845 .emit(sink, emit_info, state);
1846
1847 Inst::AluRRR {
1848 alu_op: op_hi,
1849 size: OperandSize::Size64,
1850 rd: x21wr,
1851 rn: x23,
1852 rm: x22,
1853 }
1854 .emit(sink, emit_info, state);
1855
1856 if op == AtomicRMWLoopOp::Nand {
1857 Inst::AluRRR {
1861 alu_op: ALUOp::OrrNot,
1862 size: OperandSize::Size64,
1863 rd: x28wr,
1864 rn: xzr,
1865 rm: x28,
1866 }
1867 .emit(sink, emit_info, state);
1868
1869 Inst::AluRRR {
1870 alu_op: ALUOp::OrrNot,
1871 size: OperandSize::Size64,
1872 rd: x21wr,
1873 rn: xzr,
1874 rm: x21,
1875 }
1876 .emit(sink, emit_info, state);
1877 }
1878 }
1879 }
1880
1881 if let Some(trap_code) = flags.trap_code() {
1882 sink.add_trap(trap_code);
1883 }
1884
1885 if op == AtomicRMWLoopOp::Xchg {
1886 sink.put4(enc_stlxp(I64, x24wr, x26, x22, x25)); } else {
1888 sink.put4(enc_stlxp(I64, x24wr, x28, x21, x25)); }
1890
1891 let br_offset = sink.cur_offset();
1895 sink.put4(enc_conditional_br(
1896 BranchTarget::Label(again_label),
1897 CondBrKind::NotZero(x24, OperandSize::Size64),
1898 ));
1899 sink.use_label_at_offset(br_offset, again_label, LabelUse::Branch19);
1900 }
1901 &Inst::AtomicCAS {
1902 rd,
1903 rs,
1904 rt,
1905 rn,
1906 ty,
1907 flags,
1908 } => {
1909 debug_assert_eq!(rd.to_reg(), rs);
1910 let size = match ty {
1911 I8 => 0b00,
1912 I16 => 0b01,
1913 I32 => 0b10,
1914 I64 => 0b11,
1915 _ => panic!("Unsupported type: {ty}"),
1916 };
1917
1918 if let Some(trap_code) = flags.trap_code() {
1919 sink.add_trap(trap_code);
1920 }
1921
1922 sink.put4(enc_cas(size, rd, rt, rn));
1923 }
1924 Inst::AtomicCAS128 { args } => {
1925 let &AtomicCAS128Args {
1926 rd_lo,
1927 rd_hi,
1928 rs_lo,
1929 rs_hi,
1930 rt_lo,
1931 rt_hi,
1932 rn,
1933 flags,
1934 } = &**args;
1935 debug_assert_eq!(rd_lo.to_reg(), rs_lo);
1936 debug_assert_eq!(rd_hi.to_reg(), rs_hi);
1937
1938 debug_assert_eq!(rs_hi, xreg(machreg_to_gpr(rs_lo) as u8 + 1));
1940 debug_assert_eq!(rt_hi, xreg(machreg_to_gpr(rt_lo) as u8 + 1));
1941
1942 if let Some(trap_code) = flags.trap_code() {
1943 sink.add_trap(trap_code);
1944 }
1945
1946 sink.put4(enc_casp(rd_lo, rt_lo, rn));
1947 }
1948 &Inst::AtomicCASLoop { ty, flags, .. } => {
1949 let x24 = xreg(24);
1963 let x25 = xreg(25);
1964 let x26 = xreg(26);
1965 let x27 = xreg(27);
1966 let x28 = xreg(28);
1967 let xzrwr = writable_zero_reg();
1968 let x24wr = writable_xreg(24);
1969 let x27wr = writable_xreg(27);
1970 let again_label = sink.get_label();
1971 let out_label = sink.get_label();
1972
1973 sink.bind_label(again_label, &mut state.ctrl_plane);
1975
1976 if let Some(trap_code) = flags.trap_code() {
1977 sink.add_trap(trap_code);
1978 }
1979
1980 sink.put4(enc_ldaxr(ty, x27wr, x25));
1982
1983 let (bit21, extend_op) = match ty {
1986 I8 => (0b1, 0b000000),
1987 I16 => (0b1, 0b001000),
1988 _ => (0b0, 0b000000),
1989 };
1990 let bits_31_21 = 0b111_01011_000 | bit21;
1991 sink.put4(enc_arith_rrr(bits_31_21, extend_op, xzrwr, x27, x26));
1993
1994 let br_out_offset = sink.cur_offset();
1996 sink.put4(enc_conditional_br(
1997 BranchTarget::Label(out_label),
1998 CondBrKind::Cond(Cond::Ne),
1999 ));
2000 sink.use_label_at_offset(br_out_offset, out_label, LabelUse::Branch19);
2001
2002 if let Some(trap_code) = flags.trap_code() {
2003 sink.add_trap(trap_code);
2004 }
2005
2006 sink.put4(enc_stlxr(ty, x24wr, x28, x25)); let br_again_offset = sink.cur_offset();
2012 sink.put4(enc_conditional_br(
2013 BranchTarget::Label(again_label),
2014 CondBrKind::NotZero(x24, OperandSize::Size64),
2015 ));
2016 sink.use_label_at_offset(br_again_offset, again_label, LabelUse::Branch19);
2017
2018 sink.bind_label(out_label, &mut state.ctrl_plane);
2020 }
2021 &Inst::AtomicCAS128Loop { flags, .. } => {
2022 let x21 = xreg(21);
2042 let x22 = xreg(22);
2043 let x23 = xreg(23);
2044 let x24 = xreg(24);
2045 let x25 = xreg(25);
2046 let x26 = xreg(26);
2047 let x27 = xreg(27);
2048 let x28 = xreg(28);
2049 let xzrwr = writable_zero_reg();
2050 let x21wr = writable_xreg(21);
2051 let x24wr = writable_xreg(24);
2052 let x27wr = writable_xreg(27);
2053 let again_label = sink.get_label();
2054 let keep_label = sink.get_label();
2055 let out_label = sink.get_label();
2056
2057 sink.bind_label(again_label, &mut state.ctrl_plane);
2059
2060 if let Some(trap_code) = flags.trap_code() {
2061 sink.add_trap(trap_code);
2062 }
2063
2064 sink.put4(enc_ldaxp(I64, x27wr, x21wr, x25));
2066
2067 Inst::AluRRR {
2069 alu_op: ALUOp::SubS,
2070 size: OperandSize::Size64,
2071 rd: xzrwr,
2072 rn: x27,
2073 rm: x26,
2074 }
2075 .emit(sink, emit_info, state);
2076
2077 let br_keep_offset = sink.cur_offset();
2079 sink.put4(enc_conditional_br(
2080 BranchTarget::Label(keep_label),
2081 CondBrKind::Cond(Cond::Ne),
2082 ));
2083 sink.use_label_at_offset(br_keep_offset, keep_label, LabelUse::Branch19);
2084
2085 Inst::AluRRR {
2087 alu_op: ALUOp::SubS,
2088 size: OperandSize::Size64,
2089 rd: xzrwr,
2090 rn: x21,
2091 rm: x23,
2092 }
2093 .emit(sink, emit_info, state);
2094
2095 let br_keep_offset = sink.cur_offset();
2097 sink.put4(enc_conditional_br(
2098 BranchTarget::Label(keep_label),
2099 CondBrKind::Cond(Cond::Ne),
2100 ));
2101 sink.use_label_at_offset(br_keep_offset, keep_label, LabelUse::Branch19);
2102
2103 if let Some(trap_code) = flags.trap_code() {
2104 sink.add_trap(trap_code);
2105 }
2106
2107 sink.put4(enc_stlxp(I64, x24wr, x28, x22, x25));
2109
2110 let br_again_offset = sink.cur_offset();
2112 sink.put4(enc_conditional_br(
2113 BranchTarget::Label(again_label),
2114 CondBrKind::NotZero(x24, OperandSize::Size64),
2115 ));
2116 sink.use_label_at_offset(br_again_offset, again_label, LabelUse::Branch19);
2117
2118 let b_out_offset = sink.cur_offset();
2120 sink.put4(enc_jump26(
2121 0b000101,
2122 BranchTarget::Label(out_label).as_offset26_or_zero(),
2123 ));
2124 sink.use_label_at_offset(b_out_offset, out_label, LabelUse::Branch26);
2125
2126 sink.bind_label(keep_label, &mut state.ctrl_plane);
2128
2129 if let Some(trap_code) = flags.trap_code() {
2130 sink.add_trap(trap_code);
2131 }
2132
2133 sink.put4(enc_stlxp(I64, x24wr, x27, x21, x25));
2135
2136 let br_again_offset = sink.cur_offset();
2138 sink.put4(enc_conditional_br(
2139 BranchTarget::Label(again_label),
2140 CondBrKind::NotZero(x24, OperandSize::Size64),
2141 ));
2142 sink.use_label_at_offset(br_again_offset, again_label, LabelUse::Branch19);
2143
2144 sink.bind_label(out_label, &mut state.ctrl_plane);
2146 }
2147 &Inst::LoadAcquire {
2148 access_ty,
2149 rt,
2150 rn,
2151 flags,
2152 } => {
2153 if let Some(trap_code) = flags.trap_code() {
2154 sink.add_trap(trap_code);
2155 }
2156
2157 sink.put4(enc_ldar(access_ty, rt, rn));
2158 }
2159 &Inst::LoadAcquire128 {
2160 rt1,
2161 rt2,
2162 rn,
2163 scratch,
2164 flags,
2165 } => {
2166 let again_label = sink.get_label();
2167
2168 sink.bind_label(again_label, &mut state.ctrl_plane);
2170
2171 if let Some(trap_code) = flags.trap_code() {
2172 sink.add_trap(trap_code);
2173 }
2174
2175 sink.put4(enc_ldaxp(I64, rt1, rt2, rn));
2177
2178 if let Some(trap_code) = flags.trap_code() {
2179 sink.add_trap(trap_code);
2180 }
2181
2182 sink.put4(enc_stxp(I64, scratch, rt1.to_reg(), rt2.to_reg(), rn));
2184
2185 let br_again_offset = sink.cur_offset();
2187 sink.put4(enc_conditional_br(
2188 BranchTarget::Label(again_label),
2189 CondBrKind::NotZero(scratch.to_reg(), OperandSize::Size64),
2190 ));
2191 sink.use_label_at_offset(br_again_offset, again_label, LabelUse::Branch19);
2192 }
2193 &Inst::StoreRelease {
2194 access_ty,
2195 rt,
2196 rn,
2197 flags,
2198 } => {
2199 if let Some(trap_code) = flags.trap_code() {
2200 sink.add_trap(trap_code);
2201 }
2202
2203 sink.put4(enc_stlr(access_ty, rt, rn));
2204 }
2205 &Inst::StoreRelease128 {
2206 rt1,
2207 rt2,
2208 rn,
2209 scratch,
2210 flags,
2211 } => {
2212 let again_label = sink.get_label();
2213
2214 sink.bind_label(again_label, &mut state.ctrl_plane);
2216
2217 if let Some(trap_code) = flags.trap_code() {
2218 sink.add_trap(trap_code);
2219 }
2220
2221 sink.put4(enc_ldxp(I64, writable_zero_reg(), scratch, rn));
2223
2224 if let Some(trap_code) = flags.trap_code() {
2225 sink.add_trap(trap_code);
2226 }
2227
2228 sink.put4(enc_stlxp(I64, scratch, rt1, rt2, rn));
2230
2231 let br_again_offset = sink.cur_offset();
2233 sink.put4(enc_conditional_br(
2234 BranchTarget::Label(again_label),
2235 CondBrKind::NotZero(scratch.to_reg(), OperandSize::Size64),
2236 ));
2237 sink.use_label_at_offset(br_again_offset, again_label, LabelUse::Branch19);
2238 }
2239 &Inst::Fence {} => {
2240 sink.put4(enc_dmb_ish()); }
2242 &Inst::Csdb {} => {
2243 sink.put4(0xd503229f);
2244 }
2245 &Inst::FpuMove32 { rd, rn } => {
2246 sink.put4(enc_fpurr(0b000_11110_00_1_000000_10000, rd, rn));
2247 }
2248 &Inst::FpuMove64 { rd, rn } => {
2249 sink.put4(enc_fpurr(0b000_11110_01_1_000000_10000, rd, rn));
2250 }
2251 &Inst::FpuMove128 { rd, rn } => {
2252 sink.put4(enc_vecmov(true, rd, rn));
2253 }
2254 &Inst::FpuMoveFromVec { rd, rn, idx, size } => {
2255 let (imm5, shift, mask) = match size.lane_size() {
2256 ScalarSize::Size32 => (0b00100, 3, 0b011),
2257 ScalarSize::Size64 => (0b01000, 4, 0b001),
2258 _ => unimplemented!(),
2259 };
2260 debug_assert_eq!(idx & mask, idx);
2261 let imm5 = imm5 | ((idx as u32) << shift);
2262 sink.put4(
2263 0b010_11110000_00000_000001_00000_00000
2264 | (imm5 << 16)
2265 | (machreg_to_vec(rn) << 5)
2266 | machreg_to_vec(rd.to_reg()),
2267 );
2268 }
2269 &Inst::FpuExtend { rd, rn, size } => {
2270 sink.put4(enc_fpurr(
2271 0b000_11110_00_1_000000_10000 | (size.ftype() << 12),
2272 rd,
2273 rn,
2274 ));
2275 }
2276 &Inst::FpuRR {
2277 fpu_op,
2278 size,
2279 rd,
2280 rn,
2281 } => {
2282 let top22 = match fpu_op {
2283 FPUOp1::Abs => 0b000_11110_00_1_000001_10000,
2284 FPUOp1::Neg => 0b000_11110_00_1_000010_10000,
2285 FPUOp1::Sqrt => 0b000_11110_00_1_000011_10000,
2286 FPUOp1::Cvt16To32 => {
2287 debug_assert_eq!(size, ScalarSize::Size16);
2288 0b000_11110_11_1_000100_10000
2289 }
2290 FPUOp1::Cvt32To64 => {
2291 debug_assert_eq!(size, ScalarSize::Size32);
2292 0b000_11110_00_1_000101_10000
2293 }
2294 FPUOp1::Cvt64To32 => {
2295 debug_assert_eq!(size, ScalarSize::Size64);
2296 0b000_11110_01_1_000100_10000
2297 }
2298 };
2299 let top22 = top22 | size.ftype() << 12;
2300 sink.put4(enc_fpurr(top22, rd, rn));
2301 }
2302 &Inst::FpuRRR {
2303 fpu_op,
2304 size,
2305 rd,
2306 rn,
2307 rm,
2308 } => {
2309 let top22 = match fpu_op {
2310 FPUOp2::Add => 0b000_11110_00_1_00000_001010,
2311 FPUOp2::Sub => 0b000_11110_00_1_00000_001110,
2312 FPUOp2::Mul => 0b000_11110_00_1_00000_000010,
2313 FPUOp2::Div => 0b000_11110_00_1_00000_000110,
2314 FPUOp2::Max => 0b000_11110_00_1_00000_010010,
2315 FPUOp2::Min => 0b000_11110_00_1_00000_010110,
2316 };
2317 let top22 = top22 | size.ftype() << 12;
2318 sink.put4(enc_fpurrr(top22, rd, rn, rm));
2319 }
2320 &Inst::FpuRRI { fpu_op, rd, rn } => match fpu_op {
2321 FPUOpRI::UShr32(imm) => {
2322 debug_assert_eq!(32, imm.lane_size_in_bits);
2323 sink.put4(
2324 0b0_0_1_011110_0000000_00_0_0_0_1_00000_00000
2325 | imm.enc() << 16
2326 | machreg_to_vec(rn) << 5
2327 | machreg_to_vec(rd.to_reg()),
2328 )
2329 }
2330 FPUOpRI::UShr64(imm) => {
2331 debug_assert_eq!(64, imm.lane_size_in_bits);
2332 sink.put4(
2333 0b01_1_111110_0000000_00_0_0_0_1_00000_00000
2334 | imm.enc() << 16
2335 | machreg_to_vec(rn) << 5
2336 | machreg_to_vec(rd.to_reg()),
2337 )
2338 }
2339 },
2340 &Inst::FpuRRIMod { fpu_op, rd, ri, rn } => {
2341 debug_assert_eq!(rd.to_reg(), ri);
2342 match fpu_op {
2343 FPUOpRIMod::Sli64(imm) => {
2344 debug_assert_eq!(64, imm.lane_size_in_bits);
2345 sink.put4(
2346 0b01_1_111110_0000000_010101_00000_00000
2347 | imm.enc() << 16
2348 | machreg_to_vec(rn) << 5
2349 | machreg_to_vec(rd.to_reg()),
2350 )
2351 }
2352 FPUOpRIMod::Sli32(imm) => {
2353 debug_assert_eq!(32, imm.lane_size_in_bits);
2354 sink.put4(
2355 0b0_0_1_011110_0000000_010101_00000_00000
2356 | imm.enc() << 16
2357 | machreg_to_vec(rn) << 5
2358 | machreg_to_vec(rd.to_reg()),
2359 )
2360 }
2361 }
2362 }
2363 &Inst::FpuRRRR {
2364 fpu_op,
2365 size,
2366 rd,
2367 rn,
2368 rm,
2369 ra,
2370 } => {
2371 let top17 = match fpu_op {
2372 FPUOp3::MAdd => 0b000_11111_00_0_00000_0,
2373 FPUOp3::MSub => 0b000_11111_00_0_00000_1,
2374 FPUOp3::NMAdd => 0b000_11111_00_1_00000_0,
2375 FPUOp3::NMSub => 0b000_11111_00_1_00000_1,
2376 };
2377 let top17 = top17 | size.ftype() << 7;
2378 sink.put4(enc_fpurrrr(top17, rd, rn, rm, ra));
2379 }
2380 &Inst::VecMisc { op, rd, rn, size } => {
2381 let (q, enc_size) = size.enc_size();
2382 let (u, bits_12_16, size) = match op {
2383 VecMisc2::Not => (0b1, 0b00101, 0b00),
2384 VecMisc2::Neg => (0b1, 0b01011, enc_size),
2385 VecMisc2::Abs => (0b0, 0b01011, enc_size),
2386 VecMisc2::Fabs => {
2387 debug_assert!(
2388 size == VectorSize::Size32x2
2389 || size == VectorSize::Size32x4
2390 || size == VectorSize::Size64x2
2391 );
2392 (0b0, 0b01111, enc_size)
2393 }
2394 VecMisc2::Fneg => {
2395 debug_assert!(
2396 size == VectorSize::Size32x2
2397 || size == VectorSize::Size32x4
2398 || size == VectorSize::Size64x2
2399 );
2400 (0b1, 0b01111, enc_size)
2401 }
2402 VecMisc2::Fsqrt => {
2403 debug_assert!(
2404 size == VectorSize::Size32x2
2405 || size == VectorSize::Size32x4
2406 || size == VectorSize::Size64x2
2407 );
2408 (0b1, 0b11111, enc_size)
2409 }
2410 VecMisc2::Rev16 => {
2411 debug_assert_eq!(size, VectorSize::Size8x16);
2412 (0b0, 0b00001, enc_size)
2413 }
2414 VecMisc2::Rev32 => {
2415 debug_assert!(size == VectorSize::Size8x16 || size == VectorSize::Size16x8);
2416 (0b1, 0b00000, enc_size)
2417 }
2418 VecMisc2::Rev64 => {
2419 debug_assert!(
2420 size == VectorSize::Size8x16
2421 || size == VectorSize::Size16x8
2422 || size == VectorSize::Size32x4
2423 );
2424 (0b0, 0b00000, enc_size)
2425 }
2426 VecMisc2::Fcvtzs => {
2427 debug_assert!(
2428 size == VectorSize::Size32x2
2429 || size == VectorSize::Size32x4
2430 || size == VectorSize::Size64x2
2431 );
2432 (0b0, 0b11011, enc_size)
2433 }
2434 VecMisc2::Fcvtzu => {
2435 debug_assert!(
2436 size == VectorSize::Size32x2
2437 || size == VectorSize::Size32x4
2438 || size == VectorSize::Size64x2
2439 );
2440 (0b1, 0b11011, enc_size)
2441 }
2442 VecMisc2::Scvtf => {
2443 debug_assert!(size == VectorSize::Size32x4 || size == VectorSize::Size64x2);
2444 (0b0, 0b11101, enc_size & 0b1)
2445 }
2446 VecMisc2::Ucvtf => {
2447 debug_assert!(size == VectorSize::Size32x4 || size == VectorSize::Size64x2);
2448 (0b1, 0b11101, enc_size & 0b1)
2449 }
2450 VecMisc2::Frintn => {
2451 debug_assert!(
2452 size == VectorSize::Size32x2
2453 || size == VectorSize::Size32x4
2454 || size == VectorSize::Size64x2
2455 );
2456 (0b0, 0b11000, enc_size & 0b01)
2457 }
2458 VecMisc2::Frintz => {
2459 debug_assert!(
2460 size == VectorSize::Size32x2
2461 || size == VectorSize::Size32x4
2462 || size == VectorSize::Size64x2
2463 );
2464 (0b0, 0b11001, enc_size)
2465 }
2466 VecMisc2::Frintm => {
2467 debug_assert!(
2468 size == VectorSize::Size32x2
2469 || size == VectorSize::Size32x4
2470 || size == VectorSize::Size64x2
2471 );
2472 (0b0, 0b11001, enc_size & 0b01)
2473 }
2474 VecMisc2::Frintp => {
2475 debug_assert!(
2476 size == VectorSize::Size32x2
2477 || size == VectorSize::Size32x4
2478 || size == VectorSize::Size64x2
2479 );
2480 (0b0, 0b11000, enc_size)
2481 }
2482 VecMisc2::Cnt => {
2483 debug_assert!(size == VectorSize::Size8x8 || size == VectorSize::Size8x16);
2484 (0b0, 0b00101, enc_size)
2485 }
2486 VecMisc2::Cmeq0 => (0b0, 0b01001, enc_size),
2487 VecMisc2::Cmge0 => (0b1, 0b01000, enc_size),
2488 VecMisc2::Cmgt0 => (0b0, 0b01000, enc_size),
2489 VecMisc2::Cmle0 => (0b1, 0b01001, enc_size),
2490 VecMisc2::Cmlt0 => (0b0, 0b01010, enc_size),
2491 VecMisc2::Fcmeq0 => {
2492 debug_assert!(
2493 size == VectorSize::Size32x2
2494 || size == VectorSize::Size32x4
2495 || size == VectorSize::Size64x2
2496 );
2497 (0b0, 0b01101, enc_size)
2498 }
2499 VecMisc2::Fcmge0 => {
2500 debug_assert!(
2501 size == VectorSize::Size32x2
2502 || size == VectorSize::Size32x4
2503 || size == VectorSize::Size64x2
2504 );
2505 (0b1, 0b01100, enc_size)
2506 }
2507 VecMisc2::Fcmgt0 => {
2508 debug_assert!(
2509 size == VectorSize::Size32x2
2510 || size == VectorSize::Size32x4
2511 || size == VectorSize::Size64x2
2512 );
2513 (0b0, 0b01100, enc_size)
2514 }
2515 VecMisc2::Fcmle0 => {
2516 debug_assert!(
2517 size == VectorSize::Size32x2
2518 || size == VectorSize::Size32x4
2519 || size == VectorSize::Size64x2
2520 );
2521 (0b1, 0b01101, enc_size)
2522 }
2523 VecMisc2::Fcmlt0 => {
2524 debug_assert!(
2525 size == VectorSize::Size32x2
2526 || size == VectorSize::Size32x4
2527 || size == VectorSize::Size64x2
2528 );
2529 (0b0, 0b01110, enc_size)
2530 }
2531 };
2532 sink.put4(enc_vec_rr_misc((q << 1) | u, size, bits_12_16, rd, rn));
2533 }
2534 &Inst::VecLanes { op, rd, rn, size } => {
2535 let (q, size) = match size {
2536 VectorSize::Size8x8 => (0b0, 0b00),
2537 VectorSize::Size8x16 => (0b1, 0b00),
2538 VectorSize::Size16x4 => (0b0, 0b01),
2539 VectorSize::Size16x8 => (0b1, 0b01),
2540 VectorSize::Size32x4 => (0b1, 0b10),
2541 _ => unreachable!(),
2542 };
2543 let (u, opcode) = match op {
2544 VecLanesOp::Uminv => (0b1, 0b11010),
2545 VecLanesOp::Addv => (0b0, 0b11011),
2546 };
2547 sink.put4(enc_vec_lanes(q, u, size, opcode, rd, rn));
2548 }
2549 &Inst::VecShiftImm {
2550 op,
2551 rd,
2552 rn,
2553 size,
2554 imm,
2555 } => {
2556 let (is_shr, mut template) = match op {
2557 VecShiftImmOp::Ushr => (true, 0b_001_011110_0000_000_000001_00000_00000_u32),
2558 VecShiftImmOp::Sshr => (true, 0b_000_011110_0000_000_000001_00000_00000_u32),
2559 VecShiftImmOp::Shl => (false, 0b_000_011110_0000_000_010101_00000_00000_u32),
2560 };
2561 if size.is_128bits() {
2562 template |= 0b1 << 30;
2563 }
2564 let imm = imm as u32;
2565 let immh_immb = match (size.lane_size(), is_shr) {
2568 (ScalarSize::Size64, true) if imm >= 1 && imm <= 64 => {
2569 0b_1000_000_u32 | (64 - imm)
2570 }
2571 (ScalarSize::Size32, true) if imm >= 1 && imm <= 32 => {
2572 0b_0100_000_u32 | (32 - imm)
2573 }
2574 (ScalarSize::Size16, true) if imm >= 1 && imm <= 16 => {
2575 0b_0010_000_u32 | (16 - imm)
2576 }
2577 (ScalarSize::Size8, true) if imm >= 1 && imm <= 8 => {
2578 0b_0001_000_u32 | (8 - imm)
2579 }
2580 (ScalarSize::Size64, false) if imm <= 63 => 0b_1000_000_u32 | imm,
2581 (ScalarSize::Size32, false) if imm <= 31 => 0b_0100_000_u32 | imm,
2582 (ScalarSize::Size16, false) if imm <= 15 => 0b_0010_000_u32 | imm,
2583 (ScalarSize::Size8, false) if imm <= 7 => 0b_0001_000_u32 | imm,
2584 _ => panic!(
2585 "aarch64: Inst::VecShiftImm: emit: invalid op/size/imm {op:?}, {size:?}, {imm:?}"
2586 ),
2587 };
2588 let rn_enc = machreg_to_vec(rn);
2589 let rd_enc = machreg_to_vec(rd.to_reg());
2590 sink.put4(template | (immh_immb << 16) | (rn_enc << 5) | rd_enc);
2591 }
2592 &Inst::VecShiftImmMod {
2593 op,
2594 rd,
2595 ri,
2596 rn,
2597 size,
2598 imm,
2599 } => {
2600 debug_assert_eq!(rd.to_reg(), ri);
2601 let (is_shr, mut template) = match op {
2602 VecShiftImmModOp::Sli => (false, 0b_001_011110_0000_000_010101_00000_00000_u32),
2603 };
2604 if size.is_128bits() {
2605 template |= 0b1 << 30;
2606 }
2607 let imm = imm as u32;
2608 let immh_immb = match (size.lane_size(), is_shr) {
2611 (ScalarSize::Size64, true) if imm >= 1 && imm <= 64 => {
2612 0b_1000_000_u32 | (64 - imm)
2613 }
2614 (ScalarSize::Size32, true) if imm >= 1 && imm <= 32 => {
2615 0b_0100_000_u32 | (32 - imm)
2616 }
2617 (ScalarSize::Size16, true) if imm >= 1 && imm <= 16 => {
2618 0b_0010_000_u32 | (16 - imm)
2619 }
2620 (ScalarSize::Size8, true) if imm >= 1 && imm <= 8 => {
2621 0b_0001_000_u32 | (8 - imm)
2622 }
2623 (ScalarSize::Size64, false) if imm <= 63 => 0b_1000_000_u32 | imm,
2624 (ScalarSize::Size32, false) if imm <= 31 => 0b_0100_000_u32 | imm,
2625 (ScalarSize::Size16, false) if imm <= 15 => 0b_0010_000_u32 | imm,
2626 (ScalarSize::Size8, false) if imm <= 7 => 0b_0001_000_u32 | imm,
2627 _ => panic!(
2628 "aarch64: Inst::VecShiftImmMod: emit: invalid op/size/imm {op:?}, {size:?}, {imm:?}"
2629 ),
2630 };
2631 let rn_enc = machreg_to_vec(rn);
2632 let rd_enc = machreg_to_vec(rd.to_reg());
2633 sink.put4(template | (immh_immb << 16) | (rn_enc << 5) | rd_enc);
2634 }
2635 &Inst::VecExtract { rd, rn, rm, imm4 } => {
2636 if imm4 < 16 {
2637 let template = 0b_01_101110_000_00000_0_0000_0_00000_00000_u32;
2638 let rm_enc = machreg_to_vec(rm);
2639 let rn_enc = machreg_to_vec(rn);
2640 let rd_enc = machreg_to_vec(rd.to_reg());
2641 sink.put4(
2642 template | (rm_enc << 16) | ((imm4 as u32) << 11) | (rn_enc << 5) | rd_enc,
2643 );
2644 } else {
2645 panic!("aarch64: Inst::VecExtract: emit: invalid extract index {imm4}");
2646 }
2647 }
2648 &Inst::VecTbl { rd, rn, rm } => {
2649 sink.put4(enc_tbl(false, 0b00, rd, rn, rm));
2650 }
2651 &Inst::VecTblExt { rd, ri, rn, rm } => {
2652 debug_assert_eq!(rd.to_reg(), ri);
2653 sink.put4(enc_tbl(true, 0b00, rd, rn, rm));
2654 }
2655 &Inst::VecTbl2 { rd, rn, rn2, rm } => {
2656 assert_eq!(machreg_to_vec(rn2), (machreg_to_vec(rn) + 1) % 32);
2657 sink.put4(enc_tbl(false, 0b01, rd, rn, rm));
2658 }
2659 &Inst::VecTbl2Ext {
2660 rd,
2661 ri,
2662 rn,
2663 rn2,
2664 rm,
2665 } => {
2666 debug_assert_eq!(rd.to_reg(), ri);
2667 assert_eq!(machreg_to_vec(rn2), (machreg_to_vec(rn) + 1) % 32);
2668 sink.put4(enc_tbl(true, 0b01, rd, rn, rm));
2669 }
2670 &Inst::FpuCmp { size, rn, rm } => {
2671 sink.put4(enc_fcmp(size, rn, rm));
2672 }
2673 &Inst::FpuToInt { op, rd, rn } => {
2674 let top16 = match op {
2675 FpuToIntOp::F32ToI32 => 0b000_11110_00_1_11_000,
2677 FpuToIntOp::F32ToU32 => 0b000_11110_00_1_11_001,
2679 FpuToIntOp::F32ToI64 => 0b100_11110_00_1_11_000,
2681 FpuToIntOp::F32ToU64 => 0b100_11110_00_1_11_001,
2683 FpuToIntOp::F64ToI32 => 0b000_11110_01_1_11_000,
2685 FpuToIntOp::F64ToU32 => 0b000_11110_01_1_11_001,
2687 FpuToIntOp::F64ToI64 => 0b100_11110_01_1_11_000,
2689 FpuToIntOp::F64ToU64 => 0b100_11110_01_1_11_001,
2691 };
2692 sink.put4(enc_fputoint(top16, rd, rn));
2693 }
2694 &Inst::IntToFpu { op, rd, rn } => {
2695 let top16 = match op {
2696 IntToFpuOp::I32ToF32 => 0b000_11110_00_1_00_010,
2698 IntToFpuOp::U32ToF32 => 0b000_11110_00_1_00_011,
2700 IntToFpuOp::I64ToF32 => 0b100_11110_00_1_00_010,
2702 IntToFpuOp::U64ToF32 => 0b100_11110_00_1_00_011,
2704 IntToFpuOp::I32ToF64 => 0b000_11110_01_1_00_010,
2706 IntToFpuOp::U32ToF64 => 0b000_11110_01_1_00_011,
2708 IntToFpuOp::I64ToF64 => 0b100_11110_01_1_00_010,
2710 IntToFpuOp::U64ToF64 => 0b100_11110_01_1_00_011,
2712 };
2713 sink.put4(enc_inttofpu(top16, rd, rn));
2714 }
2715 &Inst::FpuCSel16 { rd, rn, rm, cond } => {
2716 sink.put4(enc_fcsel(rd, rn, rm, cond, ScalarSize::Size16));
2717 }
2718 &Inst::FpuCSel32 { rd, rn, rm, cond } => {
2719 sink.put4(enc_fcsel(rd, rn, rm, cond, ScalarSize::Size32));
2720 }
2721 &Inst::FpuCSel64 { rd, rn, rm, cond } => {
2722 sink.put4(enc_fcsel(rd, rn, rm, cond, ScalarSize::Size64));
2723 }
2724 &Inst::FpuRound { op, rd, rn } => {
2725 let top22 = match op {
2726 FpuRoundMode::Minus32 => 0b000_11110_00_1_001_010_10000,
2727 FpuRoundMode::Minus64 => 0b000_11110_01_1_001_010_10000,
2728 FpuRoundMode::Plus32 => 0b000_11110_00_1_001_001_10000,
2729 FpuRoundMode::Plus64 => 0b000_11110_01_1_001_001_10000,
2730 FpuRoundMode::Zero32 => 0b000_11110_00_1_001_011_10000,
2731 FpuRoundMode::Zero64 => 0b000_11110_01_1_001_011_10000,
2732 FpuRoundMode::Nearest32 => 0b000_11110_00_1_001_000_10000,
2733 FpuRoundMode::Nearest64 => 0b000_11110_01_1_001_000_10000,
2734 };
2735 sink.put4(enc_fround(top22, rd, rn));
2736 }
2737 &Inst::MovToFpu { rd, rn, size } => {
2738 let template = match size {
2739 ScalarSize::Size16 => 0b000_11110_11_1_00_111_000000_00000_00000,
2740 ScalarSize::Size32 => 0b000_11110_00_1_00_111_000000_00000_00000,
2741 ScalarSize::Size64 => 0b100_11110_01_1_00_111_000000_00000_00000,
2742 _ => unreachable!(),
2743 };
2744 sink.put4(template | (machreg_to_gpr(rn) << 5) | machreg_to_vec(rd.to_reg()));
2745 }
2746 &Inst::FpuMoveFPImm { rd, imm, size } => {
2747 sink.put4(
2748 0b000_11110_00_1_00_000_000100_00000_00000
2749 | size.ftype() << 22
2750 | ((imm.enc_bits() as u32) << 13)
2751 | machreg_to_vec(rd.to_reg()),
2752 );
2753 }
2754 &Inst::MovToVec {
2755 rd,
2756 ri,
2757 rn,
2758 idx,
2759 size,
2760 } => {
2761 debug_assert_eq!(rd.to_reg(), ri);
2762 let (imm5, shift) = match size.lane_size() {
2763 ScalarSize::Size8 => (0b00001, 1),
2764 ScalarSize::Size16 => (0b00010, 2),
2765 ScalarSize::Size32 => (0b00100, 3),
2766 ScalarSize::Size64 => (0b01000, 4),
2767 _ => unreachable!(),
2768 };
2769 debug_assert_eq!(idx & (0b11111 >> shift), idx);
2770 let imm5 = imm5 | ((idx as u32) << shift);
2771 sink.put4(
2772 0b010_01110000_00000_0_0011_1_00000_00000
2773 | (imm5 << 16)
2774 | (machreg_to_gpr(rn) << 5)
2775 | machreg_to_vec(rd.to_reg()),
2776 );
2777 }
2778 &Inst::MovFromVec { rd, rn, idx, size } => {
2779 let (q, imm5, shift, mask) = match size {
2780 ScalarSize::Size8 => (0b0, 0b00001, 1, 0b1111),
2781 ScalarSize::Size16 => (0b0, 0b00010, 2, 0b0111),
2782 ScalarSize::Size32 => (0b0, 0b00100, 3, 0b0011),
2783 ScalarSize::Size64 => (0b1, 0b01000, 4, 0b0001),
2784 _ => panic!("Unexpected scalar FP operand size: {size:?}"),
2785 };
2786 debug_assert_eq!(idx & mask, idx);
2787 let imm5 = imm5 | ((idx as u32) << shift);
2788 sink.put4(
2789 0b000_01110000_00000_0_0111_1_00000_00000
2790 | (q << 30)
2791 | (imm5 << 16)
2792 | (machreg_to_vec(rn) << 5)
2793 | machreg_to_gpr(rd.to_reg()),
2794 );
2795 }
2796 &Inst::MovFromVecSigned {
2797 rd,
2798 rn,
2799 idx,
2800 size,
2801 scalar_size,
2802 } => {
2803 let (imm5, shift, half) = match size {
2804 VectorSize::Size8x8 => (0b00001, 1, true),
2805 VectorSize::Size8x16 => (0b00001, 1, false),
2806 VectorSize::Size16x4 => (0b00010, 2, true),
2807 VectorSize::Size16x8 => (0b00010, 2, false),
2808 VectorSize::Size32x2 => {
2809 debug_assert_ne!(scalar_size, OperandSize::Size32);
2810 (0b00100, 3, true)
2811 }
2812 VectorSize::Size32x4 => {
2813 debug_assert_ne!(scalar_size, OperandSize::Size32);
2814 (0b00100, 3, false)
2815 }
2816 _ => panic!("Unexpected vector operand size"),
2817 };
2818 debug_assert_eq!(idx & (0b11111 >> (half as u32 + shift)), idx);
2819 let imm5 = imm5 | ((idx as u32) << shift);
2820 sink.put4(
2821 0b000_01110000_00000_0_0101_1_00000_00000
2822 | (scalar_size.is64() as u32) << 30
2823 | (imm5 << 16)
2824 | (machreg_to_vec(rn) << 5)
2825 | machreg_to_gpr(rd.to_reg()),
2826 );
2827 }
2828 &Inst::VecDup { rd, rn, size } => {
2829 let q = size.is_128bits() as u32;
2830 let imm5 = match size.lane_size() {
2831 ScalarSize::Size8 => 0b00001,
2832 ScalarSize::Size16 => 0b00010,
2833 ScalarSize::Size32 => 0b00100,
2834 ScalarSize::Size64 => 0b01000,
2835 _ => unreachable!(),
2836 };
2837 sink.put4(
2838 0b0_0_0_01110000_00000_000011_00000_00000
2839 | (q << 30)
2840 | (imm5 << 16)
2841 | (machreg_to_gpr(rn) << 5)
2842 | machreg_to_vec(rd.to_reg()),
2843 );
2844 }
2845 &Inst::VecDupFromFpu { rd, rn, size, lane } => {
2846 let q = size.is_128bits() as u32;
2847 let imm5 = match size.lane_size() {
2848 ScalarSize::Size8 => {
2849 assert!(lane < 16);
2850 0b00001 | (u32::from(lane) << 1)
2851 }
2852 ScalarSize::Size16 => {
2853 assert!(lane < 8);
2854 0b00010 | (u32::from(lane) << 2)
2855 }
2856 ScalarSize::Size32 => {
2857 assert!(lane < 4);
2858 0b00100 | (u32::from(lane) << 3)
2859 }
2860 ScalarSize::Size64 => {
2861 assert!(lane < 2);
2862 0b01000 | (u32::from(lane) << 4)
2863 }
2864 _ => unimplemented!(),
2865 };
2866 sink.put4(
2867 0b000_01110000_00000_000001_00000_00000
2868 | (q << 30)
2869 | (imm5 << 16)
2870 | (machreg_to_vec(rn) << 5)
2871 | machreg_to_vec(rd.to_reg()),
2872 );
2873 }
2874 &Inst::VecDupFPImm { rd, imm, size } => {
2875 let imm = imm.enc_bits();
2876 let op = match size.lane_size() {
2877 ScalarSize::Size32 => 0,
2878 ScalarSize::Size64 => 1,
2879 _ => unimplemented!(),
2880 };
2881 let q_op = op | ((size.is_128bits() as u32) << 1);
2882
2883 sink.put4(enc_asimd_mod_imm(rd, q_op, 0b1111, imm));
2884 }
2885 &Inst::VecDupImm {
2886 rd,
2887 imm,
2888 invert,
2889 size,
2890 } => {
2891 let (imm, shift, shift_ones) = imm.value();
2892 let (op, cmode) = match size.lane_size() {
2893 ScalarSize::Size8 => {
2894 assert!(!invert);
2895 assert_eq!(shift, 0);
2896
2897 (0, 0b1110)
2898 }
2899 ScalarSize::Size16 => {
2900 let s = shift & 8;
2901
2902 assert!(!shift_ones);
2903 assert_eq!(s, shift);
2904
2905 (invert as u32, 0b1000 | (s >> 2))
2906 }
2907 ScalarSize::Size32 => {
2908 if shift_ones {
2909 assert!(shift == 8 || shift == 16);
2910
2911 (invert as u32, 0b1100 | (shift >> 4))
2912 } else {
2913 let s = shift & 24;
2914
2915 assert_eq!(s, shift);
2916
2917 (invert as u32, 0b0000 | (s >> 2))
2918 }
2919 }
2920 ScalarSize::Size64 => {
2921 assert!(!invert);
2922 assert_eq!(shift, 0);
2923
2924 (1, 0b1110)
2925 }
2926 _ => unreachable!(),
2927 };
2928 let q_op = op | ((size.is_128bits() as u32) << 1);
2929
2930 sink.put4(enc_asimd_mod_imm(rd, q_op, cmode, imm));
2931 }
2932 &Inst::VecExtend {
2933 t,
2934 rd,
2935 rn,
2936 high_half,
2937 lane_size,
2938 } => {
2939 let immh = match lane_size {
2940 ScalarSize::Size16 => 0b001,
2941 ScalarSize::Size32 => 0b010,
2942 ScalarSize::Size64 => 0b100,
2943 _ => panic!("Unexpected VecExtend to lane size of {lane_size:?}"),
2944 };
2945 let u = match t {
2946 VecExtendOp::Sxtl => 0b0,
2947 VecExtendOp::Uxtl => 0b1,
2948 };
2949 sink.put4(
2950 0b000_011110_0000_000_101001_00000_00000
2951 | ((high_half as u32) << 30)
2952 | (u << 29)
2953 | (immh << 19)
2954 | (machreg_to_vec(rn) << 5)
2955 | machreg_to_vec(rd.to_reg()),
2956 );
2957 }
2958 &Inst::VecRRLong {
2959 op,
2960 rd,
2961 rn,
2962 high_half,
2963 } => {
2964 let (u, size, bits_12_16) = match op {
2965 VecRRLongOp::Fcvtl16 => (0b0, 0b00, 0b10111),
2966 VecRRLongOp::Fcvtl32 => (0b0, 0b01, 0b10111),
2967 VecRRLongOp::Shll8 => (0b1, 0b00, 0b10011),
2968 VecRRLongOp::Shll16 => (0b1, 0b01, 0b10011),
2969 VecRRLongOp::Shll32 => (0b1, 0b10, 0b10011),
2970 };
2971
2972 sink.put4(enc_vec_rr_misc(
2973 ((high_half as u32) << 1) | u,
2974 size,
2975 bits_12_16,
2976 rd,
2977 rn,
2978 ));
2979 }
2980 &Inst::VecRRNarrowLow {
2981 op,
2982 rd,
2983 rn,
2984 lane_size,
2985 }
2986 | &Inst::VecRRNarrowHigh {
2987 op,
2988 rd,
2989 rn,
2990 lane_size,
2991 ..
2992 } => {
2993 let high_half = match self {
2994 &Inst::VecRRNarrowLow { .. } => false,
2995 &Inst::VecRRNarrowHigh { .. } => true,
2996 _ => unreachable!(),
2997 };
2998
2999 let size = match lane_size {
3000 ScalarSize::Size8 => 0b00,
3001 ScalarSize::Size16 => 0b01,
3002 ScalarSize::Size32 => 0b10,
3003 _ => panic!("unsupported size: {lane_size:?}"),
3004 };
3005
3006 let size = match op {
3008 VecRRNarrowOp::Fcvtn => size >> 1,
3009 _ => size,
3010 };
3011
3012 let (u, bits_12_16) = match op {
3013 VecRRNarrowOp::Xtn => (0b0, 0b10010),
3014 VecRRNarrowOp::Sqxtn => (0b0, 0b10100),
3015 VecRRNarrowOp::Sqxtun => (0b1, 0b10010),
3016 VecRRNarrowOp::Uqxtn => (0b1, 0b10100),
3017 VecRRNarrowOp::Fcvtn => (0b0, 0b10110),
3018 };
3019
3020 sink.put4(enc_vec_rr_misc(
3021 ((high_half as u32) << 1) | u,
3022 size,
3023 bits_12_16,
3024 rd,
3025 rn,
3026 ));
3027 }
3028 &Inst::VecMovElement {
3029 rd,
3030 ri,
3031 rn,
3032 dest_idx,
3033 src_idx,
3034 size,
3035 } => {
3036 debug_assert_eq!(rd.to_reg(), ri);
3037 let (imm5, shift) = match size.lane_size() {
3038 ScalarSize::Size8 => (0b00001, 1),
3039 ScalarSize::Size16 => (0b00010, 2),
3040 ScalarSize::Size32 => (0b00100, 3),
3041 ScalarSize::Size64 => (0b01000, 4),
3042 _ => unreachable!(),
3043 };
3044 let mask = 0b11111 >> shift;
3045 debug_assert_eq!(dest_idx & mask, dest_idx);
3046 debug_assert_eq!(src_idx & mask, src_idx);
3047 let imm4 = (src_idx as u32) << (shift - 1);
3048 let imm5 = imm5 | ((dest_idx as u32) << shift);
3049 sink.put4(
3050 0b011_01110000_00000_0_0000_1_00000_00000
3051 | (imm5 << 16)
3052 | (imm4 << 11)
3053 | (machreg_to_vec(rn) << 5)
3054 | machreg_to_vec(rd.to_reg()),
3055 );
3056 }
3057 &Inst::VecRRPair { op, rd, rn } => {
3058 let bits_12_16 = match op {
3059 VecPairOp::Addp => 0b11011,
3060 };
3061
3062 sink.put4(enc_vec_rr_pair(bits_12_16, rd, rn));
3063 }
3064 &Inst::VecRRRLong {
3065 rd,
3066 rn,
3067 rm,
3068 alu_op,
3069 high_half,
3070 } => {
3071 let (u, size, bit14) = match alu_op {
3072 VecRRRLongOp::Smull8 => (0b0, 0b00, 0b1),
3073 VecRRRLongOp::Smull16 => (0b0, 0b01, 0b1),
3074 VecRRRLongOp::Smull32 => (0b0, 0b10, 0b1),
3075 VecRRRLongOp::Umull8 => (0b1, 0b00, 0b1),
3076 VecRRRLongOp::Umull16 => (0b1, 0b01, 0b1),
3077 VecRRRLongOp::Umull32 => (0b1, 0b10, 0b1),
3078 };
3079 sink.put4(enc_vec_rrr_long(
3080 high_half as u32,
3081 u,
3082 size,
3083 bit14,
3084 rm,
3085 rn,
3086 rd,
3087 ));
3088 }
3089 &Inst::VecRRRLongMod {
3090 rd,
3091 ri,
3092 rn,
3093 rm,
3094 alu_op,
3095 high_half,
3096 } => {
3097 debug_assert_eq!(rd.to_reg(), ri);
3098 let (u, size, bit14) = match alu_op {
3099 VecRRRLongModOp::Umlal8 => (0b1, 0b00, 0b0),
3100 VecRRRLongModOp::Umlal16 => (0b1, 0b01, 0b0),
3101 VecRRRLongModOp::Umlal32 => (0b1, 0b10, 0b0),
3102 };
3103 sink.put4(enc_vec_rrr_long(
3104 high_half as u32,
3105 u,
3106 size,
3107 bit14,
3108 rm,
3109 rn,
3110 rd,
3111 ));
3112 }
3113 &Inst::VecRRPairLong { op, rd, rn } => {
3114 let (u, size) = match op {
3115 VecRRPairLongOp::Saddlp8 => (0b0, 0b0),
3116 VecRRPairLongOp::Uaddlp8 => (0b1, 0b0),
3117 VecRRPairLongOp::Saddlp16 => (0b0, 0b1),
3118 VecRRPairLongOp::Uaddlp16 => (0b1, 0b1),
3119 };
3120
3121 sink.put4(enc_vec_rr_pair_long(u, size, rd, rn));
3122 }
3123 &Inst::VecRRR {
3124 rd,
3125 rn,
3126 rm,
3127 alu_op,
3128 size,
3129 } => {
3130 let (q, enc_size) = size.enc_size();
3131 let is_float = match alu_op {
3132 VecALUOp::Fcmeq
3133 | VecALUOp::Fcmgt
3134 | VecALUOp::Fcmge
3135 | VecALUOp::Fadd
3136 | VecALUOp::Fsub
3137 | VecALUOp::Fdiv
3138 | VecALUOp::Fmax
3139 | VecALUOp::Fmin
3140 | VecALUOp::Fmul => true,
3141 _ => false,
3142 };
3143
3144 let (top11, bit15_10) = match alu_op {
3145 VecALUOp::Sqadd => (0b000_01110_00_1 | enc_size << 1, 0b000011),
3146 VecALUOp::Sqsub => (0b000_01110_00_1 | enc_size << 1, 0b001011),
3147 VecALUOp::Uqadd => (0b001_01110_00_1 | enc_size << 1, 0b000011),
3148 VecALUOp::Uqsub => (0b001_01110_00_1 | enc_size << 1, 0b001011),
3149 VecALUOp::Cmeq => (0b001_01110_00_1 | enc_size << 1, 0b100011),
3150 VecALUOp::Cmge => (0b000_01110_00_1 | enc_size << 1, 0b001111),
3151 VecALUOp::Cmgt => (0b000_01110_00_1 | enc_size << 1, 0b001101),
3152 VecALUOp::Cmhi => (0b001_01110_00_1 | enc_size << 1, 0b001101),
3153 VecALUOp::Cmhs => (0b001_01110_00_1 | enc_size << 1, 0b001111),
3154 VecALUOp::Fcmeq => (0b000_01110_00_1, 0b111001),
3155 VecALUOp::Fcmgt => (0b001_01110_10_1, 0b111001),
3156 VecALUOp::Fcmge => (0b001_01110_00_1, 0b111001),
3157 VecALUOp::And => (0b000_01110_00_1, 0b000111),
3160 VecALUOp::Bic => (0b000_01110_01_1, 0b000111),
3161 VecALUOp::Orr => (0b000_01110_10_1, 0b000111),
3162 VecALUOp::Orn => (0b000_01110_11_1, 0b000111),
3163 VecALUOp::Eor => (0b001_01110_00_1, 0b000111),
3164 VecALUOp::Umaxp => {
3165 debug_assert_ne!(size, VectorSize::Size64x2);
3166
3167 (0b001_01110_00_1 | enc_size << 1, 0b101001)
3168 }
3169 VecALUOp::Add => (0b000_01110_00_1 | enc_size << 1, 0b100001),
3170 VecALUOp::Sub => (0b001_01110_00_1 | enc_size << 1, 0b100001),
3171 VecALUOp::Mul => {
3172 debug_assert_ne!(size, VectorSize::Size64x2);
3173 (0b000_01110_00_1 | enc_size << 1, 0b100111)
3174 }
3175 VecALUOp::Sshl => (0b000_01110_00_1 | enc_size << 1, 0b010001),
3176 VecALUOp::Ushl => (0b001_01110_00_1 | enc_size << 1, 0b010001),
3177 VecALUOp::Umin => {
3178 debug_assert_ne!(size, VectorSize::Size64x2);
3179
3180 (0b001_01110_00_1 | enc_size << 1, 0b011011)
3181 }
3182 VecALUOp::Smin => {
3183 debug_assert_ne!(size, VectorSize::Size64x2);
3184
3185 (0b000_01110_00_1 | enc_size << 1, 0b011011)
3186 }
3187 VecALUOp::Umax => {
3188 debug_assert_ne!(size, VectorSize::Size64x2);
3189
3190 (0b001_01110_00_1 | enc_size << 1, 0b011001)
3191 }
3192 VecALUOp::Smax => {
3193 debug_assert_ne!(size, VectorSize::Size64x2);
3194
3195 (0b000_01110_00_1 | enc_size << 1, 0b011001)
3196 }
3197 VecALUOp::Urhadd => {
3198 debug_assert_ne!(size, VectorSize::Size64x2);
3199
3200 (0b001_01110_00_1 | enc_size << 1, 0b000101)
3201 }
3202 VecALUOp::Fadd => (0b000_01110_00_1, 0b110101),
3203 VecALUOp::Fsub => (0b000_01110_10_1, 0b110101),
3204 VecALUOp::Fdiv => (0b001_01110_00_1, 0b111111),
3205 VecALUOp::Fmax => (0b000_01110_00_1, 0b111101),
3206 VecALUOp::Fmin => (0b000_01110_10_1, 0b111101),
3207 VecALUOp::Fmul => (0b001_01110_00_1, 0b110111),
3208 VecALUOp::Addp => (0b000_01110_00_1 | enc_size << 1, 0b101111),
3209 VecALUOp::Zip1 => (0b01001110_00_0 | enc_size << 1, 0b001110),
3210 VecALUOp::Zip2 => (0b01001110_00_0 | enc_size << 1, 0b011110),
3211 VecALUOp::Sqrdmulh => {
3212 debug_assert!(
3213 size.lane_size() == ScalarSize::Size16
3214 || size.lane_size() == ScalarSize::Size32
3215 );
3216
3217 (0b001_01110_00_1 | enc_size << 1, 0b101101)
3218 }
3219 VecALUOp::Uzp1 => (0b01001110_00_0 | enc_size << 1, 0b000110),
3220 VecALUOp::Uzp2 => (0b01001110_00_0 | enc_size << 1, 0b010110),
3221 VecALUOp::Trn1 => (0b01001110_00_0 | enc_size << 1, 0b001010),
3222 VecALUOp::Trn2 => (0b01001110_00_0 | enc_size << 1, 0b011010),
3223 };
3224 let top11 = if is_float {
3225 top11 | size.enc_float_size() << 1
3226 } else {
3227 top11
3228 };
3229 sink.put4(enc_vec_rrr(top11 | q << 9, rm, bit15_10, rn, rd));
3230 }
3231 &Inst::VecRRRMod {
3232 rd,
3233 ri,
3234 rn,
3235 rm,
3236 alu_op,
3237 size,
3238 } => {
3239 debug_assert_eq!(rd.to_reg(), ri);
3240 let (q, _enc_size) = size.enc_size();
3241
3242 let (top11, bit15_10) = match alu_op {
3243 VecALUModOp::Bsl => (0b001_01110_01_1, 0b000111),
3244 VecALUModOp::Fmla => {
3245 (0b000_01110_00_1 | (size.enc_float_size() << 1), 0b110011)
3246 }
3247 VecALUModOp::Fmls => {
3248 (0b000_01110_10_1 | (size.enc_float_size() << 1), 0b110011)
3249 }
3250 VecALUModOp::Sdot => (0b000_01110_10_0, 0b100101),
3255 VecALUModOp::Usdot => (0b000_01110_10_0, 0b100111),
3258 };
3259 sink.put4(enc_vec_rrr(top11 | q << 9, rm, bit15_10, rn, rd));
3260 }
3261 &Inst::VecFmlaElem {
3262 rd,
3263 ri,
3264 rn,
3265 rm,
3266 alu_op,
3267 size,
3268 idx,
3269 } => {
3270 debug_assert_eq!(rd.to_reg(), ri);
3271 let idx = u32::from(idx);
3272
3273 let (q, _size) = size.enc_size();
3274 let o2 = match alu_op {
3275 VecALUModOp::Fmla => 0b0,
3276 VecALUModOp::Fmls => 0b1,
3277 _ => unreachable!(),
3278 };
3279
3280 let (h, l) = match size {
3281 VectorSize::Size32x4 => {
3282 assert!(idx < 4);
3283 (idx >> 1, idx & 1)
3284 }
3285 VectorSize::Size64x2 => {
3286 assert!(idx < 2);
3287 (idx, 0)
3288 }
3289 _ => unreachable!(),
3290 };
3291
3292 let top11 = 0b000_011111_00 | (q << 9) | (size.enc_float_size() << 1) | l;
3293 let bit15_10 = 0b000100 | (o2 << 4) | (h << 1);
3294 sink.put4(enc_vec_rrr(top11, rm, bit15_10, rn, rd));
3295 }
3296 &Inst::VecLoadReplicate {
3297 rd,
3298 rn,
3299 size,
3300 flags,
3301 } => {
3302 let (q, size) = size.enc_size();
3303
3304 if let Some(trap_code) = flags.trap_code() {
3305 sink.add_trap(trap_code);
3307 }
3308
3309 sink.put4(enc_ldst_vec(q, size, rn, rd));
3310 }
3311 &Inst::VecCSel { rd, rn, rm, cond } => {
3312 let else_label = sink.get_label();
3323 let out_label = sink.get_label();
3324
3325 let br_else_offset = sink.cur_offset();
3327 sink.put4(enc_conditional_br(
3328 BranchTarget::Label(else_label),
3329 CondBrKind::Cond(cond),
3330 ));
3331 sink.use_label_at_offset(br_else_offset, else_label, LabelUse::Branch19);
3332
3333 sink.put4(enc_vecmov(true, rd, rm));
3335
3336 let b_out_offset = sink.cur_offset();
3338 sink.use_label_at_offset(b_out_offset, out_label, LabelUse::Branch26);
3339 sink.add_uncond_branch(b_out_offset, b_out_offset + 4, out_label);
3340 sink.put4(enc_jump26(0b000101, 0 ));
3341
3342 sink.bind_label(else_label, &mut state.ctrl_plane);
3344
3345 sink.put4(enc_vecmov(true, rd, rn));
3347
3348 sink.bind_label(out_label, &mut state.ctrl_plane);
3350 }
3351 &Inst::MovToNZCV { rn } => {
3352 sink.put4(0xd51b4200 | machreg_to_gpr(rn));
3353 }
3354 &Inst::MovFromNZCV { rd } => {
3355 sink.put4(0xd53b4200 | machreg_to_gpr(rd.to_reg()));
3356 }
3357 &Inst::Extend {
3358 rd,
3359 rn,
3360 signed: false,
3361 from_bits: 1,
3362 to_bits,
3363 } => {
3364 assert!(to_bits <= 64);
3365 let imml = ImmLogic::maybe_from_u64(1, I32).unwrap();
3370 Inst::AluRRImmLogic {
3371 alu_op: ALUOp::And,
3372 size: OperandSize::Size32,
3373 rd,
3374 rn,
3375 imml,
3376 }
3377 .emit(sink, emit_info, state);
3378 }
3379 &Inst::Extend {
3380 rd,
3381 rn,
3382 signed: false,
3383 from_bits: 32,
3384 to_bits: 64,
3385 } => {
3386 let mov = Inst::Mov {
3387 size: OperandSize::Size32,
3388 rd,
3389 rm: rn,
3390 };
3391 mov.emit(sink, emit_info, state);
3392 }
3393 &Inst::Extend {
3394 rd,
3395 rn,
3396 signed,
3397 from_bits,
3398 to_bits,
3399 } => {
3400 let (bfm_op, size) = if signed {
3401 (BfmOp::SBfm, OperandSize::from_bits(to_bits))
3402 } else {
3403 (BfmOp::UBfm, OperandSize::Size32)
3404 };
3405 let opc = bfm_op.opc();
3406 sink.put4(enc_bfm(opc, size, rd, rn, 0, from_bits - 1));
3407 }
3408 &Inst::BitfieldMove {
3409 size,
3410 bfm_op,
3411 rd,
3412 rn,
3413 immr,
3414 imms,
3415 } => {
3416 let opc = bfm_op.opc();
3417 sink.put4(enc_bfm(opc, size, rd, rn, immr.value(), imms.value()));
3418 }
3419 &Inst::BitfieldMoveMod {
3420 size,
3421 rd,
3422 ri,
3423 rn,
3424 immr,
3425 imms,
3426 } => {
3427 debug_assert_eq!(rd.to_reg(), ri);
3428 sink.put4(enc_bfm(0b01, size, rd, rn, immr.value(), imms.value()));
3429 }
3430 &Inst::Jump { ref dest } => {
3431 let off = sink.cur_offset();
3432 if let Some(l) = dest.as_label() {
3434 sink.use_label_at_offset(off, l, LabelUse::Branch26);
3435 sink.add_uncond_branch(off, off + 4, l);
3436 }
3437 sink.put4(enc_jump26(0b000101, dest.as_offset26_or_zero()));
3439 }
3440 &Inst::Args { .. } | &Inst::Rets { .. } => {
3441 }
3444 &Inst::Ret {} => {
3445 sink.put4(0xd65f03c0);
3446 }
3447 &Inst::AuthenticatedRet { key, is_hint } => {
3448 let (op2, is_hint) = match key {
3449 APIKey::AZ => (0b100, true),
3450 APIKey::ASP => (0b101, is_hint),
3451 APIKey::BZ => (0b110, true),
3452 APIKey::BSP => (0b111, is_hint),
3453 };
3454
3455 if is_hint {
3456 sink.put4(key.enc_auti_hint());
3457 Inst::Ret {}.emit(sink, emit_info, state);
3458 } else {
3459 sink.put4(0xd65f0bff | (op2 << 9)); }
3461 }
3462 &Inst::Call { ref info } => {
3463 let start = sink.cur_offset();
3464 let user_stack_map = state.take_stack_map();
3465 sink.add_reloc(Reloc::Arm64Call, &info.dest, 0);
3466 sink.put4(enc_jump26(0b100101, 0));
3467 if let Some(s) = user_stack_map {
3468 let offset = sink.cur_offset();
3469 sink.push_user_stack_map(state, offset, s);
3470 }
3471
3472 if let Some(try_call) = info.try_call_info.as_ref() {
3473 sink.add_try_call_site(
3474 Some(state.frame_layout.sp_to_fp()),
3475 try_call.exception_handlers(&state.frame_layout),
3476 );
3477 } else {
3478 sink.add_call_site();
3479 }
3480
3481 if info.callee_pop_size > 0 {
3482 let callee_pop_size =
3483 i32::try_from(info.callee_pop_size).expect("callee popped more than 2GB");
3484 for inst in AArch64MachineDeps::gen_sp_reg_adjust(-callee_pop_size) {
3485 inst.emit(sink, emit_info, state);
3486 }
3487 }
3488
3489 if info.patchable {
3490 sink.add_patchable_call_site(sink.cur_offset() - start);
3491 } else {
3492 info.emit_retval_loads::<AArch64MachineDeps, _, _>(
3494 state.frame_layout().stackslots_size,
3495 |inst| inst.emit(sink, emit_info, state),
3496 |needed_space| Some(Inst::EmitIsland { needed_space }),
3497 );
3498 }
3499
3500 if let Some(try_call) = info.try_call_info.as_ref() {
3503 let jmp = Inst::Jump {
3504 dest: BranchTarget::Label(try_call.continuation),
3505 };
3506 jmp.emit(sink, emit_info, state);
3507 }
3508
3509 start_off = sink.cur_offset();
3512 }
3513 &Inst::CallInd { ref info } => {
3514 let user_stack_map = state.take_stack_map();
3515 sink.put4(
3516 0b1101011_0001_11111_000000_00000_00000 | (machreg_to_gpr(info.dest) << 5),
3517 );
3518 if let Some(s) = user_stack_map {
3519 let offset = sink.cur_offset();
3520 sink.push_user_stack_map(state, offset, s);
3521 }
3522
3523 if let Some(try_call) = info.try_call_info.as_ref() {
3524 sink.add_try_call_site(
3525 Some(state.frame_layout.sp_to_fp()),
3526 try_call.exception_handlers(&state.frame_layout),
3527 );
3528 } else {
3529 sink.add_call_site();
3530 }
3531
3532 if info.callee_pop_size > 0 {
3533 let callee_pop_size =
3534 i32::try_from(info.callee_pop_size).expect("callee popped more than 2GB");
3535 for inst in AArch64MachineDeps::gen_sp_reg_adjust(-callee_pop_size) {
3536 inst.emit(sink, emit_info, state);
3537 }
3538 }
3539
3540 info.emit_retval_loads::<AArch64MachineDeps, _, _>(
3542 state.frame_layout().stackslots_size,
3543 |inst| inst.emit(sink, emit_info, state),
3544 |needed_space| Some(Inst::EmitIsland { needed_space }),
3545 );
3546
3547 if let Some(try_call) = info.try_call_info.as_ref() {
3550 let jmp = Inst::Jump {
3551 dest: BranchTarget::Label(try_call.continuation),
3552 };
3553 jmp.emit(sink, emit_info, state);
3554 }
3555
3556 start_off = sink.cur_offset();
3559 }
3560 &Inst::ReturnCall { ref info } => {
3561 emit_return_call_common_sequence(sink, emit_info, state, info);
3562
3563 sink.add_reloc(Reloc::Arm64Call, &info.dest, 0);
3567 sink.put4(enc_jump26(0b000101, 0));
3568 sink.add_call_site();
3569
3570 start_off = sink.cur_offset();
3574 }
3575 &Inst::ReturnCallInd { ref info } => {
3576 emit_return_call_common_sequence(sink, emit_info, state, info);
3577
3578 Inst::IndirectBr {
3579 rn: info.dest,
3580 targets: vec![],
3581 }
3582 .emit(sink, emit_info, state);
3583 sink.add_call_site();
3584
3585 start_off = sink.cur_offset();
3589 }
3590 &Inst::CondBr {
3591 taken,
3592 not_taken,
3593 kind,
3594 } => {
3595 let cond_off = sink.cur_offset();
3597 if let Some(l) = taken.as_label() {
3598 sink.use_label_at_offset(cond_off, l, LabelUse::Branch19);
3599 let inverted = enc_conditional_br(taken, kind.invert()).to_le_bytes();
3600 sink.add_cond_branch(cond_off, cond_off + 4, l, &inverted[..]);
3601 }
3602 sink.put4(enc_conditional_br(taken, kind));
3603
3604 let uncond_off = sink.cur_offset();
3606 if let Some(l) = not_taken.as_label() {
3607 sink.use_label_at_offset(uncond_off, l, LabelUse::Branch26);
3608 sink.add_uncond_branch(uncond_off, uncond_off + 4, l);
3609 }
3610 sink.put4(enc_jump26(0b000101, not_taken.as_offset26_or_zero()));
3611 }
3612 &Inst::TestBitAndBranch {
3613 taken,
3614 not_taken,
3615 kind,
3616 rn,
3617 bit,
3618 } => {
3619 let cond_off = sink.cur_offset();
3621 if let Some(l) = taken.as_label() {
3622 sink.use_label_at_offset(cond_off, l, LabelUse::Branch14);
3623 let inverted =
3624 enc_test_bit_and_branch(kind.complement(), taken, rn, bit).to_le_bytes();
3625 sink.add_cond_branch(cond_off, cond_off + 4, l, &inverted[..]);
3626 }
3627 sink.put4(enc_test_bit_and_branch(kind, taken, rn, bit));
3628
3629 let uncond_off = sink.cur_offset();
3631 if let Some(l) = not_taken.as_label() {
3632 sink.use_label_at_offset(uncond_off, l, LabelUse::Branch26);
3633 sink.add_uncond_branch(uncond_off, uncond_off + 4, l);
3634 }
3635 sink.put4(enc_jump26(0b000101, not_taken.as_offset26_or_zero()));
3636 }
3637 &Inst::TrapIf { kind, trap_code } => {
3638 let label = sink.defer_trap(trap_code);
3639 let off = sink.cur_offset();
3641 sink.put4(enc_conditional_br(BranchTarget::Label(label), kind));
3642 sink.use_label_at_offset(off, label, LabelUse::Branch19);
3643 }
3644 &Inst::IndirectBr { rn, .. } => {
3645 sink.put4(enc_br(rn));
3646 }
3647 &Inst::Nop0 => {}
3648 &Inst::Nop4 => {
3649 sink.put4(0xd503201f);
3650 }
3651 &Inst::Brk => {
3652 sink.put4(0xd43e0000);
3653 }
3654 &Inst::Udf { trap_code } => {
3655 sink.add_trap(trap_code);
3656 sink.put_data(Inst::TRAP_OPCODE);
3657 }
3658 &Inst::Adr { rd, off } => {
3659 assert!(off > -(1 << 20));
3660 assert!(off < (1 << 20));
3661 sink.put4(enc_adr(off, rd));
3662 }
3663 &Inst::Adrp { rd, off } => {
3664 assert!(off > -(1 << 20));
3665 assert!(off < (1 << 20));
3666 sink.put4(enc_adrp(off, rd));
3667 }
3668 &Inst::Word4 { data } => {
3669 sink.put4(data);
3670 }
3671 &Inst::Word8 { data } => {
3672 sink.put8(data);
3673 }
3674 &Inst::JTSequence {
3675 ridx,
3676 rtmp1,
3677 rtmp2,
3678 default,
3679 ref targets,
3680 ..
3681 } => {
3682 let br =
3688 enc_conditional_br(BranchTarget::Label(default), CondBrKind::Cond(Cond::Hs));
3689
3690 let default_br_offset = sink.cur_offset();
3694 sink.use_label_at_offset(default_br_offset, default, LabelUse::Branch19);
3695 sink.put4(br);
3696
3697 let inst = Inst::CSel {
3701 rd: rtmp2,
3702 cond: Cond::Hs,
3703 rn: zero_reg(),
3704 rm: ridx,
3705 };
3706 inst.emit(sink, emit_info, state);
3707 if emit_info.flags.enable_table_access_spectre_mitigation()
3710 && emit_info.isa_flags.use_csdb()
3711 {
3712 Inst::Csdb.emit(sink, emit_info, state);
3713 }
3714
3715 let inst = Inst::Adr { rd: rtmp1, off: 16 };
3717 inst.emit(sink, emit_info, state);
3718 let inst = Inst::SLoad32 {
3720 rd: rtmp2,
3721 mem: AMode::reg_plus_reg_scaled_extended(
3722 rtmp1.to_reg(),
3723 rtmp2.to_reg(),
3724 ExtendOp::UXTW,
3725 ),
3726 flags: MemFlagsData::trusted(),
3727 };
3728 inst.emit(sink, emit_info, state);
3729 let inst = Inst::AluRRR {
3731 alu_op: ALUOp::Add,
3732 size: OperandSize::Size64,
3733 rd: rtmp1,
3734 rn: rtmp1.to_reg(),
3735 rm: rtmp2.to_reg(),
3736 };
3737 inst.emit(sink, emit_info, state);
3738 let inst = Inst::IndirectBr {
3741 rn: rtmp1.to_reg(),
3742 targets: vec![],
3743 };
3744 inst.emit(sink, emit_info, state);
3745 let jt_off = sink.cur_offset();
3747 for &target in targets.iter() {
3748 let word_off = sink.cur_offset();
3749 let off_into_table = word_off - jt_off;
3754 sink.use_label_at_offset(word_off, target, LabelUse::PCRel32);
3755 sink.put4(off_into_table);
3756 }
3757
3758 start_off = sink.cur_offset();
3761 }
3762 &Inst::LoadExtNameGot { rd, ref name } => {
3763 sink.add_reloc(Reloc::Aarch64AdrGotPage21, &**name, 0);
3772 let inst = Inst::Adrp { rd, off: 0 };
3773 inst.emit(sink, emit_info, state);
3774
3775 sink.add_reloc(Reloc::Aarch64Ld64GotLo12Nc, &**name, 0);
3777 let inst = Inst::ULoad64 {
3778 rd,
3779 mem: AMode::reg(rd.to_reg()),
3780 flags: MemFlagsData::trusted(),
3781 };
3782 inst.emit(sink, emit_info, state);
3783 }
3784 &Inst::LoadExtNameNear {
3785 rd,
3786 ref name,
3787 offset,
3788 } => {
3789 sink.add_reloc(Reloc::Aarch64AdrPrelPgHi21, &**name, offset);
3797 let inst = Inst::Adrp { rd, off: 0 };
3798 inst.emit(sink, emit_info, state);
3799
3800 sink.add_reloc(Reloc::Aarch64AddAbsLo12Nc, &**name, offset);
3802 let inst = Inst::AluRRImm12 {
3803 alu_op: ALUOp::Add,
3804 size: OperandSize::Size64,
3805 rd,
3806 rn: rd.to_reg(),
3807 imm12: Imm12::ZERO,
3808 };
3809 inst.emit(sink, emit_info, state);
3810 }
3811 &Inst::LoadExtNameFar {
3812 rd,
3813 ref name,
3814 offset,
3815 } => {
3816 let inst = Inst::ULoad64 {
3825 rd,
3826 mem: AMode::Label {
3827 label: MemLabel::PCRel(8),
3828 },
3829 flags: MemFlagsData::trusted(),
3830 };
3831 inst.emit(sink, emit_info, state);
3832 let inst = Inst::Jump {
3833 dest: BranchTarget::ResolvedOffset(12),
3834 };
3835 inst.emit(sink, emit_info, state);
3836 sink.add_reloc(Reloc::Abs8, &**name, offset);
3837 sink.put8(0);
3838 }
3839 &Inst::LoadAddr { rd, ref mem } => {
3840 let mem = mem.clone();
3841 let (mem_insts, mem) = mem_finalize(Some(sink), &mem, I8, state);
3842 for inst in mem_insts.into_iter() {
3843 inst.emit(sink, emit_info, state);
3844 }
3845
3846 let (reg, index_reg, offset) = match mem {
3847 AMode::RegExtended { rn, rm, extendop } => {
3848 let r = rn;
3849 (r, Some((rm, extendop)), 0)
3850 }
3851 AMode::Unscaled { rn, simm9 } => {
3852 let r = rn;
3853 (r, None, simm9.value())
3854 }
3855 AMode::UnsignedOffset { rn, uimm12 } => {
3856 let r = rn;
3857 (r, None, uimm12.value() as i32)
3858 }
3859 _ => panic!("Unsupported case for LoadAddr: {mem:?}"),
3860 };
3861 let abs_offset = if offset < 0 {
3862 -offset as u64
3863 } else {
3864 offset as u64
3865 };
3866 let alu_op = if offset < 0 { ALUOp::Sub } else { ALUOp::Add };
3867
3868 if let Some((idx, extendop)) = index_reg {
3869 let add = Inst::AluRRRExtend {
3870 alu_op: ALUOp::Add,
3871 size: OperandSize::Size64,
3872 rd,
3873 rn: reg,
3874 rm: idx,
3875 extendop,
3876 };
3877
3878 add.emit(sink, emit_info, state);
3879 } else if offset == 0 {
3880 if reg != rd.to_reg() {
3881 let mov = Inst::Mov {
3882 size: OperandSize::Size64,
3883 rd,
3884 rm: reg,
3885 };
3886
3887 mov.emit(sink, emit_info, state);
3888 }
3889 } else if let Some(imm12) = Imm12::maybe_from_u64(abs_offset) {
3890 let add = Inst::AluRRImm12 {
3891 alu_op,
3892 size: OperandSize::Size64,
3893 rd,
3894 rn: reg,
3895 imm12,
3896 };
3897 add.emit(sink, emit_info, state);
3898 } else {
3899 debug_assert!(rd.to_reg() != tmp2_reg());
3905 debug_assert!(reg != tmp2_reg());
3906 let tmp = writable_tmp2_reg();
3907 for insn in Inst::load_constant(tmp, abs_offset).into_iter() {
3908 insn.emit(sink, emit_info, state);
3909 }
3910 let add = Inst::AluRRR {
3911 alu_op,
3912 size: OperandSize::Size64,
3913 rd,
3914 rn: reg,
3915 rm: tmp.to_reg(),
3916 };
3917 add.emit(sink, emit_info, state);
3918 }
3919 }
3920 &Inst::Paci { key } => {
3921 let (crm, op2) = match key {
3922 APIKey::AZ => (0b0011, 0b000),
3923 APIKey::ASP => (0b0011, 0b001),
3924 APIKey::BZ => (0b0011, 0b010),
3925 APIKey::BSP => (0b0011, 0b011),
3926 };
3927
3928 sink.put4(0xd503211f | (crm << 8) | (op2 << 5));
3929 }
3930 &Inst::Xpaclri => sink.put4(0xd50320ff),
3931 &Inst::Bti { targets } => {
3932 let targets = match targets {
3933 BranchTargetType::None => 0b00,
3934 BranchTargetType::C => 0b01,
3935 BranchTargetType::J => 0b10,
3936 BranchTargetType::JC => 0b11,
3937 };
3938
3939 sink.put4(0xd503241f | targets << 6);
3940 }
3941 &Inst::EmitIsland { needed_space } => {
3942 if sink.island_needed(needed_space + 4) {
3943 let jump_around_label = sink.get_label();
3944 let jmp = Inst::Jump {
3945 dest: BranchTarget::Label(jump_around_label),
3946 };
3947 jmp.emit(sink, emit_info, state);
3948 sink.emit_island(needed_space + 4, &mut state.ctrl_plane);
3949 sink.bind_label(jump_around_label, &mut state.ctrl_plane);
3950 }
3951 }
3952
3953 &Inst::ElfTlsGetAddr {
3954 ref symbol,
3955 rd,
3956 tmp,
3957 } => {
3958 assert_eq!(xreg(0), rd.to_reg());
3959
3960 sink.add_reloc(Reloc::Aarch64TlsDescAdrPage21, &**symbol, 0);
3976 Inst::Adrp { rd, off: 0 }.emit(sink, emit_info, state);
3977
3978 sink.add_reloc(Reloc::Aarch64TlsDescLd64Lo12, &**symbol, 0);
3980 Inst::ULoad64 {
3981 rd: tmp,
3982 mem: AMode::reg(rd.to_reg()),
3983 flags: MemFlagsData::trusted(),
3984 }
3985 .emit(sink, emit_info, state);
3986
3987 sink.add_reloc(Reloc::Aarch64TlsDescAddLo12, &**symbol, 0);
3989 Inst::AluRRImm12 {
3990 alu_op: ALUOp::Add,
3991 size: OperandSize::Size64,
3992 rd,
3993 rn: rd.to_reg(),
3994 imm12: Imm12::maybe_from_u64(0).unwrap(),
3995 }
3996 .emit(sink, emit_info, state);
3997
3998 sink.add_reloc(Reloc::Aarch64TlsDescCall, &**symbol, 0);
4000 Inst::CallInd {
4001 info: crate::isa::Box::new(CallInfo::empty(tmp.to_reg(), CallConv::SystemV)),
4002 }
4003 .emit(sink, emit_info, state);
4004
4005 sink.put4(0xd53bd040 | machreg_to_gpr(tmp.to_reg()));
4007
4008 Inst::AluRRR {
4010 alu_op: ALUOp::Add,
4011 size: OperandSize::Size64,
4012 rd,
4013 rn: rd.to_reg(),
4014 rm: tmp.to_reg(),
4015 }
4016 .emit(sink, emit_info, state);
4017 }
4018
4019 &Inst::MachOTlsGetAddr { ref symbol, rd } => {
4020 assert_eq!(xreg(0), rd.to_reg());
4033 let rtmp = writable_xreg(1);
4034
4035 sink.add_reloc(Reloc::MachOAarch64TlsAdrPage21, symbol, 0);
4037 sink.put4(0x90000000);
4038
4039 sink.add_reloc(Reloc::MachOAarch64TlsAdrPageOff12, symbol, 0);
4041 sink.put4(0xf9400000);
4042
4043 Inst::ULoad64 {
4045 rd: rtmp,
4046 mem: AMode::reg(rd.to_reg()),
4047 flags: MemFlagsData::trusted(),
4048 }
4049 .emit(sink, emit_info, state);
4050
4051 Inst::CallInd {
4053 info: crate::isa::Box::new(CallInfo::empty(
4054 rtmp.to_reg(),
4055 CallConv::AppleAarch64,
4056 )),
4057 }
4058 .emit(sink, emit_info, state);
4059 }
4060
4061 &Inst::Unwind { ref inst } => {
4062 sink.add_unwind(inst.clone());
4063 }
4064
4065 &Inst::DummyUse { .. } => {}
4066
4067 &Inst::LabelAddress { dst, label } => {
4068 let inst = Inst::Adr { rd: dst, off: 0 };
4073 let offset = sink.cur_offset();
4074 inst.emit(sink, emit_info, state);
4075 sink.use_label_at_offset(offset, label, LabelUse::Adr21);
4076 }
4077
4078 &Inst::SequencePoint { .. } => {
4079 }
4081
4082 &Inst::StackProbeLoop { start, end, step } => {
4083 assert!(emit_info.flags.enable_probestack());
4084
4085 let loop_start = sink.get_label();
4108 sink.bind_label(loop_start, &mut state.ctrl_plane);
4109
4110 Inst::AluRRImm12 {
4111 alu_op: ALUOp::Sub,
4112 size: OperandSize::Size64,
4113 rd: start,
4114 rn: start.to_reg(),
4115 imm12: step,
4116 }
4117 .emit(sink, emit_info, state);
4118 Inst::Store32 {
4119 rd: regs::zero_reg(),
4120 mem: AMode::RegReg {
4121 rn: regs::stack_reg(),
4122 rm: start.to_reg(),
4123 },
4124 flags: MemFlagsData::trusted(),
4125 }
4126 .emit(sink, emit_info, state);
4127 Inst::AluRRR {
4128 alu_op: ALUOp::AddS,
4129 size: OperandSize::Size64,
4130 rd: regs::writable_zero_reg(),
4131 rn: start.to_reg(),
4132 rm: end,
4133 }
4134 .emit(sink, emit_info, state);
4135
4136 let loop_end = sink.get_label();
4137 Inst::CondBr {
4138 taken: BranchTarget::Label(loop_start),
4139 not_taken: BranchTarget::Label(loop_end),
4140 kind: CondBrKind::Cond(Cond::Gt),
4141 }
4142 .emit(sink, emit_info, state);
4143 sink.bind_label(loop_end, &mut state.ctrl_plane);
4144 }
4145 }
4146
4147 let end_off = sink.cur_offset();
4148 debug_assert!(
4149 (end_off - start_off) <= Inst::worst_case_size()
4150 || matches!(self, Inst::EmitIsland { .. }),
4151 "Worst case size exceed for {:?}: {}",
4152 self,
4153 end_off - start_off
4154 );
4155
4156 state.clear_post_insn();
4157 }
4158
4159 fn pretty_print_inst(&self, state: &mut Self::State) -> String {
4160 self.print_with_state(state)
4161 }
4162}
4163
4164fn emit_return_call_common_sequence<T>(
4165 sink: &mut MachBuffer<Inst>,
4166 emit_info: &EmitInfo,
4167 state: &mut EmitState,
4168 info: &ReturnCallInfo<T>,
4169) {
4170 for inst in AArch64MachineDeps::gen_clobber_restore(
4171 CallConv::Tail,
4172 &emit_info.flags,
4173 state.frame_layout(),
4174 ) {
4175 inst.emit(sink, emit_info, state);
4176 }
4177
4178 let setup_area_size = state.frame_layout().setup_area_size;
4179 if setup_area_size > 0 {
4180 Inst::LoadP64 {
4186 rt: writable_fp_reg(),
4187 rt2: writable_link_reg(),
4188 mem: PairAMode::SPPostIndexed {
4189 simm7: SImm7Scaled::maybe_from_i64(i64::from(setup_area_size), types::I64).unwrap(),
4193 },
4194 flags: MemFlagsData::trusted(),
4195 }
4196 .emit(sink, emit_info, state);
4197 }
4198
4199 let incoming_args_diff = state.frame_layout().tail_args_size - info.new_stack_arg_size;
4201 if incoming_args_diff > 0 {
4202 for inst in
4203 AArch64MachineDeps::gen_sp_reg_adjust(i32::try_from(incoming_args_diff).unwrap())
4204 {
4205 inst.emit(sink, emit_info, state);
4206 }
4207 }
4208
4209 if (setup_area_size > 0 || info.sign_return_address_all)
4210 && let Some(key) = info.key
4211 {
4212 sink.put4(key.enc_auti_hint());
4213 }
4214}