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