diff options
Diffstat (limited to 'yjit/src/backend/arm64/mod.rs')
-rw-r--r-- | yjit/src/backend/arm64/mod.rs | 43 |
1 files changed, 34 insertions, 9 deletions
diff --git a/yjit/src/backend/arm64/mod.rs b/yjit/src/backend/arm64/mod.rs index 692e4371e2..ee4f96c0d8 100644 --- a/yjit/src/backend/arm64/mod.rs +++ b/yjit/src/backend/arm64/mod.rs @@ -157,24 +157,31 @@ impl Assembler /// Operands that take the place of bitmask immediates must follow a /// certain encoding. In this function we ensure that those operands /// do follow that encoding, and if they don't then we load them first. - fn split_bitmask_immediate(asm: &mut Assembler, opnd: Opnd) -> Opnd { + fn split_bitmask_immediate(asm: &mut Assembler, opnd: Opnd, dest_num_bits: u8) -> Opnd { match opnd { Opnd::Reg(_) | Opnd::InsnOut { .. } => opnd, Opnd::Mem(_) => split_load_operand(asm, opnd), Opnd::Imm(imm) => { if imm <= 0 { asm.load(opnd) - } else if BitmaskImmediate::try_from(imm as u64).is_ok() { + } else if (dest_num_bits == 64 && + BitmaskImmediate::try_from(imm as u64).is_ok()) || + (dest_num_bits == 32 && + u32::try_from(imm).is_ok() && + BitmaskImmediate::new_32b_reg(imm as u32).is_ok()) { Opnd::UImm(imm as u64) } else { - asm.load(opnd) + asm.load(opnd).with_num_bits(dest_num_bits).unwrap() } }, Opnd::UImm(uimm) => { - if BitmaskImmediate::try_from(uimm).is_ok() { + if (dest_num_bits == 64 && BitmaskImmediate::try_from(uimm).is_ok()) || + (dest_num_bits == 32 && + u32::try_from(uimm).is_ok() && + BitmaskImmediate::new_32b_reg(uimm as u32).is_ok()) { opnd } else { - asm.load(opnd) + asm.load(opnd).with_num_bits(dest_num_bits).unwrap() } }, Opnd::None | Opnd::Value(_) => unreachable!() @@ -208,12 +215,12 @@ impl Assembler }, (reg_opnd @ Opnd::Reg(_), other_opnd) | (other_opnd, reg_opnd @ Opnd::Reg(_)) => { - let opnd1 = split_bitmask_immediate(asm, other_opnd); + let opnd1 = split_bitmask_immediate(asm, other_opnd, reg_opnd.rm_num_bits()); (reg_opnd, opnd1) }, _ => { let opnd0 = split_load_operand(asm, opnd0); - let opnd1 = split_bitmask_immediate(asm, opnd1); + let opnd1 = split_bitmask_immediate(asm, opnd1, opnd0.rm_num_bits()); (opnd0, opnd1) } } @@ -449,7 +456,7 @@ impl Assembler // register or an immediate that can be encoded as a // bitmask immediate. Otherwise, we'll need to split the // move into multiple instructions. - _ => split_bitmask_immediate(asm, src) + _ => split_bitmask_immediate(asm, src, dest.rm_num_bits()) }; // If we're attempting to load into a memory operand, then @@ -508,7 +515,7 @@ impl Assembler // unsigned immediate that can be encoded as a bitmask // immediate. If it's not one of those, we'll need to load // it first. - let opnd1 = split_bitmask_immediate(asm, right); + let opnd1 = split_bitmask_immediate(asm, right, opnd0.rm_num_bits()); asm.test(opnd0, opnd1); }, _ => { @@ -1187,6 +1194,24 @@ mod tests { } #[test] + fn test_emit_test_32b_reg_not_bitmask_imm() { + let (mut asm, mut cb) = setup_asm(); + let w0 = Opnd::Reg(X0_REG).with_num_bits(32).unwrap(); + asm.test(w0, Opnd::UImm(u32::MAX.into())); + // All ones is not encodable with a bitmask immediate, + // so this needs one register + asm.compile_with_num_regs(&mut cb, 1); + } + + #[test] + fn test_emit_test_32b_reg_bitmask_imm() { + let (mut asm, mut cb) = setup_asm(); + let w0 = Opnd::Reg(X0_REG).with_num_bits(32).unwrap(); + asm.test(w0, Opnd::UImm(0x80000001)); + asm.compile_with_num_regs(&mut cb, 0); + } + + #[test] fn test_emit_or() { let (mut asm, mut cb) = setup_asm(); |