1 //! This module defines 32-bit ARM specific machine instruction types.
2
3 #![allow(dead_code)]
4
5 use crate::binemit::CodeOffset;
6 use crate::ir::types::{B1, B16, B32, B8, I16, I32, I8, IFLAGS};
7 use crate::ir::{ExternalName, Opcode, TrapCode, Type};
8 use crate::machinst::*;
9 use crate::{settings, CodegenError, CodegenResult};
10
11 use regalloc::{PrettyPrint, RealRegUniverse, Reg, RegClass, SpillSlot, VirtualReg, Writable};
12 use regalloc::{RegUsageCollector, RegUsageMapper};
13
14 use alloc::boxed::Box;
15 use alloc::vec::Vec;
16 use smallvec::{smallvec, SmallVec};
17 use std::string::{String, ToString};
18
19 mod args;
20 pub use self::args::*;
21 mod emit;
22 pub use self::emit::*;
23 mod regs;
24 pub use self::regs::*;
25
26 #[cfg(test)]
27 mod emit_tests;
28
29 //=============================================================================
30 // Instructions (top level): definition
31
32 /// An ALU operation. This can be paired with several instruction formats
33 /// below (see `Inst`) in any combination.
34 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
35 pub enum ALUOp {
36 Add,
37 Adds,
38 Adc,
39 Adcs,
40 Qadd,
41 Sub,
42 Subs,
43 Sbc,
44 Sbcs,
45 Rsb,
46 Qsub,
47 Mul,
48 Smull,
49 Umull,
50 Udiv,
51 Sdiv,
52 And,
53 Orr,
54 Orn,
55 Eor,
56 Bic,
57 Lsl,
58 Lsr,
59 Asr,
60 Ror,
61 }
62
63 /// An ALU operation with one argument.
64 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
65 pub enum ALUOp1 {
66 Mvn,
67 Mov,
68 }
69
70 /// An operation on the bits of a register.
71 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
72 pub enum BitOp {
73 Rbit,
74 Rev,
75 Clz,
76 }
77
78 /// Additional information for (direct) Call instructions, left out of line to lower the size of
79 /// the Inst enum.
80 #[derive(Clone, Debug)]
81 pub struct CallInfo {
82 pub dest: ExternalName,
83 pub uses: Vec<Reg>,
84 pub defs: Vec<Writable<Reg>>,
85 pub opcode: Opcode,
86 }
87
88 /// Additional information for CallInd instructions, left out of line to lower the size of the Inst
89 /// enum.
90 #[derive(Clone, Debug)]
91 pub struct CallIndInfo {
92 pub rm: Reg,
93 pub uses: Vec<Reg>,
94 pub defs: Vec<Writable<Reg>>,
95 pub opcode: Opcode,
96 }
97
98 /// Instruction formats.
99 #[derive(Clone, Debug)]
100 pub enum Inst {
101 /// A no-op of zero size.
102 Nop0,
103
104 /// A no-op that is two bytes large.
105 Nop2,
106
107 /// An ALU operation with two register sources and one register destination.
108 AluRRR {
109 alu_op: ALUOp,
110 rd: Writable<Reg>,
111 rn: Reg,
112 rm: Reg,
113 },
114
115 /// An ALU operation with two register sources, one of which can be optionally shifted
116 /// and one register destination.
117 AluRRRShift {
118 alu_op: ALUOp,
119 rd: Writable<Reg>,
120 rn: Reg,
121 rm: Reg,
122 shift: Option<ShiftOpAndAmt>,
123 },
124
125 /// An ALU operation with one register source, which can be optionally shifted
126 /// and one register destination.
127 AluRRShift {
128 alu_op: ALUOp1,
129 rd: Writable<Reg>,
130 rm: Reg,
131 shift: Option<ShiftOpAndAmt>,
132 },
133
134 /// An ALU operation with two register sources and two register destinations.
135 AluRRRR {
136 alu_op: ALUOp,
137 rd_hi: Writable<Reg>,
138 rd_lo: Writable<Reg>,
139 rn: Reg,
140 rm: Reg,
141 },
142
143 /// An ALU operation with a register source and a 12-bit immediate source,
144 /// and a register destination.
145 AluRRImm12 {
146 alu_op: ALUOp,
147 rd: Writable<Reg>,
148 rn: Reg,
149 imm12: UImm12,
150 },
151
152 /// An ALU operation with a register source and a 8-bit immediate source,
153 /// and a register destination.
154 ///
155 /// In fact these instructions take a `modified immediate constant` operand,
156 /// which is encoded as a 12-bit immediate. The only case used here
157 /// is when high 4 bits of that 12-immediate are zeros.
158 /// In this case operand is simple 8-bit immediate.
159 /// For all possible operands see
160 /// https://static.docs.arm.com/ddi0406/c/DDI0406C_C_arm_architecture_reference_manual.pdf#G10.4954509
161 AluRRImm8 {
162 alu_op: ALUOp,
163 rd: Writable<Reg>,
164 rn: Reg,
165 imm8: UImm8,
166 },
167
168 /// An ALU operation with a 8-bit immediate and a register destination.
169 /// See `AluRRImm8` description above.
170 AluRImm8 {
171 alu_op: ALUOp1,
172 rd: Writable<Reg>,
173 imm8: UImm8,
174 },
175
176 /// A bit operation with a register source and a register destination.
177 BitOpRR {
178 bit_op: BitOp,
179 rd: Writable<Reg>,
180 rm: Reg,
181 },
182
183 /// A mov instruction with a GPR source and a GPR destination.
184 Mov {
185 rd: Writable<Reg>,
186 rm: Reg,
187 },
188
189 /// A move instruction with a 16-bit immediate source and a register destination.
190 MovImm16 {
191 rd: Writable<Reg>,
192 imm16: u16,
193 },
194
195 /// A move top instruction, which writes 16-bit immediate to the top
196 /// halfword of the destination register.
197 Movt {
198 rd: Writable<Reg>,
199 imm16: u16,
200 },
201
202 /// A compare instruction with two register arguments.
203 Cmp {
204 rn: Reg,
205 rm: Reg,
206 },
207
208 /// A compare instruction with a register operand and a 8-bit immediate operand.
209 CmpImm8 {
210 rn: Reg,
211 imm8: u8,
212 },
213
214 /// A store instruction, which stores to memory 8, 16 or 32-bit operand.
215 Store {
216 rt: Reg,
217 mem: AMode,
218 bits: u8,
219 },
220
221 /// A load instruction, which loads from memory 8, 16 or 32-bit operand,
222 /// which can be sign- or zero-extended.
223 Load {
224 rt: Writable<Reg>,
225 mem: AMode,
226 bits: u8,
227 sign_extend: bool,
228 },
229
230 /// Load address referenced by `mem` into `rd`.
231 LoadAddr {
232 rd: Writable<Reg>,
233 mem: AMode,
234 },
235
236 /// A sign- or zero-extend operation.
237 Extend {
238 rd: Writable<Reg>,
239 rm: Reg,
240 from_bits: u8,
241 signed: bool,
242 },
243
244 // An If-Then instruction, which makes up to four instructions conditinal.
245 It {
246 cond: Cond,
247 insts: Vec<CondInst>,
248 },
249
250 /// A push instuction, which stores registers to the stack and updates sp.
251 Push {
252 reg_list: Vec<Reg>,
253 },
254
255 /// A pop instuction, which load registers from the stack and updates sp.
256 Pop {
257 reg_list: Vec<Writable<Reg>>,
258 },
259
260 /// A machine call instruction.
261 Call {
262 info: Box<CallInfo>,
263 },
264
265 /// A machine indirect-call instruction.
266 CallInd {
267 info: Box<CallIndInfo>,
268 },
269
270 /// Load an inline symbol reference.
271 LoadExtName {
272 rt: Writable<Reg>,
273 name: Box<ExternalName>,
274 offset: i32,
275 },
276
277 /// A return instruction, which is encoded as `bx lr`.
278 Ret,
279
280 /// An unconditional branch.
281 Jump {
282 dest: BranchTarget,
283 },
284
285 /// A conditional branch.
286 CondBr {
287 taken: BranchTarget,
288 not_taken: BranchTarget,
289 cond: Cond,
290 },
291
292 /// An indirect branch through a register, augmented with set of all
293 /// possible successors.
294 IndirectBr {
295 rm: Reg,
296 targets: Vec<MachLabel>,
297 },
298
299 /// A conditional trap: execute a `udf` if the condition is true. This is
300 /// one VCode instruction because it uses embedded control flow; it is
301 /// logically a single-in, single-out region, but needs to appear as one
302 /// unit to the register allocator.
303 TrapIf {
304 cond: Cond,
305 trap_info: TrapCode,
306 },
307
308 /// An instruction guaranteed to always be undefined and to trigger an illegal instruction at
309 /// runtime.
310 Udf {
311 trap_info: TrapCode,
312 },
313
314 /// A "breakpoint" instruction, used for e.g. traps and debug breakpoints.
315 Bkpt,
316
317 /// Marker, no-op in generated code: SP "virtual offset" is adjusted.
318 VirtualSPOffsetAdj {
319 offset: i64,
320 },
321
322 /// A placeholder instruction, generating no code, meaning that a function epilogue must be
323 /// inserted there.
324 EpiloguePlaceholder,
325 }
326
327 /// An instruction inside an it block.
328 #[derive(Clone, Debug)]
329 pub struct CondInst {
330 inst: Inst,
331 // In which case execute the instruction:
332 // true => when it condition is met
333 // false => otherwise.
334 then: bool,
335 }
336
337 impl CondInst {
new(inst: Inst, then: bool) -> Self338 pub fn new(inst: Inst, then: bool) -> Self {
339 match inst {
340 Inst::It { .. }
341 | Inst::Ret { .. }
342 | Inst::Jump { .. }
343 | Inst::CondBr { .. }
344 | Inst::TrapIf { .. }
345 | Inst::EpiloguePlaceholder { .. }
346 | Inst::LoadExtName { .. } => panic!("Instruction {:?} cannot occur in it block", inst),
347 _ => Self { inst, then },
348 }
349 }
350 }
351
352 impl Inst {
353 /// Create a move instruction.
mov(to_reg: Writable<Reg>, from_reg: Reg) -> Inst354 pub fn mov(to_reg: Writable<Reg>, from_reg: Reg) -> Inst {
355 Inst::Mov {
356 rd: to_reg,
357 rm: from_reg,
358 }
359 }
360
361 /// Create an instruction that loads a constant.
load_constant(rd: Writable<Reg>, value: u32) -> SmallVec<[Inst; 4]>362 pub fn load_constant(rd: Writable<Reg>, value: u32) -> SmallVec<[Inst; 4]> {
363 let mut insts = smallvec![];
364 let imm_lo = (value & 0xffff) as u16;
365 let imm_hi = (value >> 16) as u16;
366
367 if imm_lo != 0 || imm_hi == 0 {
368 // imm_lo == 0 && imm_hi == 0 => we have to overwrite reg value with 0
369 insts.push(Inst::MovImm16 { rd, imm16: imm_lo });
370 }
371 if imm_hi != 0 {
372 insts.push(Inst::Movt { rd, imm16: imm_hi });
373 }
374
375 insts
376 }
377
378 /// Generic constructor for a load (zero-extending where appropriate).
gen_load(into_reg: Writable<Reg>, mem: AMode, ty: Type) -> Inst379 pub fn gen_load(into_reg: Writable<Reg>, mem: AMode, ty: Type) -> Inst {
380 assert!(ty.bits() <= 32);
381 // Load 8 bits for B1.
382 let bits = std::cmp::max(ty.bits(), 8) as u8;
383
384 Inst::Load {
385 rt: into_reg,
386 mem,
387 bits,
388 sign_extend: false,
389 }
390 }
391
392 /// Generic constructor for a store.
gen_store(from_reg: Reg, mem: AMode, ty: Type) -> Inst393 pub fn gen_store(from_reg: Reg, mem: AMode, ty: Type) -> Inst {
394 assert!(ty.bits() <= 32);
395 // Store 8 bits for B1.
396 let bits = std::cmp::max(ty.bits(), 8) as u8;
397
398 Inst::Store {
399 rt: from_reg,
400 mem,
401 bits,
402 }
403 }
404 }
405
406 //=============================================================================
407 // Instructions: get_regs
408
memarg_regs(memarg: &AMode, collector: &mut RegUsageCollector)409 fn memarg_regs(memarg: &AMode, collector: &mut RegUsageCollector) {
410 match memarg {
411 &AMode::RegReg(rn, rm, ..) => {
412 collector.add_use(rn);
413 collector.add_use(rm);
414 }
415 &AMode::RegOffset12(rn, ..) | &AMode::RegOffset(rn, _) => {
416 collector.add_use(rn);
417 }
418 &AMode::SPOffset(..) | &AMode::NominalSPOffset(..) => {
419 collector.add_use(sp_reg());
420 }
421 &AMode::FPOffset(..) => {
422 collector.add_use(fp_reg());
423 }
424 &AMode::PCRel(_) => {}
425 }
426 }
427
arm32_get_regs(inst: &Inst, collector: &mut RegUsageCollector)428 fn arm32_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
429 match inst {
430 &Inst::Nop0
431 | &Inst::Nop2
432 | &Inst::Ret
433 | &Inst::VirtualSPOffsetAdj { .. }
434 | &Inst::EpiloguePlaceholder
435 | &Inst::Jump { .. }
436 | &Inst::CondBr { .. }
437 | &Inst::Bkpt
438 | &Inst::Udf { .. }
439 | &Inst::TrapIf { .. } => {}
440 &Inst::AluRRR { rd, rn, rm, .. } => {
441 collector.add_def(rd);
442 collector.add_use(rn);
443 collector.add_use(rm);
444 }
445 &Inst::AluRRRShift { rd, rn, rm, .. } => {
446 collector.add_def(rd);
447 collector.add_use(rn);
448 collector.add_use(rm);
449 }
450 &Inst::AluRRShift { rd, rm, .. } => {
451 collector.add_def(rd);
452 collector.add_use(rm);
453 }
454 &Inst::AluRRRR {
455 rd_hi,
456 rd_lo,
457 rn,
458 rm,
459 ..
460 } => {
461 collector.add_def(rd_hi);
462 collector.add_def(rd_lo);
463 collector.add_use(rn);
464 collector.add_use(rm);
465 }
466 &Inst::AluRRImm12 { rd, rn, .. } => {
467 collector.add_def(rd);
468 collector.add_use(rn);
469 }
470 &Inst::AluRRImm8 { rd, rn, .. } => {
471 collector.add_def(rd);
472 collector.add_use(rn);
473 }
474 &Inst::AluRImm8 { rd, .. } => {
475 collector.add_def(rd);
476 }
477 &Inst::BitOpRR { rd, rm, .. } => {
478 collector.add_def(rd);
479 collector.add_use(rm);
480 }
481 &Inst::Mov { rd, rm, .. } => {
482 collector.add_def(rd);
483 collector.add_use(rm);
484 }
485 &Inst::MovImm16 { rd, .. } => {
486 collector.add_def(rd);
487 }
488 &Inst::Movt { rd, .. } => {
489 collector.add_def(rd);
490 }
491 &Inst::Cmp { rn, rm } => {
492 collector.add_use(rn);
493 collector.add_use(rm);
494 }
495 &Inst::CmpImm8 { rn, .. } => {
496 collector.add_use(rn);
497 }
498 &Inst::Store { rt, ref mem, .. } => {
499 collector.add_use(rt);
500 memarg_regs(mem, collector);
501 }
502 &Inst::Load { rt, ref mem, .. } => {
503 collector.add_def(rt);
504 memarg_regs(mem, collector);
505 }
506 &Inst::LoadAddr { rd, mem: _ } => {
507 collector.add_def(rd);
508 }
509 &Inst::Extend { rd, rm, .. } => {
510 collector.add_def(rd);
511 collector.add_use(rm);
512 }
513 &Inst::It { ref insts, .. } => {
514 for inst in insts.iter() {
515 arm32_get_regs(&inst.inst, collector);
516 }
517 }
518 &Inst::Push { ref reg_list } => {
519 for reg in reg_list {
520 collector.add_use(*reg);
521 }
522 }
523 &Inst::Pop { ref reg_list } => {
524 for reg in reg_list {
525 collector.add_def(*reg);
526 }
527 }
528 &Inst::Call { ref info, .. } => {
529 collector.add_uses(&*info.uses);
530 collector.add_defs(&*info.defs);
531 }
532 &Inst::CallInd { ref info, .. } => {
533 collector.add_uses(&*info.uses);
534 collector.add_defs(&*info.defs);
535 collector.add_use(info.rm);
536 }
537 &Inst::LoadExtName { rt, .. } => {
538 collector.add_def(rt);
539 }
540 &Inst::IndirectBr { rm, .. } => {
541 collector.add_use(rm);
542 }
543 }
544 }
545
546 //=============================================================================
547 // Instructions: map_regs
548
arm32_map_regs<RUM: RegUsageMapper>(inst: &mut Inst, mapper: &RUM)549 fn arm32_map_regs<RUM: RegUsageMapper>(inst: &mut Inst, mapper: &RUM) {
550 fn map_use<RUM: RegUsageMapper>(m: &RUM, r: &mut Reg) {
551 if r.is_virtual() {
552 let new = m.get_use(r.to_virtual_reg()).unwrap().to_reg();
553 *r = new;
554 }
555 }
556
557 fn map_def<RUM: RegUsageMapper>(m: &RUM, r: &mut Writable<Reg>) {
558 if r.to_reg().is_virtual() {
559 let new = m.get_def(r.to_reg().to_virtual_reg()).unwrap().to_reg();
560 *r = Writable::from_reg(new);
561 }
562 }
563
564 fn map_mod<RUM: RegUsageMapper>(m: &RUM, r: &mut Writable<Reg>) {
565 if r.to_reg().is_virtual() {
566 let new = m.get_mod(r.to_reg().to_virtual_reg()).unwrap().to_reg();
567 *r = Writable::from_reg(new);
568 }
569 }
570
571 fn map_mem<RUM: RegUsageMapper>(m: &RUM, mem: &mut AMode) {
572 match mem {
573 &mut AMode::RegReg(ref mut rn, ref mut rm, ..) => {
574 map_use(m, rn);
575 map_use(m, rm);
576 }
577 &mut AMode::RegOffset12(ref mut rn, ..) | &mut AMode::RegOffset(ref mut rn, ..) => {
578 map_use(m, rn)
579 }
580 &mut AMode::SPOffset(..)
581 | &mut AMode::FPOffset(..)
582 | &mut AMode::NominalSPOffset(..)
583 | &mut AMode::PCRel(_) => {}
584 };
585 }
586
587 match inst {
588 &mut Inst::Nop0
589 | &mut Inst::Nop2
590 | &mut Inst::Ret
591 | &mut Inst::VirtualSPOffsetAdj { .. }
592 | &mut Inst::EpiloguePlaceholder
593 | &mut Inst::Jump { .. }
594 | &mut Inst::CondBr { .. }
595 | &mut Inst::Bkpt
596 | &mut Inst::Udf { .. }
597 | &mut Inst::TrapIf { .. } => {}
598 &mut Inst::AluRRR {
599 ref mut rd,
600 ref mut rn,
601 ref mut rm,
602 ..
603 } => {
604 map_def(mapper, rd);
605 map_use(mapper, rn);
606 map_use(mapper, rm);
607 }
608 &mut Inst::AluRRRShift {
609 ref mut rd,
610 ref mut rn,
611 ref mut rm,
612 ..
613 } => {
614 map_def(mapper, rd);
615 map_use(mapper, rn);
616 map_use(mapper, rm);
617 }
618 &mut Inst::AluRRShift {
619 ref mut rd,
620 ref mut rm,
621 ..
622 } => {
623 map_def(mapper, rd);
624 map_use(mapper, rm);
625 }
626 &mut Inst::AluRRRR {
627 ref mut rd_hi,
628 ref mut rd_lo,
629 ref mut rn,
630 ref mut rm,
631 ..
632 } => {
633 map_def(mapper, rd_hi);
634 map_def(mapper, rd_lo);
635 map_use(mapper, rn);
636 map_use(mapper, rm);
637 }
638 &mut Inst::AluRRImm12 {
639 ref mut rd,
640 ref mut rn,
641 ..
642 } => {
643 map_def(mapper, rd);
644 map_use(mapper, rn);
645 }
646 &mut Inst::AluRRImm8 {
647 ref mut rd,
648 ref mut rn,
649 ..
650 } => {
651 map_def(mapper, rd);
652 map_use(mapper, rn);
653 }
654 &mut Inst::AluRImm8 { ref mut rd, .. } => {
655 map_def(mapper, rd);
656 }
657 &mut Inst::BitOpRR {
658 ref mut rd,
659 ref mut rm,
660 ..
661 } => {
662 map_def(mapper, rd);
663 map_use(mapper, rm);
664 }
665 &mut Inst::Mov {
666 ref mut rd,
667 ref mut rm,
668 ..
669 } => {
670 map_def(mapper, rd);
671 map_use(mapper, rm);
672 }
673 &mut Inst::MovImm16 { ref mut rd, .. } => {
674 map_def(mapper, rd);
675 }
676 &mut Inst::Movt { ref mut rd, .. } => {
677 map_def(mapper, rd);
678 }
679 &mut Inst::Cmp {
680 ref mut rn,
681 ref mut rm,
682 } => {
683 map_use(mapper, rn);
684 map_use(mapper, rm);
685 }
686 &mut Inst::CmpImm8 { ref mut rn, .. } => {
687 map_use(mapper, rn);
688 }
689 &mut Inst::Store {
690 ref mut rt,
691 ref mut mem,
692 ..
693 } => {
694 map_use(mapper, rt);
695 map_mem(mapper, mem);
696 }
697 &mut Inst::Load {
698 ref mut rt,
699 ref mut mem,
700 ..
701 } => {
702 map_def(mapper, rt);
703 map_mem(mapper, mem);
704 }
705 &mut Inst::LoadAddr {
706 ref mut rd,
707 ref mut mem,
708 } => {
709 map_def(mapper, rd);
710 map_mem(mapper, mem);
711 }
712 &mut Inst::Extend {
713 ref mut rd,
714 ref mut rm,
715 ..
716 } => {
717 map_def(mapper, rd);
718 map_use(mapper, rm);
719 }
720 &mut Inst::It { ref mut insts, .. } => {
721 for inst in insts.iter_mut() {
722 arm32_map_regs(&mut inst.inst, mapper);
723 }
724 }
725 &mut Inst::Push { ref mut reg_list } => {
726 for reg in reg_list {
727 map_use(mapper, reg);
728 }
729 }
730 &mut Inst::Pop { ref mut reg_list } => {
731 for reg in reg_list {
732 map_def(mapper, reg);
733 }
734 }
735 &mut Inst::Call { ref mut info } => {
736 for r in info.uses.iter_mut() {
737 map_use(mapper, r);
738 }
739 for r in info.defs.iter_mut() {
740 map_def(mapper, r);
741 }
742 }
743 &mut Inst::CallInd { ref mut info, .. } => {
744 for r in info.uses.iter_mut() {
745 map_use(mapper, r);
746 }
747 for r in info.defs.iter_mut() {
748 map_def(mapper, r);
749 }
750 map_use(mapper, &mut info.rm);
751 }
752 &mut Inst::LoadExtName { ref mut rt, .. } => {
753 map_def(mapper, rt);
754 }
755 &mut Inst::IndirectBr { ref mut rm, .. } => {
756 map_use(mapper, rm);
757 }
758 }
759 }
760
761 //=============================================================================
762 // Instructions: misc functions and external interface
763
764 impl MachInst for Inst {
765 type LabelUse = LabelUse;
766
get_regs(&self, collector: &mut RegUsageCollector)767 fn get_regs(&self, collector: &mut RegUsageCollector) {
768 arm32_get_regs(self, collector)
769 }
770
map_regs<RUM: RegUsageMapper>(&mut self, mapper: &RUM)771 fn map_regs<RUM: RegUsageMapper>(&mut self, mapper: &RUM) {
772 arm32_map_regs(self, mapper);
773 }
774
is_move(&self) -> Option<(Writable<Reg>, Reg)>775 fn is_move(&self) -> Option<(Writable<Reg>, Reg)> {
776 match self {
777 &Inst::Mov { rd, rm } => Some((rd, rm)),
778 _ => None,
779 }
780 }
781
is_epilogue_placeholder(&self) -> bool782 fn is_epilogue_placeholder(&self) -> bool {
783 if let Inst::EpiloguePlaceholder = self {
784 true
785 } else {
786 false
787 }
788 }
789
is_term<'a>(&'a self) -> MachTerminator<'a>790 fn is_term<'a>(&'a self) -> MachTerminator<'a> {
791 match self {
792 &Inst::Ret | &Inst::EpiloguePlaceholder => MachTerminator::Ret,
793 &Inst::Jump { dest } => MachTerminator::Uncond(dest.as_label().unwrap()),
794 &Inst::CondBr {
795 taken, not_taken, ..
796 } => MachTerminator::Cond(taken.as_label().unwrap(), not_taken.as_label().unwrap()),
797 &Inst::IndirectBr { ref targets, .. } => MachTerminator::Indirect(&targets[..]),
798 _ => MachTerminator::None,
799 }
800 }
801
gen_move(to_reg: Writable<Reg>, from_reg: Reg, _ty: Type) -> Inst802 fn gen_move(to_reg: Writable<Reg>, from_reg: Reg, _ty: Type) -> Inst {
803 assert_eq!(from_reg.get_class(), RegClass::I32);
804 assert_eq!(to_reg.to_reg().get_class(), from_reg.get_class());
805
806 Inst::mov(to_reg, from_reg)
807 }
808
gen_constant<F: FnMut(Type) -> Writable<Reg>>( to_regs: ValueRegs<Writable<Reg>>, value: u128, ty: Type, _alloc_tmp: F, ) -> SmallVec<[Inst; 4]>809 fn gen_constant<F: FnMut(Type) -> Writable<Reg>>(
810 to_regs: ValueRegs<Writable<Reg>>,
811 value: u128,
812 ty: Type,
813 _alloc_tmp: F,
814 ) -> SmallVec<[Inst; 4]> {
815 let to_reg = to_regs
816 .only_reg()
817 .expect("multi-reg values not supported yet");
818 let value = value as u64;
819
820 match ty {
821 B1 | I8 | B8 | I16 | B16 | I32 | B32 => {
822 let v: i64 = value as i64;
823
824 if v >= (1 << 32) || v < -(1 << 32) {
825 panic!("Cannot load constant value {}", value)
826 }
827 Inst::load_constant(to_reg, value as u32)
828 }
829 _ => unimplemented!(),
830 }
831 }
832
gen_nop(preferred_size: usize) -> Inst833 fn gen_nop(preferred_size: usize) -> Inst {
834 if preferred_size == 0 {
835 return Inst::Nop0;
836 }
837 assert!(preferred_size >= 2);
838 Inst::Nop2
839 }
840
maybe_direct_reload(&self, _reg: VirtualReg, _slot: SpillSlot) -> Option<Inst>841 fn maybe_direct_reload(&self, _reg: VirtualReg, _slot: SpillSlot) -> Option<Inst> {
842 None
843 }
844
rc_for_type(ty: Type) -> CodegenResult<(&'static [RegClass], &'static [Type])>845 fn rc_for_type(ty: Type) -> CodegenResult<(&'static [RegClass], &'static [Type])> {
846 match ty {
847 I8 | I16 | I32 | B1 | B8 | B16 | B32 => Ok((&[RegClass::I32], &[I32])),
848 IFLAGS => Ok((&[RegClass::I32], &[I32])),
849 _ => Err(CodegenError::Unsupported(format!(
850 "Unexpected SSA-value type: {}",
851 ty
852 ))),
853 }
854 }
855
gen_jump(target: MachLabel) -> Inst856 fn gen_jump(target: MachLabel) -> Inst {
857 Inst::Jump {
858 dest: BranchTarget::Label(target),
859 }
860 }
861
reg_universe(_flags: &settings::Flags) -> RealRegUniverse862 fn reg_universe(_flags: &settings::Flags) -> RealRegUniverse {
863 create_reg_universe()
864 }
865
worst_case_size() -> CodeOffset866 fn worst_case_size() -> CodeOffset {
867 // It inst with four 32-bit instructions
868 2 + 4 * 4
869 }
870
ref_type_regclass(_: &settings::Flags) -> RegClass871 fn ref_type_regclass(_: &settings::Flags) -> RegClass {
872 RegClass::I32
873 }
874 }
875
876 //=============================================================================
877 // Pretty-printing of instructions.
878
mem_finalize_for_show( mem: &AMode, mb_rru: Option<&RealRegUniverse>, state: &EmitState, ) -> (String, AMode)879 fn mem_finalize_for_show(
880 mem: &AMode,
881 mb_rru: Option<&RealRegUniverse>,
882 state: &EmitState,
883 ) -> (String, AMode) {
884 let (mem_insts, mem) = mem_finalize(mem, state);
885 let mut mem_str = mem_insts
886 .into_iter()
887 .map(|inst| inst.show_rru(mb_rru))
888 .collect::<Vec<_>>()
889 .join(" ; ");
890 if !mem_str.is_empty() {
891 mem_str += " ; ";
892 }
893
894 (mem_str, mem)
895 }
896
897 impl PrettyPrint for Inst {
show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String898 fn show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String {
899 self.pretty_print(mb_rru, &mut EmitState::default())
900 }
901 }
902
903 impl Inst {
print_with_state(&self, mb_rru: Option<&RealRegUniverse>, state: &mut EmitState) -> String904 fn print_with_state(&self, mb_rru: Option<&RealRegUniverse>, state: &mut EmitState) -> String {
905 fn op_name(alu_op: ALUOp) -> &'static str {
906 match alu_op {
907 ALUOp::Add => "add",
908 ALUOp::Adds => "adds",
909 ALUOp::Adc => "adc",
910 ALUOp::Adcs => "adcs",
911 ALUOp::Qadd => "qadd",
912 ALUOp::Sub => "sub",
913 ALUOp::Subs => "subs",
914 ALUOp::Sbc => "sbc",
915 ALUOp::Sbcs => "sbcs",
916 ALUOp::Rsb => "rsb",
917 ALUOp::Qsub => "qsub",
918 ALUOp::Mul => "mul",
919 ALUOp::Smull => "smull",
920 ALUOp::Umull => "umull",
921 ALUOp::Udiv => "udiv",
922 ALUOp::Sdiv => "sdiv",
923 ALUOp::And => "and",
924 ALUOp::Orr => "orr",
925 ALUOp::Orn => "orn",
926 ALUOp::Eor => "eor",
927 ALUOp::Bic => "bic",
928 ALUOp::Lsl => "lsl",
929 ALUOp::Lsr => "lsr",
930 ALUOp::Asr => "asr",
931 ALUOp::Ror => "ror",
932 }
933 }
934
935 fn reg_shift_str(
936 shift: &Option<ShiftOpAndAmt>,
937 mb_rru: Option<&RealRegUniverse>,
938 ) -> String {
939 if let Some(ref shift) = shift {
940 format!(", {}", shift.show_rru(mb_rru))
941 } else {
942 "".to_string()
943 }
944 }
945
946 match self {
947 &Inst::Nop0 => "nop-zero-len".to_string(),
948 &Inst::Nop2 => "nop".to_string(),
949 &Inst::AluRRR { alu_op, rd, rn, rm } => {
950 let op = op_name(alu_op);
951 let rd = rd.show_rru(mb_rru);
952 let rn = rn.show_rru(mb_rru);
953 let rm = rm.show_rru(mb_rru);
954 format!("{} {}, {}, {}", op, rd, rn, rm)
955 }
956 &Inst::AluRRRShift {
957 alu_op,
958 rd,
959 rn,
960 rm,
961 ref shift,
962 } => {
963 let op = op_name(alu_op);
964 let rd = rd.show_rru(mb_rru);
965 let rn = rn.show_rru(mb_rru);
966 let rm = rm.show_rru(mb_rru);
967 let shift = reg_shift_str(shift, mb_rru);
968 format!("{} {}, {}, {}{}", op, rd, rn, rm, shift)
969 }
970 &Inst::AluRRShift {
971 alu_op,
972 rd,
973 rm,
974 ref shift,
975 } => {
976 let op = match alu_op {
977 ALUOp1::Mvn => "mvn",
978 ALUOp1::Mov => "mov",
979 };
980 let rd = rd.show_rru(mb_rru);
981 let rm = rm.show_rru(mb_rru);
982 let shift = reg_shift_str(shift, mb_rru);
983 format!("{} {}, {}{}", op, rd, rm, shift)
984 }
985 &Inst::AluRRRR {
986 alu_op,
987 rd_hi,
988 rd_lo,
989 rn,
990 rm,
991 } => {
992 let op = op_name(alu_op);
993 let rd_hi = rd_hi.show_rru(mb_rru);
994 let rd_lo = rd_lo.show_rru(mb_rru);
995 let rn = rn.show_rru(mb_rru);
996 let rm = rm.show_rru(mb_rru);
997 format!("{} {}, {}, {}, {}", op, rd_lo, rd_hi, rn, rm)
998 }
999 &Inst::AluRRImm12 {
1000 alu_op,
1001 rd,
1002 rn,
1003 imm12,
1004 } => {
1005 let op = op_name(alu_op);
1006 let rd = rd.show_rru(mb_rru);
1007 let rn = rn.show_rru(mb_rru);
1008 let imm = imm12.show_rru(mb_rru);
1009 format!("{} {}, {}, {}", op, rd, rn, imm)
1010 }
1011 &Inst::AluRRImm8 {
1012 alu_op,
1013 rd,
1014 rn,
1015 imm8,
1016 } => {
1017 let op = op_name(alu_op);
1018 let rd = rd.show_rru(mb_rru);
1019 let rn = rn.show_rru(mb_rru);
1020 let imm = imm8.show_rru(mb_rru);
1021 format!("{} {}, {}, {}", op, rd, rn, imm)
1022 }
1023 &Inst::AluRImm8 { alu_op, rd, imm8 } => {
1024 let op = match alu_op {
1025 ALUOp1::Mvn => "mvn",
1026 ALUOp1::Mov => "mov",
1027 };
1028 let rd = rd.show_rru(mb_rru);
1029 let imm = imm8.show_rru(mb_rru);
1030 format!("{} {}, {}", op, rd, imm)
1031 }
1032 &Inst::BitOpRR { bit_op, rd, rm } => {
1033 let op = match bit_op {
1034 BitOp::Rbit => "rbit",
1035 BitOp::Rev => "rev",
1036 BitOp::Clz => "clz",
1037 };
1038 let rd = rd.show_rru(mb_rru);
1039 let rm = rm.show_rru(mb_rru);
1040 format!("{} {}, {}", op, rd, rm)
1041 }
1042 &Inst::Mov { rd, rm } => {
1043 let rd = rd.show_rru(mb_rru);
1044 let rm = rm.show_rru(mb_rru);
1045 format!("mov {}, {}", rd, rm)
1046 }
1047 &Inst::MovImm16 { rd, imm16 } => {
1048 let rd = rd.show_rru(mb_rru);
1049 format!("mov {}, #{}", rd, imm16)
1050 }
1051 &Inst::Movt { rd, imm16 } => {
1052 let rd = rd.show_rru(mb_rru);
1053 format!("movt {}, #{}", rd, imm16)
1054 }
1055 &Inst::Cmp { rn, rm } => {
1056 let rn = rn.show_rru(mb_rru);
1057 let rm = rm.show_rru(mb_rru);
1058 format!("cmp {}, {}", rn, rm)
1059 }
1060 &Inst::CmpImm8 { rn, imm8 } => {
1061 let rn = rn.show_rru(mb_rru);
1062 format!("cmp {}, #{}", rn, imm8)
1063 }
1064 &Inst::Store {
1065 rt, ref mem, bits, ..
1066 } => {
1067 let op = match bits {
1068 32 => "str",
1069 16 => "strh",
1070 8 => "strb",
1071 _ => panic!("Invalid bit amount {}", bits),
1072 };
1073 let rt = rt.show_rru(mb_rru);
1074 let (mem_str, mem) = mem_finalize_for_show(mem, mb_rru, state);
1075 let mem = mem.show_rru(mb_rru);
1076 format!("{}{} {}, {}", mem_str, op, rt, mem)
1077 }
1078 &Inst::Load {
1079 rt,
1080 ref mem,
1081 bits,
1082 sign_extend,
1083 ..
1084 } => {
1085 let op = match (bits, sign_extend) {
1086 (32, _) => "ldr",
1087 (16, true) => "ldrsh",
1088 (16, false) => "ldrh",
1089 (8, true) => "ldrsb",
1090 (8, false) => "ldrb",
1091 (_, _) => panic!("Invalid bit amount {}", bits),
1092 };
1093 let rt = rt.show_rru(mb_rru);
1094 let (mem_str, mem) = mem_finalize_for_show(mem, mb_rru, state);
1095 let mem = mem.show_rru(mb_rru);
1096 format!("{}{} {}, {}", mem_str, op, rt, mem)
1097 }
1098 &Inst::LoadAddr { rd, ref mem } => {
1099 let mut ret = String::new();
1100 let (mem_insts, mem) = mem_finalize(mem, state);
1101 for inst in mem_insts.into_iter() {
1102 ret.push_str(&inst.show_rru(mb_rru));
1103 }
1104 let inst = match mem {
1105 AMode::RegReg(rn, rm, shift) => {
1106 let shift = u32::from(shift);
1107 let shift_amt = ShiftOpShiftImm::maybe_from_shift(shift).unwrap();
1108 let shift = ShiftOpAndAmt::new(ShiftOp::LSL, shift_amt);
1109 Inst::AluRRRShift {
1110 alu_op: ALUOp::Add,
1111 rd,
1112 rn,
1113 rm,
1114 shift: Some(shift),
1115 }
1116 }
1117 AMode::RegOffset12(reg, imm12) => Inst::AluRRImm12 {
1118 alu_op: ALUOp::Add,
1119 rd,
1120 rn: reg,
1121 imm12,
1122 },
1123 _ => unreachable!(),
1124 };
1125 ret.push_str(&inst.show_rru(mb_rru));
1126 ret
1127 }
1128 &Inst::Extend {
1129 rd,
1130 rm,
1131 from_bits,
1132 signed,
1133 } => {
1134 let op = match (from_bits, signed) {
1135 (16, true) => "sxth",
1136 (16, false) => "uxth",
1137 (8, true) => "sxtb",
1138 (8, false) => "uxtb",
1139 _ => panic!("Unsupported extend case: {:?}", self),
1140 };
1141 let rd = rd.show_rru(mb_rru);
1142 let rm = rm.show_rru(mb_rru);
1143 format!("{} {}, {}", op, rd, rm)
1144 }
1145 &Inst::It { cond, ref insts } => {
1146 let te: String = insts
1147 .iter()
1148 .skip(1)
1149 .map(|i| if i.then { "t" } else { "e" })
1150 .collect();
1151 let cond = cond.show_rru(mb_rru);
1152 let mut ret = format!("it{} {}", te, cond);
1153 for inst in insts.into_iter() {
1154 ret.push_str(" ; ");
1155 ret.push_str(&inst.inst.show_rru(mb_rru));
1156 }
1157 ret
1158 }
1159 &Inst::Push { ref reg_list } => {
1160 assert!(!reg_list.is_empty());
1161 let first_reg = reg_list[0].show_rru(mb_rru);
1162 let regs: String = reg_list
1163 .iter()
1164 .skip(1)
1165 .map(|r| [",", &r.show_rru(mb_rru)].join(" "))
1166 .collect();
1167 format!("push {{{}{}}}", first_reg, regs)
1168 }
1169 &Inst::Pop { ref reg_list } => {
1170 assert!(!reg_list.is_empty());
1171 let first_reg = reg_list[0].show_rru(mb_rru);
1172 let regs: String = reg_list
1173 .iter()
1174 .skip(1)
1175 .map(|r| [",", &r.show_rru(mb_rru)].join(" "))
1176 .collect();
1177 format!("pop {{{}{}}}", first_reg, regs)
1178 }
1179 &Inst::Call { .. } => format!("bl 0"),
1180 &Inst::CallInd { ref info, .. } => {
1181 let rm = info.rm.show_rru(mb_rru);
1182 format!("blx {}", rm)
1183 }
1184 &Inst::LoadExtName {
1185 rt,
1186 ref name,
1187 offset,
1188 } => {
1189 let rt = rt.show_rru(mb_rru);
1190 format!("ldr {}, [pc, #4] ; b 4 ; data {:?} + {}", rt, name, offset)
1191 }
1192 &Inst::Ret => "bx lr".to_string(),
1193 &Inst::VirtualSPOffsetAdj { offset } => format!("virtual_sp_offset_adjust {}", offset),
1194 &Inst::EpiloguePlaceholder => "epilogue placeholder".to_string(),
1195 &Inst::Jump { ref dest } => {
1196 let dest = dest.show_rru(mb_rru);
1197 format!("b {}", dest)
1198 }
1199 &Inst::CondBr {
1200 ref taken,
1201 ref not_taken,
1202 ref cond,
1203 } => {
1204 let taken = taken.show_rru(mb_rru);
1205 let not_taken = not_taken.show_rru(mb_rru);
1206 let c = cond.show_rru(mb_rru);
1207 format!("b{} {} ; b {}", c, taken, not_taken)
1208 }
1209 &Inst::IndirectBr { rm, .. } => {
1210 let rm = rm.show_rru(mb_rru);
1211 format!("bx {}", rm)
1212 }
1213 &Inst::Udf { .. } => "udf #0".to_string(),
1214 &Inst::Bkpt => "bkpt #0".to_string(),
1215 &Inst::TrapIf { cond, .. } => {
1216 let c = cond.invert().show_rru(mb_rru);
1217 format!("b{} 2 ; udf #0", c)
1218 }
1219 }
1220 }
1221 }
1222
1223 //=============================================================================
1224 // Label fixups and jump veneers.
1225
1226 /// Different forms of label references for different instruction formats.
1227 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
1228 pub enum LabelUse {
1229 /// 20-bit branch offset used by 32-bit conditional jumps.
1230 Branch20,
1231
1232 /// 24-bit branch offset used by 32-bit uncoditional jump instruction.
1233 Branch24,
1234 }
1235
1236 impl MachInstLabelUse for LabelUse {
1237 /// Alignment for veneer code. Every instruction must be 4-byte-aligned.
1238 const ALIGN: CodeOffset = 2;
1239
1240 // Branches range:
1241 // 20-bit sign-extended immediate gives us range [-(2^19), 2^19 - 1].
1242 // Left-shifted by 1 => [-(2^20), 2^20 - 2].
1243 // PC is start of this instruction + 4 bytes => [-(2^20) + 4, 2^20 + 2].
1244 // Likewise for Branch24.
1245
1246 /// Maximum PC-relative range (positive), inclusive.
max_pos_range(self) -> CodeOffset1247 fn max_pos_range(self) -> CodeOffset {
1248 match self {
1249 LabelUse::Branch20 => (1 << 20) + 2,
1250 LabelUse::Branch24 => (1 << 24) + 2,
1251 }
1252 }
1253
1254 /// Maximum PC-relative range (negative).
max_neg_range(self) -> CodeOffset1255 fn max_neg_range(self) -> CodeOffset {
1256 match self {
1257 LabelUse::Branch20 => (1 << 20) - 4,
1258 LabelUse::Branch24 => (1 << 24) - 4,
1259 }
1260 }
1261
1262 /// Size of window into code needed to do the patch.
patch_size(self) -> CodeOffset1263 fn patch_size(self) -> CodeOffset {
1264 4
1265 }
1266
1267 /// Perform the patch.
patch(self, buffer: &mut [u8], use_offset: CodeOffset, label_offset: CodeOffset)1268 fn patch(self, buffer: &mut [u8], use_offset: CodeOffset, label_offset: CodeOffset) {
1269 let off = (label_offset as i64) - (use_offset as i64);
1270 debug_assert!(off <= self.max_pos_range() as i64);
1271 debug_assert!(off >= -(self.max_neg_range() as i64));
1272 let off = off - 4;
1273 match self {
1274 LabelUse::Branch20 => {
1275 let off = off as u32 >> 1;
1276 let imm11 = (off & 0x7ff) as u16;
1277 let imm6 = ((off >> 11) & 0x3f) as u16;
1278 let j1 = ((off >> 17) & 0x1) as u16;
1279 let j2 = ((off >> 18) & 0x1) as u16;
1280 let s = ((off >> 19) & 0x1) as u16;
1281 let insn_fst = u16::from_le_bytes([buffer[0], buffer[1]]);
1282 let insn_fst = (insn_fst & !0x43f) | imm6 | (s << 10);
1283 let insn_snd = u16::from_le_bytes([buffer[2], buffer[3]]);
1284 let insn_snd = (insn_snd & !0x2fff) | imm11 | (j2 << 11) | (j1 << 13);
1285 buffer[0..2].clone_from_slice(&u16::to_le_bytes(insn_fst));
1286 buffer[2..4].clone_from_slice(&u16::to_le_bytes(insn_snd));
1287 }
1288 LabelUse::Branch24 => {
1289 let off = off as u32 >> 1;
1290 let imm11 = (off & 0x7ff) as u16;
1291 let imm10 = ((off >> 11) & 0x3ff) as u16;
1292 let s = ((off >> 23) & 0x1) as u16;
1293 let j1 = (((off >> 22) & 0x1) as u16 ^ s) ^ 0x1;
1294 let j2 = (((off >> 21) & 0x1) as u16 ^ s) ^ 0x1;
1295 let insn_fst = u16::from_le_bytes([buffer[0], buffer[1]]);
1296 let insn_fst = (insn_fst & !0x07ff) | imm10 | (s << 10);
1297 let insn_snd = u16::from_le_bytes([buffer[2], buffer[3]]);
1298 let insn_snd = (insn_snd & !0x2fff) | imm11 | (j2 << 11) | (j1 << 13);
1299 buffer[0..2].clone_from_slice(&u16::to_le_bytes(insn_fst));
1300 buffer[2..4].clone_from_slice(&u16::to_le_bytes(insn_snd));
1301 }
1302 }
1303 }
1304
supports_veneer(self) -> bool1305 fn supports_veneer(self) -> bool {
1306 false
1307 }
1308
veneer_size(self) -> CodeOffset1309 fn veneer_size(self) -> CodeOffset {
1310 0
1311 }
1312
generate_veneer( self, _buffer: &mut [u8], _veneer_offset: CodeOffset, ) -> (CodeOffset, LabelUse)1313 fn generate_veneer(
1314 self,
1315 _buffer: &mut [u8],
1316 _veneer_offset: CodeOffset,
1317 ) -> (CodeOffset, LabelUse) {
1318 panic!("Veneer not supported yet.")
1319 }
1320 }
1321
1322 #[cfg(test)]
1323 mod tests {
1324 use super::*;
1325
1326 #[test]
patch_branch20()1327 fn patch_branch20() {
1328 let label_use = LabelUse::Branch20;
1329 let mut buffer = 0x8000_f000_u32.to_le_bytes(); // beq
1330 let use_offset: CodeOffset = 0;
1331 let label_offset: CodeOffset = label_use.max_pos_range();
1332 label_use.patch(&mut buffer, use_offset, label_offset);
1333 assert_eq!(u16::from_le_bytes([buffer[0], buffer[1]]), 0xf03f);
1334 assert_eq!(u16::from_le_bytes([buffer[2], buffer[3]]), 0xafff);
1335
1336 let mut buffer = 0x8000_f000_u32.to_le_bytes(); // beq
1337 let use_offset = label_use.max_neg_range();
1338 let label_offset: CodeOffset = 0;
1339 label_use.patch(&mut buffer, use_offset, label_offset);
1340 assert_eq!(u16::from_le_bytes([buffer[0], buffer[1]]), 0xf400);
1341 assert_eq!(u16::from_le_bytes([buffer[2], buffer[3]]), 0x8000);
1342 }
1343
1344 #[test]
patch_branch24()1345 fn patch_branch24() {
1346 let label_use = LabelUse::Branch24;
1347 let mut buffer = 0x9000_f000_u32.to_le_bytes(); // b
1348 let use_offset: CodeOffset = 0;
1349 let label_offset: CodeOffset = label_use.max_pos_range();
1350 label_use.patch(&mut buffer, use_offset, label_offset);
1351 assert_eq!(u16::from_le_bytes([buffer[0], buffer[1]]), 0xf3ff);
1352 assert_eq!(u16::from_le_bytes([buffer[2], buffer[3]]), 0x97ff);
1353
1354 let mut buffer = 0x9000_f000_u32.to_le_bytes(); // b
1355 let use_offset = label_use.max_neg_range();
1356 let label_offset: CodeOffset = 0;
1357 label_use.patch(&mut buffer, use_offset, label_offset);
1358 assert_eq!(u16::from_le_bytes([buffer[0], buffer[1]]), 0xf400);
1359 assert_eq!(u16::from_le_bytes([buffer[2], buffer[3]]), 0x9000);
1360 }
1361 }
1362