From 6d2c450dd8c0f7869352c81f8278c57450c61932 Mon Sep 17 00:00:00 2001 From: Hantang Sun Date: Wed, 14 May 2025 16:05:30 +0100 Subject: [PATCH] RISC-V: Lower Mulh, Mulhsu, Mulhu --- src/riscv/lib/src/instruction_context.rs | 33 ++++++ src/riscv/lib/src/interpreter/integer.rs | 94 +++++++++++++++ src/riscv/lib/src/interpreter/rv32m.rs | 41 ------- src/riscv/lib/src/jit.rs | 106 +++++++++++++++++ src/riscv/lib/src/jit/builder.rs | 28 +++++ .../lib/src/machine_state/instruction.rs | 54 +++++---- .../machine_state/instruction/constructors.rs | 110 ++++++++++++++++++ .../instruction/tagged_instruction.rs | 7 +- src/riscv/lib/src/parser/instruction.rs | 8 ++ .../lib/tests/expected/dummy/state_hash_final | 2 +- .../lib/tests/expected/jstz/state_hash_final | 2 +- 11 files changed, 418 insertions(+), 67 deletions(-) diff --git a/src/riscv/lib/src/instruction_context.rs b/src/riscv/lib/src/instruction_context.rs index cc288e63daf9..1f2b7134c935 100644 --- a/src/riscv/lib/src/instruction_context.rs +++ b/src/riscv/lib/src/instruction_context.rs @@ -146,6 +146,15 @@ pub(crate) trait ICB { #[expect(dead_code)] fn extend_unsigned(&mut self, value: Self::XValue32) -> Self::XValue; + /// Multiply two [`XValue`] values and return the high 64 bits of the result, with + /// the appropriate sign-extension passed in as 2 boolean arguments. + fn mul_high( + &mut self, + lhs: Self::XValue, + rhs: Self::XValue, + mul_high_type: MulHighType, + ) -> Self::XValue; + /// Convert a boolean value to an xvalue. /// /// Coerces to the following: @@ -315,6 +324,23 @@ impl ICB for MachineCoreState { value as u64 } + #[inline(always)] + fn mul_high( + &mut self, + lhs: Self::XValue, + rhs: Self::XValue, + mul_high_type: MulHighType, + ) -> Self::XValue { + let (lhs, rhs) = match mul_high_type { + MulHighType::Signed => (lhs as i64 as i128 as u128, rhs as i64 as i128 as u128), + MulHighType::Unsigned => (lhs as u128, rhs as u128), + MulHighType::SignedUnsigned => (lhs as i64 as i128 as u128, rhs as u128), + }; + let result = lhs.wrapping_mul(rhs); + + (result >> 64) as u64 + } + #[inline(always)] fn xvalue_from_bool(&mut self, value: Self::Bool) -> Self::XValue { value as XValue @@ -475,6 +501,13 @@ pub enum Shift { RightSigned, } +/// The type of X64 mul_high operation to perform. +pub enum MulHighType { + Signed, + Unsigned, + SignedUnsigned, +} + /// Supported value widths for loading from/storing to main memory for XRegisters. /// /// **NB** This type may be passed over C-FFI. See [state_access] for more diff --git a/src/riscv/lib/src/interpreter/integer.rs b/src/riscv/lib/src/interpreter/integer.rs index 6c1298e0a88b..2eb5b170e3fd 100644 --- a/src/riscv/lib/src/interpreter/integer.rs +++ b/src/riscv/lib/src/interpreter/integer.rs @@ -5,6 +5,7 @@ //! Implementation of integer arithmetic operations for RISC-V over the ICB. use crate::instruction_context::ICB; +use crate::instruction_context::MulHighType; use crate::instruction_context::Predicate; use crate::instruction_context::Shift; use crate::instruction_context::arithmetic::Arithmetic; @@ -357,6 +358,23 @@ pub fn run_x32_mul(icb: &mut impl ICB, rs1: XRegister, rs2: XRegister, rd: NonZe icb.xregister_write_nz(rd, result) } +// Extend `val(rs1)` and `val(rs2)` to 128 bits, multiply the 128 bits value and store the upper 64 bits in `rd` +#[inline] +pub fn run_x64_mul_high( + icb: &mut impl ICB, + rs1: NonZeroXRegister, + rs2: NonZeroXRegister, + rd: NonZeroXRegister, + mul_high_type: MulHighType, +) { + let lhs = icb.xregister_read_nz(rs1); + let rhs = icb.xregister_read_nz(rs2); + + let result = icb.mul_high(lhs, rhs, mul_high_type); + + icb.xregister_write_nz(rd, result) +} + /// Signed integer division `⌊ val(rs1) / val(rs2) ⌋`, storing the result in `rd`. /// /// If `val(rs2) == 0`, the result is `-1`. @@ -1047,4 +1065,80 @@ mod tests { .wrapping_add(state.hart.xregisters.read(a3))); }) }); + + macro_rules! test_x64_mul_high { + ($state:ident, $r1_val:expr, $r2_val:expr, $mul_high_type:expr, $expected_val:expr) => { + $state.hart.xregisters.write_nz(nz::a0, $r1_val); + $state.hart.xregisters.write_nz(nz::a1, $r2_val); + run_x64_mul_high(&mut $state, nz::a0, nz::a1, nz::a2, $mul_high_type); + assert_eq!($state.hart.xregisters.read_nz(nz::a2), $expected_val); + }; + } + + backend_test!(test_x64_mul_high, F, { + let mut state = MachineCoreState::::new(&mut F::manager()); + + // MULH (Signed × Signed) + test_x64_mul_high!( + state, + i64::MAX as u64, + i64::MAX as u64, + MulHighType::Signed, + (((i64::MAX as i128) * (i64::MAX as i128)) >> 64) as u64 + ); + test_x64_mul_high!( + state, + i64::MIN as u64, + i64::MIN as u64, + MulHighType::Signed, + (((i64::MIN as i128) * (i64::MIN as i128)) >> 64) as u64 + ); + test_x64_mul_high!( + state, + i64::MIN as u64, + i64::MAX as u64, + MulHighType::Signed, + (((i64::MIN as i128) * (i64::MAX as i128)) >> 64) as u64 + ); + + // MULHSU (Signed × Unsigned) + test_x64_mul_high!( + state, + i64::MAX as u64, + u64::MAX, + MulHighType::SignedUnsigned, + (((i64::MAX as i128) * (u64::MAX as u128) as i128) >> 64) as u64 + ); + test_x64_mul_high!( + state, + i64::MIN as u64, + u64::MAX, + MulHighType::SignedUnsigned, + (((i64::MIN as i128) * (u64::MAX as u128) as i128) >> 64) as u64 + ); + test_x64_mul_high!( + state, + -1i64 as u64, + u64::MAX, + MulHighType::SignedUnsigned, + (-((u64::MAX as u128) as i128) >> 64) as u64 + ); + + // MULHU (Unsigned × Unsigned) + test_x64_mul_high!( + state, + u64::MAX, + u64::MAX, + MulHighType::Unsigned, + (((u64::MAX as u128) * (u64::MAX as u128)) >> 64) as u64 + ); + test_x64_mul_high!( + state, + i64::MIN as u64, + 2u64, + MulHighType::Unsigned, + (((i64::MIN as u64 as u128) * (2u128)) >> 64) as u64 + ); + test_x64_mul_high!(state, 0u64, u64::MAX, MulHighType::Unsigned, 0u64); + }); } diff --git a/src/riscv/lib/src/interpreter/rv32m.rs b/src/riscv/lib/src/interpreter/rv32m.rs index 16c64820a6dd..eee6bd672d95 100644 --- a/src/riscv/lib/src/interpreter/rv32m.rs +++ b/src/riscv/lib/src/interpreter/rv32m.rs @@ -61,47 +61,6 @@ where self.write(rd, result); } - - /// `MULH` R-type instruction - /// - /// Multiply val(rs1) with val(rs2) and store the upper 64 bits of the result - /// in register `rd`. - pub fn run_mulh(&mut self, rs1: XRegister, rs2: XRegister, rd: XRegister) { - let rval1 = self.read(rs1) as i64 as i128; - let rval2 = self.read(rs2) as i64 as i128; - - let result = rval1.wrapping_mul(rval2); - - self.write(rd, (result >> 64) as i64 as u64); - } - - /// `MULHSU` R-type instruction - /// - /// Multiply val(rs1) with val(rs2) and store the upper 64 bits of the result - /// in register `rd`. val(rs1) is treated as a _signed integer_, while val(rs2) - /// is treated as an _unsigned integer_. - pub fn run_mulhsu(&mut self, rs1: XRegister, rs2: XRegister, rd: XRegister) { - let rval1 = self.read(rs1) as i64 as i128 as u128; - let rval2 = self.read(rs2) as u128; - - let result = rval1.wrapping_mul(rval2); - - self.write(rd, (result >> 64) as u64); - } - - /// `MULHU` R-type instruction - /// - /// Multiply val(rs1) with val(rs2) and store the upper 64 bits of the result - /// in register `rd`. Both val(rs1) and val(rs2) are treated as - /// _unsigned integers_. - pub fn run_mulhu(&mut self, rs1: XRegister, rs2: XRegister, rd: XRegister) { - let rval1 = self.read(rs1) as u128; - let rval2 = self.read(rs2) as u128; - - let result = rval1.wrapping_mul(rval2); - - self.write(rd, (result >> 64) as u64); - } } #[cfg(test)] diff --git a/src/riscv/lib/src/jit.rs b/src/riscv/lib/src/jit.rs index 625ce8e8c697..6b55e8244a9f 100644 --- a/src/riscv/lib/src/jit.rs +++ b/src/riscv/lib/src/jit.rs @@ -2373,4 +2373,110 @@ mod tests { scenario.run(&mut jit, &mut interpreted_bb); } }); + + backend_test!(test_mul_high, F, { + use crate::machine_state::registers::NonZeroXRegister::*; + + let test_mul_high = |constructor: fn( + NonZeroXRegister, + NonZeroXRegister, + NonZeroXRegister, + InstrWidth, + ) -> I, + lhs_reg: NonZeroXRegister, + lhs_val: u64, + rhs_reg: NonZeroXRegister, + rhs_val: u64, + expected: u64| + -> Scenario { + ScenarioBuilder::default() + .set_setup_hook(setup_hook!(core, F, { + core.hart.xregisters.write_nz(lhs_reg, lhs_val); + core.hart.xregisters.write_nz(rhs_reg, rhs_val); + })) + .set_instructions(&[constructor(x2, lhs_reg, rhs_reg, Compressed)]) + .set_assert_hook(assert_hook!(core, F, { + assert_eq!(core.hart.xregisters.read_nz(x2), expected); + })) + .build() + }; + + let scenarios: &[Scenario] = &[ + // MULH (Signed × Signed) + test_mul_high( + I::new_x64_mul_high_signed, + x1, + i64::MAX as u64, + x3, + i64::MAX as u64, + (((i64::MAX as i128) * (i64::MAX as i128)) >> 64) as u64, + ), + test_mul_high( + I::new_x64_mul_high_signed, + x1, + i64::MIN as u64, + x3, + i64::MIN as u64, + (((i64::MIN as i128) * (i64::MIN as i128)) >> 64) as u64, + ), + test_mul_high( + I::new_x64_mul_high_signed, + x1, + i64::MIN as u64, + x3, + i64::MAX as u64, + (((i64::MIN as i128) * (i64::MAX as i128)) >> 64) as u64, + ), + // MULHSU (Signed × Unsigned) + test_mul_high( + I::new_x64_mul_high_signed_unsigned, + x1, + i64::MAX as u64, + x3, + u64::MAX, + (((i64::MAX as i128) * (u64::MAX as u128) as i128) >> 64) as u64, + ), + test_mul_high( + I::new_x64_mul_high_signed_unsigned, + x1, + i64::MIN as u64, + x3, + u64::MAX, + (((i64::MIN as i128) * (u64::MAX as u128) as i128) >> 64) as u64, + ), + test_mul_high( + I::new_x64_mul_high_signed_unsigned, + x1, + -1i64 as u64, + x3, + u64::MAX, + (-((u64::MAX as u128) as i128) >> 64) as u64, + ), + // MULHU (Unsigned × Unsigned) + test_mul_high( + I::new_x64_mul_high_unsigned, + x1, + u64::MAX, + x3, + u64::MAX, + (((u64::MAX as u128) * (u64::MAX as u128)) >> 64) as u64, + ), + test_mul_high( + I::new_x64_mul_high_unsigned, + x1, + i64::MIN as u64, + x3, + 2u64, + (((i64::MIN as u64 as u128) * (2u128)) >> 64) as u64, + ), + test_mul_high(I::new_x64_mul_high_unsigned, x1, 0u64, x3, u64::MAX, 0u64), + ]; + + let mut jit = JIT::::new().unwrap(); + let mut interpreted_bb = InterpretedBlockBuilder; + + for scenario in scenarios { + scenario.run(&mut jit, &mut interpreted_bb); + } + }); } diff --git a/src/riscv/lib/src/jit/builder.rs b/src/riscv/lib/src/jit/builder.rs index 809df25d4936..11a3d041db6e 100644 --- a/src/riscv/lib/src/jit/builder.rs +++ b/src/riscv/lib/src/jit/builder.rs @@ -20,6 +20,7 @@ use cranelift::codegen::ir::condcodes::IntCC; use cranelift::codegen::ir::types::I32; use cranelift::codegen::ir::types::I64; use cranelift::frontend::FunctionBuilder; +use cranelift::prelude::types::I128; use errno::AtomicAccessGuard; use self::block_state::DynamicValues; @@ -28,6 +29,7 @@ use super::state_access::JitStateAccess; use super::state_access::JsaCalls; use crate::instruction_context::ICB; use crate::instruction_context::LoadStoreWidth; +use crate::instruction_context::MulHighType; use crate::instruction_context::PhiValue; use crate::instruction_context::Predicate; use crate::instruction_context::arithmetic::Arithmetic; @@ -289,6 +291,32 @@ impl ICB for Builder<'_, MC, JSA> { X64(self.builder.ins().uextend(I64, value.0)) } + fn mul_high( + &mut self, + lhs: Self::XValue, + rhs: Self::XValue, + mul_high_type: MulHighType, + ) -> Self::XValue { + let (lhs, rhs) = match mul_high_type { + MulHighType::Signed => ( + self.builder.ins().sextend(I128, lhs.0), + self.builder.ins().sextend(I128, rhs.0), + ), + MulHighType::Unsigned => ( + self.builder.ins().uextend(I128, lhs.0), + self.builder.ins().uextend(I128, rhs.0), + ), + MulHighType::SignedUnsigned => ( + self.builder.ins().sextend(I128, lhs.0), + self.builder.ins().uextend(I128, rhs.0), + ), + }; + let result = self.builder.ins().imul(lhs, rhs); + let (_low, high) = self.builder.ins().isplit(result); + + X64(high) + } + fn xregister_read_nz(&mut self, reg: NonZeroXRegister) -> Self::XValue { JSA::ir_xreg_read( &mut self.jsa_call, diff --git a/src/riscv/lib/src/machine_state/instruction.rs b/src/riscv/lib/src/machine_state/instruction.rs index d27a5cd23d09..5987b7326a68 100644 --- a/src/riscv/lib/src/machine_state/instruction.rs +++ b/src/riscv/lib/src/machine_state/instruction.rs @@ -40,6 +40,7 @@ use crate::instruction_context::ICB; use crate::instruction_context::IcbFnResult; use crate::instruction_context::IcbLoweringFn; use crate::instruction_context::LoadStoreWidth; +use crate::instruction_context::MulHighType; use crate::instruction_context::Predicate; use crate::instruction_context::Shift; use crate::interpreter::atomics; @@ -296,9 +297,9 @@ pub enum OpCode { Divw, Divuw, Mul, - Mulh, - Mulhsu, - Mulhu, + X64MulHighSigned, + X64MulHighSignedUnsigned, + X64MulHighUnsigned, X32Mul, // RV64F instructions @@ -513,9 +514,9 @@ impl OpCode { Self::Divw => Args::run_divw, Self::Divuw => Args::run_divuw, Self::Mul => Args::run_mul, - Self::Mulh => Args::run_mulh, - Self::Mulhsu => Args::run_mulhsu, - Self::Mulhu => Args::run_mulhu, + Self::X64MulHighSigned => Args::run_x64_mul_high_signed, + Self::X64MulHighSignedUnsigned => Args::run_x64_mul_high_signed_unsigned, + Self::X64MulHighUnsigned => Args::run_x64_mul_high_unsigned, Self::X32Mul => Args::run_x32_mul, Self::FclassS => Args::run_fclass_s, Self::Feqs => Args::run_feq_s, @@ -633,6 +634,9 @@ impl OpCode { Self::X64XorImm => Some(Args::run_x64_xor_immediate), Self::Mul => Some(Args::run_mul), Self::X32Mul => Some(Args::run_x32_mul), + Self::X64MulHighSigned => Some(Args::run_x64_mul_high_signed), + Self::X64MulHighSignedUnsigned => Some(Args::run_x64_mul_high_signed_unsigned), + Self::X64MulHighUnsigned => Some(Args::run_x64_mul_high_unsigned), Self::X64DivSigned => Some(Args::run_x64_div_signed), Self::Li => Some(Args::run_li), Self::AddImmediateToPC => Some(Args::run_add_immediate_to_pc), @@ -912,6 +916,23 @@ macro_rules! impl_x32_shift_type { }; } +macro_rules! impl_x64_mul_high_type { + ($fn: ident, $mul_high_type: ident) => { + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. + unsafe fn $fn(&self, icb: &mut I) -> IcbFnResult { + integer::run_x64_mul_high( + icb, + unsafe { self.rs1.nzx }, + unsafe { self.rs2.nzx }, + unsafe { self.rd.nzx }, + MulHighType::$mul_high_type, + ); + icb.ok(Next(self.width)) + } + }; +} + macro_rules! impl_i_type { ($fn: ident, non_zero) => { /// SAFETY: This function must only be called on an `Args` belonging @@ -1487,9 +1508,9 @@ impl Args { impl_r_type!(run_divw); impl_r_type!(run_divuw); impl_r_type!(integer::run_mul, run_mul, non_zero); - impl_r_type!(run_mulh); - impl_r_type!(run_mulhsu); - impl_r_type!(run_mulhu); + impl_x64_mul_high_type!(run_x64_mul_high_signed, Signed); + impl_x64_mul_high_type!(run_x64_mul_high_signed_unsigned, SignedUnsigned); + impl_x64_mul_high_type!(run_x64_mul_high_unsigned, Unsigned); impl_r_type!(integer::run_x32_mul, run_x32_mul, non_zero_rd); // RV64F instructions @@ -1932,18 +1953,9 @@ impl From<&InstrCacheable> for Instruction { args: args.into(), }, InstrCacheable::Mul(args) => Instruction::from_ic_mul(args), - InstrCacheable::Mulh(args) => Instruction { - opcode: OpCode::Mulh, - args: args.into(), - }, - InstrCacheable::Mulhsu(args) => Instruction { - opcode: OpCode::Mulhsu, - args: args.into(), - }, - InstrCacheable::Mulhu(args) => Instruction { - opcode: OpCode::Mulhu, - args: args.into(), - }, + InstrCacheable::Mulh(args) => Instruction::from_ic_mulh(args), + InstrCacheable::Mulhsu(args) => Instruction::from_ic_mulhsu(args), + InstrCacheable::Mulhu(args) => Instruction::from_ic_mulhu(args), InstrCacheable::Mulw(args) => { Instruction::new_x32_mul(args.rd, args.rs1, args.rs2, InstrWidth::Uncompressed) } diff --git a/src/riscv/lib/src/machine_state/instruction/constructors.rs b/src/riscv/lib/src/machine_state/instruction/constructors.rs index f96c15546610..63e27c6d17c9 100644 --- a/src/riscv/lib/src/machine_state/instruction/constructors.rs +++ b/src/riscv/lib/src/machine_state/instruction/constructors.rs @@ -1213,6 +1213,63 @@ impl Instruction { } } + /// Create a new [`Instruction`] with the appropriate [`super::ArgsShape`] for [`OpCode::X64MulHighSigned`]. + pub(crate) fn new_x64_mul_high_signed( + rd: NonZeroXRegister, + rs1: NonZeroXRegister, + rs2: NonZeroXRegister, + width: InstrWidth, + ) -> Self { + Self { + opcode: OpCode::X64MulHighSigned, + args: Args { + rd: rd.into(), + rs1: rs1.into(), + rs2: rs2.into(), + width, + ..Args::DEFAULT + }, + } + } + + /// Create a new [`Instruction`] with the appropriate [`super::ArgsShape`] for [`OpCode::X64MulHighSignedUnsigned`]. + pub(crate) fn new_x64_mul_high_signed_unsigned( + rd: NonZeroXRegister, + rs1: NonZeroXRegister, + rs2: NonZeroXRegister, + width: InstrWidth, + ) -> Self { + Self { + opcode: OpCode::X64MulHighSignedUnsigned, + args: Args { + rd: rd.into(), + rs1: rs1.into(), + rs2: rs2.into(), + width, + ..Args::DEFAULT + }, + } + } + + /// Create a new [`Instruction`] with the appropriate [`super::ArgsShape`] for [`OpCode::X64MulHighUnsigned`]. + pub(crate) fn new_x64_mul_high_unsigned( + rd: NonZeroXRegister, + rs1: NonZeroXRegister, + rs2: NonZeroXRegister, + width: InstrWidth, + ) -> Self { + Self { + opcode: OpCode::X64MulHighUnsigned, + args: Args { + rd: rd.into(), + rs1: rs1.into(), + rs2: rs2.into(), + width, + ..Args::DEFAULT + }, + } + } + /// Create a new [`Instruction`] with the appropriate [`super::ArgsShape`] for [`OpCode::X64DivSigned`]. pub(crate) fn new_x64_div_signed( rd: NonZeroXRegister, @@ -1970,6 +2027,59 @@ impl Instruction { } } + /// Converts [`InstrCacheable::Mulh`] according to whether registers are non-zero. + /// + /// [`InstrCacheable::Mulh`]: crate::parser::instruction::InstrCacheable::Mulh + pub(crate) fn from_ic_mulh(args: &RTypeArgs) -> Instruction { + use XRegisterParsed as X; + match (split_x0(args.rd), split_x0(args.rs1), split_x0(args.rs2)) { + (X::X0, _, _) => Instruction::new_nop(InstrWidth::Uncompressed), + (X::NonZero(rd), X::X0, _) | (X::NonZero(rd), _, X::X0) => { + Instruction::new_li(rd, 0, InstrWidth::Uncompressed) + } + (X::NonZero(rd), X::NonZero(rs1), X::NonZero(rs2)) => { + Instruction::new_x64_mul_high_signed(rd, rs1, rs2, InstrWidth::Uncompressed) + } + } + } + + /// Converts [`InstrCacheable::Mulhsu`] according to whether registers are non-zero. + /// + /// [`InstrCacheable::Mulhsu`]: crate::parser::instruction::InstrCacheable::Mulhsu + pub(crate) fn from_ic_mulhsu(args: &RTypeArgs) -> Instruction { + use XRegisterParsed as X; + match (split_x0(args.rd), split_x0(args.rs1), split_x0(args.rs2)) { + (X::X0, _, _) => Instruction::new_nop(InstrWidth::Uncompressed), + (X::NonZero(rd), X::X0, _) | (X::NonZero(rd), _, X::X0) => { + Instruction::new_li(rd, 0, InstrWidth::Uncompressed) + } + (X::NonZero(rd), X::NonZero(rs1), X::NonZero(rs2)) => { + Instruction::new_x64_mul_high_signed_unsigned( + rd, + rs1, + rs2, + InstrWidth::Uncompressed, + ) + } + } + } + + /// Converts [`InstrCacheable::Mulhu`] according to whether registers are non-zero. + /// + /// [`InstrCacheable::Mulhu`]: crate::parser::instruction::InstrCacheable::Mulhu + pub(crate) fn from_ic_mulhu(args: &RTypeArgs) -> Instruction { + use XRegisterParsed as X; + match (split_x0(args.rd), split_x0(args.rs1), split_x0(args.rs2)) { + (X::X0, _, _) => Instruction::new_nop(InstrWidth::Uncompressed), + (X::NonZero(rd), X::X0, _) | (X::NonZero(rd), _, X::X0) => { + Instruction::new_li(rd, 0, InstrWidth::Uncompressed) + } + (X::NonZero(rd), X::NonZero(rs1), X::NonZero(rs2)) => { + Instruction::new_x64_mul_high_unsigned(rd, rs1, rs2, InstrWidth::Uncompressed) + } + } + } + /// Convert [`InstrCacheable::Div`] according to whether registers are non-zero. /// /// [`InstrCacheable::Div`]: crate::parser::instruction::InstrCacheable::Div diff --git a/src/riscv/lib/src/machine_state/instruction/tagged_instruction.rs b/src/riscv/lib/src/machine_state/instruction/tagged_instruction.rs index e9acbf3eef23..d7ae8947a366 100644 --- a/src/riscv/lib/src/machine_state/instruction/tagged_instruction.rs +++ b/src/riscv/lib/src/machine_state/instruction/tagged_instruction.rs @@ -344,9 +344,7 @@ pub fn opcode_to_argsshape(opcode: &OpCode) -> ArgsShape { | Scw | Amoswapw | Amoaddw | Amoxorw | Amoandw | Amoorw | Amominw | Amomaxw | Amominuw | Amomaxuw | Lrd | Scd | Amoswapd | X64AtomicAdd | Amoxord | Amoandd | Amoord | Amomind | Amomaxd | Amominud | Amomaxud | Rem | Remu | Remw | Remuw | Divu | Divw | Divuw - | Mulh | Mulhsu | Mulhu | X32Mul | Csrrw | Csrrs | Csrrc | Csrrwi | Csrrsi | Csrrci => { - ArgsShape::XSrcXDest - } + | X32Mul | Csrrw | Csrrs | Csrrc | Csrrwi | Csrrsi | Csrrci => ArgsShape::XSrcXDest, Fadds | Fsubs | Fmuls | Fdivs | Fsqrts | Fmins | Fmaxs | Fsgnjs | Fsgnjns | Fsgnjxs | Fmadds | Fmsubs | Fnmsubs | Fnmadds | Faddd | Fsubd | Fmuld | Fdivd | Fsqrtd | Fmind @@ -371,6 +369,9 @@ pub fn opcode_to_argsshape(opcode: &OpCode) -> ArgsShape { | Add | Sub | Mul + | X64MulHighSigned + | X64MulHighSignedUnsigned + | X64MulHighUnsigned | Mv | Neg | And diff --git a/src/riscv/lib/src/parser/instruction.rs b/src/riscv/lib/src/parser/instruction.rs index 03a03a130645..48102790890b 100644 --- a/src/riscv/lib/src/parser/instruction.rs +++ b/src/riscv/lib/src/parser/instruction.rs @@ -493,8 +493,16 @@ pub enum InstrCacheable { Divuw(RTypeArgs), /// `MUL` - Perform bitwise-multiplication of `val(rs1)` with `val(rs2)`. Mul(RTypeArgs), + /// Multiply val(rs1) with val(rs2) and store the upper 64 bits of the result + /// in register `rd`. Mulh(RTypeArgs), + /// Multiply val(rs1) with val(rs2) and store the upper 64 bits of the result + /// in register `rd`. val(rs1) is treated as a _signed integer_, while val(rs2) + /// is treated as an _unsigned integer_. Mulhsu(RTypeArgs), + /// Multiply val(rs1) with val(rs2) and store the upper 64 bits of the result + /// in register `rd`. Both val(rs1) and val(rs2) are treated as + /// _unsigned integers_. Mulhu(RTypeArgs), /// `MULW` - Multiply the lower 32 bits of `val(rs1)` with the lower 32 bits of `val(rs2)` /// and store the sign-extended result in `rd`. diff --git a/src/riscv/lib/tests/expected/dummy/state_hash_final b/src/riscv/lib/tests/expected/dummy/state_hash_final index 3a2b6d306352..1e8bae81b16e 100644 --- a/src/riscv/lib/tests/expected/dummy/state_hash_final +++ b/src/riscv/lib/tests/expected/dummy/state_hash_final @@ -1 +1 @@ -2bcaa548d9042eada4a4767387f2f7dfa06c0855b6c2ce547df1e7a5f83a1c95 +e73d708917db6d0127da35bd720739ac642467d4ec11d24d9bd99f29a6bd9cfc diff --git a/src/riscv/lib/tests/expected/jstz/state_hash_final b/src/riscv/lib/tests/expected/jstz/state_hash_final index f27877648690..e7d5522a5452 100644 --- a/src/riscv/lib/tests/expected/jstz/state_hash_final +++ b/src/riscv/lib/tests/expected/jstz/state_hash_final @@ -1 +1 @@ -deb1ac273ed2ec5d1f33c52ee92446e0fe21cbf89481d04c8a51818a26cfe6bd +e50ec06a70137ed9e07a2eb1051d1f843f1e19228d0588ec125441efe837f6a6 -- GitLab