From 2678b03a93e526e53c2f8fd474c2db142f0d16ee Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 20 Apr 2023 21:55:42 +0200 Subject: [PATCH] Properly process multiple asm files. --- src/riscv/compiler.rs | 436 ++++++++++++++++++++++++++++-------------- src/riscv/mod.rs | 135 ++++++++----- src/riscv/parser.rs | 47 +++-- tests/riscv.rs | 4 +- 4 files changed, 410 insertions(+), 212 deletions(-) diff --git a/src/riscv/compiler.rs b/src/riscv/compiler.rs index 4840348e3..7c5ad9609 100644 --- a/src/riscv/compiler.rs +++ b/src/riscv/compiler.rs @@ -1,32 +1,39 @@ -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet, HashSet}; -use lazy_static::lazy_static; -use regex::Regex; +use itertools::Itertools; use crate::riscv::parser::{self, Argument, Register, Statement}; use super::parser::Constant; /// Compiles riscv assembly to POWDR assembly. Adds required library routines. -pub fn compile_riscv_asm(data: &str) -> String { +pub fn compile_riscv_asm(mut assemblies: BTreeMap) -> String { // stack grows towards zero let stack_start = 0x10000; // data grows away from zero let data_start = 0x20000; - let statements = parser::parse_asm(data); - let labels = parser::extract_labels(&statements); - let label_references = parser::extract_label_references(&statements); - let missing_labels = label_references.difference(&labels); + assert!(assemblies + .insert("__runtime".to_string(), runtime().to_string()) + .is_none()); - let data = data.to_string() - + &missing_labels - .into_iter() - .map(|label| library_routine(label)) - .collect::>() - .join("\n"); - let mut statements = parser::parse_asm(&data); - let objects = parser::extract_data_objects(&statements); + let parsed_assemblies = assemblies + .into_iter() + .map(|(name, contents)| (name, parser::parse_asm(&contents))) + .collect::>(); + let globals = parsed_assemblies + .iter() + .flat_map(|(_, statements)| extract_globals(statements)) + .collect::>(); + let mut statements = parsed_assemblies + .into_iter() + .map(|(name, statements)| disambiguate(&name, statements, &globals)) + .concat(); + let mut objects = parser::extract_data_objects(&statements); + + // Reduce to the code that is actually reachable from main + // (and the objects that are referred from there) + filter_reachable_from("main", &mut statements, &mut objects); // Replace dynamic references to code labels replace_dynamic_label_references(&mut statements, &objects); @@ -45,6 +52,191 @@ pub fn compile_riscv_asm(data: &str) -> String { output } +fn disambiguate( + file_name: &str, + statements: Vec, + globals: &HashSet, +) -> Vec { + let prefix = file_name.replace('-', "_dash_"); + statements + .into_iter() + .map(|s| match s { + Statement::Label(l) => { + Statement::Label(disambiguate_symbol_if_needed(l, &prefix, globals)) + } + Statement::Directive(dir, args) => Statement::Directive( + dir, + disambiguate_arguments_if_needed(args, &prefix, globals), + ), + Statement::Instruction(instr, args) => Statement::Instruction( + instr, + disambiguate_arguments_if_needed(args, &prefix, globals), + ), + }) + .collect() +} + +fn disambiguate_arguments_if_needed( + args: Vec, + prefix: &str, + globals: &HashSet, +) -> Vec { + args.into_iter() + .map(|a| disambiguate_argument_if_needed(a, prefix, globals)) + .collect() +} + +fn disambiguate_argument_if_needed( + arg: Argument, + prefix: &str, + globals: &HashSet, +) -> Argument { + match arg { + Argument::Register(_) | Argument::StringLiteral(_) => arg, + Argument::RegOffset(reg, constant) => Argument::RegOffset( + reg, + disambiguate_constant_if_needed(constant, prefix, globals), + ), + Argument::Constant(c) => { + Argument::Constant(disambiguate_constant_if_needed(c, prefix, globals)) + } + Argument::Symbol(s) => Argument::Symbol(disambiguate_symbol_if_needed(s, prefix, globals)), + Argument::Difference(l, r) => Argument::Difference( + disambiguate_symbol_if_needed(l, prefix, globals), + disambiguate_symbol_if_needed(r, prefix, globals), + ), + } +} + +fn disambiguate_constant_if_needed( + c: Constant, + prefix: &str, + globals: &HashSet, +) -> Constant { + match c { + Constant::Number(_) => c, + Constant::HiDataRef(s) => { + Constant::HiDataRef(disambiguate_symbol_if_needed(s, prefix, globals)) + } + Constant::LoDataRef(s) => { + Constant::LoDataRef(disambiguate_symbol_if_needed(s, prefix, globals)) + } + } +} + +fn disambiguate_symbol_if_needed(s: String, prefix: &str, globals: &HashSet) -> String { + if globals.contains(s.as_str()) || s.starts_with('@') { + s + } else { + format!("{prefix}__{s}") + } +} + +fn extract_globals(statements: &[Statement]) -> HashSet { + statements + .iter() + .flat_map(|s| { + if let Statement::Directive(name, args) = s { + if name == ".globl" { + return args + .iter() + .map(|a| { + if let Argument::Symbol(s) = a { + s.clone() + } else { + panic!("Invalid .globl directive: {s}"); + } + }) + // TODO possible wihtout collect? + .collect(); + } + } + vec![] + }) + .collect() +} + +fn filter_reachable_from( + label: &str, + statements: &mut Vec, + objects: &mut BTreeMap>, +) { + let label_offsets = parser::extract_label_offsets(statements); + let mut queued_labels: BTreeSet<&str> = vec![label].into_iter().collect(); + let mut referenced_labels: BTreeSet<&str> = vec![label].into_iter().collect(); + let mut processed_labels = BTreeSet::<&str>::new(); + // Labels that are included in a basic block that starts with a different label. + let mut secondary_labels = BTreeSet::<&str>::new(); + let mut label_queue = vec![label]; + while let Some(l) = label_queue.pop() { + if objects.contains_key(l) { + // We record but do not process references to objects + continue; + } + if !processed_labels.insert(l) { + continue; + } + let offset = *label_offsets.get(l).unwrap_or_else(|| { + eprintln!("The RISCV assembly code references an external routine / label that is not available:"); + eprintln!("{l}"); + panic!(); + }); + let (referenced_labels_in_block, seen_labels_in_block) = + basic_block_references_starting_from(&statements[offset..]); + assert!(!secondary_labels.contains(l)); + secondary_labels.extend(seen_labels_in_block.clone()); + secondary_labels.remove(l); + processed_labels.extend(seen_labels_in_block); + + for referenced in &referenced_labels_in_block { + if !queued_labels.contains(referenced) && !processed_labels.contains(referenced) { + label_queue.push(referenced); + queued_labels.insert(referenced); + } + } + referenced_labels.extend(referenced_labels_in_block); + } + objects.retain(|name, _value| referenced_labels.contains(name.as_str())); + let code = processed_labels + .difference(&secondary_labels) + .flat_map(|l| { + let offset = *label_offsets.get(l).unwrap(); + basic_block_code_starting_from(&statements[offset..]) + }) + .collect(); + *statements = code; +} + +fn basic_block_references_starting_from(statements: &[Statement]) -> (Vec<&str>, Vec<&str>) { + let mut seen_labels = vec![]; + let mut referenced_labels = BTreeSet::<&str>::new(); + for s in statements { + if let Statement::Label(l) = s { + seen_labels.push(l.as_str()); + } else { + referenced_labels.extend(parser::referenced_labels(s)) + } + if parser::ends_control_flow(s) { + break; + } + } + (referenced_labels.into_iter().collect(), seen_labels) +} + +fn basic_block_code_starting_from(statements: &[Statement]) -> Vec { + let mut code = vec![]; + for s in statements { + if let Statement::Directive(_, _) = s { + panic!("Included directive in code block: {s}"); + } + code.push(s.clone()); + if parser::ends_control_flow(s) { + break; + } + } + code +} + /// Replace certain patterns of references to code labels by /// special instructions. We ignore any references to data objects /// because they will be handled differently. @@ -448,127 +640,96 @@ pil{ "# } -lazy_static! { - static ref LIBRARY_ROUTINES: Vec<(Regex, &'static str)> = vec![ - ( - Regex::new(r"^_ZN4core9panicking18panic_bounds_check17h[0-9a-f]{16}E$").unwrap(), - "unimp" - ), - ( - Regex::new(r"^_ZN4core9panicking5panic17h[0-9a-f]{16}E$").unwrap(), - "unimp" - ), - ( - Regex::new(r"^_ZN4core5slice5index24slice_end_index_len_fail17h[0-9a-f]{16}E$") - .unwrap(), - "unimp" - ), - ( - Regex::new(r"^_ZN5alloc5alloc18handle_alloc_error17h[0-9a-f]{16}E$").unwrap(), - "unimp" - ), - ( - Regex::new(r"^_ZN5alloc7raw_vec17capacity_overflow17h[0-9a-f]{16}E$").unwrap(), - "unimp" - ), - ( - Regex::new(r"^_ZN5alloc7raw_vec17capacity_overflow17h[0-9a-f]{16}E$").unwrap(), - "unimp" - ), - ( - Regex::new(r"^_ZN5alloc5alloc18handle_alloc_error17h[0-9a-f]{16}E$").unwrap(), - "unimp" - ), - ( - Regex::new(r"^_ZN4core5slice5index26slice_start_index_len_fail17h[0-9a-f]{16}E$") - .unwrap(), - "unimp" - ), - // TODO rust alloc calls the global allocator - not sure why this is not automatic. - (Regex::new(r"^__rust_alloc$").unwrap(), "j __rg_alloc"), - (Regex::new(r"^__rust_realloc$").unwrap(), "j __rg_realloc"), - (Regex::new(r"^__rust_dealloc$").unwrap(), "j __rg_dealloc"), - ( - Regex::new(r"^memset@plt$").unwrap(), -/* Source cod efor memset: -// TODO c is ussualy a "c int" -pub unsafe extern "C" fn memset(s: *mut u8, c: u8, n: usize) -> *mut u8 { - // We only access u32 because then we do not have to deal with - // un-aligned memory access. - // TODO this does not really enforce that the pointers are u32-aligned. - let mut value = c as u32; - value = value | (value << 8) | (value << 16) | (value << 24); - let mut i: isize = 0; - while i + 3 < n as isize { - *((s.offset(i)) as *mut u32) = value; - i += 4; +fn runtime() -> &'static str { + // // TODO rust alloc calls the global allocator - not sure why this is not automatic. + // (Regex::new(r"^__rust_alloc$").unwrap(), "j __rg_alloc"), + // (Regex::new(r"^__rust_realloc$").unwrap(), "j __rg_realloc"), + // (Regex::new(r"^__rust_dealloc$").unwrap(), "j __rg_dealloc"), + // ( + + /* Source code: + // TODO c is usually a "c int" + pub unsafe extern "C" fn memset(s: *mut u8, c: u8, n: usize) -> *mut u8 { + // We only access u32 because then we do not have to deal with + // un-aligned memory access. + // TODO this does not really enforce that the pointers are u32-aligned. + let mut value = c as u32; + value = value | (value << 8) | (value << 16) | (value << 24); + let mut i: isize = 0; + while i + 3 < n as isize { + *((s.offset(i)) as *mut u32) = value; + i += 4; + } + if i < n { + let dest_value = (s.offset(i)) as *mut u32; + let mask = (1 << ((((n as isize) - i) * 8) as u32)) - 1; + *dest_value = (*dest_value & !mask) | (value & mask); + } + s } - if i < n { - let dest_value = (s.offset(i)) as *mut u32; - let mask = (1 << ((((n as isize) - i) * 8) as u32)) - 1; - *dest_value = (*dest_value & !mask) | (value & mask); + + pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { + // We only access u32 because then we do not have to deal with + // un-aligned memory access. + // TODO this does not really enforce that the pointers are u32-aligned. + let mut i: isize = 0; + while i + 3 < n as isize { + *((dest.offset(i)) as *mut u32) = *((src.offset(i)) as *mut u32); + i += 4; + } + if i < n as isize { + let value = *((src.offset(i)) as *mut u32); + let dest_value = (dest.offset(i)) as *mut u32; + let mask = (1 << (((n as isize - i) * 8) as u32)) - 1; + *dest_value = (*dest_value & !mask) | (value & mask); + } + dest } - s -} -*/ - r#" - li a3, 4 - blt a2, a3, __memset_LBB5_5 - li a5, 0 - lui a3, 4112 - addi a3, a3, 257 - mul a6, a1, a3 + */ + r#" +.globl rust_begin_unwind +rust_begin_unwind: + unimp + +.globl memset@plt +memset@plt: + li a3, 4 + blt a2, a3, __memset_LBB5_5 + li a5, 0 + lui a3, 4112 + addi a3, a3, 257 + mul a6, a1, a3 __memset_LBB5_2: - add a7, a0, a5 - addi a3, a5, 4 - addi a4, a5, 7 - sw a6, 0(a7) - mv a5, a3 - blt a4, a2, __memset_LBB5_2 - bge a3, a2, __memset_LBB5_6 + add a7, a0, a5 + addi a3, a5, 4 + addi a4, a5, 7 + sw a6, 0(a7) + mv a5, a3 + blt a4, a2, __memset_LBB5_2 + bge a3, a2, __memset_LBB5_6 __memset_LBB5_4: - lui a4, 16 - addi a4, a4, 257 - mul a1, a1, a4 - add a3, a3, a0 - slli a2, a2, 3 - lw a4, 0(a3) - li a5, -1 - sll a2, a5, a2 - not a5, a2 - and a2, a2, a4 - and a1, a1, a5 - or a1, a1, a2 - sw a1, 0(a3) - ret + lui a4, 16 + addi a4, a4, 257 + mul a1, a1, a4 + add a3, a3, a0 + slli a2, a2, 3 + lw a4, 0(a3) + li a5, -1 + sll a2, a5, a2 + not a5, a2 + and a2, a2, a4 + and a1, a1, a5 + or a1, a1, a2 + sw a1, 0(a3) + ret __memset_LBB5_5: - li a3, 0 - blt a3, a2, __memset_LBB5_4 + li a3, 0 + blt a3, a2, __memset_LBB5_4 __memset_LBB5_6: - ret"# - ), - ( - Regex::new(r"^memcpy@plt$").unwrap(), -/* Source code for memcpy: -pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { - // We only access u32 because then we do not have to deal with - // un-aligned memory access. - // TODO this does not really enforce that the pointers are u32-aligned. - let mut i: isize = 0; - while i + 3 < n as isize { - *((dest.offset(i)) as *mut u32) = *((src.offset(i)) as *mut u32); - i += 4; - } - if i < n as isize { - let value = *((src.offset(i)) as *mut u32); - let dest_value = (dest.offset(i)) as *mut u32; - let mask = (1 << (((n as isize - i) * 8) as u32)) - 1; - *dest_value = (*dest_value & !mask) | (value & mask); - } - dest -} -*/ - r#" + ret + +.globl memcpy@plt +memcpy@plt: li a3, 4 blt a2, a3, __memcpy_LBB2_5 li a4, 0 @@ -602,19 +763,6 @@ __memcpy_LBB2_5: __memcpy_LBB2_6: ret "# - ), - ]; -} - -fn library_routine(label: &str) -> String { - for (pattern, routine) in LIBRARY_ROUTINES.iter() { - if pattern.is_match(label) { - return format!("{label}:\n{routine}"); - } - } - eprintln!("The RISCV assembly code references an external routine / label that has not been implemented yet:"); - eprintln!("{label}"); - panic!(); } fn process_statement(s: Statement) -> String { diff --git a/src/riscv/mod.rs b/src/riscv/mod.rs index d14c131d2..efd7cf59b 100644 --- a/src/riscv/mod.rs +++ b/src/riscv/mod.rs @@ -1,4 +1,4 @@ -use std::{path::Path, process::Command}; +use std::{collections::BTreeMap, path::Path, process::Command}; use mktemp::Temp; use std::fs; @@ -28,41 +28,33 @@ pub fn compile_rust( } else { compile_rust_to_riscv_asm(file_name) }; - let riscv_asm_file_name = output_dir.join(format!( - "{}_riscv.asm", - Path::new(file_name).file_stem().unwrap().to_str().unwrap() - )); - if riscv_asm_file_name.exists() && !force_overwrite { - eprint!( - "Target file {} already exists. Not overwriting.", - riscv_asm_file_name.to_str().unwrap() - ); - return; - } - fs::write(riscv_asm_file_name.clone(), riscv_asm).unwrap(); - log::info!("Wrote {}", riscv_asm_file_name.to_str().unwrap()); + for (asm_file_name, contents) in &riscv_asm { + let riscv_asm_file_name = output_dir.join(format!( + "{}_riscv_{asm_file_name}.asm", + Path::new(file_name).file_stem().unwrap().to_str().unwrap(), + )); + if riscv_asm_file_name.exists() && !force_overwrite { + eprint!( + "Target file {} already exists. Not overwriting.", + riscv_asm_file_name.to_str().unwrap() + ); + return; + } - compile_riscv_asm( - file_name, - riscv_asm_file_name.to_str().unwrap(), - inputs, - output_dir, - force_overwrite, - ) + fs::write(riscv_asm_file_name.clone(), contents).unwrap(); + log::info!("Wrote {}", riscv_asm_file_name.to_str().unwrap()); + } + + compile_riscv_asm_bundle(file_name, riscv_asm, inputs, output_dir, force_overwrite) } -/// Compiles a riscv asm file all the way down to PIL and generates -/// fixed and witness columns. -/// Adds required library routines automatically. -pub fn compile_riscv_asm( +pub fn compile_riscv_asm_bundle( original_file_name: &str, - file_name: &str, + riscv_asm_files: BTreeMap, inputs: Vec, output_dir: &Path, force_overwrite: bool, ) { - let contents = fs::read_to_string(file_name).unwrap(); - let powdr_asm = compiler::compile_riscv_asm(&contents); let powdr_asm_file_name = output_dir.join(format!( "{}.asm", Path::new(original_file_name) @@ -78,6 +70,9 @@ pub fn compile_riscv_asm( ); return; } + + let powdr_asm = compiler::compile_riscv_asm(riscv_asm_files); + fs::write(powdr_asm_file_name.clone(), &powdr_asm).unwrap(); log::info!("Wrote {}", powdr_asm_file_name.to_str().unwrap()); @@ -90,28 +85,56 @@ pub fn compile_riscv_asm( ) } -pub fn compile_rust_to_riscv_asm(input_file: &str) -> String { - let temp_file = Temp::new_file().unwrap(); - let rustc_status = Command::new("rustc") - .args([ - "--target", - "riscv32imc-unknown-none-elf", - "--crate-type", - "lib", - "--emit=asm", - "-C", - "opt-level=3", - "-o", - temp_file.to_str().unwrap(), - input_file, - ]) - .status() - .unwrap(); - assert!(rustc_status.success()); - fs::read_to_string(temp_file.to_str().unwrap()).unwrap() +/// Compiles a riscv asm file all the way down to PIL and generates +/// fixed and witness columns. +pub fn compile_riscv_asm( + original_file_name: &str, + file_name: &str, + inputs: Vec, + output_dir: &Path, + force_overwrite: bool, +) { + let contents = fs::read_to_string(file_name).unwrap(); + compile_riscv_asm_bundle( + original_file_name, + vec![(file_name.to_string(), contents)] + .into_iter() + .collect(), + inputs, + output_dir, + force_overwrite, + ) } -pub fn compile_rust_crate_to_riscv_asm(input_dir: &str) -> String { +pub fn compile_rust_to_riscv_asm(input_file: &str) -> BTreeMap { + let crate_dir = Temp::new_dir().unwrap(); + // TODO is there no easier way? + let mut cargo_file = crate_dir.clone(); + cargo_file.push("Cargo.toml"); + + fs::write( + &cargo_file, + format!( + r#"[package] +name = "{}" +version = "0.1.0" +edition = "2021" + "#, + Path::new(input_file).file_stem().unwrap().to_str().unwrap() + ), + ) + .unwrap(); + + let mut src_file = crate_dir.clone(); + src_file.push("src"); + fs::create_dir(&src_file).unwrap(); + src_file.push("lib.rs"); + fs::write(src_file, fs::read_to_string(input_file).unwrap()).unwrap(); + + compile_rust_crate_to_riscv_asm(cargo_file.to_str().unwrap()) +} + +pub fn compile_rust_crate_to_riscv_asm(input_dir: &str) -> BTreeMap { let temp_dir = Temp::new_dir().unwrap(); let cargo_status = Command::new("cargo") @@ -119,6 +142,8 @@ pub fn compile_rust_crate_to_riscv_asm(input_dir: &str) -> String { .args([ "build", "--release", + "-Z", + "build-std=core", "--target", "riscv32imc-unknown-none-elf", "--lib", @@ -131,13 +156,19 @@ pub fn compile_rust_crate_to_riscv_asm(input_dir: &str) -> String { .unwrap(); assert!(cargo_status.success()); - let mut combined_assembly = String::new(); + let mut assemblies = BTreeMap::new(); for entry in WalkDir::new(&temp_dir) { let entry = entry.unwrap(); // TODO search only in certain subdir? - if entry.file_name().to_str().unwrap().ends_with(".s") { - combined_assembly += &fs::read_to_string(entry.path()).unwrap(); + let file_name = entry.file_name().to_str().unwrap(); + if let Some(name) = file_name.strip_suffix(".s") { + assert!( + assemblies + .insert(name.to_string(), fs::read_to_string(entry.path()).unwrap()) + .is_none(), + "Duplicate assembly file name: {name}" + ); } } - combined_assembly + assemblies } diff --git a/src/riscv/parser.rs b/src/riscv/parser.rs index ede1e6c36..438a4058f 100644 --- a/src/riscv/parser.rs +++ b/src/riscv/parser.rs @@ -42,7 +42,7 @@ impl Display for Statement { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Statement::Label(l) => writeln!(f, "{l}:"), - Statement::Directive(d, args) => writeln!(f, " .{d} {}", format_arguments(args)), + Statement::Directive(d, args) => writeln!(f, " {d} {}", format_arguments(args)), Statement::Instruction(i, args) => writeln!(f, " {i} {}", format_arguments(args)), } } @@ -102,22 +102,23 @@ pub fn parse_asm(input: &str) -> Vec { .collect() } -pub fn extract_labels(statements: &[Statement]) -> BTreeSet<&str> { +pub fn extract_label_offsets(statements: &[Statement]) -> BTreeMap<&str, usize> { statements .iter() - .filter_map(|s| match s { - Statement::Label(l) => Some(l.as_str()), + .enumerate() + .filter_map(|(i, s)| match s { + Statement::Label(l) => Some((l.as_str(), i)), Statement::Directive(_, _) | Statement::Instruction(_, _) => None, }) .collect() } -pub fn extract_label_references(statements: &[Statement]) -> BTreeSet<&str> { - statements - .iter() - .flat_map(|s| match s { - Statement::Label(_) | Statement::Directive(_, _) => None, - Statement::Instruction(_, args) => Some(args.iter().filter_map(|arg| match arg { +pub fn referenced_labels(statement: &Statement) -> BTreeSet<&str> { + match statement { + Statement::Label(_) | Statement::Directive(_, _) => Default::default(), + Statement::Instruction(_, args) => args + .iter() + .filter_map(|arg| match arg { Argument::Register(_) | Argument::StringLiteral(_) => None, Argument::Symbol(s) => Some(s.as_str()), Argument::RegOffset(_, c) | Argument::Constant(c) => match c { @@ -125,10 +126,28 @@ pub fn extract_label_references(statements: &[Statement]) -> BTreeSet<&str> { Constant::HiDataRef(s) | Constant::LoDataRef(s) => Some(s.as_str()), }, Argument::Difference(_, _) => todo!(), - })), - }) - .flatten() - .collect() + }) + .collect(), + } +} + +pub fn ends_control_flow(s: &Statement) -> bool { + match s { + Statement::Instruction(instruction, _) => match instruction.as_str() { + "li" | "lui" | "mv" | "add" | "addi" | "sub" | "neg" | "mul" | "mulhu" | "xor" + | "xori" | "and" | "andi" | "or" | "ori" | "not" | "slli" | "sll" | "srli" | "srl" + | "seqz" | "snez" | "slti" | "sltu" | "sltiu" | "beq" | "beqz" | "bgeu" | "bltu" + | "blt" | "bge" | "bltz" | "blez" | "bgtz" | "bgez" | "bne" | "bnez" | "jal" + | "jalr" | "call" | "ecall" | "ebreak" | "lw" | "lb" | "lbu" | "sw" | "sh" | "sb" => { + false + } + "j" | "jr" | "tail" | "ret" | "unimp" => true, + _ => { + panic!("Unknown instruction: {instruction}"); + } + }, + _ => false, + } } pub fn extract_data_objects(statements: &[Statement]) -> BTreeMap> { diff --git a/tests/riscv.rs b/tests/riscv.rs index 56b8dc0ba..1f1d877bb 100644 --- a/tests/riscv.rs +++ b/tests/riscv.rs @@ -61,7 +61,7 @@ fn test_keccak() { fn verify_file(case: &str, inputs: Vec) { let riscv_asm = powdr::riscv::compile_rust_to_riscv_asm(&format!("tests/riscv_data/{case}")); - let powdr_asm = powdr::riscv::compiler::compile_riscv_asm(&riscv_asm); + let powdr_asm = powdr::riscv::compiler::compile_riscv_asm(riscv_asm); verify_asm_string(&format!("{case}.asm"), &powdr_asm, inputs); } @@ -70,7 +70,7 @@ fn verify_crate(case: &str, inputs: Vec) { let riscv_asm = powdr::riscv::compile_rust_crate_to_riscv_asm(&format!( "tests/riscv_data/{case}/Cargo.toml" )); - let powdr_asm = powdr::riscv::compiler::compile_riscv_asm(&riscv_asm); + let powdr_asm = powdr::riscv::compiler::compile_riscv_asm(riscv_asm); verify_asm_string(&format!("{case}.asm"), &powdr_asm, inputs); }