Skip to content

Commit

Permalink
Devise preprocessing methods, yet to be tested
Browse files Browse the repository at this point in the history
  • Loading branch information
alexcere committed Oct 23, 2024
1 parent 0368637 commit 0a4a0ec
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 0 deletions.
Empty file added src/cfg_methods/__init__.py
Empty file.
63 changes: 63 additions & 0 deletions src/cfg_methods/function_inlining.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""
Module to perform function inlining.
"""
from typing import Set, Dict, Tuple, List
from collections import defaultdict
from parser.cfg_block import CFGBlock
from parser.cfg_block_list import CFGBlockList
from parser.cfg import CFG
from parser.cfg_block_actions.inline_function import InlineFunction


def generate_function2blocks(cfg: CFG) -> Dict[str, List[Tuple[int, CFGBlock, CFGBlockList]]]:
"""
Links each function to the block and block list in which it is used
"""
function2blocks = dict()
for object_id, cfg_object in cfg.objectCFG.items():
function_names = set(cfg_object.functions.keys())
function2blocks.update(generate_function2blocks_block_list(cfg_object.blocks, function_names))

# We also consider the information per function
for cfg_function in cfg_object.functions.values():
function2blocks.update(generate_function2blocks_block_list(cfg_function.blocks, function_names))

sub_object = cfg.get_subobject()

if sub_object is not None:
function2blocks.update(generate_function2blocks_block_list(cfg_object.blocks, function_names))

return function2blocks


def generate_function2blocks_block_list(cfg_block_list: CFGBlockList, function_names: Set[str]) -> \
Dict[str, List[Tuple[int, CFGBlock, CFGBlockList]]]:
"""
Links the function calls that appear in the block list to the exact block and the block list
"""
function2blocks = defaultdict(lambda: [])
for block_name, block in cfg_block_list.blocks.items():
for i, instruction in enumerate(block.get_instructions()):
if instruction.get_op_name() in function_names:
function2blocks[instruction.get_op_name()].append((i, block, cfg_block_list))
return function2blocks


def inline_functions(cfg: CFG, function2blocks: Dict[str, List[Tuple[int, CFGBlock, CFGBlockList]]]) -> None:
"""
Inlines the functions that are invoked just in one place
"""
for object_id, cfg_object in cfg.objectCFG.items():

# We also consider the information per function
for function_name, cfg_function in cfg_object.functions.items():
invocation_list = function2blocks[function_name]
if len(invocation_list) == 1:
pos, cfg_block, cfg_block_list = invocation_list[0]
inline_action = InlineFunction(pos, cfg_block, cfg_block_list, function_name, cfg_object)
inline_action.perform_action()

sub_object = cfg.get_subobject()

if sub_object is not None:
inline_functions(sub_object, function2blocks)
11 changes: 11 additions & 0 deletions src/cfg_methods/jump_insertion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""
Module to insert the JUMP, JUMPI and PUSH [tag] instructions before performing the liveness analysis
"""
from parser.cfg import CFG


def insert_jump_instructions(cfg: CFG):
"""
Introduces the JUMP, JUMPI and PUSH [tag] instructions in the blocks according to the CFG structure
"""
pass
59 changes: 59 additions & 0 deletions src/cfg_methods/sub_block_generation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""
Module used to generate the sub blocks and count how many times each function is invoked.
Same idea as optimizable_block_list but using the cfg actions and simplifying the process
"""
from parser.cfg_block_list import CFGBlockList
from parser.cfg import CFG
import parser.constants as constants
from parser.cfg_block_actions.split_block import SplitBlock


def split_blocks_cfg(cfg: CFG) -> None:
"""
Splits the blocks in the cfg
"""
for object_id, cfg_object in cfg.objectCFG.items():
modify_block_list_split(cfg_object.blocks)

# We also consider the information per function
for function_name, cfg_function in cfg_object.functions.items():
modify_block_list_split(cfg_function.blocks)

sub_object = cfg.get_subobject()

if sub_object is not None:
split_blocks_cfg(sub_object)


def modify_block_list_split(block_list: CFGBlockList) -> None:
"""
Modifies a CFGBlockList by splitting blocks when function calls and split instructions are found
"""
blocks_to_traverse = list(block_list.blocks.items())
new_start_block = None
for block_name, cfg_block in blocks_to_traverse:

# It can be reassigned if the block is split multiple times
current_block = cfg_block
instr_idx = 0

while instr_idx < len(current_block.get_instructions()):
instr = current_block.get_instructions()[instr_idx]

is_split_instr = instr.get_op_name() in constants.split_block
is_function_call = instr.get_op_name() in cfg_block.function_calls
is_jump = instr.get_op_name() in ["JUMP", "JUMPI"]

if is_split_instr or is_function_call or is_jump:
# Sub blocks contain a split instruction or a function call as the last instruction
split_block_action = SplitBlock(instr_idx, current_block, block_list)
split_block_action.perform_action()

# If the current block corresponds to the initial block and we modify it
if new_start_block is None and current_block.block_id == block_list.start_block:
new_start_block = split_block_action.first_half

current_block = split_block_action.second_half
instr_idx = 0
else:
instr_idx += 1

0 comments on commit 0a4a0ec

Please sign in to comment.