diff --git a/crates/codegen/src/optim/adce.rs b/crates/codegen/src/optim/adce.rs index 59e1bec..449f4b1 100644 --- a/crates/codegen/src/optim/adce.rs +++ b/crates/codegen/src/optim/adce.rs @@ -5,6 +5,7 @@ use std::collections::BTreeSet; use cranelift_entity::SecondaryMap; use sonatina_ir::{ func_cursor::{CursorLocation, FuncCursor, InstInserter}, + inst::SideEffect, BlockId, Function, InstId, }; @@ -56,7 +57,7 @@ impl AdceSolver { for block in func.layout.iter_block() { for inst in func.layout.iter_inst(block) { - if func.dfg.has_side_effect(inst) { + if matches!(func.dfg.side_effect(inst), SideEffect::Write) { self.mark_inst(func, inst); } } diff --git a/crates/codegen/src/optim/licm.rs b/crates/codegen/src/optim/licm.rs index f38cddb..f955a68 100644 --- a/crates/codegen/src/optim/licm.rs +++ b/crates/codegen/src/optim/licm.rs @@ -80,7 +80,7 @@ impl LicmSolver { /// Returns `true` if the `inst` is safe to hoist. fn is_safe_to_hoist(&self, func: &Function, inst_id: InstId) -> bool { - !(func.dfg.has_side_effect(inst_id) + !(func.dfg.side_effect(inst_id).has_effect() || func.dfg.is_branch(inst_id) || func.dfg.is_phi(inst_id)) } diff --git a/crates/codegen/src/optim/sccp.rs b/crates/codegen/src/optim/sccp.rs index cf94893..32e9980 100644 --- a/crates/codegen/src/optim/sccp.rs +++ b/crates/codegen/src/optim/sccp.rs @@ -176,7 +176,7 @@ impl SccpSolver { }; let inst = func.dfg.inst(inst_id); - if inst.has_side_effect() { + if inst.side_effect().has_effect() { return; } diff --git a/crates/ir/src/dfg.rs b/crates/ir/src/dfg.rs index e089826..2147a0b 100644 --- a/crates/ir/src/dfg.rs +++ b/crates/ir/src/dfg.rs @@ -8,7 +8,7 @@ use super::{Immediate, Type, Value, ValueId}; use crate::{ inst::{ control_flow::{self, Branch, Jump, Phi}, - InstId, + InstId, SideEffect, }, ir_writer::{FuncWriteCtx, WriteWithFunc}, module::ModuleCtx, @@ -244,8 +244,8 @@ impl DataFlowGraph { self.users[alias].append(&mut users); } - pub fn has_side_effect(&self, inst: InstId) -> bool { - self.inst(inst).has_side_effect() + pub fn side_effect(&self, inst: InstId) -> SideEffect { + self.inst(inst).side_effect() } pub fn is_branch(&self, inst: InstId) -> bool { diff --git a/crates/ir/src/inst/control_flow.rs b/crates/ir/src/inst/control_flow.rs index 34d5f98..10093f2 100644 --- a/crates/ir/src/inst/control_flow.rs +++ b/crates/ir/src/inst/control_flow.rs @@ -115,7 +115,7 @@ impl InstWrite for Phi { } #[derive(Debug, Clone, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(super::SideEffect::Write))] #[inst(terminator)] pub struct Call { callee: FuncRef, @@ -143,7 +143,7 @@ impl InstWrite for Call { } #[derive(Debug, Clone, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(super::SideEffect::Write))] #[inst(terminator)] pub struct Return { #[inst(value)] diff --git a/crates/ir/src/inst/data.rs b/crates/ir/src/inst/data.rs index ba10627..cd3ed5d 100644 --- a/crates/ir/src/inst/data.rs +++ b/crates/ir/src/inst/data.rs @@ -4,7 +4,7 @@ use smallvec::SmallVec; use crate::{inst::impl_inst_write, Type, ValueId}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(super::SideEffect::Read))] pub struct Mload { #[inst(value)] addr: ValueId, @@ -13,7 +13,7 @@ pub struct Mload { impl_inst_write!(Mload, (addr: ValueId, ty: Type)); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(super::SideEffect::Write))] pub struct Mstore { #[inst(value)] value: ValueId, diff --git a/crates/ir/src/inst/evm/mod.rs b/crates/ir/src/inst/evm/mod.rs index 422f0e0..6fc408b 100644 --- a/crates/ir/src/inst/evm/mod.rs +++ b/crates/ir/src/inst/evm/mod.rs @@ -4,7 +4,7 @@ pub mod inst_set; use crate::{inst::impl_inst_write, value::ValueId}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Write))] #[inst(terminator)] pub struct EvmStop {} impl_inst_write!(EvmStop); @@ -59,12 +59,12 @@ pub struct EvmKeccak256 { impl_inst_write!(EvmKeccak256); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmAddress {} impl_inst_write!(EvmAddress); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmBalance { #[inst(value)] contract_addr: ValueId, @@ -72,29 +72,29 @@ pub struct EvmBalance { impl_inst_write!(EvmBalance); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmOrigin {} impl_inst_write!(EvmOrigin); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmCaller {} impl_inst_write!(EvmCaller); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmCallValue {} impl_inst_write!(EvmCallValue); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmCallDataLoad { data_offset: ValueId, } impl_inst_write!(EvmCallDataLoad); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Write))] pub struct EvmCallDataCopy { #[inst(value)] dst_addr: ValueId, @@ -106,12 +106,12 @@ pub struct EvmCallDataCopy { impl_inst_write!(EvmCallDataCopy); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmCodeSize {} impl_inst_write!(EvmCodeSize); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Write))] pub struct EvmCodeCopy { #[inst(value)] dst_addr: ValueId, @@ -123,12 +123,12 @@ pub struct EvmCodeCopy { impl_inst_write!(EvmCodeCopy); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmGasPrice {} impl_inst_write!(EvmGasPrice); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmExtCodeSize { #[inst(value)] ext_addr: ValueId, @@ -136,7 +136,7 @@ pub struct EvmExtCodeSize { impl_inst_write!(EvmExtCodeSize); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Write))] pub struct EvmExtCodeCopy { #[inst(value)] ext_addr: ValueId, @@ -150,12 +150,12 @@ pub struct EvmExtCodeCopy { impl_inst_write!(EvmExtCodeCopy); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmReturnDataSize {} impl_inst_write!(EvmReturnDataSize); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Write))] pub struct EvmReturnDataCopy { #[inst(value)] dst_addr: ValueId, @@ -167,7 +167,7 @@ pub struct EvmReturnDataCopy { impl_inst_write!(EvmReturnDataCopy); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmExtCodeHash { #[inst(value)] ext_addr: ValueId, @@ -175,7 +175,7 @@ pub struct EvmExtCodeHash { impl_inst_write!(EvmExtCodeHash); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmBlockHash { #[inst(value)] block_num: ValueId, @@ -183,7 +183,7 @@ pub struct EvmBlockHash { impl_inst_write!(EvmBlockHash); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmCoinBase { #[inst(value)] block_num: ValueId, @@ -191,42 +191,42 @@ pub struct EvmCoinBase { impl_inst_write!(EvmCoinBase); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmTimestamp {} impl_inst_write!(EvmTimestamp); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmNumber {} impl_inst_write!(EvmNumber); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmPrevRandao {} impl_inst_write!(EvmPrevRandao); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmGasLimit {} impl_inst_write!(EvmGasLimit); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmChainId {} impl_inst_write!(EvmChainId); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmSelfBalance {} impl_inst_write!(EvmSelfBalance); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmBaseFee {} impl_inst_write!(EvmBaseFee); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmBlobHash { #[inst(value)] idx: ValueId, @@ -234,12 +234,12 @@ pub struct EvmBlobHash { impl_inst_write!(EvmBlobHash); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmBlobBaseFee {} impl_inst_write!(EvmBlobBaseFee); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Write))] pub struct EvmMstore8 { #[inst(value)] addr: ValueId, @@ -249,7 +249,7 @@ pub struct EvmMstore8 { impl_inst_write!(EvmMstore8); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmSload { #[inst(value)] key: ValueId, @@ -257,7 +257,7 @@ pub struct EvmSload { impl_inst_write!(EvmSload); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Write))] pub struct EvmSstore { #[inst(value)] key: ValueId, @@ -267,17 +267,17 @@ pub struct EvmSstore { impl_inst_write!(EvmSstore); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmMsize {} impl_inst_write!(EvmMsize); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmGas {} impl_inst_write!(EvmGas); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Read))] pub struct EvmTload { #[inst(value)] key: ValueId, @@ -285,7 +285,7 @@ pub struct EvmTload { impl_inst_write!(EvmTload); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Write))] pub struct EvmTstore { #[inst(value)] key: ValueId, @@ -295,7 +295,7 @@ pub struct EvmTstore { impl_inst_write!(EvmTstore); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Write))] pub struct EvmLog0 { #[inst(value)] addr: ValueId, @@ -305,7 +305,7 @@ pub struct EvmLog0 { impl_inst_write!(EvmLog0); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Write))] pub struct EvmLog1 { #[inst(value)] addr: ValueId, @@ -317,7 +317,7 @@ pub struct EvmLog1 { impl_inst_write!(EvmLog1); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Write))] pub struct EvmLog2 { #[inst(value)] addr: ValueId, @@ -331,7 +331,7 @@ pub struct EvmLog2 { impl_inst_write!(EvmLog2); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Write))] pub struct EvmLog3 { #[inst(value)] addr: ValueId, @@ -347,7 +347,7 @@ pub struct EvmLog3 { impl_inst_write!(EvmLog3); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Write))] pub struct EvmLog4 { #[inst(value)] addr: ValueId, @@ -365,7 +365,7 @@ pub struct EvmLog4 { impl_inst_write!(EvmLog4); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Write))] pub struct EvmCreate { #[inst(value)] val: ValueId, @@ -377,7 +377,7 @@ pub struct EvmCreate { impl_inst_write!(EvmCreate); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Write))] pub struct EvmCall { #[inst(value)] gas: ValueId, @@ -397,7 +397,7 @@ pub struct EvmCall { impl_inst_write!(EvmCall); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Write))] #[inst(terminator)] pub struct EvmReturn { #[inst(value)] @@ -408,7 +408,7 @@ pub struct EvmReturn { impl_inst_write!(EvmReturn); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Write))] pub struct EvmDelegateCall { #[inst(value)] gas: ValueId, @@ -426,7 +426,7 @@ pub struct EvmDelegateCall { impl_inst_write!(EvmDelegateCall); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Write))] pub struct EvmCreate2 { #[inst(value)] val: ValueId, @@ -440,7 +440,7 @@ pub struct EvmCreate2 { impl_inst_write!(EvmCreate2); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Write))] pub struct EvmStaticCall { #[inst(value)] gas: ValueId, @@ -458,7 +458,7 @@ pub struct EvmStaticCall { impl_inst_write!(EvmStaticCall); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Write))] #[inst(terminator)] pub struct EvmRevert { #[inst(value)] @@ -469,7 +469,7 @@ pub struct EvmRevert { impl_inst_write!(EvmRevert); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] -#[inst(has_side_effect)] +#[inst(side_effect(crate::inst::SideEffect::Write))] #[inst(terminator)] pub struct EvmSelfDestruct { #[inst(value)] diff --git a/crates/ir/src/inst/mod.rs b/crates/ir/src/inst/mod.rs index e0e89a7..1a22cd9 100644 --- a/crates/ir/src/inst/mod.rs +++ b/crates/ir/src/inst/mod.rs @@ -30,7 +30,7 @@ cranelift_entity::entity_impl!(InstId); pub trait Inst: inst_set::sealed::Registered + Any { fn visit_values(&self, f: &mut dyn FnMut(ValueId)); fn visit_values_mut(&mut self, f: &mut dyn FnMut(&mut ValueId)); - fn has_side_effect(&self) -> bool; + fn side_effect(&self) -> SideEffect; fn as_text(&self) -> &'static str; fn is_terminator(&self) -> bool; @@ -186,6 +186,19 @@ pub trait InstDowncastMut: Sized { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum SideEffect { + None, + Read, + Write, +} + +impl SideEffect { + pub fn has_effect(&self) -> bool { + !matches!(self, Self::None) + } +} + #[inst_prop] trait InstWrite { fn write(&self, ctx: &FuncWriteCtx, w: &mut dyn io::Write) -> io::Result<()>; diff --git a/crates/macros/src/inst.rs b/crates/macros/src/inst.rs index 92390ab..cd128e9 100644 --- a/crates/macros/src/inst.rs +++ b/crates/macros/src/inst.rs @@ -18,7 +18,7 @@ pub fn derive_inst(item: proc_macro::TokenStream) -> proc_macro::TokenStream { struct InstStruct { struct_name: syn::Ident, - has_side_effect: bool, + side_effect: Option, is_terminator: bool, fields: Vec, } @@ -31,7 +31,7 @@ struct InstField { impl InstStruct { fn new(item_struct: syn::ItemStruct) -> syn::Result { - let (has_side_effect, is_terminator) = Self::check_attr(&item_struct)?; + let (side_effect, is_terminator) = Self::check_attr(&item_struct)?; let struct_ident = item_struct.ident; @@ -46,7 +46,7 @@ impl InstStruct { Ok(Self { struct_name: struct_ident, - has_side_effect, + side_effect, is_terminator, fields, }) @@ -63,16 +63,23 @@ impl InstStruct { }) } - fn check_attr(item_struct: &syn::ItemStruct) -> syn::Result<(bool, bool)> { - let mut has_side_effect = false; + fn check_attr(item_struct: &syn::ItemStruct) -> syn::Result<(Option, bool)> { + let mut side_effect = None; let mut is_terminator = false; for attr in &item_struct.attrs { if attr.path().is_ident("inst") { let meta = attr.parse_args::()?; - if let syn::Meta::Path(path) = &meta { - if path.is_ident("has_side_effect") { - has_side_effect = true; + if let syn::Meta::List(ml) = &meta { + if ml.path.is_ident("side_effect") { + if !matches!(ml.delimiter, syn::MacroDelimiter::Paren(..)) { + return Err(syn::Error::new_spanned( + ml, + "`side_effect(...) is requried", + )); + } + + side_effect = Some(syn::parse2(ml.tokens.clone())?); } } if let syn::Meta::Path(path) = &meta { @@ -83,7 +90,7 @@ impl InstStruct { } } - Ok((has_side_effect, is_terminator)) + Ok((side_effect, is_terminator)) } fn parse_fields(fields: &syn::Fields) -> syn::Result> { @@ -219,7 +226,10 @@ impl InstStruct { fn impl_inst(&self) -> proc_macro2::TokenStream { let struct_name = &self.struct_name; - let has_side_effect = self.has_side_effect; + let side_effect = match &self.side_effect { + Some(se) => quote!(#se), + None => quote!(crate::inst::SideEffect::None), + }; let is_terminator = self.is_terminator; let visit_fields: Vec<_> = self .fields @@ -238,8 +248,8 @@ impl InstStruct { #(crate::ValueVisitable::visit_mut_with(&mut self.#visit_fields, (f));)* } - fn has_side_effect(&self) -> bool { - #has_side_effect + fn side_effect(&self) -> crate::inst::SideEffect { + #side_effect } fn is_terminator(&self) -> bool {