From 2bf0dde608f4d6f8a04512d8e1f9ce3f233a6fb5 Mon Sep 17 00:00:00 2001 From: "Matthias J. Kannwischer" Date: Mon, 16 Dec 2024 09:05:09 +0800 Subject: [PATCH] selftest: recursively determine register inputs Previously the selftest would determine which registers are supposed to contain addresses (and allocate memory accordingly) by going through all memory operations and assuming that address registers used in those are the inputs holding the addresses initially. This assumption does not hold as (1) addresses may be moved around (2) addresses may actually be a result of a previous computation. One example where this did not work was vmov rX, sY ldr tZ, [rX] here the selftest would assume that rX needs to be an address. However, sY is the register holding the address on entry of the code. This commit refines the code determining the address registers by recursively going through the DFG and determining the _input_ registers that affect values being used as addresses. Note that in the above examples rX would not be marked as an address, at it is not an input. Hopefully this approach is more robust. --- slothy/core/core.py | 2 +- slothy/core/dataflow.py | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/slothy/core/core.py b/slothy/core/core.py index 8cebbafa..889fbc3b 100644 --- a/slothy/core/core.py +++ b/slothy/core/core.py @@ -866,7 +866,7 @@ def selftest(self, log): addr = getattr(t.inst, "addr", None) if addr is None: continue - addresses.add(addr) + addresses = addresses.union(tree.find_all_predecessors_input_registers(t, addr)) # For now, we don't look into increments and immedate offsets # to gauge the amount of memory we actually need. Instaed, we diff --git a/slothy/core/dataflow.py b/slothy/core/dataflow.py index 99830121..3d83bd6c 100644 --- a/slothy/core/dataflow.py +++ b/slothy/core/dataflow.py @@ -780,6 +780,30 @@ def has_symbolic_registers(self): return True return False + def find_all_predecessors_input_registers(self, consumer, register_name): + """ recursively finds the set of input registers registers that a certain value depends on.""" + # ignore the stack pointer + if register_name == "sp": + return set() + + producer = consumer.reg_state[register_name].src + # if this is a virtual input instruction this is an actual input + # otherwise this is computed from other inputs + if isinstance(producer.inst, VirtualInputInstruction): + return set(producer.inst.args_out) + else: + # go through all predecessors and recursively call this function + # Note that we only care about inputs (i.e., produced by a VirtualInputInstruction) + regs = [] + if hasattr(producer.inst, "args_in"): + regs += producer.inst.args_in + if hasattr(producer.inst, "args_in_out"): + regs += producer.inst.args_in_out + predecessors = set() + for reg in regs: + predecessors = predecessors.union(self.find_all_predecessors_input_registers(producer, reg)) + return set(predecessors) + def ssa(self, filter_func=None): """Transform data flow graph into single static assignment (SSA) form.""" # Go through non-virtual instruction nodes and assign unique names to