sway_ir/optimize/
const_demotion.rs1use crate::{
9 AnalysisResults, Block, Constant, Context, Function, InstOp, IrError, Pass, PassMutability,
10 ScopedPass, Value,
11};
12
13use rustc_hash::FxHashMap;
14use sway_types::FxIndexMap;
15
16pub const CONST_DEMOTION_NAME: &str = "const-demotion";
17
18pub fn create_const_demotion_pass() -> Pass {
19 Pass {
20 name: CONST_DEMOTION_NAME,
21 descr: "Demotion of by-value constants to by-reference",
22 deps: Vec::new(),
23 runner: ScopedPass::FunctionPass(PassMutability::Transform(const_demotion)),
24 }
25}
26
27pub fn const_demotion(
28 context: &mut Context,
29 _: &AnalysisResults,
30 function: Function,
31) -> Result<bool, IrError> {
32 let mut candidate_values: FxIndexMap<Block, Vec<(Value, Constant)>> = FxIndexMap::default();
34
35 for (block, inst) in function.instruction_iter(context) {
36 let operands = inst.get_instruction(context).unwrap().op.get_operands();
37 for val in operands.iter() {
38 if let Some(c) = val.get_constant(context) {
39 if super::target_fuel::is_demotable_type(context, &c.get_content(context).ty) {
40 let dem = (*val, *c);
41 match candidate_values.entry(block) {
42 indexmap::map::Entry::Occupied(mut occ) => {
43 occ.get_mut().push(dem);
44 }
45 indexmap::map::Entry::Vacant(vac) => {
46 vac.insert(vec![dem]);
47 }
48 }
49 }
50 }
51 }
52 }
53
54 if candidate_values.is_empty() {
55 return Ok(false);
56 }
57
58 for (block, cands) in candidate_values {
59 let mut replace_map: FxHashMap<Value, Value> = FxHashMap::default();
60 let mut this_block_new = Vec::new();
62 for (c_val, c) in cands {
63 let var = function.new_unique_local_var(
65 context,
66 "__const".to_owned(),
67 c.get_content(context).ty,
68 Some(c),
69 false,
70 );
71 let var_val = Value::new_instruction(context, block, InstOp::GetLocal(var));
72 let load_val = Value::new_instruction(context, block, InstOp::Load(var_val));
73 replace_map.insert(c_val, load_val);
74 this_block_new.push(var_val);
75 this_block_new.push(load_val);
76 }
77 block.replace_values(context, &replace_map);
78 block.prepend_instructions(context, this_block_new);
79 }
80
81 Ok(true)
82}