Skip to main content

luaur_code_gen/functions/
try_replace_value_with_full_store.rs

1use crate::enums::ir_cmd::IrCmd;
2use crate::enums::ir_op_kind::IrOpKind;
3use crate::functions::replace_ir_utils_alt_b::replace_ir_function_ir_block_u32_ir_inst;
4use crate::macros::codegen_assert::CODEGEN_ASSERT;
5use crate::macros::has_op_d::HAS_OP_D;
6use crate::records::ir_block::IrBlock;
7use crate::records::ir_builder::IrBuilder;
8use crate::records::ir_function::IrFunction;
9use crate::records::ir_inst::IrInst;
10use crate::records::ir_op::IrOp;
11use crate::records::remove_dead_store_state::RemoveDeadStoreState;
12use crate::records::store_reg_info::StoreRegInfo;
13use crate::type_aliases::ir_ops::IrOps;
14
15fn make_split(target_op: IrOp, tag_op: IrOp, value_op: IrOp) -> IrInst {
16    let mut ops = IrOps::new();
17    ops.push_back(target_op);
18    ops.push_back(tag_op);
19    ops.push_back(value_op);
20    IrInst {
21        cmd: IrCmd::STORE_SPLIT_TVALUE,
22        ops,
23        ..IrInst::default()
24    }
25}
26
27pub fn try_replace_value_with_full_store(
28    state: &mut RemoveDeadStoreState,
29    build: &mut IrBuilder,
30    function: &mut IrFunction,
31    block: &mut IrBlock,
32    inst_index: u32,
33    target_op: IrOp,
34    value_op: IrOp,
35    reg_info: &mut StoreRegInfo,
36) -> bool {
37    // If the tag+value pair is established, we can mark both as dead and use a single split TValue store
38    if reg_info.tag_inst_idx != !0u32 && reg_info.value_inst_idx != !0u32 {
39        let prev_tag_op = function.instructions[reg_info.tag_inst_idx as usize].ops[1];
40        let prev_tag = function.tag_op(prev_tag_op);
41
42        CODEGEN_ASSERT!(reg_info.known_tag == prev_tag);
43        let repl = make_split(target_op, prev_tag_op, value_op);
44        replace_ir_function_ir_block_u32_ir_inst(function, block, inst_index, repl);
45
46        state.kill_tag_store(reg_info);
47        state.kill_value_store(reg_info);
48
49        reg_info.tvalue_inst_idx = inst_index;
50        return true;
51    }
52
53    // We can also replace a dead split TValue store with a new one, while keeping the value the same
54    if reg_info.tvalue_inst_idx != !0u32 {
55        let prev_cmd = function.instructions[reg_info.tvalue_inst_idx as usize].cmd;
56
57        if prev_cmd == IrCmd::STORE_SPLIT_TVALUE {
58            let prev_tag_op = function.instructions[reg_info.tvalue_inst_idx as usize].ops[1];
59            let prev_tag = function.tag_op(prev_tag_op);
60
61            CODEGEN_ASSERT!(reg_info.known_tag == prev_tag);
62            CODEGEN_ASSERT!(!HAS_OP_D!(
63                function.instructions[reg_info.tvalue_inst_idx as usize]
64            ));
65            let repl = make_split(target_op, prev_tag_op, value_op);
66            replace_ir_function_ir_block_u32_ir_inst(function, block, inst_index, repl);
67
68            CODEGEN_ASSERT!(reg_info.tag_inst_idx == !0u32 && reg_info.value_inst_idx == !0u32);
69            state.kill_t_value_store(reg_info);
70
71            reg_info.tvalue_inst_idx = inst_index;
72            return true;
73        } else if prev_cmd == IrCmd::STORE_VECTOR {
74            let prev_tag_op = function.instructions[reg_info.tvalue_inst_idx as usize].ops[4];
75            CODEGEN_ASSERT!(prev_tag_op.kind() != IrOpKind::None);
76            let prev_tag = function.tag_op(prev_tag_op);
77
78            CODEGEN_ASSERT!(reg_info.known_tag == prev_tag);
79            let repl = make_split(target_op, prev_tag_op, value_op);
80            replace_ir_function_ir_block_u32_ir_inst(function, block, inst_index, repl);
81
82            CODEGEN_ASSERT!(reg_info.tag_inst_idx == !0u32 && reg_info.value_inst_idx == !0u32);
83            state.kill_t_value_store(reg_info);
84
85            reg_info.tvalue_inst_idx = inst_index;
86            return true;
87        } else if prev_cmd == IrCmd::STORE_TVALUE
88            && reg_info.known_tag != 0xff
89            && reg_info.tag_inst_idx == !0u32
90        {
91            let prev_tag_op = build.const_tag(reg_info.known_tag);
92            let repl = make_split(target_op, prev_tag_op, value_op);
93            replace_ir_function_ir_block_u32_ir_inst(function, block, inst_index, repl);
94
95            CODEGEN_ASSERT!(reg_info.tag_inst_idx == !0u32 && reg_info.value_inst_idx == !0u32);
96            state.kill_t_value_store(reg_info);
97
98            reg_info.tvalue_inst_idx = inst_index;
99            return true;
100        }
101    }
102
103    false
104}