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