mirror of
https://github.com/Noratrieb/rustv32i.git
synced 2026-01-14 13:25:01 +01:00
Optimize rvdc tests
This commit is contained in:
parent
e9a689aa1a
commit
f0c04f1466
4 changed files with 118 additions and 53 deletions
52
Cargo.lock
generated
52
Cargo.lock
generated
|
|
@ -29,6 +29,37 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.10"
|
||||
|
|
@ -133,6 +164,26 @@ version = "4.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564"
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.0.1"
|
||||
|
|
@ -171,6 +222,7 @@ name = "rvdc"
|
|||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"object",
|
||||
"rayon",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -15,4 +15,5 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(slow_tests)'] }
|
|||
|
||||
[dev-dependencies]
|
||||
object = "0.36.7"
|
||||
rayon = "1.10.0"
|
||||
tempfile = "3.19.1"
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ More extensions may be implemented in the future.
|
|||
let x = 0x1101_u32;
|
||||
let expected = rvdc::Inst::Addi { imm: rvdc::Imm::new_i32(-0x20), dest: rvdc::Reg::SP, src1: rvdc::Reg::SP };
|
||||
|
||||
let (inst, is_compressed) = rvdc::Inst::decode(x).unwrap();
|
||||
let (inst, is_compressed) = rvdc::Inst::decode(x, rvdc::Xlen::Rv32).unwrap();
|
||||
assert_eq!(inst, expected);
|
||||
assert_eq!(is_compressed, rvdc::IsCompressed::Yes);
|
||||
assert_eq!(format!("{inst}"), "addi sp, sp, -32")
|
||||
|
|
@ -49,7 +49,7 @@ assert_eq!(format!("{inst}"), "addi sp, sp, -32")
|
|||
let x = 0x0000a317;
|
||||
let expected = rvdc::Inst::Auipc { uimm: rvdc::Imm::new_u32(0xa << 12), dest: rvdc::Reg::T1 };
|
||||
|
||||
let (inst, is_compressed) = rvdc::Inst::decode(x).unwrap();
|
||||
let (inst, is_compressed) = rvdc::Inst::decode(x, rvdc::Xlen::Rv32).unwrap();
|
||||
assert_eq!(inst, expected);
|
||||
assert_eq!(is_compressed, rvdc::IsCompressed::No);
|
||||
assert_eq!(format!("{inst}"), "auipc t1, 10")
|
||||
|
|
|
|||
114
rvdc/src/lib.rs
114
rvdc/src/lib.rs
|
|
@ -6,7 +6,7 @@ use core::fmt::{self, Debug, Display};
|
|||
use core::ops::RangeInclusive;
|
||||
|
||||
/// The register size of the ISA, RV32 or RV64.
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum Xlen {
|
||||
/// 32 bit
|
||||
Rv32,
|
||||
|
|
@ -928,10 +928,10 @@ impl Inst {
|
|||
/// let x = 0x1101_u16;
|
||||
/// let expected = rvdc::Inst::Addi { imm: rvdc::Imm::new_i32(-0x20), dest: rvdc::Reg::SP, src1: rvdc::Reg::SP };
|
||||
///
|
||||
/// let inst = rvdc::Inst::decode_compressed(x).unwrap();
|
||||
/// let inst = rvdc::Inst::decode_compressed(x, rvdc::Xlen::Rv32).unwrap();
|
||||
/// assert_eq!(inst, expected);
|
||||
/// ```
|
||||
pub fn decode_compressed(code: u16, xlen: Xlen) -> Result<Inst, DecodeError> {
|
||||
pub fn decode_compressed(code: u16, _xlen: Xlen) -> Result<Inst, DecodeError> {
|
||||
let code = InstCodeC(code);
|
||||
if code.0 == 0 {
|
||||
return Err(decode_error(code, "null instruction"));
|
||||
|
|
@ -1557,6 +1557,8 @@ impl Inst {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
extern crate std;
|
||||
use core::sync::atomic::AtomicU32;
|
||||
use core::sync::atomic::Ordering;
|
||||
use std::prelude::rust_2024::*;
|
||||
|
||||
use std::fmt::Write as _;
|
||||
|
|
@ -1564,6 +1566,8 @@ mod tests {
|
|||
|
||||
use object::Object;
|
||||
use object::ObjectSection;
|
||||
use rayon::iter::IntoParallelRefIterator;
|
||||
use rayon::iter::ParallelIterator;
|
||||
|
||||
use crate::Fence;
|
||||
use crate::FenceSet;
|
||||
|
|
@ -1574,18 +1578,17 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
#[cfg_attr(not(slow_tests), ignore = "cfg(slow_tests) not enabled")]
|
||||
fn exhaustive_decode_no_panic() {
|
||||
for i in 0..u32::MAX {
|
||||
if (i % (2 << 25)) == 0 {
|
||||
let percent = i as f32 / (u32::MAX as f32);
|
||||
let done = (100.0 * percent) as usize;
|
||||
std::print!("\r{}{}", "#".repeat(done), "-".repeat(100 - done));
|
||||
std::io::stdout().flush().unwrap();
|
||||
}
|
||||
let _ = Inst::decode(i, Xlen::Rv32);
|
||||
}
|
||||
let _ = Inst::decode(u32::MAX, Xlen::Rv32);
|
||||
fn exhaustive_decode_no_panic_32() {
|
||||
exhaustive_decode_no_panic(Xlen::Rv32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(not(slow_tests), ignore = "cfg(slow_tests) not enabled")]
|
||||
fn exhaustive_decode_no_panic_64() {
|
||||
exhaustive_decode_no_panic(Xlen::Rv64);
|
||||
}
|
||||
|
||||
fn exhaustive_decode_no_panic(xlen: Xlen) {
|
||||
for i in 0..u32::MAX {
|
||||
if (i % (2 << 25)) == 0 {
|
||||
let percent = i as f32 / (u32::MAX as f32);
|
||||
|
|
@ -1593,14 +1596,18 @@ mod tests {
|
|||
std::print!("\r{}{}", "#".repeat(done), "-".repeat(100 - done));
|
||||
std::io::stdout().flush().unwrap();
|
||||
}
|
||||
let _ = Inst::decode(i, Xlen::Rv64);
|
||||
let _ = Inst::decode(i, xlen);
|
||||
}
|
||||
let _ = Inst::decode(u32::MAX, Xlen::Rv64);
|
||||
let _ = Inst::decode(u32::MAX, xlen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn size_of_instruction() {
|
||||
assert!(size_of::<Inst>() <= 12);
|
||||
assert!(
|
||||
size_of::<Inst>() <= 16,
|
||||
"size of instruction is too large: {}",
|
||||
size_of::<Inst>()
|
||||
);
|
||||
}
|
||||
|
||||
const TEST_SECTION_NAME: &str = ".text.rvdctest";
|
||||
|
|
@ -1699,49 +1706,54 @@ mod tests {
|
|||
const CHUNKS: u32 = 128;
|
||||
const CHUNK_SIZE: u32 = u32::MAX / CHUNKS;
|
||||
|
||||
for (chunk_idx, start) in ((SKIP_CHUNKS * CHUNK_SIZE)..u32::MAX)
|
||||
let chunks = ((SKIP_CHUNKS * CHUNK_SIZE)..u32::MAX)
|
||||
.step_by(CHUNK_SIZE as usize)
|
||||
.enumerate()
|
||||
{
|
||||
let chunk_idx = chunk_idx + SKIP_CHUNKS as usize;
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let start_time = std::time::Instant::now();
|
||||
let start_time = std::time::Instant::now();
|
||||
let completed = AtomicU32::new(0);
|
||||
|
||||
let insts = (start..=start.saturating_add(CHUNK_SIZE))
|
||||
.filter_map(|code| Some((code, Inst::decode_normal(code, Xlen::Rv32).ok()?)))
|
||||
.filter(|(_, inst)| is_inst_supposed_to_roundtrip(inst))
|
||||
.collect::<Vec<_>>();
|
||||
chunks
|
||||
.par_iter()
|
||||
.for_each(|&start| {
|
||||
let insts = (start..=start.saturating_add(CHUNK_SIZE))
|
||||
.filter_map(|code| Some((code, Inst::decode_normal(code, Xlen::Rv32).ok()?)))
|
||||
.filter(|(_, inst)| is_inst_supposed_to_roundtrip(inst))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut text = std::format!(".section {TEST_SECTION_NAME}\n.globl _start\n_start:\n");
|
||||
for (_, inst) in &insts {
|
||||
writeln!(text, " {inst}").unwrap();
|
||||
}
|
||||
let mut text =
|
||||
std::format!(".section {TEST_SECTION_NAME}\n.globl _start\n_start:\n");
|
||||
for (_, inst) in &insts {
|
||||
writeln!(text, " {inst}").unwrap();
|
||||
}
|
||||
|
||||
let data = clang_assemble(&text, "-march=rv32ima_zihintpause");
|
||||
let data = clang_assemble(&text, "-march=rv32ima_zihintpause");
|
||||
|
||||
for (i, result_code) in data.chunks(4).enumerate() {
|
||||
let result_code = u32::from_le_bytes(result_code.try_into().unwrap());
|
||||
for (i, result_code) in data.chunks(4).enumerate() {
|
||||
let result_code = u32::from_le_bytes(result_code.try_into().unwrap());
|
||||
|
||||
assert_eq!(
|
||||
insts[i].0, result_code,
|
||||
"failed to rountrip!\n\
|
||||
instruction `{:0>32b}` failed to rountrip\n\
|
||||
resulted in `{:0>32b}` instead.\n\
|
||||
disassembly of original instruction: `{}`",
|
||||
insts[i].0, result_code, insts[i].1
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
insts[i].0, result_code,
|
||||
"failed to rountrip!\n\
|
||||
instruction `{:0>32b}` failed to rountrip\n\
|
||||
resulted in `{:0>32b}` instead.\n\
|
||||
disassembly of original instruction: `{}`",
|
||||
insts[i].0, result_code, insts[i].1
|
||||
);
|
||||
}
|
||||
|
||||
let elapsed = start_time.elapsed();
|
||||
let chunk_number = chunk_idx + 1;
|
||||
let remaining = elapsed * (CHUNKS.saturating_sub(chunk_number as u32));
|
||||
let already_completed = completed.fetch_add(1, Ordering::Relaxed);
|
||||
let already_elapsed = start_time.elapsed();
|
||||
|
||||
writeln!(
|
||||
std::io::stdout(),
|
||||
"Completed chunk {chunk_number}/{CHUNKS} (estimated {remaining:?} remaining)",
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
let remaining_chunks = CHUNKS.saturating_sub(already_completed);
|
||||
let remaining = already_elapsed / std::cmp::max(already_completed, 1) * remaining_chunks;
|
||||
|
||||
writeln!(
|
||||
std::io::stdout(),
|
||||
"Completed chunk {already_completed}/{CHUNKS} (estimated {remaining:?} remaining)",
|
||||
)
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue