diff --git a/sway-ir/src/analysis/dominator.rs b/sway-ir/src/analysis/dominator.rs index 72de08fb690..9919cd2f556 100644 --- a/sway-ir/src/analysis/dominator.rs +++ b/sway-ir/src/analysis/dominator.rs @@ -28,7 +28,8 @@ impl DomTreeNode { } // The dominator tree is represented by mapping each Block to its DomTreeNode. -pub type DomTree = FxIndexMap; +#[derive(Default)] +pub struct DomTree(FxIndexMap); impl AnalysisResultT for DomTree {} // Dominance frontier sets. @@ -120,11 +121,11 @@ fn compute_dom_tree( let entry = function.get_entry_block(context); // This is to make the algorithm happy. It'll be changed to None later. - dom_tree.insert(entry, DomTreeNode::new(Some(entry))); + dom_tree.0.insert(entry, DomTreeNode::new(Some(entry))); // initialize the dominators tree. This allows us to do dom_tree[b] fearlessly. // Note that we just previously initialized "entry", so we skip that here. for b in po.po_to_block.iter().take(po.po_to_block.len() - 1) { - dom_tree.insert(*b, DomTreeNode::new(None)); + dom_tree.0.insert(*b, DomTreeNode::new(None)); } let mut changed = true; @@ -149,12 +150,12 @@ fn compute_dom_tree( .pred_iter(context) .filter(|p| **p != picked_pred && po.block_to_po.contains_key(p)) { - if dom_tree[p].parent.is_some() { + if dom_tree.0[p].parent.is_some() { // if doms[p] already calculated new_idom = intersect(po, &dom_tree, *p, new_idom); } } - let b_node = dom_tree.get_mut(b).unwrap(); + let b_node = dom_tree.0.get_mut(b).unwrap(); match b_node.parent { Some(idom) if idom == new_idom => {} _ => { @@ -175,29 +176,54 @@ fn compute_dom_tree( ) -> Block { while finger1 != finger2 { while po.block_to_po[&finger1] < po.block_to_po[&finger2] { - finger1 = dom_tree[&finger1].parent.unwrap(); + finger1 = dom_tree.0[&finger1].parent.unwrap(); } while po.block_to_po[&finger2] < po.block_to_po[&finger1] { - finger2 = dom_tree[&finger2].parent.unwrap(); + finger2 = dom_tree.0[&finger2].parent.unwrap(); } } finger1 } // Fix the root. - dom_tree.get_mut(&entry).unwrap().parent = None; + dom_tree.0.get_mut(&entry).unwrap().parent = None; // Build the children. let child_parent: Vec<_> = dom_tree + .0 .iter() .filter_map(|(n, n_node)| n_node.parent.map(|n_parent| (*n, n_parent))) .collect(); for (child, parent) in child_parent { - dom_tree.get_mut(&parent).unwrap().children.push(child); + dom_tree.0.get_mut(&parent).unwrap().children.push(child); } Ok(Box::new(dom_tree)) } +impl DomTree { + /// Does `dominator` dominate `dominatee`? + pub fn dominates(&self, dominator: Block, dominatee: Block) -> bool { + let mut node_opt = Some(dominatee); + while let Some(node) = node_opt { + if node == dominator { + return true; + } + node_opt = self.0[&node].parent; + } + false + } + + /// Get an iterator over the children nodes + pub fn children(&self, node: Block) -> impl Iterator + '_ { + self.0[&node].children.iter().cloned() + } + + /// Get i'th child of a given node + pub fn child(&self, node: Block, i: usize) -> Option { + self.0[&node].children.get(i).cloned() + } +} + pub const DOM_FRONTS_NAME: &str = "dominance-frontiers"; pub fn create_dom_fronts_pass() -> Pass { @@ -217,23 +243,23 @@ fn compute_dom_fronts( ) -> Result { let dom_tree: &DomTree = analyses.get_analysis_result(function); let mut res = DomFronts::default(); - for (b, _) in dom_tree.iter() { + for (b, _) in dom_tree.0.iter() { res.insert(*b, IndexSet::default()); } // for all nodes, b - for (b, _) in dom_tree.iter() { + for (b, _) in dom_tree.0.iter() { // if the number of predecessors of b >= 2 if b.num_predecessors(context) > 1 { // unwrap() is safe as b is not "entry", and hence must have idom. - let b_idom = dom_tree[b].parent.unwrap(); + let b_idom = dom_tree.0[b].parent.unwrap(); // for all (reachable) predecessors, p, of b - for p in b.pred_iter(context).filter(|&p| dom_tree.contains_key(p)) { + for p in b.pred_iter(context).filter(|&p| dom_tree.0.contains_key(p)) { let mut runner = *p; while runner != b_idom { // add b to runner’s dominance frontier set res.get_mut(&runner).unwrap().insert(*b); - runner = dom_tree[&runner].parent.unwrap(); + runner = dom_tree.0[&runner].parent.unwrap(); } } } @@ -244,7 +270,7 @@ fn compute_dom_fronts( /// Print dominator tree in the graphviz dot format. pub fn print_dot(context: &Context, func_name: &str, dom_tree: &DomTree) -> String { let mut res = format!("digraph {func_name} {{\n"); - for (b, idom) in dom_tree.iter() { + for (b, idom) in dom_tree.0.iter() { if let Some(idom) = idom.parent { let _ = writeln!( res, diff --git a/sway-ir/src/instruction.rs b/sway-ir/src/instruction.rs index 1db5a4663ed..9e7b92fb5e0 100644 --- a/sway-ir/src/instruction.rs +++ b/sway-ir/src/instruction.rs @@ -205,19 +205,19 @@ pub enum FuelVmInstruction { } /// Comparison operations. -#[derive(Debug, Clone, Copy, Hash)] +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] pub enum Predicate { Equal, LessThan, GreaterThan, } -#[derive(Debug, Clone, Copy, Hash)] +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] pub enum UnaryOpKind { Not, } -#[derive(Debug, Clone, Copy, Hash)] +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] pub enum BinaryOpKind { Add, Sub, diff --git a/sway-ir/src/optimize.rs b/sway-ir/src/optimize.rs index 5a1dbeab9bf..564002fff13 100644 --- a/sway-ir/src/optimize.rs +++ b/sway-ir/src/optimize.rs @@ -21,6 +21,8 @@ pub mod constants; pub use constants::*; pub mod conditional_constprop; pub use conditional_constprop::*; +pub mod cse; +pub use cse::*; pub mod dce; pub use dce::*; pub mod inline; diff --git a/sway-ir/src/optimize/conditional_constprop.rs b/sway-ir/src/optimize/conditional_constprop.rs index 44daf1f5484..deb5a1b1623 100644 --- a/sway-ir/src/optimize/conditional_constprop.rs +++ b/sway-ir/src/optimize/conditional_constprop.rs @@ -59,17 +59,13 @@ pub fn ccp( } // lets walk the dominator tree from the root. - let Some((root_block, _root_node)) = - dom_tree.iter().find(|(_block, node)| node.parent.is_none()) - else { - panic!("Dominator tree without root"); - }; + let root_block = function.get_entry_block(context); if dom_region_replacements.is_empty() { return Ok(false); } - let mut stack = vec![(*root_block, 0)]; + let mut stack = vec![(root_block, 0)]; let mut replacements = FxHashMap::default(); while let Some((block, next_child)) = stack.last().cloned() { let cur_replacement_opt = dom_region_replacements.get(&block); @@ -83,14 +79,12 @@ pub fn ccp( block.replace_values(context, &replacements); } - let block_node = &dom_tree[&block]; - // walk children. - if let Some(child) = block_node.children.get(next_child) { + if let Some(child) = dom_tree.child(block, next_child) { // When we arrive back at "block" next time, we should process the next child. stack.last_mut().unwrap().1 = next_child + 1; // Go on to process the child. - stack.push((*child, 0)); + stack.push((child, 0)); } else { // No children left to process. Start postorder processing. if let Some(cur_replacement) = cur_replacement_opt { diff --git a/sway-ir/src/optimize/cse.rs b/sway-ir/src/optimize/cse.rs new file mode 100644 index 00000000000..7423cc2fa62 --- /dev/null +++ b/sway-ir/src/optimize/cse.rs @@ -0,0 +1,408 @@ +//! Value numbering based common subexpression elimination. +//! Reference: Value Driven Redundancy Elimination - Loren Taylor Simpson. + +use core::panic; +use itertools::Itertools; +use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; +use slotmap::Key; +use std::{ + collections::hash_map, + fmt::Debug, + hash::{Hash, Hasher}, +}; + +use crate::{ + AnalysisResults, BinaryOpKind, Context, DebugWithContext, DomTree, Function, InstOp, IrError, + Pass, PassMutability, PostOrder, Predicate, ScopedPass, Type, UnaryOpKind, Value, + DOMINATORS_NAME, POSTORDER_NAME, +}; + +pub const CSE_NAME: &str = "cse"; + +pub fn create_cse_pass() -> Pass { + Pass { + name: CSE_NAME, + descr: "Common subexpression elimination", + runner: ScopedPass::FunctionPass(PassMutability::Transform(cse)), + deps: vec![POSTORDER_NAME, DOMINATORS_NAME], + } +} + +#[derive(Clone, Copy, Eq, PartialEq, Hash, DebugWithContext)] +enum ValueNumber { + // Top of the lattice = Don't know = uninitialized + Top, + // Belongs to a congruence class represented by the inner value. + Number(Value), +} + +impl Debug for ValueNumber { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Top => write!(f, "Top"), + Self::Number(arg0) => write!(f, "v{:?}", arg0.0.data()), + } + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Hash, DebugWithContext)] +enum Expr { + Phi(Vec), + UnaryOp { + op: UnaryOpKind, + arg: ValueNumber, + }, + BinaryOp { + op: BinaryOpKind, + arg1: ValueNumber, + arg2: ValueNumber, + }, + BitCast(ValueNumber, Type), + CastPtr(ValueNumber, Type), + Cmp(Predicate, ValueNumber, ValueNumber), + GetElemPtr { + base: ValueNumber, + elem_ptr_ty: Type, + indices: Vec, + }, + IntToPtr(ValueNumber, Type), + PtrToInt(ValueNumber, Type), +} + +/// Convert an instruction to an expression for hashing +/// Instructions that we don't handle will have their value numbers be equal to themselves. +fn instr_to_expr(context: &Context, vntable: &VNTable, instr: Value) -> Option { + match &instr.get_instruction(context).unwrap().op { + InstOp::AsmBlock(_, _) => None, + InstOp::UnaryOp { op, arg } => Some(Expr::UnaryOp { + op: *op, + arg: vntable.value_map.get(arg).cloned().unwrap(), + }), + InstOp::BinaryOp { op, arg1, arg2 } => Some(Expr::BinaryOp { + op: *op, + arg1: vntable.value_map.get(arg1).cloned().unwrap(), + arg2: vntable.value_map.get(arg2).cloned().unwrap(), + }), + InstOp::BitCast(val, ty) => Some(Expr::BitCast( + vntable.value_map.get(val).cloned().unwrap(), + *ty, + )), + InstOp::Branch(_) => None, + InstOp::Call(_, _) => None, + InstOp::CastPtr(val, ty) => Some(Expr::CastPtr( + vntable.value_map.get(val).cloned().unwrap(), + *ty, + )), + InstOp::Cmp(pred, val1, val2) => Some(Expr::Cmp( + *pred, + vntable.value_map.get(val1).cloned().unwrap(), + vntable.value_map.get(val2).cloned().unwrap(), + )), + InstOp::ConditionalBranch { .. } => None, + InstOp::ContractCall { .. } => None, + InstOp::FuelVm(_) => None, + InstOp::GetLocal(_) => None, + InstOp::GetConfig(_, _) => None, + InstOp::GetElemPtr { + base, + elem_ptr_ty, + indices, + } => Some(Expr::GetElemPtr { + base: vntable.value_map.get(base).cloned().unwrap(), + elem_ptr_ty: *elem_ptr_ty, + indices: indices + .iter() + .map(|idx| vntable.value_map.get(idx).cloned().unwrap()) + .collect(), + }), + InstOp::IntToPtr(val, ty) => Some(Expr::IntToPtr( + vntable.value_map.get(val).cloned().unwrap(), + *ty, + )), + InstOp::Load(_) => None, + InstOp::MemCopyBytes { .. } => None, + InstOp::MemCopyVal { .. } => None, + InstOp::Nop => None, + InstOp::PtrToInt(val, ty) => Some(Expr::PtrToInt( + vntable.value_map.get(val).cloned().unwrap(), + *ty, + )), + InstOp::Ret(_, _) => None, + InstOp::Store { .. } => None, + } +} + +/// Convert a PHI argument to Expr +fn phi_to_expr(context: &Context, vntable: &VNTable, phi_arg: Value) -> Expr { + let phi_arg = phi_arg.get_argument(context).unwrap(); + let phi_args = phi_arg + .block + .pred_iter(context) + .map(|pred| { + let incoming_val = phi_arg + .get_val_coming_from(context, pred) + .expect("No parameter from predecessor"); + vntable.value_map.get(&incoming_val).cloned().unwrap() + }) + .collect(); + Expr::Phi(phi_args) +} + +#[derive(Default)] +struct VNTable { + value_map: FxHashMap, + expr_map: FxHashMap, +} + +impl Debug for VNTable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "value_map:")?; + self.value_map.iter().for_each(|(key, value)| { + if format!("v{:?}", key.0.data()) == "v620v3" { + writeln!(f, "\tv{:?} -> {:?}", key.0.data(), value).expect("writeln! failed"); + } + }); + Ok(()) + } +} + +/// Wrapper around [DomTree::dominates] to work at instruction level. +/// Does `inst1` dominate `inst2` ? +fn dominates(context: &Context, dom_tree: &DomTree, inst1: Value, inst2: Value) -> bool { + let block1 = match &context.values[inst1.0].value { + crate::ValueDatum::Argument(arg) => arg.block, + crate::ValueDatum::Constant(_) => { + panic!("Shouldn't be querying dominance info for constants") + } + crate::ValueDatum::Instruction(i) => i.parent, + }; + let block2 = match &context.values[inst2.0].value { + crate::ValueDatum::Argument(arg) => arg.block, + crate::ValueDatum::Constant(_) => { + panic!("Shouldn't be querying dominance info for constants") + } + crate::ValueDatum::Instruction(i) => i.parent, + }; + + if block1 == block2 { + let inst1_idx = block1 + .instruction_iter(context) + .position(|inst| inst == inst1) + // Not found indicates a block argument + .unwrap_or(0); + let inst2_idx = block1 + .instruction_iter(context) + .position(|inst| inst == inst2) + // Not found indicates a block argument + .unwrap_or(0); + inst1_idx < inst2_idx + } else { + dom_tree.dominates(block1, block2) + } +} + +pub fn cse( + context: &mut Context, + analyses: &AnalysisResults, + function: Function, +) -> Result { + let mut vntable = VNTable::default(); + + // Function arg values map to themselves. + for arg in function.args_iter(context) { + vntable.value_map.insert(arg.1, ValueNumber::Number(arg.1)); + } + + // Map all other arg values map to Top. + for block in function.block_iter(context).skip(1) { + for arg in block.arg_iter(context) { + vntable.value_map.insert(*arg, ValueNumber::Top); + } + } + + // Initialize all instructions and constants. Constants need special treatmemt. + // They don't have PartialEq implemented. So we need to value number them manually. + // This map maps the hash of a constant value to all possible collisions of it. + let mut const_map = FxHashMap::>::default(); + for (_, inst) in function.instruction_iter(context) { + vntable.value_map.insert(inst, ValueNumber::Top); + for (const_opd_val, const_opd_const) in inst + .get_instruction(context) + .unwrap() + .op + .get_operands() + .iter() + .filter_map(|opd| opd.get_constant(context).map(|copd| (opd, copd))) + { + let mut state = FxHasher::default(); + const_opd_const.hash(&mut state); + let hash = state.finish(); + if let Some(existing_const) = const_map.get(&hash).and_then(|consts| { + consts.iter().find(|val| { + let c = val + .get_constant(context) + .expect("const_map can only contain consts"); + const_opd_const.eq(context, c) + }) + }) { + vntable + .value_map + .insert(*const_opd_val, ValueNumber::Number(*existing_const)); + } else { + const_map + .entry(hash) + .and_modify(|consts| consts.push(*const_opd_val)) + .or_insert_with(|| vec![*const_opd_val]); + vntable + .value_map + .insert(*const_opd_val, ValueNumber::Number(*const_opd_val)); + } + } + } + + // We need to iterate over the blocks in RPO. + let post_order: &PostOrder = analyses.get_analysis_result(function); + + // RPO based value number (Sec 4.2). + let mut changed = true; + while changed { + changed = false; + // For each block in RPO: + for (block_idx, block) in post_order.po_to_block.iter().rev().enumerate() { + // Process PHIs and then the other instructions. + if block_idx != 0 { + // Entry block arguments are not PHIs. + for (phi, expr_opt) in block + .arg_iter(context) + .map(|arg| (*arg, Some(phi_to_expr(context, &vntable, *arg)))) + .collect_vec() + { + let expr = expr_opt.expect("PHIs must always translate to a valid Expr"); + // We first try to see if PHIs can be simplified into a single value. + let vn = { + let Expr::Phi(ref phi_args) = expr else { + panic!("Expr must be a PHI") + }; + phi_args + .iter() + .map(|vn| Some(*vn)) + .reduce(|vn1, vn2| { + // Here `None` indicates Bottom of the lattice. + if let (Some(vn1), Some(vn2)) = (vn1, vn2) { + match (vn1, vn2) { + (ValueNumber::Top, ValueNumber::Top) => { + Some(ValueNumber::Top) + } + (ValueNumber::Top, ValueNumber::Number(vn)) + | (ValueNumber::Number(vn), ValueNumber::Top) => { + Some(ValueNumber::Number(vn)) + } + (ValueNumber::Number(vn1), ValueNumber::Number(vn2)) => { + (vn1 == vn2).then_some(ValueNumber::Number(vn1)) + } + } + } else { + None + } + }) + .flatten() + // The PHI couldn't be simplified to a single ValueNumber. + .unwrap_or(ValueNumber::Number(phi)) + }; + + match vntable.value_map.entry(phi) { + hash_map::Entry::Occupied(occ) if *occ.get() == vn => {} + _ => { + changed = true; + vntable.value_map.insert(phi, vn); + } + } + } + } + + for (inst, expr_opt) in block + .instruction_iter(context) + .map(|instr| (instr, instr_to_expr(context, &vntable, instr))) + .collect_vec() + { + // lookup(expr, x) + let vn = if let Some(expr) = expr_opt { + match vntable.expr_map.entry(expr) { + hash_map::Entry::Occupied(occ) => *occ.get(), + hash_map::Entry::Vacant(vac) => *(vac.insert(ValueNumber::Number(inst))), + } + } else { + // Instructions that always map to their own value number + // (i.e., they can never be equal to some other instruction). + ValueNumber::Number(inst) + }; + match vntable.value_map.entry(inst) { + hash_map::Entry::Occupied(occ) if *occ.get() == vn => {} + _ => { + changed = true; + vntable.value_map.insert(inst, vn); + } + } + } + } + vntable.expr_map.clear(); + } + + // create a partition of congruent (equal) values. + let mut partition = FxHashMap::>::default(); + vntable.value_map.iter().for_each(|(v, vn)| { + // If v is a constant or its value number is itself, don't add to the partition. + // The latter condition is so that we have only > 1 sized partitions. + if v.is_constant(context) + || matches!(vn, ValueNumber::Top) + || matches!(vn, ValueNumber::Number(v2) if (v == v2 || v2.is_constant(context))) + { + return; + } + partition + .entry(*vn) + .and_modify(|part| { + part.insert(*v); + }) + .or_insert(vec![*v].into_iter().collect()); + }); + + // For convenience, now add back back `v` into `partition[VN[v]]` if it isn't already there. + partition.iter_mut().for_each(|(vn, v_part)| { + let ValueNumber::Number(v) = vn else { + panic!("We cannot have Top at this point"); + }; + v_part.insert(*v); + assert!( + v_part.len() > 1, + "We've only created partitions with size greater than 1" + ); + }); + + // There are two ways to replace congruent values (see the paper cited, Sec 5). + // 1. Dominator based. If v1 and v2 are equal, v1 dominates v2, we just remove v2 + // and replace its uses with v1. Simple, and what we're going to do. + // 2. AVAIL based. More powerful, but also requires a data-flow-analysis for AVAIL + // and later on, mem2reg again since replacements will need breaking SSA. + let dom_tree: &DomTree = analyses.get_analysis_result(function); + let mut replace_map = FxHashMap::::default(); + let mut modified = false; + // Check every set in the partition. + partition.iter().for_each(|(_leader, vals)| { + // Iterate over every pair of values, checking if one can replace the other. + for v_pair in vals.iter().combinations(2) { + let (v1, v2) = (*v_pair[0], *v_pair[1]); + if dominates(context, dom_tree, v1, v2) { + modified = true; + replace_map.insert(v2, v1); + } else if dominates(context, dom_tree, v2, v1) { + modified = true; + replace_map.insert(v1, v2); + } + } + }); + + function.replace_values(context, &replace_map, None); + + Ok(modified) +} diff --git a/sway-ir/src/optimize/mem2reg.rs b/sway-ir/src/optimize/mem2reg.rs index 0a3484cec4a..c7c8a5b847b 100644 --- a/sway-ir/src/optimize/mem2reg.rs +++ b/sway-ir/src/optimize/mem2reg.rs @@ -319,12 +319,12 @@ pub fn promote_to_registers( } // Process dominator children. - for child in dom_tree[&node].children.iter() { + for child in dom_tree.children(node) { record_rewrites( context, function, dom_tree, - *child, + child, safe_locals, phi_to_local, name_stack, diff --git a/sway-ir/src/pass_manager.rs b/sway-ir/src/pass_manager.rs index 7318016fae5..9edb21626c3 100644 --- a/sway-ir/src/pass_manager.rs +++ b/sway-ir/src/pass_manager.rs @@ -1,14 +1,15 @@ use crate::{ create_arg_demotion_pass, create_ccp_pass, create_const_demotion_pass, - create_const_folding_pass, create_dce_pass, create_dom_fronts_pass, create_dominators_pass, - create_escaped_symbols_pass, create_fn_dce_pass, create_fn_dedup_debug_profile_pass, - create_fn_dedup_release_profile_pass, create_fn_inline_pass, create_mem2reg_pass, - create_memcpyopt_pass, create_misc_demotion_pass, create_module_printer_pass, - create_module_verifier_pass, create_postorder_pass, create_ret_demotion_pass, - create_simplify_cfg_pass, create_sroa_pass, Context, Function, IrError, Module, - ARG_DEMOTION_NAME, CCP_NAME, CONST_DEMOTION_NAME, CONST_FOLDING_NAME, DCE_NAME, FN_DCE_NAME, - FN_DEDUP_DEBUG_PROFILE_NAME, FN_DEDUP_RELEASE_PROFILE_NAME, FN_INLINE_NAME, MEM2REG_NAME, - MEMCPYOPT_NAME, MISC_DEMOTION_NAME, RET_DEMOTION_NAME, SIMPLIFY_CFG_NAME, SROA_NAME, + create_const_folding_pass, create_cse_pass, create_dce_pass, create_dom_fronts_pass, + create_dominators_pass, create_escaped_symbols_pass, create_fn_dce_pass, + create_fn_dedup_debug_profile_pass, create_fn_dedup_release_profile_pass, + create_fn_inline_pass, create_mem2reg_pass, create_memcpyopt_pass, create_misc_demotion_pass, + create_module_printer_pass, create_module_verifier_pass, create_postorder_pass, + create_ret_demotion_pass, create_simplify_cfg_pass, create_sroa_pass, Context, Function, + IrError, Module, ARG_DEMOTION_NAME, CCP_NAME, CONST_DEMOTION_NAME, CONST_FOLDING_NAME, + CSE_NAME, DCE_NAME, FN_DCE_NAME, FN_DEDUP_DEBUG_PROFILE_NAME, FN_DEDUP_RELEASE_PROFILE_NAME, + FN_INLINE_NAME, MEM2REG_NAME, MEMCPYOPT_NAME, MISC_DEMOTION_NAME, RET_DEMOTION_NAME, + SIMPLIFY_CFG_NAME, SROA_NAME, }; use downcast_rs::{impl_downcast, Downcast}; use rustc_hash::FxHashMap; @@ -400,6 +401,7 @@ pub fn register_known_passes(pm: &mut PassManager) { pm.register(create_simplify_cfg_pass()); pm.register(create_fn_dce_pass()); pm.register(create_dce_pass()); + pm.register(create_cse_pass()); pm.register(create_arg_demotion_pass()); pm.register(create_const_demotion_pass()); pm.register(create_ret_demotion_pass()); @@ -408,7 +410,7 @@ pub fn register_known_passes(pm: &mut PassManager) { } pub fn create_o1_pass_group() -> PassGroup { - // Create a configuration to specify which passes we want to run now. + // Create a create_ccp_passo specify which passes we want to run now. let mut o1 = PassGroup::default(); // Configure to run our passes. o1.append_pass(MEM2REG_NAME); @@ -420,6 +422,7 @@ pub fn create_o1_pass_group() -> PassGroup { o1.append_pass(CCP_NAME); o1.append_pass(CONST_FOLDING_NAME); o1.append_pass(SIMPLIFY_CFG_NAME); + o1.append_pass(CSE_NAME); o1.append_pass(CONST_FOLDING_NAME); o1.append_pass(SIMPLIFY_CFG_NAME); o1.append_pass(FN_DCE_NAME); diff --git a/sway-ir/tests/cse/cse1.ir b/sway-ir/tests/cse/cse1.ir new file mode 100644 index 00000000000..687c12f8d76 --- /dev/null +++ b/sway-ir/tests/cse/cse1.ir @@ -0,0 +1,21 @@ +// regex: ID=[[:alpha:]0-9]+ +// regex: VAR=v\d+ + +script { + fn main() -> bool { + entry(): + v0 = const u64 11 + v1 = const u64 0 + // check: $(v3=$VAR) = add + v3 = add v0, v1 + // check: $(v4=$VAR) = add + v4 = add v0, v1 + v10 = const u64 10 + v11 = add v1, v0 + // check: cmp eq $v3 $v3 + v2 = cmp eq v3 v4 + v3 = cmp eq v11 v3 + v4 = cmp eq v2 v3 + ret bool v4 + } +} diff --git a/sway-ir/tests/cse/cse2.ir b/sway-ir/tests/cse/cse2.ir new file mode 100644 index 00000000000..ec609f74d60 --- /dev/null +++ b/sway-ir/tests/cse/cse2.ir @@ -0,0 +1,22 @@ +// regex: ID=[[:alpha:]0-9]+ +// regex: VAR=v\d+ + +script { + fn main() -> bool { + entry(): + v0 = const u64 11 + v0_dup = const u64 11 + v1 = const u64 0 + // check: $(v3=$VAR) = add + v3 = add v0, v1 + // check: $(v4=$VAR) = add + v4 = add v0, v1 + // check: $(v5=$VAR) = sub + v5 = sub v0, v3 + // check: $(v6=$VAR) = sub + v6 = sub v0_dup, v4 + // check: cmp eq $v5 $v5 + v2 = cmp eq v5 v6 + ret bool v2 + } +} diff --git a/sway-ir/tests/cse/cse3.ir b/sway-ir/tests/cse/cse3.ir new file mode 100644 index 00000000000..89a3df2fdd3 --- /dev/null +++ b/sway-ir/tests/cse/cse3.ir @@ -0,0 +1,29 @@ +// regex: ID=[[:alpha:]0-9]+ +// regex: VAR=v\d+ + +script { + entry fn main(a: u64, b: u64) -> () { + entry(a: u64, b: u64): + // check: $(v5=$VAR) = add a, b + v5 = add a, b + v6 = const u64 0 + br while(v6, v5) + + while(v3: u64, v4: u64): + // check: cmp lt $VAR $v5 + v8 = cmp lt v3 v4 + cbr v8, while_body(), end_while() + + while_body(): + // check: $(v10=$VAR) = add a, b + v10 = add a, b + v11 = const u64 1 + v12 = add v3, v11 + // check: br while($VAR, $v5) + br while(v12, v10) + + end_while(): + v14 = const unit () + ret () v14 + } +} diff --git a/sway-ir/tests/tests.rs b/sway-ir/tests/tests.rs index 0a577c00c9c..197d67d400e 100644 --- a/sway-ir/tests/tests.rs +++ b/sway-ir/tests/tests.rs @@ -3,12 +3,13 @@ use std::path::PathBuf; use itertools::Itertools; use sway_ir::{ create_arg_demotion_pass, create_ccp_pass, create_const_demotion_pass, - create_const_folding_pass, create_dce_pass, create_dom_fronts_pass, create_dominators_pass, - create_escaped_symbols_pass, create_mem2reg_pass, create_memcpyopt_pass, - create_misc_demotion_pass, create_postorder_pass, create_ret_demotion_pass, - create_simplify_cfg_pass, metadata_to_inline, optimize as opt, register_known_passes, Context, - ExperimentalFlags, Function, IrError, PassGroup, PassManager, Value, DCE_NAME, FN_DCE_NAME, - FN_DEDUP_DEBUG_PROFILE_NAME, FN_DEDUP_RELEASE_PROFILE_NAME, MEM2REG_NAME, SROA_NAME, + create_const_folding_pass, create_cse_pass, create_dce_pass, create_dom_fronts_pass, + create_dominators_pass, create_escaped_symbols_pass, create_mem2reg_pass, + create_memcpyopt_pass, create_misc_demotion_pass, create_postorder_pass, + create_ret_demotion_pass, create_simplify_cfg_pass, metadata_to_inline, optimize as opt, + register_known_passes, Context, ExperimentalFlags, Function, IrError, PassGroup, PassManager, + Value, DCE_NAME, FN_DCE_NAME, FN_DEDUP_DEBUG_PROFILE_NAME, FN_DEDUP_RELEASE_PROFILE_NAME, + MEM2REG_NAME, SROA_NAME, }; use sway_types::SourceEngine; @@ -282,6 +283,22 @@ fn dce() { // ------------------------------------------------------------------------------------------------- +#[allow(clippy::needless_collect)] +#[test] +fn cse() { + run_tests("cse", |_first_line, ir: &mut Context| { + let mut pass_mgr = PassManager::default(); + let mut pass_group = PassGroup::default(); + pass_mgr.register(create_postorder_pass()); + pass_mgr.register(create_dominators_pass()); + let pass = pass_mgr.register(create_cse_pass()); + pass_group.append_pass(pass); + pass_mgr.run(ir, &pass_group).unwrap() + }) +} + +// ------------------------------------------------------------------------------------------------- + #[allow(clippy::needless_collect)] #[test] fn mem2reg() { diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/json_abi_oracle_new_encoding.json index 0662cd80d0d..b5e886d1a19 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/json_abi_oracle_new_encoding.json +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/json_abi_oracle_new_encoding.json @@ -62,82 +62,82 @@ { "concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903", "name": "BOOL", - "offset": 7208 + "offset": 7216 }, { "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", "name": "U8", - "offset": 7400 + "offset": 7408 }, { "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", "name": "ANOTHER_U8", - "offset": 7136 + "offset": 7144 }, { "concreteTypeId": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef", "name": "U16", - "offset": 7344 + "offset": 7352 }, { "concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc", "name": "U32", - "offset": 7384 + "offset": 7392 }, { "concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc", "name": "U64", - "offset": 7392 + "offset": 7400 }, { "concreteTypeId": "1b5759d94094368cfd443019e7ca5ec4074300e544e5ea993a979f5da627261e", "name": "U256", - "offset": 7352 + "offset": 7360 }, { "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", "name": "B256", - "offset": 7176 + "offset": 7184 }, { "concreteTypeId": "81fc10c4681a3271cf2d66b2ec6fbc8ed007a442652930844fcf11818c295bff", "name": "CONFIGURABLE_STRUCT", - "offset": 7296 + "offset": 7304 }, { "concreteTypeId": "a2922861f03be8a650595dd76455b95383a61b46dd418f02607fa2e00dc39d5c", "name": "CONFIGURABLE_ENUM_A", - "offset": 7216 + "offset": 7224 }, { "concreteTypeId": "a2922861f03be8a650595dd76455b95383a61b46dd418f02607fa2e00dc39d5c", "name": "CONFIGURABLE_ENUM_B", - "offset": 7256 + "offset": 7264 }, { "concreteTypeId": "4926d35d1a5157936b0a29bc126b8aace6d911209a5c130e9b716b0c73643ea6", "name": "ARRAY_BOOL", - "offset": 7144 + "offset": 7152 }, { "concreteTypeId": "776fb5a3824169d6736138565fdc20aad684d9111266a5ff6d5c675280b7e199", "name": "ARRAY_U64", - "offset": 7152 + "offset": 7160 }, { "concreteTypeId": "c998ca9a5f221fe7b5c66ae70c8a9562b86d964408b00d17f883c906bc1fe4be", "name": "TUPLE_BOOL_U64", - "offset": 7328 + "offset": 7336 }, { "concreteTypeId": "94f0fa95c830be5e4f711963e83259fe7e8bc723278ab6ec34449e791a99b53a", "name": "STR_4", - "offset": 7320 + "offset": 7328 }, { "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", "name": "NOT_USED", - "offset": 7312 + "offset": 7320 } ], "encodingVersion": "1", diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/json_abi_oracle_new_encoding.json index 49a75d8d5c1..5b834c3566e 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/json_abi_oracle_new_encoding.json +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/json_abi_oracle_new_encoding.json @@ -9,7 +9,7 @@ { "concreteTypeId": "1b5759d94094368cfd443019e7ca5ec4074300e544e5ea993a979f5da627261e", "name": "SOME_U256", - "offset": 816 + "offset": 808 } ], "encodingVersion": "1", diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw index aba7556d410..575ca323135 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw @@ -6,7 +6,7 @@ use std::hash::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x14ed3cd06c2947248f69d54bfa681fe40d26267be84df7e19e253622b7921bbe; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xf9f1fec713b977865880637fc24e58cda9e69f6e711ed8e5efe7de9ce51c88ec; // AUTO-CONTRACT-ID ../../test_contracts/array_of_structs_contract --release +const CONTRACT_ID = 0xbbda20fb25bdb4b18451501418b06324376c61cb984e75fcbc983fc0a047f85b; // AUTO-CONTRACT-ID ../../test_contracts/array_of_structs_contract --release fn get_address() -> Option { Some(CONTRACT_ID.into()) diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw index f1458b54293..e177370b102 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw @@ -14,7 +14,7 @@ const FUEL_COIN_CONTRACT_ID = 0xf2fecff29038dab2ef571397ea5507359265c9154608e7de #[cfg(experimental_new_encoding = false)] const BALANCE_CONTRACT_ID = 0xf6cd545152ac83225e8e7df2efb5c6fa6e37bc9b9e977b5ea8103d28668925df; #[cfg(experimental_new_encoding = true)] -const BALANCE_CONTRACT_ID = 0xccf637b5b0071861f3074fcf963ef2339dab5d306d919b4c7e65024a7fbc64e6; // AUTO-CONTRACT-ID ../../test_contracts/balance_test_contract --release +const BALANCE_CONTRACT_ID = 0xebe7a84ed5198e9d7d3e002a571058dc24d56f61f2526ca30328f519528f98eb; // AUTO-CONTRACT-ID ../../test_contracts/balance_test_contract --release fn main() -> bool { let default_gas = 1_000_000_000_000; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/src/main.sw index a739f0d408c..3afdbe1afc2 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/src/main.sw @@ -5,7 +5,7 @@ use balance_test_abi::BalanceTest; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xf6cd545152ac83225e8e7df2efb5c6fa6e37bc9b9e977b5ea8103d28668925df; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xccf637b5b0071861f3074fcf963ef2339dab5d306d919b4c7e65024a7fbc64e6; // AUTO-CONTRACT-ID ../../test_contracts/balance_test_contract --release +const CONTRACT_ID = 0xebe7a84ed5198e9d7d3e002a571058dc24d56f61f2526ca30328f519528f98eb; // AUTO-CONTRACT-ID ../../test_contracts/balance_test_contract --release fn main() -> bool { let balance_test_contract = abi(BalanceTest, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/src/main.sw index 57633b2de20..49d7c83bf80 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/src/main.sw @@ -6,7 +6,7 @@ use abi_with_tuples::{MyContract, Location, Person}; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xfdc14550c8aee742cd556d0ab7f378b7be0d3b1e6e086c097352e94590d4ed02; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0x0328999650df8c33503c894fd6ac49b0299c9d64147feb69daa1606521dbe86e; // AUTO-CONTRACT-ID ../../test_contracts/abi_with_tuples_contract --release +const CONTRACT_ID = 0x95bff8249257356f042d500e9f7db1a964ab5739a1b156eafaca3c7a4efc8aaa; // AUTO-CONTRACT-ID ../../test_contracts/abi_with_tuples_contract --release fn main() -> bool { let the_abi = abi(MyContract, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw index 4e2144117af..b1166cfb9fb 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw @@ -4,7 +4,7 @@ use basic_storage_abi::{BasicStorage, Quad}; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x94db39f409a31b9f2ebcadeea44378e419208c20de90f5d8e1e33dc1523754cb; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0x23afacfc8eaa13d36c3f2f4d764b66e53d284e4cd31477e8bd72b4ccc411022b; // AUTO-CONTRACT-ID ../../test_contracts/basic_storage --release +const CONTRACT_ID = 0xd8e3576d2f7b2ed2d5f8935aef4837e6ff32b1c092d8ae369ad0fdd955a52169; // AUTO-CONTRACT-ID ../../test_contracts/basic_storage --release fn main() -> u64 { let addr = abi(BasicStorage, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw index aacf8538eba..bc2f5881cd6 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw @@ -5,7 +5,7 @@ use contract_with_type_aliases_abi::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x0cbeb6efe3104b460be769bdc4ea101ebf16ccc16f2d7b667ec3e1c7f5ce35b5; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xfffcb364f01ce902477fa73720ae48bfb8bc735447f75d55d441a76943a27a65; // AUTO-CONTRACT-ID ../../test_contracts/contract_with_type_aliases --release +const CONTRACT_ID = 0x514dae6ddad19623646033458f970d1286ef111806145daf80d06ca679604a96; // AUTO-CONTRACT-ID ../../test_contracts/contract_with_type_aliases --release fn main() { let caller = abi(MyContract, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw index 85deb2bb2ba..f518c022f5b 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw @@ -6,7 +6,7 @@ use dynamic_contract_call::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xd1b4047af7ef111c023ab71069e01dc2abfde487c0a0ce1268e4f447e6c6e4c2; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0x5229470a8bb907a909aba79325a347bd8849a8aceb9c8116e3d1c73ea4977b6d; // AUTO-CONTRACT-ID ../../test_contracts/increment_contract --release +const CONTRACT_ID = 0xc906accda9e1e516ee3122770217d913edca1ae6e3b8bad15c2c1a53ebf5e13e; // AUTO-CONTRACT-ID ../../test_contracts/increment_contract --release fn main() -> bool { let the_abi = abi(Incrementor, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw index ac6240cfd81..c3e736cb17f 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw @@ -5,7 +5,7 @@ use storage_enum_abi::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xc601d11767195485a6654d566c67774134668863d8c797a8c69e8778fb1f89e9; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0x4bb9cb0a4b3df7981e702609cbce4b684b3d9c21e474e9988825f48fae81b06d; // AUTO-CONTRACT-ID ../../test_contracts/storage_enum_contract --release +const CONTRACT_ID = 0xaa4e990e0796764624423b63c1bb14fdc02918294fab87682c1ee768de745a7e; // AUTO-CONTRACT-ID ../../test_contracts/storage_enum_contract --release fn main() -> u64 { let caller = abi(StorageEnum, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/src/main.sw index 6b47bf9d3a1..931e9f010df 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/src/main.sw @@ -5,7 +5,7 @@ use auth_testing_abi::AuthTesting; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xc2eec20491b53aab7232cbd27c31d15417b4e9daf0b89c74cc242ef1295f681f; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xbbd538c6fc4f6a805b4e178529e1460453aee648b5e49949bdfc8a12a585e7d2; // AUTO-CONTRACT-ID ../../test_contracts/auth_testing_contract --release +const CONTRACT_ID = 0x57892f3d8bd8c58137b35d177a8c03121193d51138ad2218e814af505e90a7f2; // AUTO-CONTRACT-ID ../../test_contracts/auth_testing_contract --release // should be false in the case of a script fn main() -> bool { diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/src/main.sw index 8da2675ccda..0f6ed8007b6 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/src/main.sw @@ -6,7 +6,7 @@ use context_testing_abi::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x6054c11cda000f5990373a4d61929396165be4dfdd61d5b7bd26da60ab0d8577; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0x7821bf368390972d4892e1f382fd954fea5b567e533eed6fac0f173800647945; // AUTO-CONTRACT-ID ../../test_contracts/context_testing_contract --release +const CONTRACT_ID = 0x6c159e40368c6a37b8c479cd63f5462832d5dbdc8d872c4b30edc38e230b7e51; // AUTO-CONTRACT-ID ../../test_contracts/context_testing_contract --release fn main() -> bool { let gas: u64 = u64::max(); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/src/main.sw index ed163d5076d..8410b0175e8 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/src/main.sw @@ -5,7 +5,7 @@ use nested_struct_args_abi::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xe63d33a1b3a6903808b379f6a41a72fa8a370e8b76626775e7d9d2f9c4c5da40; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0x90fdb746b560d271261d8fab6eba6a4381f173432b7fa8c93e2765c38bca508b; // AUTO-CONTRACT-ID ../../test_contracts/nested_struct_args_contract --release +const CONTRACT_ID = 0xc26e4f54f9bca811be460d07aaedfa12d46477378573947ae95653affba962be; // AUTO-CONTRACT-ID ../../test_contracts/nested_struct_args_contract --release fn main() -> bool { let caller = abi(NestedStructArgs, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw index eb9d9d24411..13dd55fec91 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw @@ -6,7 +6,7 @@ use std::hash::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x3bc28acd66d327b8c1b9624c1fabfc07e9ffa1b5d71c2832c3bfaaf8f4b805e9; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0x3da675876942326fd4c66b079216742f75e5f15681271a5db54a9cf19a813b22; // AUTO-CONTRACT-ID ../../test_contracts/storage_access_contract --release +const CONTRACT_ID = 0x83ec366b3623ee28ec09d3d92dcc2e113cc7427adb194fb42608103b0188fb83; // AUTO-CONTRACT-ID ../../test_contracts/storage_access_contract --release fn main() -> bool { let caller = abi(StorageAccess, CONTRACT_ID);