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