Skip to content

Commit 886becb

Browse files
authored
Add a new memcpy propagation pass (#7443)
## Description For the Sway code in #7344, the IR after #7381 and after this PR is shown here: <details> <summary> After #7381, before this PR </summary> ``` fn wrapper_1(__ret_value: __ptr { b256 }) -> (), !17 { local { u64, ( () | { b256 } ) } __matched_value_4 local { u64, ( () | { b256 } ) } __ret_val local { u64, ( () | { b256 } ) } self_ entry(__ret_value: __ptr { b256 }): v0 = get_local __ptr { u64, ( () | { b256 } ) }, __ret_val v1 = call return_option_5(v0) v2 = get_local __ptr { u64, ( () | { b256 } ) }, self_, !20 mem_copy_val v2, v0 v3 = get_local __ptr { u64, ( () | { b256 } ) }, self_, !23 v4 = get_local __ptr { u64, ( () | { b256 } ) }, __matched_value_4, !25 mem_copy_val v4, v3 v5 = get_local __ptr { u64, ( () | { b256 } ) }, self_ v6 = const u64 0 v7 = get_elem_ptr v5, __ptr u64, v6 v8 = load v7, !20 v9 = const u64 1, !22 v10 = cmp eq v8 v9, !28 cbr v10, unwrap_2_block0(), unwrap_2_block1(), !29 unwrap_2_block0(): v11 = get_local __ptr { u64, ( () | { b256 } ) }, __matched_value_4, !30 v12 = const u64 1 v13 = const u64 1 v14 = get_elem_ptr v11, __ptr { b256 }, v12, v13, !20 mem_copy_val __ret_value, v14 v15 = const unit () ret () v15 unwrap_2_block1(): v16 = const u64 0, !31 revert v16, !36 } fn return_option_5(__ret_value: __ptr { u64, ( () | { b256 } ) }) -> (), !39 { local { u64, ( () | { b256 } ) } __anon_0 entry(__ret_value: __ptr { u64, ( () | { b256 } ) }): v0 = get_local __ptr { u64, ( () | { b256 } ) }, __anon_0, !40 v1 = const u64 0 v2 = get_elem_ptr v0, __ptr u64, v1, !40 v3 = const u64 0, !40 store v3 to v2, !40 mem_copy_val __ret_value, v0 v4 = const unit () ret () v4 } ``` </details> <details> <summary> After this PR </summary> ``` fn wrapper_1(__ret_value: __ptr { b256 }) -> (), !17 { local { u64, ( () | { b256 } ) } __matched_value_4 entry(__ret_value: __ptr { b256 }): v0 = get_local __ptr { u64, ( () | { b256 } ) }, __matched_value_4 v1 = call return_option_5(v0) v2 = get_local __ptr { u64, ( () | { b256 } ) }, __matched_value_4 v3 = const u64 0 v4 = get_elem_ptr v2, __ptr u64, v3 v5 = load v4, !20 v6 = const u64 1, !22 v7 = cmp eq v5 v6, !25 cbr v7, unwrap_2_block0(), unwrap_2_block1(), !26 unwrap_2_block0(): v8 = get_local __ptr { u64, ( () | { b256 } ) }, __matched_value_4, !27 v9 = const u64 1 v10 = const u64 1 v11 = get_elem_ptr v8, __ptr { b256 }, v9, v10, !20 mem_copy_val __ret_value, v11 v12 = const unit () ret () v12 unwrap_2_block1(): v13 = const u64 0, !28 revert v13, !33 } fn return_option_5(__ret_value: __ptr { u64, ( () | { b256 } ) }) -> (), !36 { entry(__ret_value: __ptr { u64, ( () | { b256 } ) }): v0 = const u64 0 v1 = get_elem_ptr __ret_value, __ptr u64, v0, !37 v2 = const u64 0, !37 store v2 to v1, !37 v3 = const unit () ret () v3 } ``` </details> `wrapper_1`, which had 3 `memcpy`s now has 1, and `return_option_5` which had one, now has none. Closes #7344.
1 parent 6b26e50 commit 886becb

File tree

24 files changed

+830
-403
lines changed

24 files changed

+830
-403
lines changed

sway-core/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ use sway_ir::{
5858
create_o1_pass_group, register_known_passes, Context, Kind, Module, PassGroup, PassManager,
5959
PrintPassesOpts, VerifyPassesOpts, ARG_DEMOTION_NAME, ARG_POINTEE_MUTABILITY_TAGGER_NAME,
6060
CONST_DEMOTION_NAME, DCE_NAME, FN_DEDUP_DEBUG_PROFILE_NAME, FN_INLINE_NAME, GLOBALS_DCE_NAME,
61-
MEM2REG_NAME, MEMCPYOPT_NAME, MISC_DEMOTION_NAME, RET_DEMOTION_NAME, SIMPLIFY_CFG_NAME,
62-
SROA_NAME,
61+
MEM2REG_NAME, MEMCPYOPT_NAME, MEMCPYPROP_REVERSE_NAME, MISC_DEMOTION_NAME, RET_DEMOTION_NAME,
62+
SIMPLIFY_CFG_NAME, SROA_NAME,
6363
};
6464
use sway_types::span::Source;
6565
use sway_types::{SourceEngine, SourceLocation, Span};
@@ -1322,6 +1322,7 @@ pub(crate) fn compile_ast_to_ir_to_asm(
13221322

13231323
match build_config.optimization_level {
13241324
OptLevel::Opt1 => {
1325+
pass_group.append_pass(MEMCPYPROP_REVERSE_NAME);
13251326
pass_group.append_pass(SROA_NAME);
13261327
pass_group.append_pass(MEM2REG_NAME);
13271328
pass_group.append_pass(DCE_NAME);

sway-ir/src/analysis/dominator.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
22
block::Block, AnalysisResult, AnalysisResultT, AnalysisResults, BranchToWithArgs, Context,
3-
Function, IrError, Pass, PassMutability, ScopedPass,
3+
Function, IrError, Pass, PassMutability, ScopedPass, Value,
44
};
55
use indexmap::IndexSet;
66
/// Dominator tree and related algorithms.
@@ -222,6 +222,34 @@ impl DomTree {
222222
pub fn child(&self, node: Block, i: usize) -> Option<Block> {
223223
self.0[&node].children.get(i).cloned()
224224
}
225+
226+
/// Does `dominator` dominate `dominatee`?
227+
pub fn dominates_instr(&self, context: &Context, dominator: Value, dominatee: Value) -> bool {
228+
let dominator_inst = dominator.get_instruction(context).unwrap();
229+
let dominatee_inst = dominatee.get_instruction(context).unwrap();
230+
231+
if dominator == dominatee {
232+
return true;
233+
}
234+
let dominator_block = dominator_inst.parent;
235+
let dominatee_block = dominatee_inst.parent;
236+
if dominator_block == dominatee_block {
237+
// Same block, but different instructions.
238+
// Check the order of instructions in the block.
239+
let mut found_dominator = false;
240+
for instr in dominator_block.instruction_iter(context) {
241+
if instr == dominator {
242+
found_dominator = true;
243+
}
244+
if instr == dominatee {
245+
return found_dominator;
246+
}
247+
}
248+
false
249+
} else {
250+
self.dominates(dominator_block, dominatee_block)
251+
}
252+
}
225253
}
226254

227255
pub const DOM_FRONTS_NAME: &str = "dominance-frontiers";

sway-ir/src/block.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ impl BlockArgument {
7373
}
7474
None
7575
}
76+
77+
/// Get the [Value] that this argument represents.
78+
pub fn as_value(&self, context: &Context) -> Value {
79+
self.block.get_arg(context, self.idx).unwrap()
80+
}
7681
}
7782

7883
/// Each block may be explicitly named. A [`Label`] is a simple `String` synonym.

sway-ir/src/function.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,13 @@ impl Function {
219219
Ok(())
220220
}
221221

222+
/// Remove instructions from function that satisfy a given predicate.
223+
pub fn remove_instructions<T: Fn(Value) -> bool>(&self, context: &mut Context, pred: T) {
224+
for block in context.functions[self.0].blocks.clone() {
225+
block.remove_instructions(context, &pred);
226+
}
227+
}
228+
222229
/// Get a new unique block label.
223230
///
224231
/// If `hint` is `None` then the label will be in the form `"blockN"` where N is an

0 commit comments

Comments
 (0)