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
420fn enc_bfm(opc: u8, size: OperandSize, rd: Writable<Reg>, rn: Reg, immr: u8, imms: u8) -> u32 {
421 match size {
422 OperandSize::Size64 => {
423 debug_assert!(immr <= 63);
424 debug_assert!(imms <= 63);
425 }
426 OperandSize::Size32 => {
427 debug_assert!(immr <= 31);
428 debug_assert!(imms <= 31);
429 }
430 }
431 debug_assert_eq!(opc & 0b11, opc);
432 let n_bit = size.sf_bit();
433 0b0_00_100110_0_000000_000000_00000_00000
434 | size.sf_bit() << 31
435 | u32::from(opc) << 29
436 | n_bit << 22
437 | u32::from(immr) << 16
438 | u32::from(imms) << 10
439 | machreg_to_gpr(rn) << 5
440 | machreg_to_gpr(rd.to_reg())
441}
442
443fn enc_vecmov(is_16b: bool, rd: Writable<Reg>, rn: Reg) -> u32 {
444 0b00001110_101_00000_00011_1_00000_00000
445 | ((is_16b as u32) << 30)
446 | machreg_to_vec(rd.to_reg())
447 | (machreg_to_vec(rn) << 16)
448 | (machreg_to_vec(rn) << 5)
449}
450
451fn enc_fpurr(top22: u32, rd: Writable<Reg>, rn: Reg) -> u32 {
452 (top22 << 10) | (machreg_to_vec(rn) << 5) | machreg_to_vec(rd.to_reg())
453}
454
455fn enc_fpurrr(top22: u32, rd: Writable<Reg>, rn: Reg, rm: Reg) -> u32 {
456 (top22 << 10)
457 | (machreg_to_vec(rm) << 16)
458 | (machreg_to_vec(rn) << 5)
459 | machreg_to_vec(rd.to_reg())
460}
461
462fn enc_fpurrrr(top17: u32, rd: Writable<Reg>, rn: Reg, rm: Reg, ra: Reg) -> u32 {
463 (top17 << 15)
464 | (machreg_to_vec(rm) << 16)
465 | (machreg_to_vec(ra) << 10)
466 | (machreg_to_vec(rn) << 5)
467 | machreg_to_vec(rd.to_reg())
468}
469
470fn enc_fcmp(size: ScalarSize, rn: Reg, rm: Reg) -> u32 {
471 0b000_11110_00_1_00000_00_1000_00000_00000
472 | (size.ftype() << 22)
473 | (machreg_to_vec(rm) << 16)
474 | (machreg_to_vec(rn) << 5)
475}
476
477fn enc_fputoint(top16: u32, rd: Writable<Reg>, rn: Reg) -> u32 {
478 (top16 << 16) | (machreg_to_vec(rn) << 5) | machreg_to_gpr(rd.to_reg())
479}
480
481fn enc_inttofpu(top16: u32, rd: Writable<Reg>, rn: Reg) -> u32 {
482 (top16 << 16) | (machreg_to_gpr(rn) << 5) | machreg_to_vec(rd.to_reg())
483}
484
485fn enc_fround(top22: u32, rd: Writable<Reg>, rn: Reg) -> u32 {
486 (top22 << 10) | (machreg_to_vec(rn) << 5) | machreg_to_vec(rd.to_reg())
487}
488
489fn enc_vec_rr_misc(qu: u32, size: u32, bits_12_16: u32, rd: Writable<Reg>, rn: Reg) -> u32 {
490 debug_assert_eq!(qu & 0b11, qu);
491 debug_assert_eq!(size & 0b11, size);
492 debug_assert_eq!(bits_12_16 & 0b11111, bits_12_16);
493 let bits = 0b0_00_01110_00_10000_00000_10_00000_00000;
494 bits | qu << 29
495 | size << 22
496 | bits_12_16 << 12
497 | machreg_to_vec(rn) << 5
498 | machreg_to_vec(rd.to_reg())
499}
500
501fn enc_vec_rr_pair(bits_12_16: u32, rd: Writable<Reg>, rn: Reg) -> u32 {
502 debug_assert_eq!(bits_12_16 & 0b11111, bits_12_16);
503
504 0b010_11110_11_11000_11011_10_00000_00000
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_long(u: u32, enc_size: u32, rd: Writable<Reg>, rn: Reg) -> u32 {
511 debug_assert_eq!(u & 0b1, u);
512 debug_assert_eq!(enc_size & 0b1, enc_size);
513
514 0b0_1_0_01110_00_10000_00_0_10_10_00000_00000
515 | u << 29
516 | enc_size << 22
517 | machreg_to_vec(rn) << 5
518 | machreg_to_vec(rd.to_reg())
519}
520
521fn enc_vec_lanes(q: u32, u: u32, size: u32, opcode: u32, rd: Writable<Reg>, rn: Reg) -> u32 {
522 debug_assert_eq!(q & 0b1, q);
523 debug_assert_eq!(u & 0b1, u);
524 debug_assert_eq!(size & 0b11, size);
525 debug_assert_eq!(opcode & 0b11111, opcode);
526 0b0_0_0_01110_00_11000_0_0000_10_00000_00000
527 | q << 30
528 | u << 29
529 | size << 22
530 | opcode << 12
531 | machreg_to_vec(rn) << 5
532 | machreg_to_vec(rd.to_reg())
533}
534
535fn enc_tbl(is_extension: bool, len: u32, rd: Writable<Reg>, rn: Reg, rm: Reg) -> u32 {
536 debug_assert_eq!(len & 0b11, len);
537 0b0_1_001110_000_00000_0_00_0_00_00000_00000
538 | (machreg_to_vec(rm) << 16)
539 | len << 13
540 | (is_extension as u32) << 12
541 | (machreg_to_vec(rn) << 5)
542 | machreg_to_vec(rd.to_reg())
543}
544
545fn enc_dmb_ish() -> u32 {
546 0xD5033BBF
547}
548
549fn enc_acq_rel(ty: Type, op: AtomicRMWOp, rs: Reg, rt: Writable<Reg>, rn: Reg) -> u32 {
550 assert!(machreg_to_gpr(rt.to_reg()) != 31);
551 let sz = match ty {
552 I64 => 0b11,
553 I32 => 0b10,
554 I16 => 0b01,
555 I8 => 0b00,
556 _ => unreachable!(),
557 };
558 let bit15 = match op {
559 AtomicRMWOp::Swp => 0b1,
560 _ => 0b0,
561 };
562 let op = match op {
563 AtomicRMWOp::Add => 0b000,
564 AtomicRMWOp::Clr => 0b001,
565 AtomicRMWOp::Eor => 0b010,
566 AtomicRMWOp::Set => 0b011,
567 AtomicRMWOp::Smax => 0b100,
568 AtomicRMWOp::Smin => 0b101,
569 AtomicRMWOp::Umax => 0b110,
570 AtomicRMWOp::Umin => 0b111,
571 AtomicRMWOp::Swp => 0b000,
572 };
573 0b00_111_000_111_00000_0_000_00_00000_00000
574 | (sz << 30)
575 | (machreg_to_gpr(rs) << 16)
576 | bit15 << 15
577 | (op << 12)
578 | (machreg_to_gpr(rn) << 5)
579 | machreg_to_gpr(rt.to_reg())
580}
581
582fn enc_ldar(ty: Type, rt: Writable<Reg>, rn: Reg) -> u32 {
583 let sz = match ty {
584 I64 => 0b11,
585 I32 => 0b10,
586 I16 => 0b01,
587 I8 => 0b00,
588 _ => unreachable!(),
589 };
590 0b00_001000_1_1_0_11111_1_11111_00000_00000
591 | (sz << 30)
592 | (machreg_to_gpr(rn) << 5)
593 | machreg_to_gpr(rt.to_reg())
594}
595
596fn enc_stlr(ty: Type, rt: Reg, rn: Reg) -> u32 {
597 let sz = match ty {
598 I64 => 0b11,
599 I32 => 0b10,
600 I16 => 0b01,
601 I8 => 0b00,
602 _ => unreachable!(),
603 };
604 0b00_001000_100_11111_1_11111_00000_00000
605 | (sz << 30)
606 | (machreg_to_gpr(rn) << 5)
607 | machreg_to_gpr(rt)
608}
609
610fn enc_ldaxr(ty: Type, rt: Writable<Reg>, rn: Reg) -> u32 {
611 let sz = match ty {
612 I64 => 0b11,
613 I32 => 0b10,
614 I16 => 0b01,
615 I8 => 0b00,
616 _ => unreachable!(),
617 };
618 0b00_001000_0_1_0_11111_1_11111_00000_00000
619 | (sz << 30)
620 | (machreg_to_gpr(rn) << 5)
621 | machreg_to_gpr(rt.to_reg())
622}
623
624fn enc_stlxr(ty: Type, rs: Writable<Reg>, rt: Reg, rn: Reg) -> u32 {
625 let sz = match ty {
626 I64 => 0b11,
627 I32 => 0b10,
628 I16 => 0b01,
629 I8 => 0b00,
630 _ => unreachable!(),
631 };
632 0b00_001000_000_00000_1_11111_00000_00000
633 | (sz << 30)
634 | (machreg_to_gpr(rs.to_reg()) << 16)
635 | (machreg_to_gpr(rn) << 5)
636 | machreg_to_gpr(rt)
637}
638
639fn enc_cas(size: u32, rs: Writable<Reg>, rt: Reg, rn: Reg) -> u32 {
640 debug_assert_eq!(size & 0b11, size);
641
642 0b00_0010001_1_1_00000_1_11111_00000_00000
643 | size << 30
644 | machreg_to_gpr(rs.to_reg()) << 16
645 | machreg_to_gpr(rn) << 5
646 | machreg_to_gpr(rt)
647}
648
649fn enc_casp(rs: Writable<Reg>, rt: Reg, rn: Reg) -> u32 {
650 debug_assert_eq!(machreg_to_gpr(rs.to_reg()) & 1, 0);
651 debug_assert_eq!(machreg_to_gpr(rt) & 1, 0);
652
653 0b0_1_0010000_1_1_00000_1_11111_00000_00000
654 | machreg_to_gpr(rs.to_reg()) << 16
655 | machreg_to_gpr(rn) << 5
656 | machreg_to_gpr(rt)
657}
658
659fn enc_asimd_mod_imm(rd: Writable<Reg>, q_op: u32, cmode: u32, imm: u8) -> u32 {
660 let abc = (imm >> 5) as u32;
661 let defgh = (imm & 0b11111) as u32;
662
663 debug_assert_eq!(cmode & 0b1111, cmode);
664 debug_assert_eq!(q_op & 0b11, q_op);
665
666 0b0_0_0_0111100000_000_0000_01_00000_00000
667 | (q_op << 29)
668 | (abc << 16)
669 | (cmode << 12)
670 | (defgh << 5)
671 | machreg_to_vec(rd.to_reg())
672}
673
674#[derive(Default, Clone, Debug)]
676pub struct EmitState {
677 user_stack_map: Option<ir::UserStackMap>,
680
681 ctrl_plane: ControlPlane,
684
685 frame_layout: FrameLayout,
686}
687
688impl MachInstEmitState<Inst> for EmitState {
689 fn new(abi: &Callee<AArch64MachineDeps>, ctrl_plane: ControlPlane) -> Self {
690 EmitState {
691 user_stack_map: None,
692 ctrl_plane,
693 frame_layout: abi.frame_layout().clone(),
694 }
695 }
696
697 fn pre_safepoint(&mut self, user_stack_map: Option<ir::UserStackMap>) {
698 self.user_stack_map = user_stack_map;
699 }
700
701 fn ctrl_plane_mut(&mut self) -> &mut ControlPlane {
702 &mut self.ctrl_plane
703 }
704
705 fn take_ctrl_plane(self) -> ControlPlane {
706 self.ctrl_plane
707 }
708
709 fn frame_layout(&self) -> &FrameLayout {
710 &self.frame_layout
711 }
712}
713
714impl EmitState {
715 fn take_stack_map(&mut self) -> Option<ir::UserStackMap> {
716 self.user_stack_map.take()
717 }
718
719 fn clear_post_insn(&mut self) {
720 self.user_stack_map = None;
721 }
722}
723
724pub struct EmitInfo {
726 flags: settings::Flags,
727 isa_flags: aarch64::settings::Flags,
728}
729
730impl EmitInfo {
731 pub fn new(flags: settings::Flags, isa_flags: aarch64::settings::Flags) -> Self {
733 Self { flags, isa_flags }
734 }
735}
736
737impl MachInstEmit for Inst {
738 type State = EmitState;
739 type Info = EmitInfo;
740
741 fn emit(&self, sink: &mut MachBuffer<Inst>, emit_info: &Self::Info, state: &mut EmitState) {
742 let mut start_off = sink.cur_offset();
748
749 match self {
750 &Inst::AluRRR {
751 alu_op,
752 size,
753 rd,
754 rn,
755 rm,
756 } => {
757 debug_assert!(match alu_op {
758 ALUOp::SMulH | ALUOp::UMulH => size == OperandSize::Size64,
759 _ => true,
760 });
761 let top11 = match alu_op {
762 ALUOp::Add => 0b00001011_000,
763 ALUOp::Adc => 0b00011010_000,
764 ALUOp::AdcS => 0b00111010_000,
765 ALUOp::Sub => 0b01001011_000,
766 ALUOp::Sbc => 0b01011010_000,
767 ALUOp::SbcS => 0b01111010_000,
768 ALUOp::Orr => 0b00101010_000,
769 ALUOp::And => 0b00001010_000,
770 ALUOp::AndS => 0b01101010_000,
771 ALUOp::Eor => 0b01001010_000,
772 ALUOp::OrrNot => 0b00101010_001,
773 ALUOp::AndNot => 0b00001010_001,
774 ALUOp::EorNot => 0b01001010_001,
775 ALUOp::AddS => 0b00101011_000,
776 ALUOp::SubS => 0b01101011_000,
777 ALUOp::SDiv | ALUOp::UDiv => 0b00011010_110,
778 ALUOp::Extr | ALUOp::Lsr | ALUOp::Asr | ALUOp::Lsl => 0b00011010_110,
779 ALUOp::SMulH => 0b10011011_010,
780 ALUOp::UMulH => 0b10011011_110,
781 };
782
783 let top11 = top11 | size.sf_bit() << 10;
784 let bit15_10 = match alu_op {
785 ALUOp::SDiv => 0b000011,
786 ALUOp::UDiv => 0b000010,
787 ALUOp::Extr => 0b001011,
788 ALUOp::Lsr => 0b001001,
789 ALUOp::Asr => 0b001010,
790 ALUOp::Lsl => 0b001000,
791 ALUOp::SMulH | ALUOp::UMulH => 0b011111,
792 _ => 0b000000,
793 };
794 debug_assert_ne!(writable_stack_reg(), rd);
795 debug_assert_ne!(stack_reg(), rn);
798 debug_assert_ne!(stack_reg(), rm);
799 sink.put4(enc_arith_rrr(top11, bit15_10, rd, rn, rm));
800 }
801 &Inst::AluRRRR {
802 alu_op,
803 size,
804 rd,
805 rm,
806 rn,
807 ra,
808 } => {
809 let (top11, bit15) = match alu_op {
810 ALUOp3::MAdd => (0b0_00_11011_000, 0),
811 ALUOp3::MSub => (0b0_00_11011_000, 1),
812 ALUOp3::UMAddL => {
813 debug_assert!(size == OperandSize::Size32);
814 (0b1_00_11011_1_01, 0)
815 }
816 ALUOp3::SMAddL => {
817 debug_assert!(size == OperandSize::Size32);
818 (0b1_00_11011_0_01, 0)
819 }
820 };
821 let top11 = top11 | size.sf_bit() << 10;
822 sink.put4(enc_arith_rrrr(top11, rm, bit15, ra, rn, rd));
823 }
824 &Inst::AluRRImm12 {
825 alu_op,
826 size,
827 rd,
828 rn,
829 ref imm12,
830 } => {
831 let top8 = match alu_op {
832 ALUOp::Add => 0b000_10001,
833 ALUOp::Sub => 0b010_10001,
834 ALUOp::AddS => 0b001_10001,
835 ALUOp::SubS => 0b011_10001,
836 _ => unimplemented!("{:?}", alu_op),
837 };
838 let top8 = top8 | size.sf_bit() << 7;
839 sink.put4(enc_arith_rr_imm12(
840 top8,
841 imm12.shift_bits(),
842 imm12.imm_bits(),
843 rn,
844 rd,
845 ));
846 }
847 &Inst::AluRRImmLogic {
848 alu_op,
849 size,
850 rd,
851 rn,
852 ref imml,
853 } => {
854 let (top9, inv) = match alu_op {
855 ALUOp::Orr => (0b001_100100, false),
856 ALUOp::And => (0b000_100100, false),
857 ALUOp::AndS => (0b011_100100, false),
858 ALUOp::Eor => (0b010_100100, false),
859 ALUOp::OrrNot => (0b001_100100, true),
860 ALUOp::AndNot => (0b000_100100, true),
861 ALUOp::EorNot => (0b010_100100, true),
862 _ => unimplemented!("{:?}", alu_op),
863 };
864 let top9 = top9 | size.sf_bit() << 8;
865 let imml = if inv { imml.invert() } else { *imml };
866 sink.put4(enc_arith_rr_imml(top9, imml.enc_bits(), rn, rd));
867 }
868
869 &Inst::AluRRImmShift {
870 alu_op,
871 size,
872 rd,
873 rn,
874 ref immshift,
875 } => {
876 let amt = immshift.value();
877 let (top10, immr, imms) = match alu_op {
878 ALUOp::Extr => (0b0001001110, machreg_to_gpr(rn), u32::from(amt)),
879 ALUOp::Lsr => (0b0101001100, u32::from(amt), 0b011111),
880 ALUOp::Asr => (0b0001001100, u32::from(amt), 0b011111),
881 ALUOp::Lsl => {
882 let bits = if size.is64() { 64 } else { 32 };
883 (
884 0b0101001100,
885 u32::from((bits - amt) % bits),
886 u32::from(bits - 1 - amt),
887 )
888 }
889 _ => unimplemented!("{:?}", alu_op),
890 };
891 let top10 = top10 | size.sf_bit() << 9 | size.sf_bit();
892 let imms = match alu_op {
893 ALUOp::Lsr | ALUOp::Asr => imms | size.sf_bit() << 5,
894 _ => imms,
895 };
896 sink.put4(
897 (top10 << 22)
898 | (immr << 16)
899 | (imms << 10)
900 | (machreg_to_gpr(rn) << 5)
901 | machreg_to_gpr(rd.to_reg()),
902 );
903 }
904
905 &Inst::AluRRRShift {
906 alu_op,
907 size,
908 rd,
909 rn,
910 rm,
911 ref shiftop,
912 } => {
913 let top11: u32 = match alu_op {
914 ALUOp::Add => 0b000_01011000,
915 ALUOp::AddS => 0b001_01011000,
916 ALUOp::Sub => 0b010_01011000,
917 ALUOp::SubS => 0b011_01011000,
918 ALUOp::Orr => 0b001_01010000,
919 ALUOp::And => 0b000_01010000,
920 ALUOp::AndS => 0b011_01010000,
921 ALUOp::Eor => 0b010_01010000,
922 ALUOp::OrrNot => 0b001_01010001,
923 ALUOp::EorNot => 0b010_01010001,
924 ALUOp::AndNot => 0b000_01010001,
925 ALUOp::Extr => 0b000_10011100,
926 _ => unimplemented!("{:?}", alu_op),
927 };
928 let top11 = top11 | size.sf_bit() << 10;
929 let top11 = top11 | (u32::from(shiftop.op().bits()) << 1);
930 let bits_15_10 = u32::from(shiftop.amt().value());
931 sink.put4(enc_arith_rrr(top11, bits_15_10, rd, rn, rm));
932 }
933
934 &Inst::AluRRRExtend {
935 alu_op,
936 size,
937 rd,
938 rn,
939 rm,
940 extendop,
941 } => {
942 let top11: u32 = match alu_op {
943 ALUOp::Add => 0b00001011001,
944 ALUOp::Sub => 0b01001011001,
945 ALUOp::AddS => 0b00101011001,
946 ALUOp::SubS => 0b01101011001,
947 _ => unimplemented!("{:?}", alu_op),
948 };
949 let top11 = top11 | size.sf_bit() << 10;
950 let bits_15_10 = u32::from(extendop.bits()) << 3;
951 sink.put4(enc_arith_rrr(top11, bits_15_10, rd, rn, rm));
952 }
953
954 &Inst::BitRR {
955 op, size, rd, rn, ..
956 } => {
957 let (op1, op2) = match op {
958 BitOp::RBit => (0b00000, 0b000000),
959 BitOp::Clz => (0b00000, 0b000100),
960 BitOp::Cls => (0b00000, 0b000101),
961 BitOp::Rev16 => (0b00000, 0b000001),
962 BitOp::Rev32 => (0b00000, 0b000010),
963 BitOp::Rev64 => (0b00000, 0b000011),
964 };
965 sink.put4(enc_bit_rr(size.sf_bit(), op1, op2, rn, rd))
966 }
967
968 &Inst::ULoad8 { rd, ref mem, flags }
969 | &Inst::SLoad8 { rd, ref mem, flags }
970 | &Inst::ULoad16 { rd, ref mem, flags }
971 | &Inst::SLoad16 { rd, ref mem, flags }
972 | &Inst::ULoad32 { rd, ref mem, flags }
973 | &Inst::SLoad32 { rd, ref mem, flags }
974 | &Inst::ULoad64 {
975 rd, ref mem, flags, ..
976 }
977 | &Inst::FpuLoad16 { rd, ref mem, flags }
978 | &Inst::FpuLoad32 { rd, ref mem, flags }
979 | &Inst::FpuLoad64 { rd, ref mem, flags }
980 | &Inst::FpuLoad128 { rd, ref mem, flags } => {
981 let mem = mem.clone();
982 let access_ty = self.mem_type().unwrap();
983 let (mem_insts, mem) = mem_finalize(Some(sink), &mem, access_ty, state);
984
985 for inst in mem_insts.into_iter() {
986 inst.emit(sink, emit_info, state);
987 }
988
989 let rd = rd.to_reg();
991
992 let op = match self {
996 Inst::ULoad8 { .. } => 0b0011100001,
997 Inst::SLoad8 { .. } => 0b0011100010,
998 Inst::ULoad16 { .. } => 0b0111100001,
999 Inst::SLoad16 { .. } => 0b0111100010,
1000 Inst::ULoad32 { .. } => 0b1011100001,
1001 Inst::SLoad32 { .. } => 0b1011100010,
1002 Inst::ULoad64 { .. } => 0b1111100001,
1003 Inst::FpuLoad16 { .. } => 0b0111110001,
1004 Inst::FpuLoad32 { .. } => 0b1011110001,
1005 Inst::FpuLoad64 { .. } => 0b1111110001,
1006 Inst::FpuLoad128 { .. } => 0b0011110011,
1007 _ => unreachable!(),
1008 };
1009
1010 if let Some(trap_code) = flags.trap_code() {
1011 sink.add_trap(trap_code);
1013 }
1014
1015 match &mem {
1016 &AMode::Unscaled { rn, simm9 } => {
1017 let reg = rn;
1018 sink.put4(enc_ldst_simm9(op, simm9, 0b00, reg, rd));
1019 }
1020 &AMode::UnsignedOffset { rn, uimm12 } => {
1021 let reg = rn;
1022 sink.put4(enc_ldst_uimm12(op, uimm12, reg, rd));
1023 }
1024 &AMode::RegReg { rn, rm } => {
1025 let r1 = rn;
1026 let r2 = rm;
1027 sink.put4(enc_ldst_reg(
1028 op, r1, r2, false, None, rd,
1029 ));
1030 }
1031 &AMode::RegScaled { rn, rm } | &AMode::RegScaledExtended { rn, rm, .. } => {
1032 let r1 = rn;
1033 let r2 = rm;
1034 let extendop = match &mem {
1035 &AMode::RegScaled { .. } => None,
1036 &AMode::RegScaledExtended { extendop, .. } => Some(extendop),
1037 _ => unreachable!(),
1038 };
1039 sink.put4(enc_ldst_reg(
1040 op, r1, r2, true, extendop, rd,
1041 ));
1042 }
1043 &AMode::RegExtended { rn, rm, extendop } => {
1044 let r1 = rn;
1045 let r2 = rm;
1046 sink.put4(enc_ldst_reg(
1047 op,
1048 r1,
1049 r2,
1050 false,
1051 Some(extendop),
1052 rd,
1053 ));
1054 }
1055 &AMode::Label { ref label } => {
1056 let offset = match label {
1057 MemLabel::PCRel(off) => *off as u32,
1059 MemLabel::Mach(label) => {
1064 sink.use_label_at_offset(
1065 sink.cur_offset(),
1066 *label,
1067 LabelUse::Ldr19,
1068 );
1069 0
1070 }
1071 } / 4;
1072 assert!(offset < (1 << 19));
1073 match self {
1074 &Inst::ULoad32 { .. } => {
1075 sink.put4(enc_ldst_imm19(0b00011000, offset, rd));
1076 }
1077 &Inst::SLoad32 { .. } => {
1078 sink.put4(enc_ldst_imm19(0b10011000, offset, rd));
1079 }
1080 &Inst::FpuLoad32 { .. } => {
1081 sink.put4(enc_ldst_imm19(0b00011100, offset, rd));
1082 }
1083 &Inst::ULoad64 { .. } => {
1084 sink.put4(enc_ldst_imm19(0b01011000, offset, rd));
1085 }
1086 &Inst::FpuLoad64 { .. } => {
1087 sink.put4(enc_ldst_imm19(0b01011100, offset, rd));
1088 }
1089 &Inst::FpuLoad128 { .. } => {
1090 sink.put4(enc_ldst_imm19(0b10011100, offset, rd));
1091 }
1092 _ => panic!("Unsupported size for LDR from constant pool!"),
1093 }
1094 }
1095 &AMode::SPPreIndexed { simm9 } => {
1096 let reg = stack_reg();
1097 sink.put4(enc_ldst_simm9(op, simm9, 0b11, reg, rd));
1098 }
1099 &AMode::SPPostIndexed { simm9 } => {
1100 let reg = stack_reg();
1101 sink.put4(enc_ldst_simm9(op, simm9, 0b01, reg, rd));
1102 }
1103 &AMode::SPOffset { .. }
1105 | &AMode::FPOffset { .. }
1106 | &AMode::IncomingArg { .. }
1107 | &AMode::SlotOffset { .. }
1108 | &AMode::Const { .. }
1109 | &AMode::RegOffset { .. } => {
1110 panic!("Should not see {mem:?} here!")
1111 }
1112 }
1113 }
1114
1115 &Inst::Store8 { rd, ref mem, flags }
1116 | &Inst::Store16 { rd, ref mem, flags }
1117 | &Inst::Store32 { rd, ref mem, flags }
1118 | &Inst::Store64 { rd, ref mem, flags }
1119 | &Inst::FpuStore16 { rd, ref mem, flags }
1120 | &Inst::FpuStore32 { rd, ref mem, flags }
1121 | &Inst::FpuStore64 { rd, ref mem, flags }
1122 | &Inst::FpuStore128 { rd, ref mem, flags } => {
1123 let mem = mem.clone();
1124 let access_ty = self.mem_type().unwrap();
1125 let (mem_insts, mem) = mem_finalize(Some(sink), &mem, access_ty, state);
1126
1127 for inst in mem_insts.into_iter() {
1128 inst.emit(sink, emit_info, state);
1129 }
1130
1131 let op = match self {
1132 Inst::Store8 { .. } => 0b0011100000,
1133 Inst::Store16 { .. } => 0b0111100000,
1134 Inst::Store32 { .. } => 0b1011100000,
1135 Inst::Store64 { .. } => 0b1111100000,
1136 Inst::FpuStore16 { .. } => 0b0111110000,
1137 Inst::FpuStore32 { .. } => 0b1011110000,
1138 Inst::FpuStore64 { .. } => 0b1111110000,
1139 Inst::FpuStore128 { .. } => 0b0011110010,
1140 _ => unreachable!(),
1141 };
1142
1143 if let Some(trap_code) = flags.trap_code() {
1144 sink.add_trap(trap_code);
1146 }
1147
1148 match &mem {
1149 &AMode::Unscaled { rn, simm9 } => {
1150 let reg = rn;
1151 sink.put4(enc_ldst_simm9(op, simm9, 0b00, reg, rd));
1152 }
1153 &AMode::UnsignedOffset { rn, uimm12 } => {
1154 let reg = rn;
1155 sink.put4(enc_ldst_uimm12(op, uimm12, reg, rd));
1156 }
1157 &AMode::RegReg { rn, rm } => {
1158 let r1 = rn;
1159 let r2 = rm;
1160 sink.put4(enc_ldst_reg(
1161 op, r1, r2, false, None, rd,
1162 ));
1163 }
1164 &AMode::RegScaled { rn, rm } | &AMode::RegScaledExtended { rn, rm, .. } => {
1165 let r1 = rn;
1166 let r2 = rm;
1167 let extendop = match &mem {
1168 &AMode::RegScaled { .. } => None,
1169 &AMode::RegScaledExtended { extendop, .. } => Some(extendop),
1170 _ => unreachable!(),
1171 };
1172 sink.put4(enc_ldst_reg(
1173 op, r1, r2, true, extendop, rd,
1174 ));
1175 }
1176 &AMode::RegExtended { rn, rm, extendop } => {
1177 let r1 = rn;
1178 let r2 = rm;
1179 sink.put4(enc_ldst_reg(
1180 op,
1181 r1,
1182 r2,
1183 false,
1184 Some(extendop),
1185 rd,
1186 ));
1187 }
1188 &AMode::Label { .. } => {
1189 panic!("Store to a MemLabel not implemented!");
1190 }
1191 &AMode::SPPreIndexed { simm9 } => {
1192 let reg = stack_reg();
1193 sink.put4(enc_ldst_simm9(op, simm9, 0b11, reg, rd));
1194 }
1195 &AMode::SPPostIndexed { simm9 } => {
1196 let reg = stack_reg();
1197 sink.put4(enc_ldst_simm9(op, simm9, 0b01, reg, rd));
1198 }
1199 &AMode::SPOffset { .. }
1201 | &AMode::FPOffset { .. }
1202 | &AMode::IncomingArg { .. }
1203 | &AMode::SlotOffset { .. }
1204 | &AMode::Const { .. }
1205 | &AMode::RegOffset { .. } => {
1206 panic!("Should not see {mem:?} here!")
1207 }
1208 }
1209 }
1210
1211 &Inst::StoreP64 {
1212 rt,
1213 rt2,
1214 ref mem,
1215 flags,
1216 } => {
1217 let mem = mem.clone();
1218 if let Some(trap_code) = flags.trap_code() {
1219 sink.add_trap(trap_code);
1221 }
1222 match &mem {
1223 &PairAMode::SignedOffset { reg, simm7 } => {
1224 assert_eq!(simm7.scale_ty, I64);
1225 sink.put4(enc_ldst_pair(0b1010100100, simm7, reg, rt, rt2));
1226 }
1227 &PairAMode::SPPreIndexed { simm7 } => {
1228 assert_eq!(simm7.scale_ty, I64);
1229 let reg = stack_reg();
1230 sink.put4(enc_ldst_pair(0b1010100110, simm7, reg, rt, rt2));
1231 }
1232 &PairAMode::SPPostIndexed { simm7 } => {
1233 assert_eq!(simm7.scale_ty, I64);
1234 let reg = stack_reg();
1235 sink.put4(enc_ldst_pair(0b1010100010, simm7, reg, rt, rt2));
1236 }
1237 }
1238 }
1239 &Inst::LoadP64 {
1240 rt,
1241 rt2,
1242 ref mem,
1243 flags,
1244 } => {
1245 let rt = rt.to_reg();
1246 let rt2 = rt2.to_reg();
1247 let mem = mem.clone();
1248 if let Some(trap_code) = flags.trap_code() {
1249 sink.add_trap(trap_code);
1251 }
1252
1253 match &mem {
1254 &PairAMode::SignedOffset { reg, simm7 } => {
1255 assert_eq!(simm7.scale_ty, I64);
1256 sink.put4(enc_ldst_pair(0b1010100101, simm7, reg, rt, rt2));
1257 }
1258 &PairAMode::SPPreIndexed { simm7 } => {
1259 assert_eq!(simm7.scale_ty, I64);
1260 let reg = stack_reg();
1261 sink.put4(enc_ldst_pair(0b1010100111, simm7, reg, rt, rt2));
1262 }
1263 &PairAMode::SPPostIndexed { simm7 } => {
1264 assert_eq!(simm7.scale_ty, I64);
1265 let reg = stack_reg();
1266 sink.put4(enc_ldst_pair(0b1010100011, simm7, reg, rt, rt2));
1267 }
1268 }
1269 }
1270 &Inst::FpuLoadP64 {
1271 rt,
1272 rt2,
1273 ref mem,
1274 flags,
1275 }
1276 | &Inst::FpuLoadP128 {
1277 rt,
1278 rt2,
1279 ref mem,
1280 flags,
1281 } => {
1282 let rt = rt.to_reg();
1283 let rt2 = rt2.to_reg();
1284 let mem = mem.clone();
1285
1286 if let Some(trap_code) = flags.trap_code() {
1287 sink.add_trap(trap_code);
1289 }
1290
1291 let opc = match self {
1292 &Inst::FpuLoadP64 { .. } => 0b01,
1293 &Inst::FpuLoadP128 { .. } => 0b10,
1294 _ => unreachable!(),
1295 };
1296
1297 match &mem {
1298 &PairAMode::SignedOffset { reg, simm7 } => {
1299 assert!(simm7.scale_ty == F64 || simm7.scale_ty == I8X16);
1300 sink.put4(enc_ldst_vec_pair(opc, 0b10, true, simm7, reg, rt, rt2));
1301 }
1302 &PairAMode::SPPreIndexed { simm7 } => {
1303 assert!(simm7.scale_ty == F64 || simm7.scale_ty == I8X16);
1304 let reg = stack_reg();
1305 sink.put4(enc_ldst_vec_pair(opc, 0b11, true, simm7, reg, rt, rt2));
1306 }
1307 &PairAMode::SPPostIndexed { simm7 } => {
1308 assert!(simm7.scale_ty == F64 || simm7.scale_ty == I8X16);
1309 let reg = stack_reg();
1310 sink.put4(enc_ldst_vec_pair(opc, 0b01, true, simm7, reg, rt, rt2));
1311 }
1312 }
1313 }
1314 &Inst::FpuStoreP64 {
1315 rt,
1316 rt2,
1317 ref mem,
1318 flags,
1319 }
1320 | &Inst::FpuStoreP128 {
1321 rt,
1322 rt2,
1323 ref mem,
1324 flags,
1325 } => {
1326 let mem = mem.clone();
1327
1328 if let Some(trap_code) = flags.trap_code() {
1329 sink.add_trap(trap_code);
1331 }
1332
1333 let opc = match self {
1334 &Inst::FpuStoreP64 { .. } => 0b01,
1335 &Inst::FpuStoreP128 { .. } => 0b10,
1336 _ => unreachable!(),
1337 };
1338
1339 match &mem {
1340 &PairAMode::SignedOffset { reg, simm7 } => {
1341 assert!(simm7.scale_ty == F64 || simm7.scale_ty == I8X16);
1342 sink.put4(enc_ldst_vec_pair(opc, 0b10, false, simm7, reg, rt, rt2));
1343 }
1344 &PairAMode::SPPreIndexed { simm7 } => {
1345 assert!(simm7.scale_ty == F64 || simm7.scale_ty == I8X16);
1346 let reg = stack_reg();
1347 sink.put4(enc_ldst_vec_pair(opc, 0b11, false, simm7, reg, rt, rt2));
1348 }
1349 &PairAMode::SPPostIndexed { simm7 } => {
1350 assert!(simm7.scale_ty == F64 || simm7.scale_ty == I8X16);
1351 let reg = stack_reg();
1352 sink.put4(enc_ldst_vec_pair(opc, 0b01, false, simm7, reg, rt, rt2));
1353 }
1354 }
1355 }
1356 &Inst::Mov { size, rd, rm } => {
1357 assert!(rd.to_reg().class() == rm.class());
1358 assert!(rm.class() == RegClass::Int);
1359
1360 match size {
1361 OperandSize::Size64 => {
1362 assert!(rd.to_reg() != stack_reg());
1365
1366 if rm == stack_reg() {
1367 let imm12 = Imm12::maybe_from_u64(0).unwrap();
1369 sink.put4(enc_arith_rr_imm12(
1370 0b100_10001,
1371 imm12.shift_bits(),
1372 imm12.imm_bits(),
1373 rm,
1374 rd,
1375 ));
1376 } else {
1377 sink.put4(enc_arith_rrr(0b10101010_000, 0b000_000, rd, zero_reg(), rm));
1379 }
1380 }
1381 OperandSize::Size32 => {
1382 assert!(machreg_to_gpr(rd.to_reg()) != 31);
1385 sink.put4(enc_arith_rrr(0b00101010_000, 0b000_000, rd, zero_reg(), rm));
1387 }
1388 }
1389 }
1390 &Inst::MovFromPReg { rd, rm } => {
1391 let rm: Reg = rm.into();
1392 debug_assert!(
1393 [
1394 regs::fp_reg(),
1395 regs::stack_reg(),
1396 regs::link_reg(),
1397 regs::pinned_reg()
1398 ]
1399 .contains(&rm)
1400 );
1401 assert!(rm.class() == RegClass::Int);
1402 assert!(rd.to_reg().class() == rm.class());
1403 let size = OperandSize::Size64;
1404 Inst::Mov { size, rd, rm }.emit(sink, emit_info, state);
1405 }
1406 &Inst::MovToPReg { rd, rm } => {
1407 let rd: Writable<Reg> = Writable::from_reg(rd.into());
1408 debug_assert!(
1409 [
1410 regs::fp_reg(),
1411 regs::stack_reg(),
1412 regs::link_reg(),
1413 regs::pinned_reg()
1414 ]
1415 .contains(&rd.to_reg())
1416 );
1417 assert!(rd.to_reg().class() == RegClass::Int);
1418 assert!(rm.class() == rd.to_reg().class());
1419 let size = OperandSize::Size64;
1420 Inst::Mov { size, rd, rm }.emit(sink, emit_info, state);
1421 }
1422 &Inst::MovWide { op, rd, imm, size } => {
1423 sink.put4(enc_move_wide(op, rd, imm, size));
1424 }
1425 &Inst::MovK { rd, rn, imm, size } => {
1426 debug_assert_eq!(rn, rd.to_reg());
1427 sink.put4(enc_movk(rd, imm, size));
1428 }
1429 &Inst::CSel { rd, rn, rm, cond } => {
1430 sink.put4(enc_csel(rd, rn, rm, cond, 0, 0));
1431 }
1432 &Inst::CSNeg { rd, rn, rm, cond } => {
1433 sink.put4(enc_csel(rd, rn, rm, cond, 1, 1));
1434 }
1435 &Inst::CSet { rd, cond } => {
1436 sink.put4(enc_csel(rd, zero_reg(), zero_reg(), cond.invert(), 0, 1));
1437 }
1438 &Inst::CSetm { rd, cond } => {
1439 sink.put4(enc_csel(rd, zero_reg(), zero_reg(), cond.invert(), 1, 0));
1440 }
1441 &Inst::CCmp {
1442 size,
1443 rn,
1444 rm,
1445 nzcv,
1446 cond,
1447 } => {
1448 sink.put4(enc_ccmp(size, rn, rm, nzcv, cond));
1449 }
1450 &Inst::CCmpImm {
1451 size,
1452 rn,
1453 imm,
1454 nzcv,
1455 cond,
1456 } => {
1457 sink.put4(enc_ccmp_imm(size, rn, imm, nzcv, cond));
1458 }
1459 &Inst::AtomicRMW {
1460 ty,
1461 op,
1462 rs,
1463 rt,
1464 rn,
1465 flags,
1466 } => {
1467 if let Some(trap_code) = flags.trap_code() {
1468 sink.add_trap(trap_code);
1469 }
1470
1471 sink.put4(enc_acq_rel(ty, op, rs, rt, rn));
1472 }
1473 &Inst::AtomicRMWLoop { ty, op, flags, .. } => {
1474 let xzr = zero_reg();
1494 let x24 = xreg(24);
1495 let x25 = xreg(25);
1496 let x26 = xreg(26);
1497 let x27 = xreg(27);
1498 let x28 = xreg(28);
1499 let x24wr = writable_xreg(24);
1500 let x27wr = writable_xreg(27);
1501 let x28wr = writable_xreg(28);
1502 let again_label = sink.get_label();
1503
1504 sink.bind_label(again_label, &mut state.ctrl_plane);
1506
1507 if let Some(trap_code) = flags.trap_code() {
1508 sink.add_trap(trap_code);
1509 }
1510
1511 sink.put4(enc_ldaxr(ty, x27wr, x25)); let size = OperandSize::from_ty(ty);
1513 let sign_ext = match op {
1514 AtomicRMWLoopOp::Smin | AtomicRMWLoopOp::Smax => match ty {
1515 I16 => Some((ExtendOp::SXTH, 16)),
1516 I8 => Some((ExtendOp::SXTB, 8)),
1517 _ => None,
1518 },
1519 _ => None,
1520 };
1521 let zero_ext = match op {
1522 AtomicRMWLoopOp::Umin | AtomicRMWLoopOp::Umax => match ty {
1523 I16 => Some(ExtendOp::UXTH),
1524 I8 => Some(ExtendOp::UXTB),
1525 _ => None,
1526 },
1527 _ => None,
1528 };
1529 if sign_ext.is_some() {
1531 let (_, from_bits) = sign_ext.unwrap();
1532 Inst::Extend {
1533 rd: x27wr,
1534 rn: x27,
1535 signed: true,
1536 from_bits,
1537 to_bits: size.bits(),
1538 }
1539 .emit(sink, emit_info, state);
1540 }
1541
1542 match op {
1543 AtomicRMWLoopOp::Xchg => {} AtomicRMWLoopOp::Nand => {
1545 Inst::AluRRR {
1549 alu_op: ALUOp::And,
1550 size,
1551 rd: x28wr,
1552 rn: x27,
1553 rm: x26,
1554 }
1555 .emit(sink, emit_info, state);
1556
1557 Inst::AluRRR {
1558 alu_op: ALUOp::OrrNot,
1559 size,
1560 rd: x28wr,
1561 rn: xzr,
1562 rm: x28,
1563 }
1564 .emit(sink, emit_info, state);
1565 }
1566 AtomicRMWLoopOp::Umin
1567 | AtomicRMWLoopOp::Umax
1568 | AtomicRMWLoopOp::Smin
1569 | AtomicRMWLoopOp::Smax => {
1570 let cond = match op {
1574 AtomicRMWLoopOp::Umin => Cond::Lo,
1575 AtomicRMWLoopOp::Umax => Cond::Hi,
1576 AtomicRMWLoopOp::Smin => Cond::Lt,
1577 AtomicRMWLoopOp::Smax => Cond::Gt,
1578 _ => unreachable!(),
1579 };
1580
1581 if let Some(extendop) = sign_ext.map(|(op, _)| op).or(zero_ext) {
1582 Inst::AluRRRExtend {
1583 alu_op: ALUOp::SubS,
1584 size,
1585 rd: writable_zero_reg(),
1586 rn: x27,
1587 rm: x26,
1588 extendop,
1589 }
1590 .emit(sink, emit_info, state);
1591 } else {
1592 Inst::AluRRR {
1593 alu_op: ALUOp::SubS,
1594 size,
1595 rd: writable_zero_reg(),
1596 rn: x27,
1597 rm: x26,
1598 }
1599 .emit(sink, emit_info, state);
1600 }
1601
1602 Inst::CSel {
1603 cond,
1604 rd: x28wr,
1605 rn: x27,
1606 rm: x26,
1607 }
1608 .emit(sink, emit_info, state);
1609 }
1610 _ => {
1611 let alu_op = match op {
1613 AtomicRMWLoopOp::Add => ALUOp::Add,
1614 AtomicRMWLoopOp::Sub => ALUOp::Sub,
1615 AtomicRMWLoopOp::And => ALUOp::And,
1616 AtomicRMWLoopOp::Orr => ALUOp::Orr,
1617 AtomicRMWLoopOp::Eor => ALUOp::Eor,
1618 AtomicRMWLoopOp::Nand
1619 | AtomicRMWLoopOp::Umin
1620 | AtomicRMWLoopOp::Umax
1621 | AtomicRMWLoopOp::Smin
1622 | AtomicRMWLoopOp::Smax
1623 | AtomicRMWLoopOp::Xchg => unreachable!(),
1624 };
1625
1626 Inst::AluRRR {
1627 alu_op,
1628 size,
1629 rd: x28wr,
1630 rn: x27,
1631 rm: x26,
1632 }
1633 .emit(sink, emit_info, state);
1634 }
1635 }
1636
1637 if let Some(trap_code) = flags.trap_code() {
1638 sink.add_trap(trap_code);
1639 }
1640 if op == AtomicRMWLoopOp::Xchg {
1641 sink.put4(enc_stlxr(ty, x24wr, x26, x25)); } else {
1643 sink.put4(enc_stlxr(ty, x24wr, x28, x25)); }
1645
1646 let br_offset = sink.cur_offset();
1650 sink.put4(enc_conditional_br(
1651 BranchTarget::Label(again_label),
1652 CondBrKind::NotZero(x24, OperandSize::Size64),
1653 ));
1654 sink.use_label_at_offset(br_offset, again_label, LabelUse::Branch19);
1655 }
1656 &Inst::AtomicCAS {
1657 rd,
1658 rs,
1659 rt,
1660 rn,
1661 ty,
1662 flags,
1663 } => {
1664 debug_assert_eq!(rd.to_reg(), rs);
1665 let size = match ty {
1666 I8 => 0b00,
1667 I16 => 0b01,
1668 I32 => 0b10,
1669 I64 => 0b11,
1670 _ => panic!("Unsupported type: {ty}"),
1671 };
1672
1673 if let Some(trap_code) = flags.trap_code() {
1674 sink.add_trap(trap_code);
1675 }
1676
1677 sink.put4(enc_cas(size, rd, rt, rn));
1678 }
1679 Inst::AtomicCAS128 { args } => {
1680 let &AtomicCAS128Args {
1681 rd_lo,
1682 rd_hi,
1683 rs_lo,
1684 rs_hi,
1685 rt_lo,
1686 rt_hi,
1687 rn,
1688 flags,
1689 } = &**args;
1690 debug_assert_eq!(rd_lo.to_reg(), rs_lo);
1691 debug_assert_eq!(rd_hi.to_reg(), rs_hi);
1692
1693 debug_assert_eq!(rs_hi, xreg(machreg_to_gpr(rs_lo) as u8 + 1));
1695 debug_assert_eq!(rt_hi, xreg(machreg_to_gpr(rt_lo) as u8 + 1));
1696
1697 if let Some(trap_code) = flags.trap_code() {
1698 sink.add_trap(trap_code);
1699 }
1700
1701 sink.put4(enc_casp(rd_lo, rt_lo, rn));
1702 }
1703 &Inst::AtomicCASLoop { ty, flags, .. } => {
1704 let x24 = xreg(24);
1718 let x25 = xreg(25);
1719 let x26 = xreg(26);
1720 let x27 = xreg(27);
1721 let x28 = xreg(28);
1722 let xzrwr = writable_zero_reg();
1723 let x24wr = writable_xreg(24);
1724 let x27wr = writable_xreg(27);
1725 let again_label = sink.get_label();
1726 let out_label = sink.get_label();
1727
1728 sink.bind_label(again_label, &mut state.ctrl_plane);
1730
1731 if let Some(trap_code) = flags.trap_code() {
1732 sink.add_trap(trap_code);
1733 }
1734
1735 sink.put4(enc_ldaxr(ty, x27wr, x25));
1737
1738 let (bit21, extend_op) = match ty {
1741 I8 => (0b1, 0b000000),
1742 I16 => (0b1, 0b001000),
1743 _ => (0b0, 0b000000),
1744 };
1745 let bits_31_21 = 0b111_01011_000 | bit21;
1746 sink.put4(enc_arith_rrr(bits_31_21, extend_op, xzrwr, x27, x26));
1748
1749 let br_out_offset = sink.cur_offset();
1751 sink.put4(enc_conditional_br(
1752 BranchTarget::Label(out_label),
1753 CondBrKind::Cond(Cond::Ne),
1754 ));
1755 sink.use_label_at_offset(br_out_offset, out_label, LabelUse::Branch19);
1756
1757 if let Some(trap_code) = flags.trap_code() {
1758 sink.add_trap(trap_code);
1759 }
1760
1761 sink.put4(enc_stlxr(ty, x24wr, x28, x25)); let br_again_offset = sink.cur_offset();
1767 sink.put4(enc_conditional_br(
1768 BranchTarget::Label(again_label),
1769 CondBrKind::NotZero(x24, OperandSize::Size64),
1770 ));
1771 sink.use_label_at_offset(br_again_offset, again_label, LabelUse::Branch19);
1772
1773 sink.bind_label(out_label, &mut state.ctrl_plane);
1775 }
1776 &Inst::LoadAcquire {
1777 access_ty,
1778 rt,
1779 rn,
1780 flags,
1781 } => {
1782 if let Some(trap_code) = flags.trap_code() {
1783 sink.add_trap(trap_code);
1784 }
1785
1786 sink.put4(enc_ldar(access_ty, rt, rn));
1787 }
1788 &Inst::StoreRelease {
1789 access_ty,
1790 rt,
1791 rn,
1792 flags,
1793 } => {
1794 if let Some(trap_code) = flags.trap_code() {
1795 sink.add_trap(trap_code);
1796 }
1797
1798 sink.put4(enc_stlr(access_ty, rt, rn));
1799 }
1800 &Inst::Fence {} => {
1801 sink.put4(enc_dmb_ish()); }
1803 &Inst::Csdb {} => {
1804 sink.put4(0xd503229f);
1805 }
1806 &Inst::FpuMove32 { rd, rn } => {
1807 sink.put4(enc_fpurr(0b000_11110_00_1_000000_10000, rd, rn));
1808 }
1809 &Inst::FpuMove64 { rd, rn } => {
1810 sink.put4(enc_fpurr(0b000_11110_01_1_000000_10000, rd, rn));
1811 }
1812 &Inst::FpuMove128 { rd, rn } => {
1813 sink.put4(enc_vecmov(true, rd, rn));
1814 }
1815 &Inst::FpuMoveFromVec { rd, rn, idx, size } => {
1816 let (imm5, shift, mask) = match size.lane_size() {
1817 ScalarSize::Size32 => (0b00100, 3, 0b011),
1818 ScalarSize::Size64 => (0b01000, 4, 0b001),
1819 _ => unimplemented!(),
1820 };
1821 debug_assert_eq!(idx & mask, idx);
1822 let imm5 = imm5 | ((idx as u32) << shift);
1823 sink.put4(
1824 0b010_11110000_00000_000001_00000_00000
1825 | (imm5 << 16)
1826 | (machreg_to_vec(rn) << 5)
1827 | machreg_to_vec(rd.to_reg()),
1828 );
1829 }
1830 &Inst::FpuExtend { rd, rn, size } => {
1831 sink.put4(enc_fpurr(
1832 0b000_11110_00_1_000000_10000 | (size.ftype() << 12),
1833 rd,
1834 rn,
1835 ));
1836 }
1837 &Inst::FpuRR {
1838 fpu_op,
1839 size,
1840 rd,
1841 rn,
1842 } => {
1843 let top22 = match fpu_op {
1844 FPUOp1::Abs => 0b000_11110_00_1_000001_10000,
1845 FPUOp1::Neg => 0b000_11110_00_1_000010_10000,
1846 FPUOp1::Sqrt => 0b000_11110_00_1_000011_10000,
1847 FPUOp1::Cvt32To64 => {
1848 debug_assert_eq!(size, ScalarSize::Size32);
1849 0b000_11110_00_1_000101_10000
1850 }
1851 FPUOp1::Cvt64To32 => {
1852 debug_assert_eq!(size, ScalarSize::Size64);
1853 0b000_11110_01_1_000100_10000
1854 }
1855 };
1856 let top22 = top22 | size.ftype() << 12;
1857 sink.put4(enc_fpurr(top22, rd, rn));
1858 }
1859 &Inst::FpuRRR {
1860 fpu_op,
1861 size,
1862 rd,
1863 rn,
1864 rm,
1865 } => {
1866 let top22 = match fpu_op {
1867 FPUOp2::Add => 0b000_11110_00_1_00000_001010,
1868 FPUOp2::Sub => 0b000_11110_00_1_00000_001110,
1869 FPUOp2::Mul => 0b000_11110_00_1_00000_000010,
1870 FPUOp2::Div => 0b000_11110_00_1_00000_000110,
1871 FPUOp2::Max => 0b000_11110_00_1_00000_010010,
1872 FPUOp2::Min => 0b000_11110_00_1_00000_010110,
1873 };
1874 let top22 = top22 | size.ftype() << 12;
1875 sink.put4(enc_fpurrr(top22, rd, rn, rm));
1876 }
1877 &Inst::FpuRRI { fpu_op, rd, rn } => match fpu_op {
1878 FPUOpRI::UShr32(imm) => {
1879 debug_assert_eq!(32, imm.lane_size_in_bits);
1880 sink.put4(
1881 0b0_0_1_011110_0000000_00_0_0_0_1_00000_00000
1882 | imm.enc() << 16
1883 | machreg_to_vec(rn) << 5
1884 | machreg_to_vec(rd.to_reg()),
1885 )
1886 }
1887 FPUOpRI::UShr64(imm) => {
1888 debug_assert_eq!(64, imm.lane_size_in_bits);
1889 sink.put4(
1890 0b01_1_111110_0000000_00_0_0_0_1_00000_00000
1891 | imm.enc() << 16
1892 | machreg_to_vec(rn) << 5
1893 | machreg_to_vec(rd.to_reg()),
1894 )
1895 }
1896 },
1897 &Inst::FpuRRIMod { fpu_op, rd, ri, rn } => {
1898 debug_assert_eq!(rd.to_reg(), ri);
1899 match fpu_op {
1900 FPUOpRIMod::Sli64(imm) => {
1901 debug_assert_eq!(64, imm.lane_size_in_bits);
1902 sink.put4(
1903 0b01_1_111110_0000000_010101_00000_00000
1904 | imm.enc() << 16
1905 | machreg_to_vec(rn) << 5
1906 | machreg_to_vec(rd.to_reg()),
1907 )
1908 }
1909 FPUOpRIMod::Sli32(imm) => {
1910 debug_assert_eq!(32, imm.lane_size_in_bits);
1911 sink.put4(
1912 0b0_0_1_011110_0000000_010101_00000_00000
1913 | imm.enc() << 16
1914 | machreg_to_vec(rn) << 5
1915 | machreg_to_vec(rd.to_reg()),
1916 )
1917 }
1918 }
1919 }
1920 &Inst::FpuRRRR {
1921 fpu_op,
1922 size,
1923 rd,
1924 rn,
1925 rm,
1926 ra,
1927 } => {
1928 let top17 = match fpu_op {
1929 FPUOp3::MAdd => 0b000_11111_00_0_00000_0,
1930 FPUOp3::MSub => 0b000_11111_00_0_00000_1,
1931 FPUOp3::NMAdd => 0b000_11111_00_1_00000_0,
1932 FPUOp3::NMSub => 0b000_11111_00_1_00000_1,
1933 };
1934 let top17 = top17 | size.ftype() << 7;
1935 sink.put4(enc_fpurrrr(top17, rd, rn, rm, ra));
1936 }
1937 &Inst::VecMisc { op, rd, rn, size } => {
1938 let (q, enc_size) = size.enc_size();
1939 let (u, bits_12_16, size) = match op {
1940 VecMisc2::Not => (0b1, 0b00101, 0b00),
1941 VecMisc2::Neg => (0b1, 0b01011, enc_size),
1942 VecMisc2::Abs => (0b0, 0b01011, enc_size),
1943 VecMisc2::Fabs => {
1944 debug_assert!(
1945 size == VectorSize::Size32x2
1946 || size == VectorSize::Size32x4
1947 || size == VectorSize::Size64x2
1948 );
1949 (0b0, 0b01111, enc_size)
1950 }
1951 VecMisc2::Fneg => {
1952 debug_assert!(
1953 size == VectorSize::Size32x2
1954 || size == VectorSize::Size32x4
1955 || size == VectorSize::Size64x2
1956 );
1957 (0b1, 0b01111, enc_size)
1958 }
1959 VecMisc2::Fsqrt => {
1960 debug_assert!(
1961 size == VectorSize::Size32x2
1962 || size == VectorSize::Size32x4
1963 || size == VectorSize::Size64x2
1964 );
1965 (0b1, 0b11111, enc_size)
1966 }
1967 VecMisc2::Rev16 => {
1968 debug_assert_eq!(size, VectorSize::Size8x16);
1969 (0b0, 0b00001, enc_size)
1970 }
1971 VecMisc2::Rev32 => {
1972 debug_assert!(size == VectorSize::Size8x16 || size == VectorSize::Size16x8);
1973 (0b1, 0b00000, enc_size)
1974 }
1975 VecMisc2::Rev64 => {
1976 debug_assert!(
1977 size == VectorSize::Size8x16
1978 || size == VectorSize::Size16x8
1979 || size == VectorSize::Size32x4
1980 );
1981 (0b0, 0b00000, enc_size)
1982 }
1983 VecMisc2::Fcvtzs => {
1984 debug_assert!(
1985 size == VectorSize::Size32x2
1986 || size == VectorSize::Size32x4
1987 || size == VectorSize::Size64x2
1988 );
1989 (0b0, 0b11011, enc_size)
1990 }
1991 VecMisc2::Fcvtzu => {
1992 debug_assert!(
1993 size == VectorSize::Size32x2
1994 || size == VectorSize::Size32x4
1995 || size == VectorSize::Size64x2
1996 );
1997 (0b1, 0b11011, enc_size)
1998 }
1999 VecMisc2::Scvtf => {
2000 debug_assert!(size == VectorSize::Size32x4 || size == VectorSize::Size64x2);
2001 (0b0, 0b11101, enc_size & 0b1)
2002 }
2003 VecMisc2::Ucvtf => {
2004 debug_assert!(size == VectorSize::Size32x4 || size == VectorSize::Size64x2);
2005 (0b1, 0b11101, enc_size & 0b1)
2006 }
2007 VecMisc2::Frintn => {
2008 debug_assert!(
2009 size == VectorSize::Size32x2
2010 || size == VectorSize::Size32x4
2011 || size == VectorSize::Size64x2
2012 );
2013 (0b0, 0b11000, enc_size & 0b01)
2014 }
2015 VecMisc2::Frintz => {
2016 debug_assert!(
2017 size == VectorSize::Size32x2
2018 || size == VectorSize::Size32x4
2019 || size == VectorSize::Size64x2
2020 );
2021 (0b0, 0b11001, enc_size)
2022 }
2023 VecMisc2::Frintm => {
2024 debug_assert!(
2025 size == VectorSize::Size32x2
2026 || size == VectorSize::Size32x4
2027 || size == VectorSize::Size64x2
2028 );
2029 (0b0, 0b11001, enc_size & 0b01)
2030 }
2031 VecMisc2::Frintp => {
2032 debug_assert!(
2033 size == VectorSize::Size32x2
2034 || size == VectorSize::Size32x4
2035 || size == VectorSize::Size64x2
2036 );
2037 (0b0, 0b11000, enc_size)
2038 }
2039 VecMisc2::Cnt => {
2040 debug_assert!(size == VectorSize::Size8x8 || size == VectorSize::Size8x16);
2041 (0b0, 0b00101, enc_size)
2042 }
2043 VecMisc2::Cmeq0 => (0b0, 0b01001, enc_size),
2044 VecMisc2::Cmge0 => (0b1, 0b01000, enc_size),
2045 VecMisc2::Cmgt0 => (0b0, 0b01000, enc_size),
2046 VecMisc2::Cmle0 => (0b1, 0b01001, enc_size),
2047 VecMisc2::Cmlt0 => (0b0, 0b01010, enc_size),
2048 VecMisc2::Fcmeq0 => {
2049 debug_assert!(
2050 size == VectorSize::Size32x2
2051 || size == VectorSize::Size32x4
2052 || size == VectorSize::Size64x2
2053 );
2054 (0b0, 0b01101, enc_size)
2055 }
2056 VecMisc2::Fcmge0 => {
2057 debug_assert!(
2058 size == VectorSize::Size32x2
2059 || size == VectorSize::Size32x4
2060 || size == VectorSize::Size64x2
2061 );
2062 (0b1, 0b01100, enc_size)
2063 }
2064 VecMisc2::Fcmgt0 => {
2065 debug_assert!(
2066 size == VectorSize::Size32x2
2067 || size == VectorSize::Size32x4
2068 || size == VectorSize::Size64x2
2069 );
2070 (0b0, 0b01100, enc_size)
2071 }
2072 VecMisc2::Fcmle0 => {
2073 debug_assert!(
2074 size == VectorSize::Size32x2
2075 || size == VectorSize::Size32x4
2076 || size == VectorSize::Size64x2
2077 );
2078 (0b1, 0b01101, enc_size)
2079 }
2080 VecMisc2::Fcmlt0 => {
2081 debug_assert!(
2082 size == VectorSize::Size32x2
2083 || size == VectorSize::Size32x4
2084 || size == VectorSize::Size64x2
2085 );
2086 (0b0, 0b01110, enc_size)
2087 }
2088 };
2089 sink.put4(enc_vec_rr_misc((q << 1) | u, size, bits_12_16, rd, rn));
2090 }
2091 &Inst::VecLanes { op, rd, rn, size } => {
2092 let (q, size) = match size {
2093 VectorSize::Size8x8 => (0b0, 0b00),
2094 VectorSize::Size8x16 => (0b1, 0b00),
2095 VectorSize::Size16x4 => (0b0, 0b01),
2096 VectorSize::Size16x8 => (0b1, 0b01),
2097 VectorSize::Size32x4 => (0b1, 0b10),
2098 _ => unreachable!(),
2099 };
2100 let (u, opcode) = match op {
2101 VecLanesOp::Uminv => (0b1, 0b11010),
2102 VecLanesOp::Addv => (0b0, 0b11011),
2103 };
2104 sink.put4(enc_vec_lanes(q, u, size, opcode, rd, rn));
2105 }
2106 &Inst::VecShiftImm {
2107 op,
2108 rd,
2109 rn,
2110 size,
2111 imm,
2112 } => {
2113 let (is_shr, mut template) = match op {
2114 VecShiftImmOp::Ushr => (true, 0b_001_011110_0000_000_000001_00000_00000_u32),
2115 VecShiftImmOp::Sshr => (true, 0b_000_011110_0000_000_000001_00000_00000_u32),
2116 VecShiftImmOp::Shl => (false, 0b_000_011110_0000_000_010101_00000_00000_u32),
2117 };
2118 if size.is_128bits() {
2119 template |= 0b1 << 30;
2120 }
2121 let imm = imm as u32;
2122 let immh_immb = match (size.lane_size(), is_shr) {
2125 (ScalarSize::Size64, true) if imm >= 1 && imm <= 64 => {
2126 0b_1000_000_u32 | (64 - imm)
2127 }
2128 (ScalarSize::Size32, true) if imm >= 1 && imm <= 32 => {
2129 0b_0100_000_u32 | (32 - imm)
2130 }
2131 (ScalarSize::Size16, true) if imm >= 1 && imm <= 16 => {
2132 0b_0010_000_u32 | (16 - imm)
2133 }
2134 (ScalarSize::Size8, true) if imm >= 1 && imm <= 8 => {
2135 0b_0001_000_u32 | (8 - imm)
2136 }
2137 (ScalarSize::Size64, false) if imm <= 63 => 0b_1000_000_u32 | imm,
2138 (ScalarSize::Size32, false) if imm <= 31 => 0b_0100_000_u32 | imm,
2139 (ScalarSize::Size16, false) if imm <= 15 => 0b_0010_000_u32 | imm,
2140 (ScalarSize::Size8, false) if imm <= 7 => 0b_0001_000_u32 | imm,
2141 _ => panic!(
2142 "aarch64: Inst::VecShiftImm: emit: invalid op/size/imm {op:?}, {size:?}, {imm:?}"
2143 ),
2144 };
2145 let rn_enc = machreg_to_vec(rn);
2146 let rd_enc = machreg_to_vec(rd.to_reg());
2147 sink.put4(template | (immh_immb << 16) | (rn_enc << 5) | rd_enc);
2148 }
2149 &Inst::VecShiftImmMod {
2150 op,
2151 rd,
2152 ri,
2153 rn,
2154 size,
2155 imm,
2156 } => {
2157 debug_assert_eq!(rd.to_reg(), ri);
2158 let (is_shr, mut template) = match op {
2159 VecShiftImmModOp::Sli => (false, 0b_001_011110_0000_000_010101_00000_00000_u32),
2160 };
2161 if size.is_128bits() {
2162 template |= 0b1 << 30;
2163 }
2164 let imm = imm as u32;
2165 let immh_immb = match (size.lane_size(), is_shr) {
2168 (ScalarSize::Size64, true) if imm >= 1 && imm <= 64 => {
2169 0b_1000_000_u32 | (64 - imm)
2170 }
2171 (ScalarSize::Size32, true) if imm >= 1 && imm <= 32 => {
2172 0b_0100_000_u32 | (32 - imm)
2173 }
2174 (ScalarSize::Size16, true) if imm >= 1 && imm <= 16 => {
2175 0b_0010_000_u32 | (16 - imm)
2176 }
2177 (ScalarSize::Size8, true) if imm >= 1 && imm <= 8 => {
2178 0b_0001_000_u32 | (8 - imm)
2179 }
2180 (ScalarSize::Size64, false) if imm <= 63 => 0b_1000_000_u32 | imm,
2181 (ScalarSize::Size32, false) if imm <= 31 => 0b_0100_000_u32 | imm,
2182 (ScalarSize::Size16, false) if imm <= 15 => 0b_0010_000_u32 | imm,
2183 (ScalarSize::Size8, false) if imm <= 7 => 0b_0001_000_u32 | imm,
2184 _ => panic!(
2185 "aarch64: Inst::VecShiftImmMod: emit: invalid op/size/imm {op:?}, {size:?}, {imm:?}"
2186 ),
2187 };
2188 let rn_enc = machreg_to_vec(rn);
2189 let rd_enc = machreg_to_vec(rd.to_reg());
2190 sink.put4(template | (immh_immb << 16) | (rn_enc << 5) | rd_enc);
2191 }
2192 &Inst::VecExtract { rd, rn, rm, imm4 } => {
2193 if imm4 < 16 {
2194 let template = 0b_01_101110_000_00000_0_0000_0_00000_00000_u32;
2195 let rm_enc = machreg_to_vec(rm);
2196 let rn_enc = machreg_to_vec(rn);
2197 let rd_enc = machreg_to_vec(rd.to_reg());
2198 sink.put4(
2199 template | (rm_enc << 16) | ((imm4 as u32) << 11) | (rn_enc << 5) | rd_enc,
2200 );
2201 } else {
2202 panic!("aarch64: Inst::VecExtract: emit: invalid extract index {imm4}");
2203 }
2204 }
2205 &Inst::VecTbl { rd, rn, rm } => {
2206 sink.put4(enc_tbl(false, 0b00, rd, rn, rm));
2207 }
2208 &Inst::VecTblExt { rd, ri, rn, rm } => {
2209 debug_assert_eq!(rd.to_reg(), ri);
2210 sink.put4(enc_tbl(true, 0b00, rd, rn, rm));
2211 }
2212 &Inst::VecTbl2 { rd, rn, rn2, rm } => {
2213 assert_eq!(machreg_to_vec(rn2), (machreg_to_vec(rn) + 1) % 32);
2214 sink.put4(enc_tbl(false, 0b01, rd, rn, rm));
2215 }
2216 &Inst::VecTbl2Ext {
2217 rd,
2218 ri,
2219 rn,
2220 rn2,
2221 rm,
2222 } => {
2223 debug_assert_eq!(rd.to_reg(), ri);
2224 assert_eq!(machreg_to_vec(rn2), (machreg_to_vec(rn) + 1) % 32);
2225 sink.put4(enc_tbl(true, 0b01, rd, rn, rm));
2226 }
2227 &Inst::FpuCmp { size, rn, rm } => {
2228 sink.put4(enc_fcmp(size, rn, rm));
2229 }
2230 &Inst::FpuToInt { op, rd, rn } => {
2231 let top16 = match op {
2232 FpuToIntOp::F32ToI32 => 0b000_11110_00_1_11_000,
2234 FpuToIntOp::F32ToU32 => 0b000_11110_00_1_11_001,
2236 FpuToIntOp::F32ToI64 => 0b100_11110_00_1_11_000,
2238 FpuToIntOp::F32ToU64 => 0b100_11110_00_1_11_001,
2240 FpuToIntOp::F64ToI32 => 0b000_11110_01_1_11_000,
2242 FpuToIntOp::F64ToU32 => 0b000_11110_01_1_11_001,
2244 FpuToIntOp::F64ToI64 => 0b100_11110_01_1_11_000,
2246 FpuToIntOp::F64ToU64 => 0b100_11110_01_1_11_001,
2248 };
2249 sink.put4(enc_fputoint(top16, rd, rn));
2250 }
2251 &Inst::IntToFpu { op, rd, rn } => {
2252 let top16 = match op {
2253 IntToFpuOp::I32ToF32 => 0b000_11110_00_1_00_010,
2255 IntToFpuOp::U32ToF32 => 0b000_11110_00_1_00_011,
2257 IntToFpuOp::I64ToF32 => 0b100_11110_00_1_00_010,
2259 IntToFpuOp::U64ToF32 => 0b100_11110_00_1_00_011,
2261 IntToFpuOp::I32ToF64 => 0b000_11110_01_1_00_010,
2263 IntToFpuOp::U32ToF64 => 0b000_11110_01_1_00_011,
2265 IntToFpuOp::I64ToF64 => 0b100_11110_01_1_00_010,
2267 IntToFpuOp::U64ToF64 => 0b100_11110_01_1_00_011,
2269 };
2270 sink.put4(enc_inttofpu(top16, rd, rn));
2271 }
2272 &Inst::FpuCSel16 { rd, rn, rm, cond } => {
2273 sink.put4(enc_fcsel(rd, rn, rm, cond, ScalarSize::Size16));
2274 }
2275 &Inst::FpuCSel32 { rd, rn, rm, cond } => {
2276 sink.put4(enc_fcsel(rd, rn, rm, cond, ScalarSize::Size32));
2277 }
2278 &Inst::FpuCSel64 { rd, rn, rm, cond } => {
2279 sink.put4(enc_fcsel(rd, rn, rm, cond, ScalarSize::Size64));
2280 }
2281 &Inst::FpuRound { op, rd, rn } => {
2282 let top22 = match op {
2283 FpuRoundMode::Minus32 => 0b000_11110_00_1_001_010_10000,
2284 FpuRoundMode::Minus64 => 0b000_11110_01_1_001_010_10000,
2285 FpuRoundMode::Plus32 => 0b000_11110_00_1_001_001_10000,
2286 FpuRoundMode::Plus64 => 0b000_11110_01_1_001_001_10000,
2287 FpuRoundMode::Zero32 => 0b000_11110_00_1_001_011_10000,
2288 FpuRoundMode::Zero64 => 0b000_11110_01_1_001_011_10000,
2289 FpuRoundMode::Nearest32 => 0b000_11110_00_1_001_000_10000,
2290 FpuRoundMode::Nearest64 => 0b000_11110_01_1_001_000_10000,
2291 };
2292 sink.put4(enc_fround(top22, rd, rn));
2293 }
2294 &Inst::MovToFpu { rd, rn, size } => {
2295 let template = match size {
2296 ScalarSize::Size16 => 0b000_11110_11_1_00_111_000000_00000_00000,
2297 ScalarSize::Size32 => 0b000_11110_00_1_00_111_000000_00000_00000,
2298 ScalarSize::Size64 => 0b100_11110_01_1_00_111_000000_00000_00000,
2299 _ => unreachable!(),
2300 };
2301 sink.put4(template | (machreg_to_gpr(rn) << 5) | machreg_to_vec(rd.to_reg()));
2302 }
2303 &Inst::FpuMoveFPImm { rd, imm, size } => {
2304 sink.put4(
2305 0b000_11110_00_1_00_000_000100_00000_00000
2306 | size.ftype() << 22
2307 | ((imm.enc_bits() as u32) << 13)
2308 | machreg_to_vec(rd.to_reg()),
2309 );
2310 }
2311 &Inst::MovToVec {
2312 rd,
2313 ri,
2314 rn,
2315 idx,
2316 size,
2317 } => {
2318 debug_assert_eq!(rd.to_reg(), ri);
2319 let (imm5, shift) = match size.lane_size() {
2320 ScalarSize::Size8 => (0b00001, 1),
2321 ScalarSize::Size16 => (0b00010, 2),
2322 ScalarSize::Size32 => (0b00100, 3),
2323 ScalarSize::Size64 => (0b01000, 4),
2324 _ => unreachable!(),
2325 };
2326 debug_assert_eq!(idx & (0b11111 >> shift), idx);
2327 let imm5 = imm5 | ((idx as u32) << shift);
2328 sink.put4(
2329 0b010_01110000_00000_0_0011_1_00000_00000
2330 | (imm5 << 16)
2331 | (machreg_to_gpr(rn) << 5)
2332 | machreg_to_vec(rd.to_reg()),
2333 );
2334 }
2335 &Inst::MovFromVec { rd, rn, idx, size } => {
2336 let (q, imm5, shift, mask) = match size {
2337 ScalarSize::Size8 => (0b0, 0b00001, 1, 0b1111),
2338 ScalarSize::Size16 => (0b0, 0b00010, 2, 0b0111),
2339 ScalarSize::Size32 => (0b0, 0b00100, 3, 0b0011),
2340 ScalarSize::Size64 => (0b1, 0b01000, 4, 0b0001),
2341 _ => panic!("Unexpected scalar FP operand size: {size:?}"),
2342 };
2343 debug_assert_eq!(idx & mask, idx);
2344 let imm5 = imm5 | ((idx as u32) << shift);
2345 sink.put4(
2346 0b000_01110000_00000_0_0111_1_00000_00000
2347 | (q << 30)
2348 | (imm5 << 16)
2349 | (machreg_to_vec(rn) << 5)
2350 | machreg_to_gpr(rd.to_reg()),
2351 );
2352 }
2353 &Inst::MovFromVecSigned {
2354 rd,
2355 rn,
2356 idx,
2357 size,
2358 scalar_size,
2359 } => {
2360 let (imm5, shift, half) = match size {
2361 VectorSize::Size8x8 => (0b00001, 1, true),
2362 VectorSize::Size8x16 => (0b00001, 1, false),
2363 VectorSize::Size16x4 => (0b00010, 2, true),
2364 VectorSize::Size16x8 => (0b00010, 2, false),
2365 VectorSize::Size32x2 => {
2366 debug_assert_ne!(scalar_size, OperandSize::Size32);
2367 (0b00100, 3, true)
2368 }
2369 VectorSize::Size32x4 => {
2370 debug_assert_ne!(scalar_size, OperandSize::Size32);
2371 (0b00100, 3, false)
2372 }
2373 _ => panic!("Unexpected vector operand size"),
2374 };
2375 debug_assert_eq!(idx & (0b11111 >> (half as u32 + shift)), idx);
2376 let imm5 = imm5 | ((idx as u32) << shift);
2377 sink.put4(
2378 0b000_01110000_00000_0_0101_1_00000_00000
2379 | (scalar_size.is64() as u32) << 30
2380 | (imm5 << 16)
2381 | (machreg_to_vec(rn) << 5)
2382 | machreg_to_gpr(rd.to_reg()),
2383 );
2384 }
2385 &Inst::VecDup { rd, rn, size } => {
2386 let q = size.is_128bits() as u32;
2387 let imm5 = match size.lane_size() {
2388 ScalarSize::Size8 => 0b00001,
2389 ScalarSize::Size16 => 0b00010,
2390 ScalarSize::Size32 => 0b00100,
2391 ScalarSize::Size64 => 0b01000,
2392 _ => unreachable!(),
2393 };
2394 sink.put4(
2395 0b0_0_0_01110000_00000_000011_00000_00000
2396 | (q << 30)
2397 | (imm5 << 16)
2398 | (machreg_to_gpr(rn) << 5)
2399 | machreg_to_vec(rd.to_reg()),
2400 );
2401 }
2402 &Inst::VecDupFromFpu { rd, rn, size, lane } => {
2403 let q = size.is_128bits() as u32;
2404 let imm5 = match size.lane_size() {
2405 ScalarSize::Size8 => {
2406 assert!(lane < 16);
2407 0b00001 | (u32::from(lane) << 1)
2408 }
2409 ScalarSize::Size16 => {
2410 assert!(lane < 8);
2411 0b00010 | (u32::from(lane) << 2)
2412 }
2413 ScalarSize::Size32 => {
2414 assert!(lane < 4);
2415 0b00100 | (u32::from(lane) << 3)
2416 }
2417 ScalarSize::Size64 => {
2418 assert!(lane < 2);
2419 0b01000 | (u32::from(lane) << 4)
2420 }
2421 _ => unimplemented!(),
2422 };
2423 sink.put4(
2424 0b000_01110000_00000_000001_00000_00000
2425 | (q << 30)
2426 | (imm5 << 16)
2427 | (machreg_to_vec(rn) << 5)
2428 | machreg_to_vec(rd.to_reg()),
2429 );
2430 }
2431 &Inst::VecDupFPImm { rd, imm, size } => {
2432 let imm = imm.enc_bits();
2433 let op = match size.lane_size() {
2434 ScalarSize::Size32 => 0,
2435 ScalarSize::Size64 => 1,
2436 _ => unimplemented!(),
2437 };
2438 let q_op = op | ((size.is_128bits() as u32) << 1);
2439
2440 sink.put4(enc_asimd_mod_imm(rd, q_op, 0b1111, imm));
2441 }
2442 &Inst::VecDupImm {
2443 rd,
2444 imm,
2445 invert,
2446 size,
2447 } => {
2448 let (imm, shift, shift_ones) = imm.value();
2449 let (op, cmode) = match size.lane_size() {
2450 ScalarSize::Size8 => {
2451 assert!(!invert);
2452 assert_eq!(shift, 0);
2453
2454 (0, 0b1110)
2455 }
2456 ScalarSize::Size16 => {
2457 let s = shift & 8;
2458
2459 assert!(!shift_ones);
2460 assert_eq!(s, shift);
2461
2462 (invert as u32, 0b1000 | (s >> 2))
2463 }
2464 ScalarSize::Size32 => {
2465 if shift_ones {
2466 assert!(shift == 8 || shift == 16);
2467
2468 (invert as u32, 0b1100 | (shift >> 4))
2469 } else {
2470 let s = shift & 24;
2471
2472 assert_eq!(s, shift);
2473
2474 (invert as u32, 0b0000 | (s >> 2))
2475 }
2476 }
2477 ScalarSize::Size64 => {
2478 assert!(!invert);
2479 assert_eq!(shift, 0);
2480
2481 (1, 0b1110)
2482 }
2483 _ => unreachable!(),
2484 };
2485 let q_op = op | ((size.is_128bits() as u32) << 1);
2486
2487 sink.put4(enc_asimd_mod_imm(rd, q_op, cmode, imm));
2488 }
2489 &Inst::VecExtend {
2490 t,
2491 rd,
2492 rn,
2493 high_half,
2494 lane_size,
2495 } => {
2496 let immh = match lane_size {
2497 ScalarSize::Size16 => 0b001,
2498 ScalarSize::Size32 => 0b010,
2499 ScalarSize::Size64 => 0b100,
2500 _ => panic!("Unexpected VecExtend to lane size of {lane_size:?}"),
2501 };
2502 let u = match t {
2503 VecExtendOp::Sxtl => 0b0,
2504 VecExtendOp::Uxtl => 0b1,
2505 };
2506 sink.put4(
2507 0b000_011110_0000_000_101001_00000_00000
2508 | ((high_half as u32) << 30)
2509 | (u << 29)
2510 | (immh << 19)
2511 | (machreg_to_vec(rn) << 5)
2512 | machreg_to_vec(rd.to_reg()),
2513 );
2514 }
2515 &Inst::VecRRLong {
2516 op,
2517 rd,
2518 rn,
2519 high_half,
2520 } => {
2521 let (u, size, bits_12_16) = match op {
2522 VecRRLongOp::Fcvtl16 => (0b0, 0b00, 0b10111),
2523 VecRRLongOp::Fcvtl32 => (0b0, 0b01, 0b10111),
2524 VecRRLongOp::Shll8 => (0b1, 0b00, 0b10011),
2525 VecRRLongOp::Shll16 => (0b1, 0b01, 0b10011),
2526 VecRRLongOp::Shll32 => (0b1, 0b10, 0b10011),
2527 };
2528
2529 sink.put4(enc_vec_rr_misc(
2530 ((high_half as u32) << 1) | u,
2531 size,
2532 bits_12_16,
2533 rd,
2534 rn,
2535 ));
2536 }
2537 &Inst::VecRRNarrowLow {
2538 op,
2539 rd,
2540 rn,
2541 lane_size,
2542 }
2543 | &Inst::VecRRNarrowHigh {
2544 op,
2545 rd,
2546 rn,
2547 lane_size,
2548 ..
2549 } => {
2550 let high_half = match self {
2551 &Inst::VecRRNarrowLow { .. } => false,
2552 &Inst::VecRRNarrowHigh { .. } => true,
2553 _ => unreachable!(),
2554 };
2555
2556 let size = match lane_size {
2557 ScalarSize::Size8 => 0b00,
2558 ScalarSize::Size16 => 0b01,
2559 ScalarSize::Size32 => 0b10,
2560 _ => panic!("unsupported size: {lane_size:?}"),
2561 };
2562
2563 let size = match op {
2565 VecRRNarrowOp::Fcvtn => size >> 1,
2566 _ => size,
2567 };
2568
2569 let (u, bits_12_16) = match op {
2570 VecRRNarrowOp::Xtn => (0b0, 0b10010),
2571 VecRRNarrowOp::Sqxtn => (0b0, 0b10100),
2572 VecRRNarrowOp::Sqxtun => (0b1, 0b10010),
2573 VecRRNarrowOp::Uqxtn => (0b1, 0b10100),
2574 VecRRNarrowOp::Fcvtn => (0b0, 0b10110),
2575 };
2576
2577 sink.put4(enc_vec_rr_misc(
2578 ((high_half as u32) << 1) | u,
2579 size,
2580 bits_12_16,
2581 rd,
2582 rn,
2583 ));
2584 }
2585 &Inst::VecMovElement {
2586 rd,
2587 ri,
2588 rn,
2589 dest_idx,
2590 src_idx,
2591 size,
2592 } => {
2593 debug_assert_eq!(rd.to_reg(), ri);
2594 let (imm5, shift) = match size.lane_size() {
2595 ScalarSize::Size8 => (0b00001, 1),
2596 ScalarSize::Size16 => (0b00010, 2),
2597 ScalarSize::Size32 => (0b00100, 3),
2598 ScalarSize::Size64 => (0b01000, 4),
2599 _ => unreachable!(),
2600 };
2601 let mask = 0b11111 >> shift;
2602 debug_assert_eq!(dest_idx & mask, dest_idx);
2603 debug_assert_eq!(src_idx & mask, src_idx);
2604 let imm4 = (src_idx as u32) << (shift - 1);
2605 let imm5 = imm5 | ((dest_idx as u32) << shift);
2606 sink.put4(
2607 0b011_01110000_00000_0_0000_1_00000_00000
2608 | (imm5 << 16)
2609 | (imm4 << 11)
2610 | (machreg_to_vec(rn) << 5)
2611 | machreg_to_vec(rd.to_reg()),
2612 );
2613 }
2614 &Inst::VecRRPair { op, rd, rn } => {
2615 let bits_12_16 = match op {
2616 VecPairOp::Addp => 0b11011,
2617 };
2618
2619 sink.put4(enc_vec_rr_pair(bits_12_16, rd, rn));
2620 }
2621 &Inst::VecRRRLong {
2622 rd,
2623 rn,
2624 rm,
2625 alu_op,
2626 high_half,
2627 } => {
2628 let (u, size, bit14) = match alu_op {
2629 VecRRRLongOp::Smull8 => (0b0, 0b00, 0b1),
2630 VecRRRLongOp::Smull16 => (0b0, 0b01, 0b1),
2631 VecRRRLongOp::Smull32 => (0b0, 0b10, 0b1),
2632 VecRRRLongOp::Umull8 => (0b1, 0b00, 0b1),
2633 VecRRRLongOp::Umull16 => (0b1, 0b01, 0b1),
2634 VecRRRLongOp::Umull32 => (0b1, 0b10, 0b1),
2635 };
2636 sink.put4(enc_vec_rrr_long(
2637 high_half as u32,
2638 u,
2639 size,
2640 bit14,
2641 rm,
2642 rn,
2643 rd,
2644 ));
2645 }
2646 &Inst::VecRRRLongMod {
2647 rd,
2648 ri,
2649 rn,
2650 rm,
2651 alu_op,
2652 high_half,
2653 } => {
2654 debug_assert_eq!(rd.to_reg(), ri);
2655 let (u, size, bit14) = match alu_op {
2656 VecRRRLongModOp::Umlal8 => (0b1, 0b00, 0b0),
2657 VecRRRLongModOp::Umlal16 => (0b1, 0b01, 0b0),
2658 VecRRRLongModOp::Umlal32 => (0b1, 0b10, 0b0),
2659 };
2660 sink.put4(enc_vec_rrr_long(
2661 high_half as u32,
2662 u,
2663 size,
2664 bit14,
2665 rm,
2666 rn,
2667 rd,
2668 ));
2669 }
2670 &Inst::VecRRPairLong { op, rd, rn } => {
2671 let (u, size) = match op {
2672 VecRRPairLongOp::Saddlp8 => (0b0, 0b0),
2673 VecRRPairLongOp::Uaddlp8 => (0b1, 0b0),
2674 VecRRPairLongOp::Saddlp16 => (0b0, 0b1),
2675 VecRRPairLongOp::Uaddlp16 => (0b1, 0b1),
2676 };
2677
2678 sink.put4(enc_vec_rr_pair_long(u, size, rd, rn));
2679 }
2680 &Inst::VecRRR {
2681 rd,
2682 rn,
2683 rm,
2684 alu_op,
2685 size,
2686 } => {
2687 let (q, enc_size) = size.enc_size();
2688 let is_float = match alu_op {
2689 VecALUOp::Fcmeq
2690 | VecALUOp::Fcmgt
2691 | VecALUOp::Fcmge
2692 | VecALUOp::Fadd
2693 | VecALUOp::Fsub
2694 | VecALUOp::Fdiv
2695 | VecALUOp::Fmax
2696 | VecALUOp::Fmin
2697 | VecALUOp::Fmul => true,
2698 _ => false,
2699 };
2700
2701 let (top11, bit15_10) = match alu_op {
2702 VecALUOp::Sqadd => (0b000_01110_00_1 | enc_size << 1, 0b000011),
2703 VecALUOp::Sqsub => (0b000_01110_00_1 | enc_size << 1, 0b001011),
2704 VecALUOp::Uqadd => (0b001_01110_00_1 | enc_size << 1, 0b000011),
2705 VecALUOp::Uqsub => (0b001_01110_00_1 | enc_size << 1, 0b001011),
2706 VecALUOp::Cmeq => (0b001_01110_00_1 | enc_size << 1, 0b100011),
2707 VecALUOp::Cmge => (0b000_01110_00_1 | enc_size << 1, 0b001111),
2708 VecALUOp::Cmgt => (0b000_01110_00_1 | enc_size << 1, 0b001101),
2709 VecALUOp::Cmhi => (0b001_01110_00_1 | enc_size << 1, 0b001101),
2710 VecALUOp::Cmhs => (0b001_01110_00_1 | enc_size << 1, 0b001111),
2711 VecALUOp::Fcmeq => (0b000_01110_00_1, 0b111001),
2712 VecALUOp::Fcmgt => (0b001_01110_10_1, 0b111001),
2713 VecALUOp::Fcmge => (0b001_01110_00_1, 0b111001),
2714 VecALUOp::And => (0b000_01110_00_1, 0b000111),
2717 VecALUOp::Bic => (0b000_01110_01_1, 0b000111),
2718 VecALUOp::Orr => (0b000_01110_10_1, 0b000111),
2719 VecALUOp::Orn => (0b000_01110_11_1, 0b000111),
2720 VecALUOp::Eor => (0b001_01110_00_1, 0b000111),
2721 VecALUOp::Umaxp => {
2722 debug_assert_ne!(size, VectorSize::Size64x2);
2723
2724 (0b001_01110_00_1 | enc_size << 1, 0b101001)
2725 }
2726 VecALUOp::Add => (0b000_01110_00_1 | enc_size << 1, 0b100001),
2727 VecALUOp::Sub => (0b001_01110_00_1 | enc_size << 1, 0b100001),
2728 VecALUOp::Mul => {
2729 debug_assert_ne!(size, VectorSize::Size64x2);
2730 (0b000_01110_00_1 | enc_size << 1, 0b100111)
2731 }
2732 VecALUOp::Sshl => (0b000_01110_00_1 | enc_size << 1, 0b010001),
2733 VecALUOp::Ushl => (0b001_01110_00_1 | enc_size << 1, 0b010001),
2734 VecALUOp::Umin => {
2735 debug_assert_ne!(size, VectorSize::Size64x2);
2736
2737 (0b001_01110_00_1 | enc_size << 1, 0b011011)
2738 }
2739 VecALUOp::Smin => {
2740 debug_assert_ne!(size, VectorSize::Size64x2);
2741
2742 (0b000_01110_00_1 | enc_size << 1, 0b011011)
2743 }
2744 VecALUOp::Umax => {
2745 debug_assert_ne!(size, VectorSize::Size64x2);
2746
2747 (0b001_01110_00_1 | enc_size << 1, 0b011001)
2748 }
2749 VecALUOp::Smax => {
2750 debug_assert_ne!(size, VectorSize::Size64x2);
2751
2752 (0b000_01110_00_1 | enc_size << 1, 0b011001)
2753 }
2754 VecALUOp::Urhadd => {
2755 debug_assert_ne!(size, VectorSize::Size64x2);
2756
2757 (0b001_01110_00_1 | enc_size << 1, 0b000101)
2758 }
2759 VecALUOp::Fadd => (0b000_01110_00_1, 0b110101),
2760 VecALUOp::Fsub => (0b000_01110_10_1, 0b110101),
2761 VecALUOp::Fdiv => (0b001_01110_00_1, 0b111111),
2762 VecALUOp::Fmax => (0b000_01110_00_1, 0b111101),
2763 VecALUOp::Fmin => (0b000_01110_10_1, 0b111101),
2764 VecALUOp::Fmul => (0b001_01110_00_1, 0b110111),
2765 VecALUOp::Addp => (0b000_01110_00_1 | enc_size << 1, 0b101111),
2766 VecALUOp::Zip1 => (0b01001110_00_0 | enc_size << 1, 0b001110),
2767 VecALUOp::Zip2 => (0b01001110_00_0 | enc_size << 1, 0b011110),
2768 VecALUOp::Sqrdmulh => {
2769 debug_assert!(
2770 size.lane_size() == ScalarSize::Size16
2771 || size.lane_size() == ScalarSize::Size32
2772 );
2773
2774 (0b001_01110_00_1 | enc_size << 1, 0b101101)
2775 }
2776 VecALUOp::Uzp1 => (0b01001110_00_0 | enc_size << 1, 0b000110),
2777 VecALUOp::Uzp2 => (0b01001110_00_0 | enc_size << 1, 0b010110),
2778 VecALUOp::Trn1 => (0b01001110_00_0 | enc_size << 1, 0b001010),
2779 VecALUOp::Trn2 => (0b01001110_00_0 | enc_size << 1, 0b011010),
2780 };
2781 let top11 = if is_float {
2782 top11 | size.enc_float_size() << 1
2783 } else {
2784 top11
2785 };
2786 sink.put4(enc_vec_rrr(top11 | q << 9, rm, bit15_10, rn, rd));
2787 }
2788 &Inst::VecRRRMod {
2789 rd,
2790 ri,
2791 rn,
2792 rm,
2793 alu_op,
2794 size,
2795 } => {
2796 debug_assert_eq!(rd.to_reg(), ri);
2797 let (q, _enc_size) = size.enc_size();
2798
2799 let (top11, bit15_10) = match alu_op {
2800 VecALUModOp::Bsl => (0b001_01110_01_1, 0b000111),
2801 VecALUModOp::Fmla => {
2802 (0b000_01110_00_1 | (size.enc_float_size() << 1), 0b110011)
2803 }
2804 VecALUModOp::Fmls => {
2805 (0b000_01110_10_1 | (size.enc_float_size() << 1), 0b110011)
2806 }
2807 VecALUModOp::Sdot => (0b000_01110_10_0, 0b100101),
2812 VecALUModOp::Usdot => (0b000_01110_10_0, 0b100111),
2815 };
2816 sink.put4(enc_vec_rrr(top11 | q << 9, rm, bit15_10, rn, rd));
2817 }
2818 &Inst::VecFmlaElem {
2819 rd,
2820 ri,
2821 rn,
2822 rm,
2823 alu_op,
2824 size,
2825 idx,
2826 } => {
2827 debug_assert_eq!(rd.to_reg(), ri);
2828 let idx = u32::from(idx);
2829
2830 let (q, _size) = size.enc_size();
2831 let o2 = match alu_op {
2832 VecALUModOp::Fmla => 0b0,
2833 VecALUModOp::Fmls => 0b1,
2834 _ => unreachable!(),
2835 };
2836
2837 let (h, l) = match size {
2838 VectorSize::Size32x4 => {
2839 assert!(idx < 4);
2840 (idx >> 1, idx & 1)
2841 }
2842 VectorSize::Size64x2 => {
2843 assert!(idx < 2);
2844 (idx, 0)
2845 }
2846 _ => unreachable!(),
2847 };
2848
2849 let top11 = 0b000_011111_00 | (q << 9) | (size.enc_float_size() << 1) | l;
2850 let bit15_10 = 0b000100 | (o2 << 4) | (h << 1);
2851 sink.put4(enc_vec_rrr(top11, rm, bit15_10, rn, rd));
2852 }
2853 &Inst::VecLoadReplicate {
2854 rd,
2855 rn,
2856 size,
2857 flags,
2858 } => {
2859 let (q, size) = size.enc_size();
2860
2861 if let Some(trap_code) = flags.trap_code() {
2862 sink.add_trap(trap_code);
2864 }
2865
2866 sink.put4(enc_ldst_vec(q, size, rn, rd));
2867 }
2868 &Inst::VecCSel { rd, rn, rm, cond } => {
2869 let else_label = sink.get_label();
2880 let out_label = sink.get_label();
2881
2882 let br_else_offset = sink.cur_offset();
2884 sink.put4(enc_conditional_br(
2885 BranchTarget::Label(else_label),
2886 CondBrKind::Cond(cond),
2887 ));
2888 sink.use_label_at_offset(br_else_offset, else_label, LabelUse::Branch19);
2889
2890 sink.put4(enc_vecmov(true, rd, rm));
2892
2893 let b_out_offset = sink.cur_offset();
2895 sink.use_label_at_offset(b_out_offset, out_label, LabelUse::Branch26);
2896 sink.add_uncond_branch(b_out_offset, b_out_offset + 4, out_label);
2897 sink.put4(enc_jump26(0b000101, 0 ));
2898
2899 sink.bind_label(else_label, &mut state.ctrl_plane);
2901
2902 sink.put4(enc_vecmov(true, rd, rn));
2904
2905 sink.bind_label(out_label, &mut state.ctrl_plane);
2907 }
2908 &Inst::MovToNZCV { rn } => {
2909 sink.put4(0xd51b4200 | machreg_to_gpr(rn));
2910 }
2911 &Inst::MovFromNZCV { rd } => {
2912 sink.put4(0xd53b4200 | machreg_to_gpr(rd.to_reg()));
2913 }
2914 &Inst::Extend {
2915 rd,
2916 rn,
2917 signed: false,
2918 from_bits: 1,
2919 to_bits,
2920 } => {
2921 assert!(to_bits <= 64);
2922 let imml = ImmLogic::maybe_from_u64(1, I32).unwrap();
2927 Inst::AluRRImmLogic {
2928 alu_op: ALUOp::And,
2929 size: OperandSize::Size32,
2930 rd,
2931 rn,
2932 imml,
2933 }
2934 .emit(sink, emit_info, state);
2935 }
2936 &Inst::Extend {
2937 rd,
2938 rn,
2939 signed: false,
2940 from_bits: 32,
2941 to_bits: 64,
2942 } => {
2943 let mov = Inst::Mov {
2944 size: OperandSize::Size32,
2945 rd,
2946 rm: rn,
2947 };
2948 mov.emit(sink, emit_info, state);
2949 }
2950 &Inst::Extend {
2951 rd,
2952 rn,
2953 signed,
2954 from_bits,
2955 to_bits,
2956 } => {
2957 let (opc, size) = if signed {
2958 (0b00, OperandSize::from_bits(to_bits))
2959 } else {
2960 (0b10, OperandSize::Size32)
2961 };
2962 sink.put4(enc_bfm(opc, size, rd, rn, 0, from_bits - 1));
2963 }
2964 &Inst::Jump { ref dest } => {
2965 let off = sink.cur_offset();
2966 if let Some(l) = dest.as_label() {
2968 sink.use_label_at_offset(off, l, LabelUse::Branch26);
2969 sink.add_uncond_branch(off, off + 4, l);
2970 }
2971 sink.put4(enc_jump26(0b000101, dest.as_offset26_or_zero()));
2973 }
2974 &Inst::Args { .. } | &Inst::Rets { .. } => {
2975 }
2978 &Inst::Ret {} => {
2979 sink.put4(0xd65f03c0);
2980 }
2981 &Inst::AuthenticatedRet { key, is_hint } => {
2982 let (op2, is_hint) = match key {
2983 APIKey::AZ => (0b100, true),
2984 APIKey::ASP => (0b101, is_hint),
2985 APIKey::BZ => (0b110, true),
2986 APIKey::BSP => (0b111, is_hint),
2987 };
2988
2989 if is_hint {
2990 sink.put4(key.enc_auti_hint());
2991 Inst::Ret {}.emit(sink, emit_info, state);
2992 } else {
2993 sink.put4(0xd65f0bff | (op2 << 9)); }
2995 }
2996 &Inst::Call { ref info } => {
2997 let start = sink.cur_offset();
2998 let user_stack_map = state.take_stack_map();
2999 sink.add_reloc(Reloc::Arm64Call, &info.dest, 0);
3000 sink.put4(enc_jump26(0b100101, 0));
3001 if let Some(s) = user_stack_map {
3002 let offset = sink.cur_offset();
3003 sink.push_user_stack_map(state, offset, s);
3004 }
3005
3006 if let Some(try_call) = info.try_call_info.as_ref() {
3007 sink.add_try_call_site(
3008 Some(state.frame_layout.sp_to_fp()),
3009 try_call.exception_handlers(&state.frame_layout),
3010 );
3011 } else {
3012 sink.add_call_site();
3013 }
3014
3015 if info.callee_pop_size > 0 {
3016 let callee_pop_size =
3017 i32::try_from(info.callee_pop_size).expect("callee popped more than 2GB");
3018 for inst in AArch64MachineDeps::gen_sp_reg_adjust(-callee_pop_size) {
3019 inst.emit(sink, emit_info, state);
3020 }
3021 }
3022
3023 if info.patchable {
3024 sink.add_patchable_call_site(sink.cur_offset() - start);
3025 } else {
3026 info.emit_retval_loads::<AArch64MachineDeps, _, _>(
3028 state.frame_layout().stackslots_size,
3029 |inst| inst.emit(sink, emit_info, state),
3030 |needed_space| Some(Inst::EmitIsland { needed_space }),
3031 );
3032 }
3033
3034 if let Some(try_call) = info.try_call_info.as_ref() {
3037 let jmp = Inst::Jump {
3038 dest: BranchTarget::Label(try_call.continuation),
3039 };
3040 jmp.emit(sink, emit_info, state);
3041 }
3042
3043 start_off = sink.cur_offset();
3046 }
3047 &Inst::CallInd { ref info } => {
3048 let user_stack_map = state.take_stack_map();
3049 sink.put4(
3050 0b1101011_0001_11111_000000_00000_00000 | (machreg_to_gpr(info.dest) << 5),
3051 );
3052 if let Some(s) = user_stack_map {
3053 let offset = sink.cur_offset();
3054 sink.push_user_stack_map(state, offset, s);
3055 }
3056
3057 if let Some(try_call) = info.try_call_info.as_ref() {
3058 sink.add_try_call_site(
3059 Some(state.frame_layout.sp_to_fp()),
3060 try_call.exception_handlers(&state.frame_layout),
3061 );
3062 } else {
3063 sink.add_call_site();
3064 }
3065
3066 if info.callee_pop_size > 0 {
3067 let callee_pop_size =
3068 i32::try_from(info.callee_pop_size).expect("callee popped more than 2GB");
3069 for inst in AArch64MachineDeps::gen_sp_reg_adjust(-callee_pop_size) {
3070 inst.emit(sink, emit_info, state);
3071 }
3072 }
3073
3074 info.emit_retval_loads::<AArch64MachineDeps, _, _>(
3076 state.frame_layout().stackslots_size,
3077 |inst| inst.emit(sink, emit_info, state),
3078 |needed_space| Some(Inst::EmitIsland { needed_space }),
3079 );
3080
3081 if let Some(try_call) = info.try_call_info.as_ref() {
3084 let jmp = Inst::Jump {
3085 dest: BranchTarget::Label(try_call.continuation),
3086 };
3087 jmp.emit(sink, emit_info, state);
3088 }
3089
3090 start_off = sink.cur_offset();
3093 }
3094 &Inst::ReturnCall { ref info } => {
3095 emit_return_call_common_sequence(sink, emit_info, state, info);
3096
3097 sink.add_reloc(Reloc::Arm64Call, &info.dest, 0);
3101 sink.put4(enc_jump26(0b000101, 0));
3102 sink.add_call_site();
3103
3104 start_off = sink.cur_offset();
3108 }
3109 &Inst::ReturnCallInd { ref info } => {
3110 emit_return_call_common_sequence(sink, emit_info, state, info);
3111
3112 Inst::IndirectBr {
3113 rn: info.dest,
3114 targets: vec![],
3115 }
3116 .emit(sink, emit_info, state);
3117 sink.add_call_site();
3118
3119 start_off = sink.cur_offset();
3123 }
3124 &Inst::CondBr {
3125 taken,
3126 not_taken,
3127 kind,
3128 } => {
3129 let cond_off = sink.cur_offset();
3131 if let Some(l) = taken.as_label() {
3132 sink.use_label_at_offset(cond_off, l, LabelUse::Branch19);
3133 let inverted = enc_conditional_br(taken, kind.invert()).to_le_bytes();
3134 sink.add_cond_branch(cond_off, cond_off + 4, l, &inverted[..]);
3135 }
3136 sink.put4(enc_conditional_br(taken, kind));
3137
3138 let uncond_off = sink.cur_offset();
3140 if let Some(l) = not_taken.as_label() {
3141 sink.use_label_at_offset(uncond_off, l, LabelUse::Branch26);
3142 sink.add_uncond_branch(uncond_off, uncond_off + 4, l);
3143 }
3144 sink.put4(enc_jump26(0b000101, not_taken.as_offset26_or_zero()));
3145 }
3146 &Inst::TestBitAndBranch {
3147 taken,
3148 not_taken,
3149 kind,
3150 rn,
3151 bit,
3152 } => {
3153 let cond_off = sink.cur_offset();
3155 if let Some(l) = taken.as_label() {
3156 sink.use_label_at_offset(cond_off, l, LabelUse::Branch14);
3157 let inverted =
3158 enc_test_bit_and_branch(kind.complement(), taken, rn, bit).to_le_bytes();
3159 sink.add_cond_branch(cond_off, cond_off + 4, l, &inverted[..]);
3160 }
3161 sink.put4(enc_test_bit_and_branch(kind, taken, rn, bit));
3162
3163 let uncond_off = sink.cur_offset();
3165 if let Some(l) = not_taken.as_label() {
3166 sink.use_label_at_offset(uncond_off, l, LabelUse::Branch26);
3167 sink.add_uncond_branch(uncond_off, uncond_off + 4, l);
3168 }
3169 sink.put4(enc_jump26(0b000101, not_taken.as_offset26_or_zero()));
3170 }
3171 &Inst::TrapIf { kind, trap_code } => {
3172 let label = sink.defer_trap(trap_code);
3173 let off = sink.cur_offset();
3175 sink.put4(enc_conditional_br(BranchTarget::Label(label), kind));
3176 sink.use_label_at_offset(off, label, LabelUse::Branch19);
3177 }
3178 &Inst::IndirectBr { rn, .. } => {
3179 sink.put4(enc_br(rn));
3180 }
3181 &Inst::Nop0 => {}
3182 &Inst::Nop4 => {
3183 sink.put4(0xd503201f);
3184 }
3185 &Inst::Brk => {
3186 sink.put4(0xd43e0000);
3187 }
3188 &Inst::Udf { trap_code } => {
3189 sink.add_trap(trap_code);
3190 sink.put_data(Inst::TRAP_OPCODE);
3191 }
3192 &Inst::Adr { rd, off } => {
3193 assert!(off > -(1 << 20));
3194 assert!(off < (1 << 20));
3195 sink.put4(enc_adr(off, rd));
3196 }
3197 &Inst::Adrp { rd, off } => {
3198 assert!(off > -(1 << 20));
3199 assert!(off < (1 << 20));
3200 sink.put4(enc_adrp(off, rd));
3201 }
3202 &Inst::Word4 { data } => {
3203 sink.put4(data);
3204 }
3205 &Inst::Word8 { data } => {
3206 sink.put8(data);
3207 }
3208 &Inst::JTSequence {
3209 ridx,
3210 rtmp1,
3211 rtmp2,
3212 default,
3213 ref targets,
3214 ..
3215 } => {
3216 let br =
3222 enc_conditional_br(BranchTarget::Label(default), CondBrKind::Cond(Cond::Hs));
3223
3224 let default_br_offset = sink.cur_offset();
3228 sink.use_label_at_offset(default_br_offset, default, LabelUse::Branch19);
3229 sink.put4(br);
3230
3231 let inst = Inst::CSel {
3235 rd: rtmp2,
3236 cond: Cond::Hs,
3237 rn: zero_reg(),
3238 rm: ridx,
3239 };
3240 inst.emit(sink, emit_info, state);
3241 if emit_info.flags.enable_table_access_spectre_mitigation()
3244 && emit_info.isa_flags.use_csdb()
3245 {
3246 Inst::Csdb.emit(sink, emit_info, state);
3247 }
3248
3249 let inst = Inst::Adr { rd: rtmp1, off: 16 };
3251 inst.emit(sink, emit_info, state);
3252 let inst = Inst::SLoad32 {
3254 rd: rtmp2,
3255 mem: AMode::reg_plus_reg_scaled_extended(
3256 rtmp1.to_reg(),
3257 rtmp2.to_reg(),
3258 ExtendOp::UXTW,
3259 ),
3260 flags: MemFlagsData::trusted(),
3261 };
3262 inst.emit(sink, emit_info, state);
3263 let inst = Inst::AluRRR {
3265 alu_op: ALUOp::Add,
3266 size: OperandSize::Size64,
3267 rd: rtmp1,
3268 rn: rtmp1.to_reg(),
3269 rm: rtmp2.to_reg(),
3270 };
3271 inst.emit(sink, emit_info, state);
3272 let inst = Inst::IndirectBr {
3275 rn: rtmp1.to_reg(),
3276 targets: vec![],
3277 };
3278 inst.emit(sink, emit_info, state);
3279 let jt_off = sink.cur_offset();
3281 for &target in targets.iter() {
3282 let word_off = sink.cur_offset();
3283 let off_into_table = word_off - jt_off;
3288 sink.use_label_at_offset(word_off, target, LabelUse::PCRel32);
3289 sink.put4(off_into_table);
3290 }
3291
3292 start_off = sink.cur_offset();
3295 }
3296 &Inst::LoadExtNameGot { rd, ref name } => {
3297 sink.add_reloc(Reloc::Aarch64AdrGotPage21, &**name, 0);
3306 let inst = Inst::Adrp { rd, off: 0 };
3307 inst.emit(sink, emit_info, state);
3308
3309 sink.add_reloc(Reloc::Aarch64Ld64GotLo12Nc, &**name, 0);
3311 let inst = Inst::ULoad64 {
3312 rd,
3313 mem: AMode::reg(rd.to_reg()),
3314 flags: MemFlagsData::trusted(),
3315 };
3316 inst.emit(sink, emit_info, state);
3317 }
3318 &Inst::LoadExtNameNear {
3319 rd,
3320 ref name,
3321 offset,
3322 } => {
3323 sink.add_reloc(Reloc::Aarch64AdrPrelPgHi21, &**name, offset);
3331 let inst = Inst::Adrp { rd, off: 0 };
3332 inst.emit(sink, emit_info, state);
3333
3334 sink.add_reloc(Reloc::Aarch64AddAbsLo12Nc, &**name, offset);
3336 let inst = Inst::AluRRImm12 {
3337 alu_op: ALUOp::Add,
3338 size: OperandSize::Size64,
3339 rd,
3340 rn: rd.to_reg(),
3341 imm12: Imm12::ZERO,
3342 };
3343 inst.emit(sink, emit_info, state);
3344 }
3345 &Inst::LoadExtNameFar {
3346 rd,
3347 ref name,
3348 offset,
3349 } => {
3350 let inst = Inst::ULoad64 {
3359 rd,
3360 mem: AMode::Label {
3361 label: MemLabel::PCRel(8),
3362 },
3363 flags: MemFlagsData::trusted(),
3364 };
3365 inst.emit(sink, emit_info, state);
3366 let inst = Inst::Jump {
3367 dest: BranchTarget::ResolvedOffset(12),
3368 };
3369 inst.emit(sink, emit_info, state);
3370 sink.add_reloc(Reloc::Abs8, &**name, offset);
3371 sink.put8(0);
3372 }
3373 &Inst::LoadAddr { rd, ref mem } => {
3374 let mem = mem.clone();
3375 let (mem_insts, mem) = mem_finalize(Some(sink), &mem, I8, state);
3376 for inst in mem_insts.into_iter() {
3377 inst.emit(sink, emit_info, state);
3378 }
3379
3380 let (reg, index_reg, offset) = match mem {
3381 AMode::RegExtended { rn, rm, extendop } => {
3382 let r = rn;
3383 (r, Some((rm, extendop)), 0)
3384 }
3385 AMode::Unscaled { rn, simm9 } => {
3386 let r = rn;
3387 (r, None, simm9.value())
3388 }
3389 AMode::UnsignedOffset { rn, uimm12 } => {
3390 let r = rn;
3391 (r, None, uimm12.value() as i32)
3392 }
3393 _ => panic!("Unsupported case for LoadAddr: {mem:?}"),
3394 };
3395 let abs_offset = if offset < 0 {
3396 -offset as u64
3397 } else {
3398 offset as u64
3399 };
3400 let alu_op = if offset < 0 { ALUOp::Sub } else { ALUOp::Add };
3401
3402 if let Some((idx, extendop)) = index_reg {
3403 let add = Inst::AluRRRExtend {
3404 alu_op: ALUOp::Add,
3405 size: OperandSize::Size64,
3406 rd,
3407 rn: reg,
3408 rm: idx,
3409 extendop,
3410 };
3411
3412 add.emit(sink, emit_info, state);
3413 } else if offset == 0 {
3414 if reg != rd.to_reg() {
3415 let mov = Inst::Mov {
3416 size: OperandSize::Size64,
3417 rd,
3418 rm: reg,
3419 };
3420
3421 mov.emit(sink, emit_info, state);
3422 }
3423 } else if let Some(imm12) = Imm12::maybe_from_u64(abs_offset) {
3424 let add = Inst::AluRRImm12 {
3425 alu_op,
3426 size: OperandSize::Size64,
3427 rd,
3428 rn: reg,
3429 imm12,
3430 };
3431 add.emit(sink, emit_info, state);
3432 } else {
3433 debug_assert!(rd.to_reg() != tmp2_reg());
3439 debug_assert!(reg != tmp2_reg());
3440 let tmp = writable_tmp2_reg();
3441 for insn in Inst::load_constant(tmp, abs_offset).into_iter() {
3442 insn.emit(sink, emit_info, state);
3443 }
3444 let add = Inst::AluRRR {
3445 alu_op,
3446 size: OperandSize::Size64,
3447 rd,
3448 rn: reg,
3449 rm: tmp.to_reg(),
3450 };
3451 add.emit(sink, emit_info, state);
3452 }
3453 }
3454 &Inst::Paci { key } => {
3455 let (crm, op2) = match key {
3456 APIKey::AZ => (0b0011, 0b000),
3457 APIKey::ASP => (0b0011, 0b001),
3458 APIKey::BZ => (0b0011, 0b010),
3459 APIKey::BSP => (0b0011, 0b011),
3460 };
3461
3462 sink.put4(0xd503211f | (crm << 8) | (op2 << 5));
3463 }
3464 &Inst::Xpaclri => sink.put4(0xd50320ff),
3465 &Inst::Bti { targets } => {
3466 let targets = match targets {
3467 BranchTargetType::None => 0b00,
3468 BranchTargetType::C => 0b01,
3469 BranchTargetType::J => 0b10,
3470 BranchTargetType::JC => 0b11,
3471 };
3472
3473 sink.put4(0xd503241f | targets << 6);
3474 }
3475 &Inst::EmitIsland { needed_space } => {
3476 if sink.island_needed(needed_space + 4) {
3477 let jump_around_label = sink.get_label();
3478 let jmp = Inst::Jump {
3479 dest: BranchTarget::Label(jump_around_label),
3480 };
3481 jmp.emit(sink, emit_info, state);
3482 sink.emit_island(needed_space + 4, &mut state.ctrl_plane);
3483 sink.bind_label(jump_around_label, &mut state.ctrl_plane);
3484 }
3485 }
3486
3487 &Inst::ElfTlsGetAddr {
3488 ref symbol,
3489 rd,
3490 tmp,
3491 } => {
3492 assert_eq!(xreg(0), rd.to_reg());
3493
3494 sink.add_reloc(Reloc::Aarch64TlsDescAdrPage21, &**symbol, 0);
3510 Inst::Adrp { rd, off: 0 }.emit(sink, emit_info, state);
3511
3512 sink.add_reloc(Reloc::Aarch64TlsDescLd64Lo12, &**symbol, 0);
3514 Inst::ULoad64 {
3515 rd: tmp,
3516 mem: AMode::reg(rd.to_reg()),
3517 flags: MemFlagsData::trusted(),
3518 }
3519 .emit(sink, emit_info, state);
3520
3521 sink.add_reloc(Reloc::Aarch64TlsDescAddLo12, &**symbol, 0);
3523 Inst::AluRRImm12 {
3524 alu_op: ALUOp::Add,
3525 size: OperandSize::Size64,
3526 rd,
3527 rn: rd.to_reg(),
3528 imm12: Imm12::maybe_from_u64(0).unwrap(),
3529 }
3530 .emit(sink, emit_info, state);
3531
3532 sink.add_reloc(Reloc::Aarch64TlsDescCall, &**symbol, 0);
3534 Inst::CallInd {
3535 info: crate::isa::Box::new(CallInfo::empty(tmp.to_reg(), CallConv::SystemV)),
3536 }
3537 .emit(sink, emit_info, state);
3538
3539 sink.put4(0xd53bd040 | machreg_to_gpr(tmp.to_reg()));
3541
3542 Inst::AluRRR {
3544 alu_op: ALUOp::Add,
3545 size: OperandSize::Size64,
3546 rd,
3547 rn: rd.to_reg(),
3548 rm: tmp.to_reg(),
3549 }
3550 .emit(sink, emit_info, state);
3551 }
3552
3553 &Inst::MachOTlsGetAddr { ref symbol, rd } => {
3554 assert_eq!(xreg(0), rd.to_reg());
3567 let rtmp = writable_xreg(1);
3568
3569 sink.add_reloc(Reloc::MachOAarch64TlsAdrPage21, symbol, 0);
3571 sink.put4(0x90000000);
3572
3573 sink.add_reloc(Reloc::MachOAarch64TlsAdrPageOff12, symbol, 0);
3575 sink.put4(0xf9400000);
3576
3577 Inst::ULoad64 {
3579 rd: rtmp,
3580 mem: AMode::reg(rd.to_reg()),
3581 flags: MemFlagsData::trusted(),
3582 }
3583 .emit(sink, emit_info, state);
3584
3585 Inst::CallInd {
3587 info: crate::isa::Box::new(CallInfo::empty(
3588 rtmp.to_reg(),
3589 CallConv::AppleAarch64,
3590 )),
3591 }
3592 .emit(sink, emit_info, state);
3593 }
3594
3595 &Inst::Unwind { ref inst } => {
3596 sink.add_unwind(inst.clone());
3597 }
3598
3599 &Inst::DummyUse { .. } => {}
3600
3601 &Inst::LabelAddress { dst, label } => {
3602 let inst = Inst::Adr { rd: dst, off: 0 };
3607 let offset = sink.cur_offset();
3608 inst.emit(sink, emit_info, state);
3609 sink.use_label_at_offset(offset, label, LabelUse::Adr21);
3610 }
3611
3612 &Inst::SequencePoint { .. } => {
3613 }
3615
3616 &Inst::StackProbeLoop { start, end, step } => {
3617 assert!(emit_info.flags.enable_probestack());
3618
3619 let loop_start = sink.get_label();
3642 sink.bind_label(loop_start, &mut state.ctrl_plane);
3643
3644 Inst::AluRRImm12 {
3645 alu_op: ALUOp::Sub,
3646 size: OperandSize::Size64,
3647 rd: start,
3648 rn: start.to_reg(),
3649 imm12: step,
3650 }
3651 .emit(sink, emit_info, state);
3652 Inst::Store32 {
3653 rd: regs::zero_reg(),
3654 mem: AMode::RegReg {
3655 rn: regs::stack_reg(),
3656 rm: start.to_reg(),
3657 },
3658 flags: MemFlagsData::trusted(),
3659 }
3660 .emit(sink, emit_info, state);
3661 Inst::AluRRR {
3662 alu_op: ALUOp::AddS,
3663 size: OperandSize::Size64,
3664 rd: regs::writable_zero_reg(),
3665 rn: start.to_reg(),
3666 rm: end,
3667 }
3668 .emit(sink, emit_info, state);
3669
3670 let loop_end = sink.get_label();
3671 Inst::CondBr {
3672 taken: BranchTarget::Label(loop_start),
3673 not_taken: BranchTarget::Label(loop_end),
3674 kind: CondBrKind::Cond(Cond::Gt),
3675 }
3676 .emit(sink, emit_info, state);
3677 sink.bind_label(loop_end, &mut state.ctrl_plane);
3678 }
3679 }
3680
3681 let end_off = sink.cur_offset();
3682 debug_assert!(
3683 (end_off - start_off) <= Inst::worst_case_size()
3684 || matches!(self, Inst::EmitIsland { .. }),
3685 "Worst case size exceed for {:?}: {}",
3686 self,
3687 end_off - start_off
3688 );
3689
3690 state.clear_post_insn();
3691 }
3692
3693 fn pretty_print_inst(&self, state: &mut Self::State) -> String {
3694 self.print_with_state(state)
3695 }
3696}
3697
3698fn emit_return_call_common_sequence<T>(
3699 sink: &mut MachBuffer<Inst>,
3700 emit_info: &EmitInfo,
3701 state: &mut EmitState,
3702 info: &ReturnCallInfo<T>,
3703) {
3704 for inst in AArch64MachineDeps::gen_clobber_restore(
3705 CallConv::Tail,
3706 &emit_info.flags,
3707 state.frame_layout(),
3708 ) {
3709 inst.emit(sink, emit_info, state);
3710 }
3711
3712 let setup_area_size = state.frame_layout().setup_area_size;
3713 if setup_area_size > 0 {
3714 Inst::LoadP64 {
3720 rt: writable_fp_reg(),
3721 rt2: writable_link_reg(),
3722 mem: PairAMode::SPPostIndexed {
3723 simm7: SImm7Scaled::maybe_from_i64(i64::from(setup_area_size), types::I64).unwrap(),
3727 },
3728 flags: MemFlagsData::trusted(),
3729 }
3730 .emit(sink, emit_info, state);
3731 }
3732
3733 let incoming_args_diff = state.frame_layout().tail_args_size - info.new_stack_arg_size;
3735 if incoming_args_diff > 0 {
3736 for inst in
3737 AArch64MachineDeps::gen_sp_reg_adjust(i32::try_from(incoming_args_diff).unwrap())
3738 {
3739 inst.emit(sink, emit_info, state);
3740 }
3741 }
3742
3743 if (setup_area_size > 0 || info.sign_return_address_all)
3744 && let Some(key) = info.key
3745 {
3746 sink.put4(key.enc_auti_hint());
3747 }
3748}