xref: /wasmtime-44.0.1/pulley/src/lib.rs (revision dfc4358d)
1 //! The pulley bytecode for fast interpreters.
2 
3 #![cfg_attr(docsrs, feature(doc_auto_cfg))]
4 #![deny(missing_docs)]
5 #![no_std]
6 
7 #[cfg(feature = "std")]
8 #[macro_use]
9 extern crate std;
10 
11 #[allow(unused_extern_crates)] // Some cfg's don't use this.
12 extern crate alloc;
13 
14 // TODO: make `struct BinaryOpRegs<T> { dst: T, src1: T, src2: T }` or something
15 // and pack it into 2 bytes (5 bits for each operand; 2**5 = 32 possible
16 // registers, and then only special isntructions to access special x registers)
17 
18 /// Calls the given macro with each opcode.
19 macro_rules! for_each_op {
20     ( $macro:ident ) => {
21         $macro! {
22             /// Transfer control the address in the `lr` register.
23             ret = Ret;
24 
25             /// Transfer control to the PC at the given offset and set the `lr`
26             /// register to the PC just after this instruction.
27             call = Call { offset: PcRelOffset };
28 
29             /// Unconditionally transfer control to the PC at the given offset.
30             jump = Jump { offset: PcRelOffset };
31 
32             /// Conditionally transfer control to the given PC offset if `cond`
33             /// contains a non-zero value.
34             br_if = BrIf { cond: XReg, offset: PcRelOffset };
35 
36             /// Conditionally transfer control to the given PC offset if `cond`
37             /// contains a zero value.
38             br_if_not = BrIfNot { cond: XReg, offset: PcRelOffset };
39 
40             /// Branch if `a == b`.
41             br_if_xeq32 = BrIfXeq32 { a: XReg, b: XReg, offset: PcRelOffset };
42             /// Branch if `a != `b.
43             br_if_xneq32 = BrIfXneq32 { a: XReg, b: XReg, offset: PcRelOffset };
44             /// Branch if signed `a < b`.
45             br_if_xslt32 = BrIfXslt32 { a: XReg, b: XReg, offset: PcRelOffset };
46             /// Branch if signed `a <= b`.
47             br_if_xslteq32 = BrIfXslteq32 { a: XReg, b: XReg, offset: PcRelOffset };
48             /// Branch if unsigned `a < b`.
49             br_if_xult32 = BrIfXult32 { a: XReg, b: XReg, offset: PcRelOffset };
50             /// Branch if unsigned `a <= b`.
51             br_if_xulteq32 = BrIfXulteq32 { a: XReg, b: XReg, offset: PcRelOffset };
52 
53             /// Move between `x` registers.
54             xmov = Xmov { dst: XReg, src: XReg };
55             /// Move between `f` registers.
56             fmov = Fmov { dst: FReg, src: FReg };
57             /// Move between `v` registers.
58             vmov = Vmov { dst: VReg, src: VReg };
59 
60             /// Set `dst = zero_extend(imm8)`.
61             xconst8 = Xconst8 { dst: XReg, imm: u8 };
62             /// Set `dst = zero_extend(imm16)`.
63             xconst16 = Xconst16 { dst: XReg, imm: u16 };
64             /// Set `dst = zero_extend(imm32)`.
65             xconst32 = Xconst32 { dst: XReg, imm: u32 };
66             /// Set `dst = imm64`.
67             xconst64 = Xconst64 { dst: XReg, imm: u64 };
68 
69             /// 32-bit wrapping addition: `low32(dst) = low32(src1) + low32(src2)`.
70             ///
71             /// The upper 32-bits of `dst` are unmodified.
72             xadd32 = Xadd32 { dst: XReg, src1: XReg, src2: XReg };
73 
74             /// 64-bit wrapping addition: `dst = src1 + src2`.
75             xadd64 = Xadd64 { dst: XReg, src1: XReg, src2: XReg };
76 
77             /// 64-bit equality.
78             xeq64 = Xeq64 { dst: XReg, src1: XReg, src2: XReg };
79             /// 64-bit inequality.
80             xneq64 = Xneq64 { dst: XReg, src1: XReg, src2: XReg };
81             /// 64-bit signed less-than.
82             xslt64 = Xslt64 { dst: XReg, src1: XReg, src2: XReg };
83             /// 64-bit signed less-than-equal.
84             xslteq64 = Xslteq64 { dst: XReg, src1: XReg, src2: XReg };
85             /// 64-bit unsigned less-than.
86             xult64 = Xult64 { dst: XReg, src1: XReg, src2: XReg };
87             /// 64-bit unsigned less-than-equal.
88             xulteq64 = Xulteq64 { dst: XReg, src1: XReg, src2: XReg };
89             /// 32-bit equality.
90             xeq32 = Xeq32 { dst: XReg, src1: XReg, src2: XReg };
91             /// 32-bit inequality.
92             xneq32 = Xneq32 { dst: XReg, src1: XReg, src2: XReg };
93             /// 32-bit signed less-than.
94             xslt32 = Xslt32 { dst: XReg, src1: XReg, src2: XReg };
95             /// 32-bit signed less-than-equal.
96             xslteq32 = Xslteq32 { dst: XReg, src1: XReg, src2: XReg };
97             /// 32-bit unsigned less-than.
98             xult32 = Xult32 { dst: XReg, src1: XReg, src2: XReg };
99             /// 32-bit unsigned less-than-equal.
100             xulteq32 = Xulteq32 { dst: XReg, src1: XReg, src2: XReg };
101 
102             /// `dst = zero_extend(load32(ptr))`
103             load32_u = Load32U { dst: XReg, ptr: XReg };
104             /// `dst = sign_extend(load32(ptr))`
105             load32_s = Load32S { dst: XReg, ptr: XReg };
106             /// `dst = load64(ptr)`
107             load64 = Load64 { dst: XReg, ptr: XReg };
108 
109             /// `dst = zero_extend(load32(ptr + offset8))`
110             load32_u_offset8 = Load32UOffset8 { dst: XReg, ptr: XReg, offset: i8 };
111             /// `dst = sign_extend(load32(ptr + offset8))`
112             load32_s_offset8 = Load32SOffset8 { dst: XReg, ptr: XReg, offset: i8 };
113             /// `dst = load64(ptr + offset8)`
114             load64_offset8 = Load64Offset8 { dst: XReg, ptr: XReg, offset: i8 };
115 
116             /// `*ptr = low32(src)`
117             store32 = Store32 { ptr: XReg, src: XReg };
118             /// `*ptr = src`
119             store64 = Store64 { ptr: XReg, src: XReg };
120 
121             /// `*(ptr + sign_extend(offset8)) = low32(src)`
122             store32_offset8 = Store32SOffset8 { ptr: XReg, offset: i8, src: XReg };
123             /// `*(ptr + sign_extend(offset8)) = src`
124             store64_offset8 = Store64Offset8 { ptr: XReg, offset: i8, src: XReg };
125 
126             /// `low32(dst) = bitcast low32(src) as i32`
127             bitcast_int_from_float_32 = BitcastIntFromFloat32 { dst: XReg, src: FReg };
128             /// `dst = bitcast src as i64`
129             bitcast_int_from_float_64 = BitcastIntFromFloat64 { dst: XReg, src: FReg };
130             /// `low32(dst) = bitcast low32(src) as f32`
131             bitcast_float_from_int_32 = BitcastFloatFromInt32 { dst: FReg, src: XReg };
132             /// `dst = bitcast src as f64`
133             bitcast_float_from_int_64 = BitcastFloatFromInt64 { dst: FReg, src: XReg };
134         }
135     };
136 }
137 
138 /// Calls the given macro with each extended opcode.
139 macro_rules! for_each_extended_op {
140     ( $macro:ident ) => {
141         $macro! {
142             /// Raise a trap.
143             trap = Trap;
144 
145             /// Do nothing.
146             nop = Nop;
147 
148             /// Copy the special `sp` stack pointer register into an `x` register.
149             get_sp = GetSp { dst: XReg };
150         }
151     };
152 }
153 
154 #[cfg(feature = "decode")]
155 pub mod decode;
156 #[cfg(feature = "disas")]
157 pub mod disas;
158 #[cfg(feature = "encode")]
159 pub mod encode;
160 #[cfg(feature = "interp")]
161 pub mod interp;
162 
163 pub mod regs;
164 pub use regs::*;
165 
166 pub mod imms;
167 pub use imms::*;
168 
169 pub mod op;
170 pub use op::*;
171 
172 pub mod opcode;
173 pub use opcode::*;
174 
175 #[allow(dead_code)] // Unused in some `cfg`s.
176 pub(crate) unsafe fn unreachable_unchecked<T>() -> T {
177     #[cfg(debug_assertions)]
178     unreachable!();
179 
180     #[cfg_attr(debug_assertions, allow(unreachable_code))]
181     unsafe {
182         core::hint::unreachable_unchecked()
183     }
184 }
185