From 2e494f3f5657d5348d4da6dc71a310f601571103 Mon Sep 17 00:00:00 2001 From: Vaivaswatha N Date: Wed, 19 Apr 2023 01:19:33 +0530 Subject: [PATCH] Remove unused locals (#4458) --- sway-ir/src/function.rs | 9 ++++++ sway-ir/src/optimize/dce.rs | 31 +++++++++++++++++-- sway-ir/tests/dce/dce2.ir | 12 +++++++ .../array_of_structs_caller/src/main.sw | 2 +- .../call_basic_storage/src/main.sw | 2 +- .../src/main.sw | 2 +- .../call_increment_contract/src/main.sw | 2 +- .../caller_context_test/src/main.sw | 2 +- .../get_storage_key_caller/src/main.sw | 2 +- .../nested_struct_args_caller/src/main.sw | 2 +- .../storage_access_caller/src/main.sw | 2 +- .../tests/simple_contract_call.sw | 1 - 12 files changed, 57 insertions(+), 12 deletions(-) create mode 100644 sway-ir/tests/dce/dce2.ir diff --git a/sway-ir/src/function.rs b/sway-ir/src/function.rs index 86e5591faf4..e87270ac1ee 100644 --- a/sway-ir/src/function.rs +++ b/sway-ir/src/function.rs @@ -398,6 +398,15 @@ impl Function { context.functions[self.0].local_storage.iter() } + /// Remove given list of locals + pub fn remove_locals(&self, context: &mut Context, removals: &Vec) { + for remove in removals { + if let Some(local) = context.functions[self.0].local_storage.remove(remove) { + context.local_vars.remove(local.0); + } + } + } + /// Merge values from another [`Function`] into this one. /// /// The names of the merged values are guaranteed to be unique via the use of diff --git a/sway-ir/src/optimize/dce.rs b/sway-ir/src/optimize/dce.rs index 9ca8778c2f4..53657c3ddb8 100644 --- a/sway-ir/src/optimize/dce.rs +++ b/sway-ir/src/optimize/dce.rs @@ -6,8 +6,8 @@ //! This pass does not do CFG transformations. That is handled by simplify_cfg. use crate::{ - AnalysisResults, Block, Context, Function, Instruction, IrError, Module, Pass, PassMutability, - ScopedPass, Value, ValueDatum, + AnalysisResults, Block, Context, Function, Instruction, IrError, LocalVar, Module, Pass, + PassMutability, ScopedPass, Value, ValueDatum, }; use std::collections::{HashMap, HashSet}; @@ -47,10 +47,18 @@ pub fn dce( ) -> Result { // Number of uses that an instruction has. let mut num_uses: HashMap = HashMap::new(); + let mut num_local_uses: HashMap = HashMap::new(); // Go through each instruction and update use_count. for (block, inst) in function.instruction_iter(context) { - let opds = inst.get_instruction(context).unwrap().get_operands(); + let inst = inst.get_instruction(context).unwrap(); + if let Instruction::GetLocal(local) = inst { + num_local_uses + .entry(*local) + .and_modify(|count| *count += 1) + .or_insert(1); + } + let opds = inst.get_operands(); for v in opds { match context.values[v.0].value { ValueDatum::Instruction(_) => { @@ -94,7 +102,24 @@ pub fn dce( } in_block.remove_instruction(context, dead); + + if let ValueDatum::Instruction(Instruction::GetLocal(local)) = context.values[dead.0].value + { + let count = num_local_uses.get_mut(&local).unwrap(); + *count -= 1; + } + modified = true; + } + + let local_removals: Vec<_> = function + .locals_iter(context) + .filter_map(|(name, local)| { + (num_local_uses.get(local).cloned().unwrap_or(0) == 0).then_some(name.clone()) + }) + .collect(); + if !local_removals.is_empty() { modified = true; + function.remove_locals(context, &local_removals); } Ok(modified) diff --git a/sway-ir/tests/dce/dce2.ir b/sway-ir/tests/dce/dce2.ir new file mode 100644 index 00000000000..aa661661118 --- /dev/null +++ b/sway-ir/tests/dce/dce2.ir @@ -0,0 +1,12 @@ +// regex: ID=[[:alpha:]0-9]+ + +script { + fn main() -> bool { +// not: local u64 i + local u64 i + + entry(): + v9 = const bool false + ret bool v9 + } +} 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 ee6b0330d8c..ba1faf60475 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 @@ -4,7 +4,7 @@ use array_of_structs_abi::{Id, TestContract, Wrapper}; use std::hash::sha256; fn main() -> u64 { - let addr = abi(TestContract, 0xa5d354e58efd316c2eb3f4b273a2143e7d534952fae5e191e057b27403ae829e); + let addr = abi(TestContract, 0xfd87acbc9cfdbae40894dc1be15c8f5f07a5775ca110df2584f053ac6ad10672); let input = [Wrapper { id: 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 657f158c191..fd02c728e16 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 @@ -2,7 +2,7 @@ script; use basic_storage_abi::{BasicStorage, Quad}; fn main() -> u64 { - let addr = abi(BasicStorage, 0xc98246b75472af9196be66b65a979ebbe5cd5975d1331f18ce2cda66a9819379); + let addr = abi(BasicStorage, 0x6906bdbccb7ca8e66c11ce16518c2f946da094d3e2c8561ca38d5a6d9a13e996); let key = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; let value = 4242; 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 c19d11d3ed8..bf6ede3afb0 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 @@ -3,7 +3,7 @@ script; use contract_with_type_aliases_abi::*; fn main() { - let caller = abi(MyContract, 0xaa380eacd28dbfba42ee88a1df59544f5cbc3e862a5b12bc2af894923ec4f5e8); + let caller = abi(MyContract, 0xf5030df8b9336a88f24afa90afe33aea6affd5295821aeb4eade84cd1fee4345); let x = AssetId::from(0x0101010101010101010101010101010101010101010101010101010101010101); 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 08db8de4bb9..a670332f4ab 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 @@ -3,7 +3,7 @@ script; use increment_abi::Incrementor; fn main() -> bool { - let the_abi = abi(Incrementor, 0xc9baa3acb84a53e91b31b2ecc514d5ad8a715083282dc16d520b5d40a9fc94a7); + let the_abi = abi(Incrementor, 0x6b259c454583b3995b9e35effa476f8cb2155ff44d1d8d567a83108b4fe65444); the_abi.increment(5); the_abi.increment(5); let result = the_abi.get(); 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 d62d48954dd..3e64c0ca3c2 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 @@ -7,7 +7,7 @@ fn main() -> bool { let zero = b256::min(); let gas: u64 = u64::max(); let amount: u64 = 11; - let other_contract_id = ContractId::from(0xc29171776f4d174a9e338d12c3b84e1de1694ba8bd64fb725d9eaf2842c7c6f1); + let other_contract_id = ContractId::from(0x338000acdb5764cdaaf90a70b2fa73c68fed43ce2b7bdb329d361cb6b5393a43); let base_asset_id = BASE_ASSET_ID; let test_contract = abi(ContextTesting, other_contract_id.into()); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/get_storage_key_caller/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/get_storage_key_caller/src/main.sw index 60848ebbdb1..7b108518e93 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/get_storage_key_caller/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/get_storage_key_caller/src/main.sw @@ -3,7 +3,7 @@ script; use get_storage_key_abi::TestContract; fn main() -> u64 { - let caller = abi(TestContract, 0x79fd3f7662e227f8ff7bef65b683fa4417b7e9f6d6bdbc0eb4d899ea2d73cad3); + let caller = abi(TestContract, 0xfd77b8770d4b9ad2402e8d6c838c8a837d2a56dd02ec4445c4c212bfce66b143); // Get the storage keys directly by calling the contract methods from_f1, // from_f2, from_f3, from_f4. The keys correspond to different entries in 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 93a5b044d6f..7fc78bd5ef0 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 @@ -3,7 +3,7 @@ script; use nested_struct_args_abi::*; fn main() -> bool { - let contract_id = 0xc07c133be5867020f483c34e045c9162867d6b40accc022525e50c048d17d679; + let contract_id = 0x1ce4c30fc1fe5d4639683ad1330de7739efd297671a540ffe9012e9cf3953fe7; let caller = abi(NestedStructArgs, contract_id); let param_one = StructOne { 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 5acc117878c..a1eefc7fee2 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 @@ -4,7 +4,7 @@ use storage_access_abi::*; use std::hash::sha256; fn main() -> bool { - let contract_id = 0x9ec7ac3cce15b1b75adabd598a374e96b606471a56229486a2d0ca26c08ed994; + let contract_id = 0x8982d742b1f313818d24516f7410519ca4fd4bbab470012809ffde710c45c0a4; let caller = abi(StorageAccess, contract_id); // Test initializers diff --git a/test/src/ir_generation/tests/simple_contract_call.sw b/test/src/ir_generation/tests/simple_contract_call.sw index 7e6fcd938c3..63be6db1b9a 100644 --- a/test/src/ir_generation/tests/simple_contract_call.sw +++ b/test/src/ir_generation/tests/simple_contract_call.sw @@ -48,7 +48,6 @@ fn main() -> u64 { // check: local b256 $(asset_id_2_const=$ID) = const b256 0x0000000000000000000000000000000000000000000000000000000000000000 // check: local u64 a -// check: local b256 arg_for_get_b256 // check: local { u64, b256 } args_struct_for_get_s // check: local b256 b // check: local { u64, b256 } s