diff --git a/asm_utils/src/lib.rs b/asm_utils/src/lib.rs index 36443c4927..62b6b6c09a 100644 --- a/asm_utils/src/lib.rs +++ b/asm_utils/src/lib.rs @@ -1,5 +1,7 @@ //! Common crate for generalized assembly handling. +use ast::{Argument, FunctionOpKind, Register}; + pub mod ast; pub mod data_parser; pub mod data_storage; @@ -9,4 +11,8 @@ pub mod utils; pub trait Architecture { fn instruction_ends_control_flow(instr: &str) -> bool; + fn get_references<'a, R: Register, F: FunctionOpKind>( + instr: &str, + args: &'a [Argument], + ) -> Vec<&'a str>; } diff --git a/asm_utils/src/reachability.rs b/asm_utils/src/reachability.rs index 3d5cbaa855..b517883241 100644 --- a/asm_utils/src/reachability.rs +++ b/asm_utils/src/reachability.rs @@ -168,25 +168,32 @@ pub fn extract_label_offsets( }) } -pub fn references_in_statement( +pub fn references_in_statement( statement: &Statement, ) -> BTreeSet<&str> { let mut ret = BTreeSet::new(); match statement { Statement::Label(_) | Statement::Directive(_, _) => (), - Statement::Instruction(_, args) => { - for arg in args { - arg.post_visit_expressions(&mut |expr| { - if let Expression::Symbol(sym) = expr { - ret.insert(sym.as_str()); - } - }); - } + Statement::Instruction(name, args) => { + ret.extend(A::get_references(name, args)); } }; ret } +pub fn symbols_in_args(args: &[Argument]) -> Vec<&str> { + let mut ret = Vec::new(); + for arg in args { + arg.post_visit_expressions(&mut |expr| { + if let Expression::Symbol(sym) = expr { + ret.push(sym.as_str()); + } + }); + } + + ret +} + fn basic_block_references_starting_from( statements: &[Statement], ) -> (Vec<&str>, Vec<&str>) { @@ -196,7 +203,7 @@ fn basic_block_references_starting_from(s)) } }); (referenced_labels.into_iter().collect(), seen_labels) diff --git a/riscv/src/compiler.rs b/riscv/src/compiler.rs index ee1e4daa5e..3218583c85 100644 --- a/riscv/src/compiler.rs +++ b/riscv/src/compiler.rs @@ -8,7 +8,7 @@ use asm_utils::{ data_parser::{self, DataValue}, data_storage::{store_data_objects, SingleDataValue}, parser::parse_asm, - reachability, + reachability::{self, symbols_in_args}, utils::{ argument_to_escaped_symbol, argument_to_number, escape_label, expression_to_number, quote, }, @@ -70,13 +70,28 @@ impl Architecture for RiscvArchitecture { | "srli" | "srl" | "srai" | "seqz" | "snez" | "slt" | "slti" | "sltu" | "sltiu" | "sgtz" | "beq" | "beqz" | "bgeu" | "bltu" | "blt" | "bge" | "bltz" | "blez" | "bgtz" | "bgez" | "bne" | "bnez" | "jal" | "jalr" | "call" | "ecall" | "ebreak" - | "lw" | "lb" | "lbu" | "lhu" | "sw" | "sh" | "sb" | "nop" => false, + | "lw" | "lb" | "lbu" | "lhu" | "sw" | "sh" | "sb" | "nop" | "fence" | "fence.i" => { + false + } "j" | "jr" | "tail" | "ret" | "unimp" => true, _ => { panic!("Unknown instruction: {instr}"); } } } + + fn get_references<'a, R: asm_utils::ast::Register, F: asm_utils::ast::FunctionOpKind>( + instr: &str, + args: &'a [asm_utils::ast::Argument], + ) -> Vec<&'a str> { + // fence arguments are not symbols, they are like reserved + // keywords affecting the instruction behavior + if instr.starts_with("fence") { + Vec::new() + } else { + symbols_in_args(args) + } + } } pub fn machine_decls() -> Vec<&'static str> { @@ -670,7 +685,7 @@ fn preamble() -> String { wrap_bit * (1 - wrap_bit) = 0; } - // Input is a 32 bit unsigned number. We check the 7th bit and set all higher bits to that value. + // Input is a 32 bit unsigned number. We check bit 7 and set all higher bits to that value. instr sign_extend_byte Y -> X { // wrap_bit is used as sign_bit here. Y = Y_7bit + wrap_bit * 0x80 + X_b2 * 0x100 + X_b3 * 0x10000 + X_b4 * 0x1000000, @@ -1346,6 +1361,9 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec { only_if_no_write_to_zero(format!("{rd} <== load_label({label});"), rd) } + // atomic and synchronization + "fence" | "fence.i" => vec![], + _ => { panic!("Unknown instruction: {instr}"); }