Skip to content

Commit

Permalink
Add support for parsing assembly .if .else .endif
Browse files Browse the repository at this point in the history
This hoists out a change from the armv7m branch that adds
support for assembly conditionals.
  • Loading branch information
mkannwischer committed Dec 4, 2024
1 parent 25a6d4a commit 7f5b3c1
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 2 deletions.
3 changes: 2 additions & 1 deletion slothy/core/slothy.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
from slothy.core.core import Config
from slothy.core.heuristics import Heuristics
from slothy.helper import CPreprocessor, SourceLine
from slothy.helper import AsmAllocation, AsmMacro, AsmHelper
from slothy.helper import AsmAllocation, AsmMacro, AsmHelper, AsmIfElse
from slothy.helper import CPreprocessor, LLVM_Mca, LLVM_Mca_Error

class Slothy:
Expand Down Expand Up @@ -251,6 +251,7 @@ def optimize(self, start=None, end=None, loop_synthesis_cb=None, logname=None):
body = SourceLine.split_semicolons(body)
body = AsmMacro.unfold_all_macros(pre, body, inherit_comments=c.inherit_macro_comments)
body = AsmAllocation.unfold_all_aliases(c.register_aliases, body)
body = AsmIfElse.process_instructions(body)
body = SourceLine.apply_indentation(body, indentation)
self.logger.info("Instructions in body: %d", len(list(filter(None, body))))

Expand Down
103 changes: 102 additions & 1 deletion slothy/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@
import subprocess
import logging
from abc import ABC, abstractmethod

from sympy import simplify
from slothy.targets.common import *


class SourceLine:
"""Representation of a single line of source code"""

Expand Down Expand Up @@ -935,6 +936,106 @@ def extract_from_file(filename):
res = AsmMacro.extract(f.read().splitlines())
return res


class AsmIfElse():
_REGEXP_IF_TXT = r"\s*\.if\s+(?P<cond>.*)"
_REGEXP_ELSE_TXT = r"\s*\.else"
_REGEXP_ENDIF_TXT = r"\s*\.endif"

_REGEXP_IF = re.compile(_REGEXP_IF_TXT)
_REGEXP_ELSE = re.compile(_REGEXP_ELSE_TXT)
_REGEXP_ENDIF = re.compile(_REGEXP_ENDIF_TXT)

@staticmethod
def check_if(line):
"""Check if an assembly line is a .req directive. Return the pair
of alias and register, if so. Otherwise, return None."""
assert SourceLine.is_source_line(line)

p = AsmIfElse._REGEXP_IF.match(line.text)
if p is not None:
return p.group("cond")
return None

@staticmethod
def is_if(line):
return AsmIfElse.check_if(line) is not None

@staticmethod
def check_else(line):
"""Check if an assembly line is a .req directive. Return the pair
of alias and register, if so. Otherwise, return None."""
assert SourceLine.is_source_line(line)

p = AsmIfElse._REGEXP_ELSE.match(line.text)
if p is not None:
return True
return None

@staticmethod
def is_else(line):
return AsmIfElse.check_else(line) is not None

@staticmethod
def check_endif(line):
"""Check if an assembly line is a .req directive. Return the pair
of alias and register, if so. Otherwise, return None."""
assert SourceLine.is_source_line(line)

p = AsmIfElse._REGEXP_ENDIF.match(line.text)
if p is not None:
return True
return None

@staticmethod
def is_endif(line):
return AsmIfElse.check_endif(line) is not None

@staticmethod
def evaluate_condition(condition):
"""Evaluates the condition string and returns True or False."""
try:
# Evaluate the condition and return the result.
return simplify(condition)
except Exception as e:
print(f"Error evaluating condition '{condition}': {e}")
return False

@staticmethod
def process_instructions(instructions):
"""Processes a list of instructions with conditional statements."""
output_lines = []
skip_stack = []

for instruction in instructions:
if AsmIfElse.is_if(instruction):
# Extract condition and evaluate it.
condition = AsmIfElse.check_if(instruction)
if AsmIfElse.evaluate_condition(condition):
skip_stack.append(False)
else:
skip_stack.append(True)
continue
elif AsmIfElse.is_else(instruction):
if skip_stack:
# Invert the top of the stack
skip_stack[-1] = not skip_stack[-1]
continue # Skip adding the .else line to output
elif AsmIfElse.is_endif(instruction):
if skip_stack:
skip_stack.pop() # Exit the current .if block
continue # Skip adding the .endif line to output

# Determine if the current line should be skipped
if skip_stack and True in skip_stack:
continue # Skip lines when inside a false .if block

# Add the line to output if not skipped
output_lines.append(instruction)

return output_lines


class CPreprocessor():
"""Helper class for the application of the C preprocessor"""

Expand Down

0 comments on commit 7f5b3c1

Please sign in to comment.