diff options
-rw-r--r-- | yjit/src/asm/arm64/arg/condition.rs | 34 | ||||
-rw-r--r-- | yjit/src/asm/arm64/inst/branch_cond.rs | 4 | ||||
-rw-r--r-- | yjit/src/asm/arm64/mod.rs | 2 | ||||
-rw-r--r-- | yjit/src/asm/mod.rs | 6 | ||||
-rw-r--r-- | yjit/src/asm/x86_64/mod.rs | 66 | ||||
-rw-r--r-- | yjit/src/backend/arm64/mod.rs | 20 |
6 files changed, 67 insertions, 65 deletions
diff --git a/yjit/src/asm/arm64/arg/condition.rs b/yjit/src/asm/arm64/arg/condition.rs index db269726d7..e791e4b078 100644 --- a/yjit/src/asm/arm64/arg/condition.rs +++ b/yjit/src/asm/arm64/arg/condition.rs @@ -1,20 +1,22 @@ /// Various instructions in A64 can have condition codes attached. This enum /// includes all of the various kinds of conditions along with their respective /// encodings. -pub enum Condition { - EQ = 0b0000, // equal to - NE = 0b0001, // not equal to - CS = 0b0010, // carry set (alias for HS) - CC = 0b0011, // carry clear (alias for LO) - MI = 0b0100, // minus, negative - PL = 0b0101, // positive or zero - VS = 0b0110, // signed overflow - VC = 0b0111, // no signed overflow - HI = 0b1000, // greater than (unsigned) - LS = 0b1001, // less than or equal to (unsigned) - GE = 0b1010, // greater than or equal to (signed) - LT = 0b1011, // less than (signed) - GT = 0b1100, // greater than (signed) - LE = 0b1101, // less than or equal to (signed) - AL = 0b1110, // always +pub struct Condition; + +impl Condition { + pub const EQ: u8 = 0b0000; // equal to + pub const NE: u8 = 0b0001; // not equal to + pub const CS: u8 = 0b0010; // carry set (alias for HS) + pub const CC: u8 = 0b0011; // carry clear (alias for LO) + pub const MI: u8 = 0b0100; // minus, negative + pub const PL: u8 = 0b0101; // positive or zero + pub const VS: u8 = 0b0110; // signed overflow + pub const VC: u8 = 0b0111; // no signed overflow + pub const HI: u8 = 0b1000; // greater than (unsigned) + pub const LS: u8 = 0b1001; // less than or equal to (unsigned) + pub const GE: u8 = 0b1010; // greater than or equal to (signed) + pub const LT: u8 = 0b1011; // less than (signed) + pub const GT: u8 = 0b1100; // greater than (signed) + pub const LE: u8 = 0b1101; // less than or equal to (signed) + pub const AL: u8 = 0b1110; // always } diff --git a/yjit/src/asm/arm64/inst/branch_cond.rs b/yjit/src/asm/arm64/inst/branch_cond.rs index 21fdda5d3f..33cc9c3649 100644 --- a/yjit/src/asm/arm64/inst/branch_cond.rs +++ b/yjit/src/asm/arm64/inst/branch_cond.rs @@ -11,7 +11,7 @@ use super::super::arg::Condition; /// pub struct BranchCond { /// The kind of condition to check before branching. - cond: Condition, + cond: u8, /// The instruction offset from this instruction to branch to. imm19: i32 @@ -20,7 +20,7 @@ pub struct BranchCond { impl BranchCond { /// B.cond /// https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/B-cond--Branch-conditionally- - pub fn bcond(cond: Condition, byte_offset: i32) -> Self { + pub fn bcond(cond: u8, byte_offset: i32) -> Self { Self { cond, imm19: byte_offset >> 2 } } } diff --git a/yjit/src/asm/arm64/mod.rs b/yjit/src/asm/arm64/mod.rs index 2dc5aa9388..3b5f1ff022 100644 --- a/yjit/src/asm/arm64/mod.rs +++ b/yjit/src/asm/arm64/mod.rs @@ -167,7 +167,7 @@ pub const fn bcond_offset_fits_bits(offset: i64) -> bool { } /// B.cond - branch to target if condition is true -pub fn bcond(cb: &mut CodeBlock, cond: Condition, byte_offset: A64Opnd) { +pub fn bcond(cb: &mut CodeBlock, cond: u8, byte_offset: A64Opnd) { let bytes: [u8; 4] = match byte_offset { A64Opnd::Imm(imm) => { assert!(bcond_offset_fits_bits(imm), "The immediate operand must be 21 bits or less and be aligned to a 2-bit boundary."); diff --git a/yjit/src/asm/mod.rs b/yjit/src/asm/mod.rs index 126c9a8548..2fc75083e4 100644 --- a/yjit/src/asm/mod.rs +++ b/yjit/src/asm/mod.rs @@ -30,7 +30,7 @@ struct LabelRef { num_bytes: usize, /// The object that knows how to encode the branch instruction. - encode: Box<dyn FnOnce(&mut CodeBlock, i64, i64)> + encode: fn(&mut CodeBlock, i64, i64) } /// Block of memory into which instructions can be assembled @@ -227,11 +227,11 @@ impl CodeBlock { } // Add a label reference at the current write position - pub fn label_ref<E: 'static>(&mut self, label_idx: usize, num_bytes: usize, encode: E) where E: FnOnce(&mut CodeBlock, i64, i64) { + pub fn label_ref(&mut self, label_idx: usize, num_bytes: usize, encode: fn(&mut CodeBlock, i64, i64)) { assert!(label_idx < self.label_addrs.len()); // Keep track of the reference - self.label_refs.push(LabelRef { pos: self.write_pos, label_idx, num_bytes, encode: Box::new(encode) }); + self.label_refs.push(LabelRef { pos: self.write_pos, label_idx, num_bytes, encode }); // Move past however many bytes the instruction takes up self.write_pos += num_bytes; diff --git a/yjit/src/asm/x86_64/mod.rs b/yjit/src/asm/x86_64/mod.rs index a2a3b47f82..d23279f277 100644 --- a/yjit/src/asm/x86_64/mod.rs +++ b/yjit/src/asm/x86_64/mod.rs @@ -799,45 +799,45 @@ pub fn int3(cb: &mut CodeBlock) { // Encode a conditional relative jump to a label // Note: this always encodes a 32-bit offset -fn write_jcc(cb: &mut CodeBlock, op: u8, label_idx: usize) { - cb.label_ref(label_idx, 6, move |cb, src_addr, dst_addr| { +fn write_jcc<const OP: u8>(cb: &mut CodeBlock, label_idx: usize) { + cb.label_ref(label_idx, 6, |cb, src_addr, dst_addr| { cb.write_byte(0x0F); - cb.write_byte(op); + cb.write_byte(OP); cb.write_int((dst_addr - src_addr) as u64, 32); }); } /// jcc - relative jumps to a label -pub fn ja_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x87, label_idx); } -pub fn jae_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x83, label_idx); } -pub fn jb_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x82, label_idx); } -pub fn jbe_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x86, label_idx); } -pub fn jc_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x82, label_idx); } -pub fn je_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x84, label_idx); } -pub fn jg_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8F, label_idx); } -pub fn jge_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8D, label_idx); } -pub fn jl_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8C, label_idx); } -pub fn jle_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8E, label_idx); } -pub fn jna_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x86, label_idx); } -pub fn jnae_label(cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x82, label_idx); } -pub fn jnb_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x83, label_idx); } -pub fn jnbe_label(cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x87, label_idx); } -pub fn jnc_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x83, label_idx); } -pub fn jne_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x85, label_idx); } -pub fn jng_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8E, label_idx); } -pub fn jnge_label(cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8C, label_idx); } -pub fn jnl_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8D, label_idx); } -pub fn jnle_label(cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8F, label_idx); } -pub fn jno_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x81, label_idx); } -pub fn jnp_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8b, label_idx); } -pub fn jns_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x89, label_idx); } -pub fn jnz_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x85, label_idx); } -pub fn jo_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x80, label_idx); } -pub fn jp_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8A, label_idx); } -pub fn jpe_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8A, label_idx); } -pub fn jpo_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8B, label_idx); } -pub fn js_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x88, label_idx); } -pub fn jz_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x84, label_idx); } +pub fn ja_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x87>(cb, label_idx); } +pub fn jae_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x83>(cb, label_idx); } +pub fn jb_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x82>(cb, label_idx); } +pub fn jbe_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x86>(cb, label_idx); } +pub fn jc_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x82>(cb, label_idx); } +pub fn je_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x84>(cb, label_idx); } +pub fn jg_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x8F>(cb, label_idx); } +pub fn jge_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x8D>(cb, label_idx); } +pub fn jl_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x8C>(cb, label_idx); } +pub fn jle_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x8E>(cb, label_idx); } +pub fn jna_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x86>(cb, label_idx); } +pub fn jnae_label(cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x82>(cb, label_idx); } +pub fn jnb_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x83>(cb, label_idx); } +pub fn jnbe_label(cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x87>(cb, label_idx); } +pub fn jnc_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x83>(cb, label_idx); } +pub fn jne_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x85>(cb, label_idx); } +pub fn jng_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x8E>(cb, label_idx); } +pub fn jnge_label(cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x8C>(cb, label_idx); } +pub fn jnl_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x8D>(cb, label_idx); } +pub fn jnle_label(cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x8F>(cb, label_idx); } +pub fn jno_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x81>(cb, label_idx); } +pub fn jnp_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x8b>(cb, label_idx); } +pub fn jns_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x89>(cb, label_idx); } +pub fn jnz_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x85>(cb, label_idx); } +pub fn jo_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x80>(cb, label_idx); } +pub fn jp_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x8A>(cb, label_idx); } +pub fn jpe_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x8A>(cb, label_idx); } +pub fn jpo_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x8B>(cb, label_idx); } +pub fn js_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x88>(cb, label_idx); } +pub fn jz_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc::<0x84>(cb, label_idx); } pub fn jmp_label(cb: &mut CodeBlock, label_idx: usize) { cb.label_ref(label_idx, 5, |cb, src_addr, dst_addr| { diff --git a/yjit/src/backend/arm64/mod.rs b/yjit/src/backend/arm64/mod.rs index 0fee18c068..f6429dbcea 100644 --- a/yjit/src/backend/arm64/mod.rs +++ b/yjit/src/backend/arm64/mod.rs @@ -284,7 +284,7 @@ impl Assembler /// Emit a conditional jump instruction to a specific target. This is /// called when lowering any of the conditional jump instructions. - fn emit_conditional_jump(cb: &mut CodeBlock, condition: Condition, target: Target) { + fn emit_conditional_jump<const CONDITION: u8>(cb: &mut CodeBlock, target: Target) { match target { Target::CodePtr(dst_ptr) => { let src_addr = cb.get_write_ptr().into_i64() + 4; @@ -297,12 +297,12 @@ impl Assembler // to load the address into a register and use the branch // register instruction. if bcond_offset_fits_bits(offset) { - bcond(cb, condition, A64Opnd::new_imm(dst_addr - src_addr)); + bcond(cb, CONDITION, A64Opnd::new_imm(dst_addr - src_addr)); } else { // If the condition is met, then we'll skip past the // next instruction, put the address in a register, and // jump to it. - bcond(cb, condition, A64Opnd::new_imm(4)); + bcond(cb, CONDITION, A64Opnd::new_imm(4)); // If the offset fits into a direct jump, then we'll use // that and the number of instructions will be shorter. @@ -333,7 +333,7 @@ impl Assembler // offset. We're going to assume we can fit into a single // b.cond instruction. It will panic otherwise. cb.label_ref(label_idx, 4, |cb, src_addr, dst_addr| { - bcond(cb, condition, A64Opnd::new_imm(dst_addr - src_addr)); + bcond(cb, CONDITION, A64Opnd::new_imm(dst_addr - src_addr)); }); }, Target::FunPtr(_) => unreachable!() @@ -395,7 +395,7 @@ impl Assembler // being loaded is a heap object, we'll report that // back out to the gc_offsets list. ldr(cb, insn.out.into(), 1); - b(cb, A64Opnd::new_uimm((SIZEOF_VALUE as u64) / 4)); + b(cb, A64Opnd::new_imm((SIZEOF_VALUE as i64) / 4)); cb.write_bytes(&value.as_u64().to_le_bytes()); if !value.special_const_p() { @@ -507,19 +507,19 @@ impl Assembler }; }, Op::Je => { - emit_conditional_jump(cb, Condition::EQ, insn.target.unwrap()); + emit_conditional_jump::<{Condition::EQ}>(cb, insn.target.unwrap()); }, Op::Jbe => { - emit_conditional_jump(cb, Condition::LS, insn.target.unwrap()); + emit_conditional_jump::<{Condition::LS}>(cb, insn.target.unwrap()); }, Op::Jz => { - emit_conditional_jump(cb, Condition::EQ, insn.target.unwrap()); + emit_conditional_jump::<{Condition::EQ}>(cb, insn.target.unwrap()); }, Op::Jnz => { - emit_conditional_jump(cb, Condition::NE, insn.target.unwrap()); + emit_conditional_jump::<{Condition::NE}>(cb, insn.target.unwrap()); }, Op::Jo => { - emit_conditional_jump(cb, Condition::VS, insn.target.unwrap()); + emit_conditional_jump::<{Condition::VS}>(cb, insn.target.unwrap()); }, Op::IncrCounter => { ldaddal(cb, insn.opnds[0].into(), insn.opnds[0].into(), insn.opnds[1].into()); |