Skip to content

Commit

Permalink
Special case: functions with no return values that appear by the end …
Browse files Browse the repository at this point in the history
…of a block were not handled correctly
  • Loading branch information
alexcere committed Feb 26, 2025
1 parent 8716390 commit db6e232
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 9 deletions.
11 changes: 8 additions & 3 deletions src/cfg_methods/jump_insertion.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@ def insert_jumps_tags_cfg(cfg: CFG) -> Dict[cfg_object_T, Dict[block_id_T, int]]
# Insert a tag for the initial block of the function
tag_from_tag_dict(start_block_id, tags_object)

# We need to pass an additional parameter as the initial value
return_value = f"out_{function_name}"
cfg_function.arguments.insert(0, return_value)
return_value = None
# We only insert a return value if the function has any return block
if len(cfg_function.blocks.function_return_blocks) > 0:
# We need to pass an additional parameter as the initial value
return_value = f"out_{function_name}"
cfg_function.arguments.insert(0, return_value)

# Insert the tags and jumps of the block list
insert_jumps_tags_block_list(cfg_function.blocks, tags_object, return_value)
Expand Down Expand Up @@ -57,6 +60,8 @@ def insert_jumps_tags_block_list(cfg_block_list: CFGBlockList, tags_dict: Dict[s
return_instruction = block.get_instructions()[-1]
assert return_instruction.op == "functionReturn", "Function return blocks must " \
f"have functionReturn instructions: {return_instruction}"
assert jump_value is not None, "When inserting the tags of a function return, " \
"the jump_value must be not None"
return_instruction.in_args.insert(0, jump_value)


Expand Down
39 changes: 33 additions & 6 deletions src/cfg_methods/sub_block_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ def split_blocks_cfg(cfg: CFG, tags_object: Dict[cfg_object_T, Dict[block_id_T,
"""
for object_id, cfg_object in cfg.objectCFG.items():
tag_dict = tags_object[object_id]
function2tag = {function_name: tag_dict[function.blocks.start_block]
for function_name, function in cfg_object.functions.items()}
function2tag = {}
for function_name, function in cfg_object.functions.items():
# We obtain the tag from the initial block (generate a new one)
start_block_tag = tag_from_tag_dict(function.blocks.start_block, tag_dict)
function2tag[function_name] = start_block_tag

modify_block_list_split(cfg_object.blocks, function2tag, tag_dict)

# We also consider the information per function
Expand Down Expand Up @@ -102,10 +106,33 @@ def modify_block_list_split(block_list: CFGBlockList, function2tag: Dict[functio

# Nevertheless, we check if the last instruction is a split one and set it
last_instr = current_block.get_instructions()[-1] if len(current_block.get_instructions()) > 0 else None
if last_instr is not None and \
last_instr.get_op_name() in itertools.chain(constants.split_block, function2tag.keys(), ["JUMP", "JUMPI"],
constants.terminal_ops):
current_block.split_instruction = last_instr
if last_instr is not None:

# First case: function call. We have to introduce the jumps to invoke the function.
# If this is the last instruction, it means we don't need to jump back, as there is no function return.
# We only jump to the function
tag_function = function2tag.get(last_instr.get_op_name(), None)
if tag_function is not None:

# Again, we need to skip the phi functions for inserting the jump tag
i = 0
while i < len(current_block.get_instructions()) and \
current_block.get_instructions()[i].get_op_name() == "PhiFunction":
i += 1

# We just need to introduce one tag (to invoke the function)
current_block.insert_instruction(i, CFGInstruction("PUSH [tag]", [], [str(tag_function)]))

# We update the in args accordingly
last_instr.in_args = [str(tag_function)] + last_instr.in_args

# The function call is still the split instruction
current_block.split_instruction = last_instr

# Other split instructions: we set the last instruction as a split instruction
elif last_instr.get_op_name() in itertools.chain(constants.split_block, ["JUMP", "JUMPI"],
constants.terminal_ops):
current_block.split_instruction = last_instr


# Methods for generating the CFG graph after the inlining and identifying the sub-blocks
Expand Down

0 comments on commit db6e232

Please sign in to comment.