From f3c1eb0836f6e44ca75277bd0052735f3e723338 Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Sun, 15 Jun 2025 02:05:06 +0200 Subject: [PATCH 01/24] print warning for implicit truncations (asignment only) (TODO: cli) --- m2isar/backends/etiss/instruction_generator.py | 3 ++- m2isar/backends/etiss/instruction_transform.py | 5 +++++ m2isar/backends/etiss/instruction_utils.py | 4 +++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/m2isar/backends/etiss/instruction_generator.py b/m2isar/backends/etiss/instruction_generator.py index 49acb45b..c0de4940 100644 --- a/m2isar/backends/etiss/instruction_generator.py +++ b/m2isar/backends/etiss/instruction_generator.py @@ -46,8 +46,9 @@ def generate_functions(core: arch.CoreDef, static_scalars: bool, decls_only: boo return_type += f'{fn_def.actual_size}' # set up a transformer context and generate code + ignore_trunc_warnings = False context = instruction_utils.TransformerContext(core.constants, core.memories, core.memory_aliases, fn_def.args, fn_def.attributes, - core.functions, 0, core_default_width, core_name, static_scalars, core.intrinsics, generate_coverage, True) + core.functions, 0, core_default_width, core_name, static_scalars, core.intrinsics, generate_coverage, True, ignore_trunc_warnings) logger.debug("generating code for %s", fn_name) diff --git a/m2isar/backends/etiss/instruction_transform.py b/m2isar/backends/etiss/instruction_transform.py index 0e0d62c5..e420eb79 100644 --- a/m2isar/backends/etiss/instruction_transform.py +++ b/m2isar/backends/etiss/instruction_transform.py @@ -471,6 +471,11 @@ def assignment(self: behav.Assignment, context: TransformerContext): context.affected_regs.update(target.regs_affected) context.dependent_regs.update(expr.regs_affected) + # TODO: move to parser! + if target.size < expr.size and not context.ignore_trunc_warnings: + # TODO: add position? + logger.warning("Implicit truncation %d -> %d found", expr.size, target.size) + if not target.is_mem_access and not expr.is_mem_access: if target.actual_size > target.size: if target.signed: diff --git a/m2isar/backends/etiss/instruction_utils.py b/m2isar/backends/etiss/instruction_utils.py index d8424f3d..e20359a4 100644 --- a/m2isar/backends/etiss/instruction_utils.py +++ b/m2isar/backends/etiss/instruction_utils.py @@ -141,7 +141,7 @@ class TransformerContext: def __init__(self, constants: "dict[str, arch.Constant]", memories: "dict[str, arch.Memory]", memory_aliases: "dict[str, arch.Memory]", fields: "dict[str, arch.BitFieldDescr]", attributes: "list[arch.InstrAttribute]", functions: "dict[str, arch.Function]", - instr_size: int, native_size: int, arch_name: str, static_scalars: bool, intrinsics, generate_coverage: bool, ignore_static=False): + instr_size: int, native_size: int, arch_name: str, static_scalars: bool, intrinsics, generate_coverage: bool, ignore_static=False, ignore_trunc_warnings=False): self.constants = constants self.memories = memories @@ -155,6 +155,8 @@ def __init__(self, constants: "dict[str, arch.Constant]", memories: "dict[str, a self.intrinsics = intrinsics self.static_scalars = static_scalars self.generate_coverage = generate_coverage + self.ignore_trunc_warnings = ignore_trunc_warnings + # TODO: warnings as errors? self.ignore_static = ignore_static From fb2473543a6baf546f0c3088123b003d328748a2 Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Sun, 15 Jun 2025 02:06:17 +0200 Subject: [PATCH 02/24] print warning for shift width overflows (TODO: cli & LOC) --- m2isar/backends/etiss/instruction_transform.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/m2isar/backends/etiss/instruction_transform.py b/m2isar/backends/etiss/instruction_transform.py index e420eb79..aaab3fcf 100644 --- a/m2isar/backends/etiss/instruction_transform.py +++ b/m2isar/backends/etiss/instruction_transform.py @@ -537,6 +537,9 @@ def binary_operation(self: behav.BinaryOperation, context: TransformerContext): if not right.static and left.static and not left.is_literal: left.code = context.make_static(left.code, left.signed) + if op.value == "<<" and left.size <= right.size: + # TODO: add LOC + logger.warning("Shift count overflow for << operation (%d vs. %d)", left.size, right.size) c = CodeString(f'{left.code} {op.value} {right.code}', left.static and right.static, left.size if left.size > right.size else right.size, left.signed or right.signed, set.union(left.regs_affected, right.regs_affected), [self.line_info] + left.line_infos + right.line_infos) # keep track of any memory accesses From e495b5805190e10b0661832a3125682ac633783b Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Fri, 4 Jul 2025 18:23:26 +0200 Subject: [PATCH 03/24] add warnings manager --- .../backends/etiss/instruction_generator.py | 12 +-- .../backends/etiss/instruction_transform.py | 8 +- m2isar/backends/etiss/instruction_utils.py | 12 ++- m2isar/backends/etiss/instruction_writer.py | 5 +- m2isar/backends/etiss/warnings.py | 97 +++++++++++++++++++ m2isar/backends/etiss/writer.py | 4 +- 6 files changed, 121 insertions(+), 17 deletions(-) create mode 100644 m2isar/backends/etiss/warnings.py diff --git a/m2isar/backends/etiss/instruction_generator.py b/m2isar/backends/etiss/instruction_generator.py index c0de4940..f981624a 100644 --- a/m2isar/backends/etiss/instruction_generator.py +++ b/m2isar/backends/etiss/instruction_generator.py @@ -15,6 +15,7 @@ from ...metamodel import arch, behav, patch_model from . import BlockEndType, instruction_transform, instruction_utils from .templates import template_dir +from .warnings import WarningsInfo logger = logging.getLogger("instruction_generator") @@ -46,9 +47,8 @@ def generate_functions(core: arch.CoreDef, static_scalars: bool, decls_only: boo return_type += f'{fn_def.actual_size}' # set up a transformer context and generate code - ignore_trunc_warnings = False context = instruction_utils.TransformerContext(core.constants, core.memories, core.memory_aliases, fn_def.args, fn_def.attributes, - core.functions, 0, core_default_width, core_name, static_scalars, core.intrinsics, generate_coverage, True, ignore_trunc_warnings) + core.functions, 0, core_default_width, core_name, static_scalars, core.intrinsics, generate_coverage, True, warnings_info) logger.debug("generating code for %s", fn_name) @@ -140,7 +140,7 @@ def generate_fields(core_default_width, instr_def: arch.Instruction): return (fields_code, asm_printer_code, seen_fields, enc_idx) -def generate_instruction_callback(core: arch.CoreDef, instr_def: arch.Instruction, fields, static_scalars: bool, block_end_on: BlockEndType, generate_coverage: bool): +def generate_instruction_callback(core: arch.CoreDef, instr_def: arch.Instruction, fields, static_scalars: bool, block_end_on: BlockEndType, generate_coverage: bool, warnings_info: WarningsInfo): patch_model(instruction_transform) instr_name = instr_def.name @@ -152,7 +152,7 @@ def generate_instruction_callback(core: arch.CoreDef, instr_def: arch.Instructio callback_template = Template(filename=str(template_dir/'etiss_instruction_callback.mako')) context = instruction_utils.TransformerContext(core.constants, core.memories, core.memory_aliases, instr_def.fields, instr_def.attributes, - core.functions, enc_idx, core_default_width, core_name, static_scalars, core.intrinsics, generate_coverage) + core.functions, enc_idx, core_default_width, core_name, static_scalars, core.intrinsics, generate_coverage, warnings_info) # force a block end if necessary if ((arch.InstrAttribute.NO_CONT in instr_def.attributes @@ -187,7 +187,7 @@ def generate_instruction_callback(core: arch.CoreDef, instr_def: arch.Instructio return callback_str -def generate_instructions(core: arch.CoreDef, static_scalars: bool, block_end_on: BlockEndType, generate_coverage: bool): +def generate_instructions(core: arch.CoreDef, static_scalars: bool, block_end_on: BlockEndType, generate_coverage: bool, warnings_info: WarningsInfo): """Return a generator object to generate instruction behavior code. Uses instruction definitions in the core object. """ @@ -231,7 +231,7 @@ def generate_instructions(core: arch.CoreDef, static_scalars: bool, block_end_on instr_def.operation = new_op instr_def.throws = True - callback_str = generate_instruction_callback(core, instr_def, fields, static_scalars, block_end_on, generate_coverage) + callback_str = generate_instruction_callback(core, instr_def, fields, static_scalars, block_end_on, generate_coverage, warnings_info) # render code for whole instruction templ_str = instr_template.render( diff --git a/m2isar/backends/etiss/instruction_transform.py b/m2isar/backends/etiss/instruction_transform.py index aaab3fcf..4fad6e93 100644 --- a/m2isar/backends/etiss/instruction_transform.py +++ b/m2isar/backends/etiss/instruction_transform.py @@ -472,9 +472,9 @@ def assignment(self: behav.Assignment, context: TransformerContext): context.dependent_regs.update(expr.regs_affected) # TODO: move to parser! - if target.size < expr.size and not context.ignore_trunc_warnings: - # TODO: add position? - logger.warning("Implicit truncation %d -> %d found", expr.size, target.size) + # if target.size < expr.size and not context.ignore_trunc_warnings: + if target.size < expr.size: + context.emit_warning(f"Implicit truncation {expr.size} -> {target.size} found", "implicit-trunc", logger=logger, line_info=self.line_info) if not target.is_mem_access and not expr.is_mem_access: if target.actual_size > target.size: @@ -539,7 +539,7 @@ def binary_operation(self: behav.BinaryOperation, context: TransformerContext): if op.value == "<<" and left.size <= right.size: # TODO: add LOC - logger.warning("Shift count overflow for << operation (%d vs. %d)", left.size, right.size) + context.emit_warning(f"Shift count overflow for << operation ({left.size} vs. {right.size})", "shift-overflow", logger=logger, line_info=self.line_info) c = CodeString(f'{left.code} {op.value} {right.code}', left.static and right.static, left.size if left.size > right.size else right.size, left.signed or right.signed, set.union(left.regs_affected, right.regs_affected), [self.line_info] + left.line_infos + right.line_infos) # keep track of any memory accesses diff --git a/m2isar/backends/etiss/instruction_utils.py b/m2isar/backends/etiss/instruction_utils.py index e20359a4..2f13b86b 100644 --- a/m2isar/backends/etiss/instruction_utils.py +++ b/m2isar/backends/etiss/instruction_utils.py @@ -17,6 +17,7 @@ from ...metamodel.code_info import LineInfo from ...metamodel.utils import StaticType from . import replacements +from .warnings import WarningsManager data_type_map = { arch.DataType.S: 'etiss_int', @@ -134,14 +135,19 @@ def format(self, mapping={}, **kwargs): setattr(self, name, formatted) -class TransformerContext: +class EtissWriterWarningsManager(WarningsManager): + pass + + +class TransformerContext(EtissWriterWarningsManager): """Track miscellaneous information throughout the code generation process. Also provides helper functions for staticness conversion etc. """ def __init__(self, constants: "dict[str, arch.Constant]", memories: "dict[str, arch.Memory]", memory_aliases: "dict[str, arch.Memory]", fields: "dict[str, arch.BitFieldDescr]", attributes: "list[arch.InstrAttribute]", functions: "dict[str, arch.Function]", - instr_size: int, native_size: int, arch_name: str, static_scalars: bool, intrinsics, generate_coverage: bool, ignore_static=False, ignore_trunc_warnings=False): + instr_size: int, native_size: int, arch_name: str, static_scalars: bool, intrinsics, generate_coverage: bool, ignore_static: bool = False, warnings_info: WarningsInfo = None): + super().__init__(warnings_info) self.constants = constants self.memories = memories @@ -155,8 +161,6 @@ def __init__(self, constants: "dict[str, arch.Constant]", memories: "dict[str, a self.intrinsics = intrinsics self.static_scalars = static_scalars self.generate_coverage = generate_coverage - self.ignore_trunc_warnings = ignore_trunc_warnings - # TODO: warnings as errors? self.ignore_static = ignore_static diff --git a/m2isar/backends/etiss/instruction_writer.py b/m2isar/backends/etiss/instruction_writer.py index d852f062..b5bdd061 100644 --- a/m2isar/backends/etiss/instruction_writer.py +++ b/m2isar/backends/etiss/instruction_writer.py @@ -18,6 +18,7 @@ from . import BlockEndType from .instruction_generator import generate_functions, generate_instructions from .templates import template_dir +from .warnings import WarningsInfo logger = logging.getLogger("instruction_writer") @@ -69,7 +70,7 @@ def write_functions(core: arch.CoreDef, start_time: str, output_path: pathlib.Pa funcs_f.write("// clang-format on\n") def write_instructions(core: arch.CoreDef, start_time: str, output_path: pathlib.Path, separate: bool, static_scalars: bool, - block_end_on: BlockEndType, generate_coverage: bool): + block_end_on: BlockEndType, generate_coverage: bool, warnings_info: WarningsInfo): """Generate and write the instruction model C++ files for ETISS.""" instr_set_template = Template(filename=str(template_dir/'etiss_instruction_set.mako')) @@ -103,7 +104,7 @@ def write_instructions(core: arch.CoreDef, start_time: str, output_path: pathlib out_f.write(instr_set_str) # generate instruction behavior models - for instr_name, _, ext_name, templ_str in generate_instructions(core, static_scalars, block_end_on, generate_coverage): + for instr_name, _, ext_name, templ_str in generate_instructions(core, static_scalars, block_end_on, generate_coverage, warnings_info): logger.debug("writing instruction %s", instr_name) outfiles.get(ext_name, outfiles['default']).write(templ_str) for outfile in outfiles.values(): diff --git a/m2isar/backends/etiss/warnings.py b/m2isar/backends/etiss/warnings.py new file mode 100644 index 00000000..0902876b --- /dev/null +++ b/m2isar/backends/etiss/warnings.py @@ -0,0 +1,97 @@ +import argparse +from dataclasses import dataclass +from typing import Set + +KNOWN_WARNINGS = { + 'implicit-trunc', + 'shift-outofrange', + 'implicit-extend', + 'signed-compare', + 'unused-value', +} + + +@dataclass +class WarningsInfo: + known: Set[str] = default + defaults: Set[str] = {} + enabled: Set[str] = {} + disabled: Set[str] = {} + as_error: Set[str] = {} + all_as_error: bool = False + + @property + def warnings(self): + return self.defaults - self.disabled + self.enabled + + @property + def errors(self): + return self.as_error if not self.all_as_error else self.warnings + + +class WarningFlagAction(argparse.Action): + def __call__(self, parser, namespace, values, option_string=None): + warnings_info = getattr(namespace, 'warnings_info', WarningsInfo()) + + for val in values: + if val.startswith('no-'): + warn = val[3:] + assert warn in warnings_info.known, f"Unknown warning: {warn}" + disabled.add(warn) + elif val.startswith('error='): + warn = val[6:] + assert warn in warnings_info.known, f"Unknown warning: {warn}" + error_set.add(warn) + elif val == 'error': + all_as_error = True + elif val == 'all': + warnings_info.enabled.update(warnings_info.known) + else: + assert warn in warnings_info.known, f"Unknown warning: {val}" + enabled.add(val) + # No need for -Wall as all warnings are enabled by default + + setattr(namespace, 'warnings_info', warnings_info) + +def add_warnings_flags(parser, known_warnings: Set[str], default_warnings: Set[str]): + parser.add_argument( + '-W', + dest='warnings', + metavar='warning', + action=WarningFlagAction, + nargs='+', + help=( + "Enable/disable warnings like -Wfoo or -Wno-foo; " + "Make fatal with -Werror or -Werror=foo" + ), + ) + + # Defaults + warnings_info = WarningsInfo(known=known_warnings, default=default_warnings) + parser.set_defaults(enabled_warnings=warnings_info) + + +class WarningsManager: + def __init__(self, warnings_info: WarningsInfo): + self.warnings_info = warnings_info + + # TODO: warnings as errors? + def emit_warning(self, msg, name=None, logger=None, line_info=None): + log_warn_f = logging.warning if logger is None else logger.warning + log_err_f = logging.error if logger is None else logger.error + assert name in self.warnings_info.known, f"Unknown warning: {name}" + is_err = name in self.warnings_info.errors + if name not in self.wwarnings_info.warnings: + # do nothing + return + log_f = log_err_f if is_err else log_warn_f + if name is not None: + msg += f" [-W{name}]" + if line_info is not None: + line_info_str = f"{line_info.file_path}:{line_info.start_line_no}" + msg += f" @ {line_info_str}" + log_f(msg) + if is_err: + raise RuntimeError(msg) + + diff --git a/m2isar/backends/etiss/writer.py b/m2isar/backends/etiss/writer.py index bd1b41ff..e232ffea 100755 --- a/m2isar/backends/etiss/writer.py +++ b/m2isar/backends/etiss/writer.py @@ -26,6 +26,7 @@ write_arch_specific_header, write_arch_struct) from .instruction_writer import write_functions, write_instructions +from .warnings import add_warnings_flags class BooleanOptionalAction(argparse.Action): @@ -85,6 +86,7 @@ def setup(): help="Force end translation blocks on no instructions, uncoditional jumps or all jumps.") parser.add_argument("--coverage", action=BooleanOptionalAction, default=False, help="Generate coverage tracking code into model.") parser.add_argument("--log", default="info", choices=["critical", "error", "warning", "info", "debug"]) + add_warnings_flags(parser) args = parser.parse_args() # configure logging @@ -172,7 +174,7 @@ def main(): write_arch_cmake(core, start_time, output_path, args.separate) write_arch_gdbcore(core, start_time, output_path) write_functions(core, start_time, output_path, args.static_scalars, args.coverage) - write_instructions(core, start_time, output_path, args.separate, args.static_scalars, BlockEndType[args.block_end_on.upper()], args.coverage) + write_instructions(core, start_time, output_path, args.separate, args.static_scalars, BlockEndType[args.block_end_on.upper()], args.coverage, args.warnings_info) with open(output_path / "coverage.csv", "w") as f: for c_id, c_info in sorted(CodeInfoTracker.tracker[core_name].items()): From 234df0c08041207019acdfbeecf196d0345370d5 Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Mon, 13 Apr 2026 08:54:40 +0200 Subject: [PATCH 04/24] warnings: fixes --- m2isar/backends/etiss/architecture_writer.py | 2 +- .../backends/etiss/instruction_generator.py | 4 +-- m2isar/backends/etiss/instruction_utils.py | 2 +- m2isar/backends/etiss/instruction_writer.py | 6 ++-- m2isar/backends/etiss/warnings.py | 33 +++++++++++-------- m2isar/backends/etiss/writer.py | 8 ++--- 6 files changed, 30 insertions(+), 25 deletions(-) diff --git a/m2isar/backends/etiss/architecture_writer.py b/m2isar/backends/etiss/architecture_writer.py index 6bb671d3..bc69f8f7 100644 --- a/m2isar/backends/etiss/architecture_writer.py +++ b/m2isar/backends/etiss/architecture_writer.py @@ -201,7 +201,7 @@ def write_arch_specific_cpp(core: arch.CoreDef, start_time: str, output_path: pa error_instr._size = bitsize # pylint: disable=protected-access error_fields = generate_fields(32, error_instr) - error_callbacks[bitsize] = generate_instruction_callback(core, error_instr, error_fields, True, BlockEndType.NONE, False) + error_callbacks[bitsize] = generate_instruction_callback(core, error_instr, error_fields, True, BlockEndType.NONE, False, None) logger.info("writing architecture specific file") diff --git a/m2isar/backends/etiss/instruction_generator.py b/m2isar/backends/etiss/instruction_generator.py index f981624a..005081fe 100644 --- a/m2isar/backends/etiss/instruction_generator.py +++ b/m2isar/backends/etiss/instruction_generator.py @@ -23,7 +23,7 @@ def generate_arg_str(arg: arch.FnParam): arg_name = f" {arg.name}" if arg.name is not None else "" return f'{instruction_utils.data_type_map[arg.data_type]}{arg.actual_size}{arg_name}' -def generate_functions(core: arch.CoreDef, static_scalars: bool, decls_only: bool, generate_coverage: bool): +def generate_functions(core: arch.CoreDef, static_scalars: bool, decls_only: bool, generate_coverage: bool, warnings_info: WarningsInfo): """Return a generator object to generate function behavior code. Uses function definitions in the core object. """ @@ -152,7 +152,7 @@ def generate_instruction_callback(core: arch.CoreDef, instr_def: arch.Instructio callback_template = Template(filename=str(template_dir/'etiss_instruction_callback.mako')) context = instruction_utils.TransformerContext(core.constants, core.memories, core.memory_aliases, instr_def.fields, instr_def.attributes, - core.functions, enc_idx, core_default_width, core_name, static_scalars, core.intrinsics, generate_coverage, warnings_info) + core.functions, enc_idx, core_default_width, core_name, static_scalars, core.intrinsics, generate_coverage, False, warnings_info) # force a block end if necessary if ((arch.InstrAttribute.NO_CONT in instr_def.attributes diff --git a/m2isar/backends/etiss/instruction_utils.py b/m2isar/backends/etiss/instruction_utils.py index 2f13b86b..9df52d8a 100644 --- a/m2isar/backends/etiss/instruction_utils.py +++ b/m2isar/backends/etiss/instruction_utils.py @@ -17,7 +17,7 @@ from ...metamodel.code_info import LineInfo from ...metamodel.utils import StaticType from . import replacements -from .warnings import WarningsManager +from .warnings import WarningsManager, WarningsInfo data_type_map = { arch.DataType.S: 'etiss_int', diff --git a/m2isar/backends/etiss/instruction_writer.py b/m2isar/backends/etiss/instruction_writer.py index b5bdd061..2eff89f2 100644 --- a/m2isar/backends/etiss/instruction_writer.py +++ b/m2isar/backends/etiss/instruction_writer.py @@ -22,7 +22,7 @@ logger = logging.getLogger("instruction_writer") -def write_functions(core: arch.CoreDef, start_time: str, output_path: pathlib.Path, static_scalars: bool, generate_coverage: bool): +def write_functions(core: arch.CoreDef, start_time: str, output_path: pathlib.Path, static_scalars: bool, generate_coverage: bool, warnings_info: WarningsInfo): """Generate and write the {CoreName}Funcs.h file for ETISS.""" fn_set_header_template = Template(filename=str(template_dir/'etiss_function_set_header.mako')) @@ -45,7 +45,7 @@ def write_functions(core: arch.CoreDef, start_time: str, output_path: pathlib.Pa funcs_f.write(" // clang-format off\n") # generate and write function declarations - for fn_name, templ_str in generate_functions(core, static_scalars, True, generate_coverage): + for fn_name, templ_str in generate_functions(core, static_scalars, True, generate_coverage, warnings_info): logger.debug("writing function decl %s", fn_name) funcs_f.write(templ_str) @@ -64,7 +64,7 @@ def write_functions(core: arch.CoreDef, start_time: str, output_path: pathlib.Pa funcs_f.write("// clang-format off\n") # generate and write function definitions - for fn_name, templ_str in generate_functions(core, static_scalars, False, generate_coverage): + for fn_name, templ_str in generate_functions(core, static_scalars, False, generate_coverage, warnings_info): logger.debug("writing function def %s", fn_name) funcs_f.write(templ_str) funcs_f.write("// clang-format on\n") diff --git a/m2isar/backends/etiss/warnings.py b/m2isar/backends/etiss/warnings.py index 0902876b..c1ccdab0 100644 --- a/m2isar/backends/etiss/warnings.py +++ b/m2isar/backends/etiss/warnings.py @@ -1,5 +1,5 @@ import argparse -from dataclasses import dataclass +from dataclasses import dataclass, field from typing import Set KNOWN_WARNINGS = { @@ -13,16 +13,18 @@ @dataclass class WarningsInfo: - known: Set[str] = default - defaults: Set[str] = {} - enabled: Set[str] = {} - disabled: Set[str] = {} - as_error: Set[str] = {} + # known: Set[str] = field(default_factory=set) + known: Set[str] = field(default_factory=lambda: set(KNOWN_WARNINGS)) + # defaults: Set[str] = field(default_factory=set) + defaults: Set[str] = field(default_factory=lambda: set(KNOWN_WARNINGS)) + enabled: Set[str] = field(default_factory=set) + disabled: Set[str] = field(default_factory=set) + as_error: Set[str] = field(default_factory=set) all_as_error: bool = False @property def warnings(self): - return self.defaults - self.disabled + self.enabled + return (self.defaults - self.disabled) | self.enabled @property def errors(self): @@ -37,21 +39,22 @@ def __call__(self, parser, namespace, values, option_string=None): if val.startswith('no-'): warn = val[3:] assert warn in warnings_info.known, f"Unknown warning: {warn}" - disabled.add(warn) + warnings_info.disabled.add(warn) elif val.startswith('error='): warn = val[6:] assert warn in warnings_info.known, f"Unknown warning: {warn}" - error_set.add(warn) + warnings_info.error_set.add(warn) elif val == 'error': - all_as_error = True + warnings_info.all_as_error = True elif val == 'all': warnings_info.enabled.update(warnings_info.known) else: + warn = val[3:] assert warn in warnings_info.known, f"Unknown warning: {val}" - enabled.add(val) + warnings_info.enabled.add(val) # No need for -Wall as all warnings are enabled by default - setattr(namespace, 'warnings_info', warnings_info) + setattr(namespace, 'warnings', warnings_info) def add_warnings_flags(parser, known_warnings: Set[str], default_warnings: Set[str]): parser.add_argument( @@ -67,7 +70,7 @@ def add_warnings_flags(parser, known_warnings: Set[str], default_warnings: Set[s ) # Defaults - warnings_info = WarningsInfo(known=known_warnings, default=default_warnings) + warnings_info = WarningsInfo(known=known_warnings, defaults=default_warnings) parser.set_defaults(enabled_warnings=warnings_info) @@ -79,9 +82,11 @@ def __init__(self, warnings_info: WarningsInfo): def emit_warning(self, msg, name=None, logger=None, line_info=None): log_warn_f = logging.warning if logger is None else logger.warning log_err_f = logging.error if logger is None else logger.error + if self.warnings_info is None: + return # ignore assert name in self.warnings_info.known, f"Unknown warning: {name}" is_err = name in self.warnings_info.errors - if name not in self.wwarnings_info.warnings: + if name not in self.warnings_info.warnings: # do nothing return log_f = log_err_f if is_err else log_warn_f diff --git a/m2isar/backends/etiss/writer.py b/m2isar/backends/etiss/writer.py index e232ffea..8906fc5a 100755 --- a/m2isar/backends/etiss/writer.py +++ b/m2isar/backends/etiss/writer.py @@ -26,7 +26,7 @@ write_arch_specific_header, write_arch_struct) from .instruction_writer import write_functions, write_instructions -from .warnings import add_warnings_flags +from .warnings import add_warnings_flags, KNOWN_WARNINGS class BooleanOptionalAction(argparse.Action): @@ -86,7 +86,7 @@ def setup(): help="Force end translation blocks on no instructions, uncoditional jumps or all jumps.") parser.add_argument("--coverage", action=BooleanOptionalAction, default=False, help="Generate coverage tracking code into model.") parser.add_argument("--log", default="info", choices=["critical", "error", "warning", "info", "debug"]) - add_warnings_flags(parser) + add_warnings_flags(parser, KNOWN_WARNINGS, KNOWN_WARNINGS) args = parser.parse_args() # configure logging @@ -173,8 +173,8 @@ def main(): write_arch_lib(core, start_time, output_path) write_arch_cmake(core, start_time, output_path, args.separate) write_arch_gdbcore(core, start_time, output_path) - write_functions(core, start_time, output_path, args.static_scalars, args.coverage) - write_instructions(core, start_time, output_path, args.separate, args.static_scalars, BlockEndType[args.block_end_on.upper()], args.coverage, args.warnings_info) + write_functions(core, start_time, output_path, args.static_scalars, args.coverage, args.warnings) + write_instructions(core, start_time, output_path, args.separate, args.static_scalars, BlockEndType[args.block_end_on.upper()], args.coverage, args.warnings) with open(output_path / "coverage.csv", "w") as f: for c_id, c_info in sorted(CodeInfoTracker.tracker[core_name].items()): From b284f1cab96677846e253d2883debb8df102bcff Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Mon, 13 Apr 2026 08:54:54 +0200 Subject: [PATCH 05/24] warnings: drop comment --- m2isar/backends/etiss/instruction_transform.py | 1 - 1 file changed, 1 deletion(-) diff --git a/m2isar/backends/etiss/instruction_transform.py b/m2isar/backends/etiss/instruction_transform.py index 4fad6e93..9a76c1c1 100644 --- a/m2isar/backends/etiss/instruction_transform.py +++ b/m2isar/backends/etiss/instruction_transform.py @@ -538,7 +538,6 @@ def binary_operation(self: behav.BinaryOperation, context: TransformerContext): left.code = context.make_static(left.code, left.signed) if op.value == "<<" and left.size <= right.size: - # TODO: add LOC context.emit_warning(f"Shift count overflow for << operation ({left.size} vs. {right.size})", "shift-overflow", logger=logger, line_info=self.line_info) c = CodeString(f'{left.code} {op.value} {right.code}', left.static and right.static, left.size if left.size > right.size else right.size, left.signed or right.signed, set.union(left.regs_affected, right.regs_affected), [self.line_info] + left.line_infos + right.line_infos) From 790a44dd5945528de74fb8075166070794f78cef Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Mon, 13 Apr 2026 08:55:20 +0200 Subject: [PATCH 06/24] warnings: add shift-signed & sign-compare --- m2isar/backends/etiss/instruction_transform.py | 10 ++++++++++ m2isar/backends/etiss/warnings.py | 5 +++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/m2isar/backends/etiss/instruction_transform.py b/m2isar/backends/etiss/instruction_transform.py index 9a76c1c1..20b0c7a2 100644 --- a/m2isar/backends/etiss/instruction_transform.py +++ b/m2isar/backends/etiss/instruction_transform.py @@ -530,6 +530,16 @@ def binary_operation(self: behav.BinaryOperation, context: TransformerContext): left = self.left.generate(context) op = self.op right = self.right.generate(context) + if op.value in ["<<", ">>", ">>>"] and right.signed: + context.emit_warning(f"Shift by signed amount", "shift-signed", logger=logger, line_info=self.line_info) + if op.value in ["<", "<=", ">", ">=", "==", "!="] and left.signed != right.signed: + # TODO: handle unsigned < 0 + if left.static and left.is_literal and left.code == "0": + pass + elif right.static and right.is_literal and right.code == "0": + pass + else: + context.emit_warning(f"Signed vs. unsigned comparison", "sign-compare", logger=logger, line_info=self.line_info) # convert staticness if needed if not left.static and right.static and not right.is_literal: diff --git a/m2isar/backends/etiss/warnings.py b/m2isar/backends/etiss/warnings.py index c1ccdab0..968e3ff4 100644 --- a/m2isar/backends/etiss/warnings.py +++ b/m2isar/backends/etiss/warnings.py @@ -4,9 +4,10 @@ KNOWN_WARNINGS = { 'implicit-trunc', - 'shift-outofrange', + 'shift-overflow', + 'shift-signed', 'implicit-extend', - 'signed-compare', + 'sign-compare', 'unused-value', } From ba433c03cf32aac30b77545e1440b1e18f430e24 Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Wed, 15 Apr 2026 17:00:04 +0200 Subject: [PATCH 07/24] fix warnings manager --- m2isar/backends/etiss/warnings.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/m2isar/backends/etiss/warnings.py b/m2isar/backends/etiss/warnings.py index 968e3ff4..ee5499fc 100644 --- a/m2isar/backends/etiss/warnings.py +++ b/m2isar/backends/etiss/warnings.py @@ -37,7 +37,9 @@ def __call__(self, parser, namespace, values, option_string=None): warnings_info = getattr(namespace, 'warnings_info', WarningsInfo()) for val in values: - if val.startswith('no-'): + if val == 'no-error': + warnings_info.all_as_error = False + elif val.startswith('no-'): warn = val[3:] assert warn in warnings_info.known, f"Unknown warning: {warn}" warnings_info.disabled.add(warn) @@ -72,7 +74,7 @@ def add_warnings_flags(parser, known_warnings: Set[str], default_warnings: Set[s # Defaults warnings_info = WarningsInfo(known=known_warnings, defaults=default_warnings) - parser.set_defaults(enabled_warnings=warnings_info) + parser.set_defaults(warnings=warnings_info) class WarningsManager: From 5d0f39c3f4123cdb0b12dc10c944afd7779e703f Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Wed, 15 Apr 2026 17:00:29 +0200 Subject: [PATCH 08/24] m2isar/metamodel/__init__.py: add helpers load_model & dump_model --- m2isar/metamodel/__init__.py | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/m2isar/metamodel/__init__.py b/m2isar/metamodel/__init__.py index e6268df2..55c0b155 100644 --- a/m2isar/metamodel/__init__.py +++ b/m2isar/metamodel/__init__.py @@ -28,8 +28,11 @@ the hierarchy. """ +import pickle import inspect import logging +from typing import Union +from pathlib import Path from dataclasses import dataclass from . import arch, behav, code_info @@ -91,3 +94,38 @@ def __post_init__(self): self.line_infos[idx] = c elif isinstance(c, code_info.FunctionInfo): self.function_infos[idx] = c + + +def load_model( + model_path: Union[str, Path], allow_missmatch: bool = False +) -> M2Model: + logger = logging.getLogger("load_model") + logger.debug("loading model: %s", str(model_path)) + with open(model_path, "rb") as f: + # models: "dict[str, arch.CoreDef]" = pickle.load(f) + # sets: "dict[str, arch.InstructionSet]" = pickle.load(f) + model_obj: M2Model = pickle.load(f) + assert isinstance(model_obj, M2Model), "Expected M2Model" + required_version = M2_METAMODEL_VERSION + if model_obj.model_version != required_version: + err_handler = logger.warning if allow_missmatch else RuntimeError + err_handler("Loaded model version mismatch") + return model_obj + + +def dump_model( + model_obj: M2Model, out_path: Union[str, Path], ignore_suffix: bool = False +): + logger = logging.getLogger("dump_model") + if not ignore_suffix: + out_path = Path(out_path) + suffix = out_path.suffix + required_suffix = ".m2isarmodel" + if suffix not in [required_suffix]: + assert len(suffix) == 0, f"Invalid suffix: {suffix}" + out_path = out_path.parent / f"{out_path.stem}{required_suffix}" + else: + assert suffix == required_suffix, f"Invalid suffix: {suffix}, Expected: {required_suffix}" + logger.debug("dumping model: %s", out_path) + with open(out_path, "wb") as f: + pickle.dump(model_obj, f) From 9b511fb72d8041acb336637f151c46849894544a Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Wed, 15 Apr 2026 17:00:53 +0200 Subject: [PATCH 09/24] m2isar/metamodel/arch.py: add __repr__ method for DataType --- m2isar/metamodel/arch.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/m2isar/metamodel/arch.py b/m2isar/metamodel/arch.py index adcd7e9f..88b6ed8e 100644 --- a/m2isar/metamodel/arch.py +++ b/m2isar/metamodel/arch.py @@ -266,6 +266,13 @@ def width(self): return get_const_or_val(self._width) + def __str__(self) -> str: + return f'{super().__repr__()}, width={self.width}, signed={self.signed}' + + def __repr__(self): + return self.__str__() + + @property def actual_width(self): """Returns the resolved width value rounded to the nearest multiple of 8.""" From d65c3359d4fbdceeee6b5931224cf829464edd74 Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Wed, 15 Apr 2026 17:01:11 +0200 Subject: [PATCH 10/24] add m2isar/transforms/__init__.py --- m2isar/transforms/__init__.py | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 m2isar/transforms/__init__.py diff --git a/m2isar/transforms/__init__.py b/m2isar/transforms/__init__.py new file mode 100644 index 00000000..044d6037 --- /dev/null +++ b/m2isar/transforms/__init__.py @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# This file is part of the M2-ISA-R project: https://github.com/tum-ei-eda/M2-ISA-R +# +# Copyright (C) 2024 +# Chair of Electrical Design Automation +# Technical University of Munich + +"""This module contains various transforms for M2-ISA-R models.""" From 963db922d415df88ac08a1e1f37d286e6c9ccbca Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Wed, 15 Apr 2026 17:01:22 +0200 Subject: [PATCH 11/24] add m2isar/transforms/infer_types --- m2isar/transforms/infer_types/__init__.py | 9 + m2isar/transforms/infer_types/transform.py | 69 +++ m2isar/transforms/infer_types/visitor.py | 470 +++++++++++++++++++++ 3 files changed, 548 insertions(+) create mode 100644 m2isar/transforms/infer_types/__init__.py create mode 100644 m2isar/transforms/infer_types/transform.py create mode 100644 m2isar/transforms/infer_types/visitor.py diff --git a/m2isar/transforms/infer_types/__init__.py b/m2isar/transforms/infer_types/__init__.py new file mode 100644 index 00000000..9e0ff52b --- /dev/null +++ b/m2isar/transforms/infer_types/__init__.py @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# This file is part of the M2-ISA-R project: https://github.com/tum-ei-eda/M2-ISA-R +# +# Copyright (C) 2024 +# Chair of Electrical Design Automation +# Technical University of Munich + +"""This module contains a type inference pass for M2-ISA-R models.""" diff --git a/m2isar/transforms/infer_types/transform.py b/m2isar/transforms/infer_types/transform.py new file mode 100644 index 00000000..149e3056 --- /dev/null +++ b/m2isar/transforms/infer_types/transform.py @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# This file is part of the M2-ISA-R project: https://github.com/tum-ei-eda/M2-ISA-R +# +# Copyright (C) 2022 +# Chair of Electrical Design Automation +# Technical University of Munich + +"""Type inference for M2-ISA-R metamodel.""" + +import sys +import argparse +import logging +import pathlib + +from m2isar.metamodel import patch_model, load_model, dump_model + +from . import visitor + + +def get_parser(): + # read command line args + parser = argparse.ArgumentParser() + parser.add_argument("top_level", help="A .m2isarmodel file.") + parser.add_argument("--log", default="info", choices=["critical", "error", "warning", "info", "debug"]) + parser.add_argument("--output", "-o", type=str, default=None) + return parser + + +def run(args): + # initialize logging + logging.basicConfig(level=getattr(logging, args.log.upper())) + logger = logging.getLogger("infer_types") + logger.setLevel(getattr(logging, args.log.upper())) + + # resolve model paths + top_level = pathlib.Path(args.top_level) + + out_path = (top_level.parent / top_level.stem) if args.output is None else args.output + print("out_path", out_path) + + model_obj = load_model(top_level) + + for _, core_def in model_obj.cores.items(): + logger.debug("inferring types for core %s", core_def.name) + patch_model(visitor) + for _, instr_def in core_def.instructions.items(): + logger.debug("inferring types for instr %s", instr_def.name) + instr_def.operation.generate(None) + # input("!") + for _, set_def in model_obj.sets.items(): + logger.debug("inferring types for set %s", set_def.name) + patch_model(visitor) + for _, instr_def in set_def.instructions.items(): + logger.debug("inferring types for instr %s", instr_def.name) + instr_def.operation.generate(None) + # input("!") + + dump_model(model_obj, out_path) + + +def main(argv): + parser = get_parser() + args = parser.parse_args(argv) + run(args) + + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/m2isar/transforms/infer_types/visitor.py b/m2isar/transforms/infer_types/visitor.py new file mode 100644 index 00000000..5d8297f0 --- /dev/null +++ b/m2isar/transforms/infer_types/visitor.py @@ -0,0 +1,470 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# This file is part of the M2-ISA-R project: https://github.com/tum-ei-eda/M2-ISA-R +# +# Copyright (C) 2022 +# Chair of Electrical Design Automation +# Technical University of Munich + +"""A transformation module for simplifying M2-ISA-R behavior expressions. The following +simplifications are done: + +* Resolvable :class:`m2isar.metamodel.arch.Constant` s are replaced by + `m2isar.metamodel.arch.IntLiteral` s representing their value +* Fully resolvable arithmetic operations are carried out and their results + represented as a matching :class:`m2isar.metamodel.arch.IntLiteral` +* Conditions and loops with fully resolvable conditions are either discarded entirely + or transformed into code blocks without any conditions +* Ternaries with fully resolvable conditions are transformed into only the matching part +* Type conversions of :class:`m2isar.metamodel.arch.IntLiteral` s apply the desired + type directly to the :class:`IntLiteral` and discard the type conversion +""" + +import logging +from copy import copy + +from m2isar.metamodel import arch, behav + +logger = logging.getLogger("infer_types") + +# pylint: disable=unused-argument + + +def operation(self: behav.Operation, context): + print("operation", operation) + statements = [] + for stmt in self.statements: + # try: + temp = stmt.generate(context) + if isinstance(temp, list): + statements.extend(temp) + else: + statements.append(temp) + # except (NotImplementedError, ValueError): + # print(f"cant simplify {stmt}") + + self.statements = statements + return self + + +def binary_operation(self: behav.BinaryOperation, context): + print("binary_operation") + print("self.op.value", self.op.value) + + self.left = self.left.generate(context) + self.right = self.right.generate(context) + print("self.left", self.left) + print("self.right", self.right) + + print("self.left.inferred_type", self.left.inferred_type) + print("self.right.inferred_type", self.right.inferred_type) + print("self.inferred_type_", self.inferred_type) + + # see: https://github.com/Minres/CoreDSL/wiki/Expressions#arithmetic-type-rules + if self.op.value in ["+", "-", "*", "/", "%", "|", "&", "^", "<<", ">>"]: + if self.left.inferred_type is None or self.right.inferred_type is None: + logger.warning("Slice Operation needs inferred type. Skipping...") + self.inferred_type = None + return self + assert isinstance(self.left.inferred_type, arch.IntegerType) + assert isinstance(self.right.inferred_type, arch.IntegerType) + w1 = self.left.inferred_type._width + w2 = self.right.inferred_type._width + s1 = self.left.inferred_type.signed + s2 = self.right.inferred_type.signed + if self.op.value == "+": + if not s1 and not s2: + wr = max(w1, w2) + 1 + sr = False + elif s1 and s2: + wr = max(w1, w2) + 1 + sr = True + elif s1 and not s2: + wr = max(w1, w2 + 1) + 1 + sr = True + elif not s1 and s2: + wr = max(w1 + 1, w2) + 1 + sr = True + elif self.op.value == "-": + sr = True + if not s1 and not s2: + wr = max(w1 + 1, w2 + 1) + elif s1 and s2: + wr = max(w1 + 1, w2 + 1) + elif s1 and not s2: + wr = max(w1, w2 + 1) + 1 + elif not s1 and s2: + wr = max(w1 + 1, w2) + 1 + elif self.op.value == "*": + wr = w1 + w2 + sr = s1 or s2 + elif self.op.value == "/": + wr = w1 if not s2 else (w1 + 1) + sr = s1 or s2 + elif self.op.value == "%": + if not s1 and not s2: + wr = min(w1, w2) + sr = False + elif s1 and s2: + wr = min(w1, w2) + sr = True + elif s1 and not s2: + wr = min(w1, w2 + 1) + sr = True + elif not s1 and s2: + wr = min(w1, max(1, w2 - 1)) + sr = False + elif self.op.value in ["|", "&", "^"]: + wr = max(w1, w2) + sr = s1 or s2 + elif self.op.value in [">>", "<<"]: + wr = w1 + sr = s1 + self.inferred_type = arch.IntegerType(wr, sr, None) + else: + if self.op.value in ["||", "&&"]: + self.inferred_type = arch.IntegerType(1, False, None) # unsigned<1> / bool + elif self.op.value in ["<", ">", "==", "!=", ">=", "<="]: + self.inferred_type = arch.IntegerType(1, False, None) # unsigned<1> / bool + # print("sit", self.inferred_type.width) + print("self.inferred_type", self.inferred_type) + assert self.inferred_type is not None + # input("!x!") + + return self + + +def slice_operation(self: behav.SliceOperation, context): + print("slice_operation") + self.expr = self.expr.generate(context) + self.left = self.left.generate(context) + self.right = self.right.generate(context) + # print("self.expr", self.expr) + # print("self.left", self.left) + # print("self.right", self.right) + # input("slice") + + # type inference + if self.expr.inferred_type is None: + logger.warning("Slice Operation needs inferred type. Skipping...") + return self + assert isinstance(self.expr.inferred_type, arch.IntegerType) + ty = self.expr.inferred_type + # For non-static slices, we cann not infer the type! + if not isinstance(self.left, behav.IntLiteral): + logger.warning("Can not infer type of non-static slice operation. Skipping...") + return self + lval = self.left.value + if not isinstance(self.right, behav.IntLiteral): + logger.warning("Can not infer type of non-static slice operation. Skipping...") + return self + rval = self.right.value + width = lval - rval + 1 if lval > rval else rval - lval + 1 + ty_ = copy(ty) + ty_._width = width + self.inferred_type = ty_ + # print("sit", ty) + # input("*") + + return self + + +def concat_operation(self: behav.ConcatOperation, context): + print("concat_coperation") + self.left = self.left.generate(context) + self.right = self.right.generate(context) + # print("self", self) + # print("dir(self)", dir(self)) + # print("self.left", self.left) + # print("dir(self.left)", dir(self.left)) + # print("self.right", self.right) + # print("dir(self.right)", dir(self.right)) + # input("!") + if self.left.inferred_type is None: + logger.warning("Concat Operation needs inferred type. Skipping...") + return self + if self.right.inferred_type is None: + logger.warning("Concat Operation needs inferred type. Skipping...") + return self + width = self.left.inferred_type.width + self.right.inferred_type.width + ty = arch.IntegerType(width, False, None) + self.inferred_type = ty + + return self + + +def number_literal(self: behav.IntLiteral, context): + print("number_literal") + if isinstance(self, behav.IntLiteral): + bit_size = self.bit_size + signed = self.signed + + self.inferred_type = arch.IntegerType(bit_size, signed, None) + return self + + +def int_literal(self: behav.IntLiteral, context): + print("int_literal") + + # type inference + bit_size = self.bit_size + signed = self.signed + + self.inferred_type = arch.IntegerType(bit_size, signed, None) + + return self + + +def scalar_definition(self: behav.ScalarDefinition, context): + print("scalar_definition") + # type inference + # print("scalar_definition", self, dir(self), self.scalar, self.scalar.size, self.scalar.data_type) + signed = self.scalar.data_type == arch.DataType.S + width = self.scalar.size + self.inferred_type = arch.IntegerType(width, signed, None) + return self + + +def assignment(self: behav.Assignment, context): + print("assignment", self) + # print("at_", self.target) + # print("ae_", self.expr) + self.target = self.target.generate(context) + self.expr = self.expr.generate(context) + + # if isinstance(self.expr, behav.IntLiteral) and isinstance(self.target, behav.ScalarDefinition): + # self.target.scalar.value = self.expr.value + + # type inference + # print("at", self.target) + # print("ae", self.expr) + # print("at1", self.target.inferred_type) + # print("ae1", self.expr.inferred_type) + # print("at2", self.target.inferred_type.width) + # print("ae2", self.expr.inferred_type.width) + # input("ccc") + self.inferred_type = None + + return self + + +def conditional(self: behav.Conditional, context): + print("conditional") + self.conds = [x.generate(context) for x in self.conds] + # self.stmts = [[y.generate(context) for y in x] for x in self.stmts] + stmts = [] + for stmt in self.stmts: + if isinstance(stmt, list): # TODO: legacy? + new = [y.generate(context) for y in stmt] + else: + new = stmt.generate(context) + stmts.append(new) + self.stmts = stmts + + return self + + +def loop(self: behav.Loop, context): + print("loop") + self.cond = self.cond.generate(context) + self.stmts = [x.generate(context) for x in self.stmts] + + return self + + +def ternary(self: behav.Ternary, context): + print("ternary") + + self.cond = self.cond.generate(context) + self.then_expr = self.then_expr.generate(context) + self.else_expr = self.else_expr.generate(context) + + # print("ste", self.then_expr) + # print("see", self.else_expr) + # print("ste1", self.then_expr.inferred_type) + # print("see1", self.else_expr.inferred_type) + # print("ste2", self.then_expr.inferred_type.width) + # print("see2", self.else_expr.inferred_type.width) + # TODO + then_ty = self.then_expr.inferred_type + else_ty = self.else_expr.inferred_type + if then_ty and else_ty: + # assert then_ty.signed == else_ty.signed + wt = then_ty.width + we = else_ty.width + wr = max(wt, we) + # print("wr", wr) + # input("o") + self.inferred_type = arch.IntegerType(wr, True, None) + # input("ppp") + + return self + + +def return_(self: behav.Return, context): + print("return_") + if self.expr is not None: + self.expr = self.expr.generate(context) + + return self + + +def unary_operation(self: behav.UnaryOperation, context): + print("unary_operation") + + self.right = self.right.generate(context) + + # print("sr", self.right) + # print("sr1", self.right.inferred_type) + # print("sr2", self.right.inferred_type.width) + # input("!") + if self.right.inferred_type: + w1 = self.right.inferred_type.width + if self.op.value == "-": + inferred_type = arch.IntegerType(w1 + 1, True, None) + elif self.op.value == "~": + inferred_type = arch.IntegerType(w1, True, None) + elif self.op.value == "!": + inferred_type = arch.IntegerType(1, False, None) + else: + inferred_type = None + self.inferred_type = inferred_type + + return self + + +def named_reference(self: behav.NamedReference, context): + print("named_reference", self) + # print("dir", dir(self)) + # print("self.reference", self.reference) + reference = self.reference + + # type inference + # self.infered_type = ? + if isinstance(reference, arch.BitFieldDescr): + # print("BITFIELD", reference) + # print("self.reference", self.reference) + # print("self.reference.data_type", self.reference.data_type) + assert self.reference.data_type in [arch.DataType.U, arch.DataType.S] + ty = arch.IntegerType(reference.size, reference.data_type == arch.DataType.S, None) + # print("ty", ty) + self.inferred_type = ty + + elif isinstance(reference, arch.Scalar): + # print("SCALAR", reference) + dt = reference.data_type + sz = reference.size + assert dt in [arch.DataType.U, arch.DataType.S] + signed = dt == arch.DataType.S + ty = arch.IntegerType(sz, signed, None) + self.inferred_type = ty + elif isinstance(reference, arch.Memory): + # print("MEMORY", reference) + self.inferred_type = arch.IntegerType(reference.size, False, None) + # print("dir(reference)", dir(reference)) + # input("%%%%%") + elif isinstance(reference, arch.Intrinsic): + # print("INTRIN", reference) + # print("dir(reference)", dir(reference)) + # print("reference.size", reference.size) + # print("reference.data_type", reference.data_type) + assert self.reference.data_type in [arch.DataType.U, arch.DataType.S] + self.inferred_type = arch.IntegerType(reference.size, reference.data_type == arch.DataType.S, None) + elif isinstance(reference, arch.Constant): + # print("CONST", reference) + # print("dir(reference)", dir(reference)) + # print("reference.size", reference.size) + # print("reference.signed", reference.signed) + self.inferred_type = arch.IntegerType(reference.size, reference.signed, None) + else: + # print("ELSE", reference) + # print("reference.size", reference.size) + # print("reference.data_type", reference.data_type) + assert False, "Unhandled reference" + + # print("self.inferred_type", self.inferred_type) + # input("222") + + return self + + +def indexed_reference(self: behav.IndexedReference, context): + print("indexed_reference") + self.index = self.index.generate(context) + + # type inference + assert isinstance(self.reference, arch.Memory) + ty = arch.DataType.U # TODO: Memory class should keep track of dtype, not only size? + assert ty in [arch.DataType.U, arch.DataType.S] + size = self.reference.size + ty_ = arch.IntegerType(size, ty == arch.DataType.S, None) + + self.inferred_type = ty_ + # print("self.inferred_type", self.inferred_type) + # input("111") + + return self + + +def type_conv(self: behav.TypeConv, context): + print("type_conv") + self.expr = self.expr.generate(context) + print("self.expr", self.expr) + + ty = self.expr.inferred_type + if ty is None: + logger.warning("Type conv needs inferred type. Skipping...") + input("!!@@") + return self + assert isinstance(ty, arch.IntegerType) + assert self.data_type in [arch.DataType.U, arch.DataType.S] + ty.signed = self.data_type == arch.DataType.S + if self.size is not None: + ty._width = self.size + + # type inference + self.inferred_type = ty + + return self + + +def callable_(self: behav.Callable, context): + print("callable_") + print("self", self) + print("dir(self)", dir(self)) + print("self.ref_or_name", self.ref_or_name) + if isinstance(self.ref_or_name, arch.Function): + print("dir(self.ref_or_name)", dir(self.ref_or_name)) + assert self.ref_or_name.data_type in [arch.DataType.U, arch.DataType.S] + signed = self.ref_or_name.data_type == arch.DataType.S + width = self.ref_or_name.size + self.inferred_type = arch.IntegerType(width, signed, None) + # print("self.inferred_type", self.inferred_type) + self.args = [stmt.generate(context) for stmt in self.args] + + return self + + +def procedure_call(self: behav.ProcedureCall, context): + print("procedure_call") + self.args = [stmt.generate(context) for stmt in self.args] + + return self + + +def group(self: behav.Group, context): + print("group") + self.expr = self.expr.generate(context) + + if isinstance(self.expr, behav.IntLiteral): + return self.expr + + # type inference + self.inferred_type = self.expr.inferred_type + + return self + + +def break_(self: behav.Break, context): + print("break_") + return self From fd497e2171cea068adf133b5a5480ad60962e6cd Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Wed, 15 Apr 2026 17:01:40 +0200 Subject: [PATCH 12/24] add m2isar/transforms/validate_behav --- m2isar/transforms/validate_behav/__init__.py | 11 + m2isar/transforms/validate_behav/validate.py | 77 +++++++ m2isar/transforms/validate_behav/visitor.py | 217 +++++++++++++++++++ 3 files changed, 305 insertions(+) create mode 100644 m2isar/transforms/validate_behav/__init__.py create mode 100644 m2isar/transforms/validate_behav/validate.py create mode 100644 m2isar/transforms/validate_behav/visitor.py diff --git a/m2isar/transforms/validate_behav/__init__.py b/m2isar/transforms/validate_behav/__init__.py new file mode 100644 index 00000000..71ee24de --- /dev/null +++ b/m2isar/transforms/validate_behav/__init__.py @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# This file is part of the M2-ISA-R project: https://github.com/tum-ei-eda/M2-ISA-R +# +# Copyright (C) 2024 +# Chair of Electrical Design Automation +# Technical University of Munich + +"""This module contains a behavior validator pass for M2-ISA-R models. +Type inference has to be run first! +""" diff --git a/m2isar/transforms/validate_behav/validate.py b/m2isar/transforms/validate_behav/validate.py new file mode 100644 index 00000000..36d1604b --- /dev/null +++ b/m2isar/transforms/validate_behav/validate.py @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# This file is part of the M2-ISA-R project: https://github.com/tum-ei-eda/M2-ISA-R +# +# Copyright (C) 2022 +# Chair of Electrical Design Automation +# Technical University of Munich + +"""validate behavior in M2-ISA-R metamodel.""" + +import sys +import argparse +import logging +import pathlib + +from m2isar.metamodel import patch_model, load_model, dump_model +from m2isar.backends.etiss.warnings import WarningsManager, WarningsInfo, add_warnings_flags, KNOWN_WARNINGS + +from . import visitor + +class ValidatorContext(WarningsManager): + """Track miscellaneous information throughout the validation process.""" + def __init__(self, warnings_info: WarningsInfo = None): + super().__init__(warnings_info) + + +def get_parser(): + # read command line args + parser = argparse.ArgumentParser() + parser.add_argument("top_level", help="A .m2isarmodel file.") + parser.add_argument("--log", default="info", choices=["critical", "error", "warning", "info", "debug"]) + parser.add_argument("--output", "-o", type=str, default=None) + add_warnings_flags(parser, KNOWN_WARNINGS, KNOWN_WARNINGS) + return parser + + +def run(args): + # initialize logging + logging.basicConfig(level=getattr(logging, args.log.upper())) + logger = logging.getLogger("validate_behav") + logger.setLevel(getattr(logging, args.log.upper())) + + # resolve model paths + top_level = pathlib.Path(args.top_level) + + out_path = (top_level.parent / top_level.stem) if args.output is None else args.output + print("out_path", out_path) + + model_obj = load_model(top_level) + warnings_info = args.warnings + + for _, core_def in model_obj.cores.items(): + logger.debug("validating behavior for core %s", core_def.name) + context = ValidatorContext(warnings_info) + patch_model(visitor) + for _, instr_def in core_def.instructions.items(): + logger.debug("validating behavior for instr %s", instr_def.name) + instr_def.operation.generate(context) + for _, set_def in model_obj.sets.items(): + logger.debug("validating behavior for set %s", set_def.name) + context = ValidatorContext(warnings_info) + patch_model(visitor) + for _, instr_def in set_def.instructions.items(): + logger.debug("validating behavior for instr %s", instr_def.name) + instr_def.operation.generate(context) + + dump_model(model_obj, out_path) + + +def main(argv): + parser = get_parser() + args = parser.parse_args(argv) + run(args) + + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/m2isar/transforms/validate_behav/visitor.py b/m2isar/transforms/validate_behav/visitor.py new file mode 100644 index 00000000..3293e066 --- /dev/null +++ b/m2isar/transforms/validate_behav/visitor.py @@ -0,0 +1,217 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# This file is part of the M2-ISA-R project: https://github.com/tum-ei-eda/M2-ISA-R +# +# Copyright (C) 2022 +# Chair of Electrical Design Automation +# Technical University of Munich + +"""A transformation module for simplifying M2-ISA-R behavior expressions. The following +simplifications are done: + +* Resolvable :class:`m2isar.metamodel.arch.Constant` s are replaced by + `m2isar.metamodel.arch.IntLiteral` s representing their value +* Fully resolvable arithmetic operations are carried out and their results + represented as a matching :class:`m2isar.metamodel.arch.IntLiteral` +* Conditions and loops with fully resolvable conditions are either discarded entirely + or transformed into code blocks without any conditions +* Ternaries with fully resolvable conditions are transformed into only the matching part +* Type conversions of :class:`m2isar.metamodel.arch.IntLiteral` s apply the desired + type directly to the :class:`IntLiteral` and discard the type conversion +""" + +import logging +from copy import copy + +from m2isar.metamodel import arch, behav + +logger = logging.getLogger("validate_behav") + +# pylint: disable=unused-argument + + +def operation(self: behav.Operation, context): + print("operation", operation) + statements = [] + for stmt in self.statements: + # try: + temp = stmt.generate(context) + if isinstance(temp, list): + statements.extend(temp) + else: + statements.append(temp) + # except (NotImplementedError, ValueError): + # print(f"cant simplify {stmt}") + + self.statements = statements + return self + + +def binary_operation(self: behav.BinaryOperation, context): + print("binary_operation") + self.left = self.left.generate(context) + op = self.op + self.right = self.right.generate(context) + + print("self.left", self.left) + print("op", op) + print("self.right", self.right) + if isinstance(self.right, behav.NamedReference): + print("self.right.reference", self.right.reference) + assert self.left.inferred_type is not None + assert self.right.inferred_type is not None + if op.value in ["|", "&", "^"] and self.left.inferred_type.width != self.right.inferred_type.width: + context.emit_warning(f"Bitwise operations with differently size operands are discouraged.", "bit-op-missmatch", logger=logger, line_info=self.line_info) + # input("!!") + # print("self.left.inferred_type", self.left.inferred_type) + # print("self.right.inferred_type", self.right.inferred_type) + if op.value in ["<<", ">>", ">>>"] and self.right.inferred_type.signed: + context.emit_warning(f"Shift by signed amount", "shift-signed", logger=logger, line_info=self.line_info) + # input("!!5") + if op.value in ["<", "<=", ">", ">=", "==", "!="] and self.left.inferred_type.signed != self.right.inferred_type.signed: + # TODO: handle unsigned < 0 + print("self.left", self.left, dir(self.left), self.left.inferred_type) + print("self.right", self.right, dir(self.right), self.right.inferred_type) + if isinstance(self.left, behav.IntLiteral) and self.left.value == 0: + pass + if isinstance(self.right, behav.IntLiteral) and self.right.value == 0: + pass + else: + context.emit_warning(f"Signed vs. unsigned comparison", "sign-compare", logger=logger, line_info=self.line_info) + # input("!!4") + if op.value == "<<" and self.left.inferred_type.width <= self.right.inferred_type.width: + context.emit_warning(f"Shift count overflow for << operation ({self.left.inferred_type.width} vs. {self.right.inferred_type.width})", "shift-overflow", logger=logger, line_info=self.line_info) + input("!!6") + return self + + +def slice_operation(self: behav.SliceOperation, context): + print("slice_operation") + self.expr = self.expr.generate(context) + self.left = self.left.generate(context) + self.right = self.right.generate(context) + return self + + +def concat_operation(self: behav.ConcatOperation, context): + print("concat_coperation") + self.left = self.left.generate(context) + self.right = self.right.generate(context) + return self + + +def number_literal(self: behav.IntLiteral, context): + print("number_literal") + return self + + +def int_literal(self: behav.IntLiteral, context): + print("int_literal") + return self + + +def scalar_definition(self: behav.ScalarDefinition, context): + print("scalar_definition") + return self + + +def assignment(self: behav.Assignment, context): + print("assignment", self) + self.target = self.target.generate(context) + self.expr = self.expr.generate(context) + print("self.target", self.target) + print("self.expr", self.expr) + assert self.target.inferred_type is not None + assert self.expr.inferred_type is not None + if self.target.inferred_type.width < self.expr.inferred_type.width: + context.emit_warning(f"Implicit truncation {self.expr.inferred_type.width} -> {self.target.inferred_type.width} found", "implicit-trunc", logger=logger, line_info=self.line_info) + # input("!!2") + if self.target.inferred_type.width > self.expr.inferred_type.width: + context.emit_warning(f"Implicit extend {self.expr.inferred_type.width} -> {self.target.inferred_type.width} found", "implicit-extend", logger=logger, line_info=self.line_info) + # input("!!3") + return self + + +def conditional(self: behav.Conditional, context): + print("conditional") + self.conds = [x.generate(context) for x in self.conds] + stmts = [] + for stmt in self.stmts: + if isinstance(stmt, list): # TODO: legacy? + new = [y.generate(context) for y in stmt] + else: + new = stmt.generate(context) + stmts.append(new) + self.stmts = stmts + return self + + +def loop(self: behav.Loop, context): + print("loop") + self.cond = self.cond.generate(context) + self.stmts = [x.generate(context) for x in self.stmts] + return self + + +def ternary(self: behav.Ternary, context): + print("ternary") + self.cond = self.cond.generate(context) + self.then_expr = self.then_expr.generate(context) + self.else_expr = self.else_expr.generate(context) + + return self + + +def return_(self: behav.Return, context): + print("return_") + if self.expr is not None: + self.expr = self.expr.generate(context) + return self + + +def unary_operation(self: behav.UnaryOperation, context): + print("unary_operation") + self.right = self.right.generate(context) + return self + + +def named_reference(self: behav.NamedReference, context): + print("named_reference", self) + return self + + +def indexed_reference(self: behav.IndexedReference, context): + print("indexed_reference") + self.index = self.index.generate(context) + return self + + +def type_conv(self: behav.TypeConv, context): + print("type_conv") + self.expr = self.expr.generate(context) + return self + + +def callable_(self: behav.Callable, context): + print("callable_") + self.args = [stmt.generate(context) for stmt in self.args] + return self + + +def procedure_call(self: behav.ProcedureCall, context): + print("procedure_call") + self.args = [stmt.generate(context) for stmt in self.args] + return self + + +def group(self: behav.Group, context): + print("group") + self.expr = self.expr.generate(context) + if isinstance(self.expr, behav.IntLiteral): + return self.expr + return self + + +def break_(self: behav.Break, context): + print("break_") + return self From 37e874c960e1017348a3e2083a23d2d0cf65b615 Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Wed, 15 Apr 2026 17:01:54 +0200 Subject: [PATCH 13/24] m2isar/backends/etiss/warnings.py: add bit-op-missmatch --- m2isar/backends/etiss/warnings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/m2isar/backends/etiss/warnings.py b/m2isar/backends/etiss/warnings.py index ee5499fc..20df07fc 100644 --- a/m2isar/backends/etiss/warnings.py +++ b/m2isar/backends/etiss/warnings.py @@ -9,6 +9,7 @@ 'implicit-extend', 'sign-compare', 'unused-value', + 'bit-op-missmatch', } From 94642be97bde11040293b77e3a0786c29185bd53 Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Wed, 15 Apr 2026 17:06:15 +0200 Subject: [PATCH 14/24] move common warnings code to toplevel --- m2isar/backends/etiss/instruction_generator.py | 2 +- m2isar/backends/etiss/instruction_utils.py | 2 +- m2isar/backends/etiss/instruction_writer.py | 2 +- m2isar/backends/etiss/writer.py | 13 +++++++++++-- m2isar/{backends/etiss => }/warnings.py | 0 5 files changed, 14 insertions(+), 5 deletions(-) rename m2isar/{backends/etiss => }/warnings.py (100%) diff --git a/m2isar/backends/etiss/instruction_generator.py b/m2isar/backends/etiss/instruction_generator.py index 005081fe..0700bb15 100644 --- a/m2isar/backends/etiss/instruction_generator.py +++ b/m2isar/backends/etiss/instruction_generator.py @@ -15,7 +15,7 @@ from ...metamodel import arch, behav, patch_model from . import BlockEndType, instruction_transform, instruction_utils from .templates import template_dir -from .warnings import WarningsInfo +from ...warnings import WarningsInfo logger = logging.getLogger("instruction_generator") diff --git a/m2isar/backends/etiss/instruction_utils.py b/m2isar/backends/etiss/instruction_utils.py index 9df52d8a..8829452e 100644 --- a/m2isar/backends/etiss/instruction_utils.py +++ b/m2isar/backends/etiss/instruction_utils.py @@ -17,7 +17,7 @@ from ...metamodel.code_info import LineInfo from ...metamodel.utils import StaticType from . import replacements -from .warnings import WarningsManager, WarningsInfo +from ...warnings import WarningsManager, WarningsInfo data_type_map = { arch.DataType.S: 'etiss_int', diff --git a/m2isar/backends/etiss/instruction_writer.py b/m2isar/backends/etiss/instruction_writer.py index 2eff89f2..0a9326fa 100644 --- a/m2isar/backends/etiss/instruction_writer.py +++ b/m2isar/backends/etiss/instruction_writer.py @@ -18,7 +18,7 @@ from . import BlockEndType from .instruction_generator import generate_functions, generate_instructions from .templates import template_dir -from .warnings import WarningsInfo +from ...warnings import WarningsInfo logger = logging.getLogger("instruction_writer") diff --git a/m2isar/backends/etiss/writer.py b/m2isar/backends/etiss/writer.py index 8906fc5a..591b7588 100755 --- a/m2isar/backends/etiss/writer.py +++ b/m2isar/backends/etiss/writer.py @@ -26,7 +26,16 @@ write_arch_specific_header, write_arch_struct) from .instruction_writer import write_functions, write_instructions -from .warnings import add_warnings_flags, KNOWN_WARNINGS +from ...warnings import add_warnings_flags + +ETISS_WRITER_WARNINGS = { + 'implicit-trunc', + 'shift-overflow', + 'shift-signed', + 'implicit-extend', + 'sign-compare', + 'unused-value', +} class BooleanOptionalAction(argparse.Action): @@ -86,7 +95,7 @@ def setup(): help="Force end translation blocks on no instructions, uncoditional jumps or all jumps.") parser.add_argument("--coverage", action=BooleanOptionalAction, default=False, help="Generate coverage tracking code into model.") parser.add_argument("--log", default="info", choices=["critical", "error", "warning", "info", "debug"]) - add_warnings_flags(parser, KNOWN_WARNINGS, KNOWN_WARNINGS) + add_warnings_flags(parser, ETISS_WRITER_WARNINGS, ETISS_WRITER_WARNINGS) args = parser.parse_args() # configure logging diff --git a/m2isar/backends/etiss/warnings.py b/m2isar/warnings.py similarity index 100% rename from m2isar/backends/etiss/warnings.py rename to m2isar/warnings.py From 857f25fb5d5263ea069980c97b992621a2718fdc Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Wed, 15 Apr 2026 17:24:54 +0200 Subject: [PATCH 15/24] m2isar/backends/etiss/writer.py: add comment --- m2isar/backends/etiss/writer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/m2isar/backends/etiss/writer.py b/m2isar/backends/etiss/writer.py index 591b7588..2ed6723d 100755 --- a/m2isar/backends/etiss/writer.py +++ b/m2isar/backends/etiss/writer.py @@ -38,6 +38,7 @@ } +# TODO: not required anymore for Python >= v3.9 class BooleanOptionalAction(argparse.Action): """A boolean optional action for argparse, supports automatic generation of --no-x flags.""" From 8ffa0ede21fed706b6f3d4d511615f22d34f41ad Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Wed, 15 Apr 2026 17:25:22 +0200 Subject: [PATCH 16/24] add --validate flag for parser --- m2isar/frontends/coredsl2/parser.py | 27 ++++++++++++---- m2isar/transforms/infer_types/transform.py | 31 +++++++++--------- m2isar/transforms/validate_behav/validate.py | 33 +++++++++----------- 3 files changed, 52 insertions(+), 39 deletions(-) diff --git a/m2isar/frontends/coredsl2/parser.py b/m2isar/frontends/coredsl2/parser.py index bcc88501..f3bda456 100644 --- a/m2isar/frontends/coredsl2/parser.py +++ b/m2isar/frontends/coredsl2/parser.py @@ -23,6 +23,10 @@ from .importer import recursive_import from .load_order import LoadOrder from .utils import make_parser +from ...backends.etiss.writer import BooleanOptionalAction # TODO: refactor +from ...transforms.infer_types.transform import infer_types +from ...transforms.validate_behav.validate import validate_behav +from ...warnings import add_warnings_flags, KNOWN_WARNINGS def main(): @@ -30,6 +34,8 @@ def main(): parser.add_argument("top_level", help="The top-level CoreDSL file.") parser.add_argument("--log", default="info", choices=["critical", "error", "warning", "info", "debug"]) parser.add_argument("-I", dest="includes", action="append", default=[], help="Extra include directories") + parser.add_argument('--validate', action=BooleanOptionalAction, default=False, help="Run type inference and validator after parsing.") + add_warnings_flags(parser, KNOWN_WARNINGS, KNOWN_WARNINGS) # only if --validate args = parser.parse_args() @@ -251,14 +257,23 @@ def main(): op.statements = always_block_statements + op.statements instr_def.operation = op + model_obj = M2Model( + M2_METAMODEL_VERSION, + models, + {}, + CodeInfoBase.database + ) + + print("args.validate", args.validate) + if args.validate: + logger.info("Running type inference") + model_obj = infer_types(model_obj) + logger.info("Running validator") + warnings_info = args.warnings + validate_behav(model_obj, warnings_info) + logger.info("dumping model") with open(model_path / (abs_top_level.stem + '.m2isarmodel'), 'wb') as f: - model_obj = M2Model( - M2_METAMODEL_VERSION, - models, - {}, - CodeInfoBase.database - ) pickle.dump(model_obj, f) diff --git a/m2isar/transforms/infer_types/transform.py b/m2isar/transforms/infer_types/transform.py index 149e3056..7707bb8c 100644 --- a/m2isar/transforms/infer_types/transform.py +++ b/m2isar/transforms/infer_types/transform.py @@ -27,34 +27,35 @@ def get_parser(): return parser -def run(args): - # initialize logging - logging.basicConfig(level=getattr(logging, args.log.upper())) +def infer_types(model_obj): logger = logging.getLogger("infer_types") - logger.setLevel(getattr(logging, args.log.upper())) - - # resolve model paths - top_level = pathlib.Path(args.top_level) - - out_path = (top_level.parent / top_level.stem) if args.output is None else args.output - print("out_path", out_path) - - model_obj = load_model(top_level) - for _, core_def in model_obj.cores.items(): logger.debug("inferring types for core %s", core_def.name) patch_model(visitor) for _, instr_def in core_def.instructions.items(): logger.debug("inferring types for instr %s", instr_def.name) instr_def.operation.generate(None) - # input("!") for _, set_def in model_obj.sets.items(): logger.debug("inferring types for set %s", set_def.name) patch_model(visitor) for _, instr_def in set_def.instructions.items(): logger.debug("inferring types for instr %s", instr_def.name) instr_def.operation.generate(None) - # input("!") + return model_obj + + +def run(args): + # initialize logging + logging.basicConfig(level=getattr(logging, args.log.upper())) + + # resolve model paths + top_level = pathlib.Path(args.top_level) + + out_path = (top_level.parent / top_level.stem) if args.output is None else args.output + print("out_path", out_path) + + model_obj = load_model(top_level) + model_obj = infer_types(model_obj) dump_model(model_obj, out_path) diff --git a/m2isar/transforms/validate_behav/validate.py b/m2isar/transforms/validate_behav/validate.py index 36d1604b..c9a931d4 100644 --- a/m2isar/transforms/validate_behav/validate.py +++ b/m2isar/transforms/validate_behav/validate.py @@ -13,8 +13,8 @@ import logging import pathlib -from m2isar.metamodel import patch_model, load_model, dump_model -from m2isar.backends.etiss.warnings import WarningsManager, WarningsInfo, add_warnings_flags, KNOWN_WARNINGS +from ...metamodel import patch_model, load_model, dump_model +from ...warnings import WarningsManager, WarningsInfo, add_warnings_flags, KNOWN_WARNINGS from . import visitor @@ -29,26 +29,12 @@ def get_parser(): parser = argparse.ArgumentParser() parser.add_argument("top_level", help="A .m2isarmodel file.") parser.add_argument("--log", default="info", choices=["critical", "error", "warning", "info", "debug"]) - parser.add_argument("--output", "-o", type=str, default=None) add_warnings_flags(parser, KNOWN_WARNINGS, KNOWN_WARNINGS) return parser -def run(args): - # initialize logging - logging.basicConfig(level=getattr(logging, args.log.upper())) +def validate_behav(model_obj, warnings_info): logger = logging.getLogger("validate_behav") - logger.setLevel(getattr(logging, args.log.upper())) - - # resolve model paths - top_level = pathlib.Path(args.top_level) - - out_path = (top_level.parent / top_level.stem) if args.output is None else args.output - print("out_path", out_path) - - model_obj = load_model(top_level) - warnings_info = args.warnings - for _, core_def in model_obj.cores.items(): logger.debug("validating behavior for core %s", core_def.name) context = ValidatorContext(warnings_info) @@ -63,8 +49,19 @@ def run(args): for _, instr_def in set_def.instructions.items(): logger.debug("validating behavior for instr %s", instr_def.name) instr_def.operation.generate(context) + # return model_obj - dump_model(model_obj, out_path) + +def run(args): + # initialize logging + logging.basicConfig(level=getattr(logging, args.log.upper())) + + # resolve model paths + top_level = pathlib.Path(args.top_level) + + model_obj = load_model(top_level) + warnings_info = args.warnings + alidate_behav(model_obj, warnings_info) def main(argv): From a83a3817dfbf6a2c174565386ce98bce3b1f65fb Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Wed, 15 Apr 2026 17:25:48 +0200 Subject: [PATCH 17/24] comment out prints in transforms --- m2isar/transforms/validate_behav/visitor.py | 58 ++++++++++----------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/m2isar/transforms/validate_behav/visitor.py b/m2isar/transforms/validate_behav/visitor.py index 3293e066..3f939c35 100644 --- a/m2isar/transforms/validate_behav/visitor.py +++ b/m2isar/transforms/validate_behav/visitor.py @@ -31,7 +31,7 @@ def operation(self: behav.Operation, context): - print("operation", operation) + # print("operation", operation) statements = [] for stmt in self.statements: # try: @@ -48,16 +48,14 @@ def operation(self: behav.Operation, context): def binary_operation(self: behav.BinaryOperation, context): - print("binary_operation") + # print("binary_operation") self.left = self.left.generate(context) op = self.op self.right = self.right.generate(context) - print("self.left", self.left) - print("op", op) - print("self.right", self.right) - if isinstance(self.right, behav.NamedReference): - print("self.right.reference", self.right.reference) + # print("self.left", self.left) + # print("op", op) + # print("self.right", self.right) assert self.left.inferred_type is not None assert self.right.inferred_type is not None if op.value in ["|", "&", "^"] and self.left.inferred_type.width != self.right.inferred_type.width: @@ -70,8 +68,8 @@ def binary_operation(self: behav.BinaryOperation, context): # input("!!5") if op.value in ["<", "<=", ">", ">=", "==", "!="] and self.left.inferred_type.signed != self.right.inferred_type.signed: # TODO: handle unsigned < 0 - print("self.left", self.left, dir(self.left), self.left.inferred_type) - print("self.right", self.right, dir(self.right), self.right.inferred_type) + # print("self.left", self.left, dir(self.left), self.left.inferred_type) + # print("self.right", self.right, dir(self.right), self.right.inferred_type) if isinstance(self.left, behav.IntLiteral) and self.left.value == 0: pass if isinstance(self.right, behav.IntLiteral) and self.right.value == 0: @@ -81,12 +79,12 @@ def binary_operation(self: behav.BinaryOperation, context): # input("!!4") if op.value == "<<" and self.left.inferred_type.width <= self.right.inferred_type.width: context.emit_warning(f"Shift count overflow for << operation ({self.left.inferred_type.width} vs. {self.right.inferred_type.width})", "shift-overflow", logger=logger, line_info=self.line_info) - input("!!6") + # input("!!6") return self def slice_operation(self: behav.SliceOperation, context): - print("slice_operation") + # print("slice_operation") self.expr = self.expr.generate(context) self.left = self.left.generate(context) self.right = self.right.generate(context) @@ -94,33 +92,33 @@ def slice_operation(self: behav.SliceOperation, context): def concat_operation(self: behav.ConcatOperation, context): - print("concat_coperation") + # print("concat_coperation") self.left = self.left.generate(context) self.right = self.right.generate(context) return self def number_literal(self: behav.IntLiteral, context): - print("number_literal") + # print("number_literal") return self def int_literal(self: behav.IntLiteral, context): - print("int_literal") + # print("int_literal") return self def scalar_definition(self: behav.ScalarDefinition, context): - print("scalar_definition") + # print("scalar_definition") return self def assignment(self: behav.Assignment, context): - print("assignment", self) + # print("assignment", self) self.target = self.target.generate(context) self.expr = self.expr.generate(context) - print("self.target", self.target) - print("self.expr", self.expr) + # print("self.target", self.target) + # print("self.expr", self.expr) assert self.target.inferred_type is not None assert self.expr.inferred_type is not None if self.target.inferred_type.width < self.expr.inferred_type.width: @@ -133,7 +131,7 @@ def assignment(self: behav.Assignment, context): def conditional(self: behav.Conditional, context): - print("conditional") + # print("conditional") self.conds = [x.generate(context) for x in self.conds] stmts = [] for stmt in self.stmts: @@ -147,14 +145,14 @@ def conditional(self: behav.Conditional, context): def loop(self: behav.Loop, context): - print("loop") + # print("loop") self.cond = self.cond.generate(context) self.stmts = [x.generate(context) for x in self.stmts] return self def ternary(self: behav.Ternary, context): - print("ternary") + # print("ternary") self.cond = self.cond.generate(context) self.then_expr = self.then_expr.generate(context) self.else_expr = self.else_expr.generate(context) @@ -163,49 +161,49 @@ def ternary(self: behav.Ternary, context): def return_(self: behav.Return, context): - print("return_") + # print("return_") if self.expr is not None: self.expr = self.expr.generate(context) return self def unary_operation(self: behav.UnaryOperation, context): - print("unary_operation") + # print("unary_operation") self.right = self.right.generate(context) return self def named_reference(self: behav.NamedReference, context): - print("named_reference", self) + # print("named_reference", self) return self def indexed_reference(self: behav.IndexedReference, context): - print("indexed_reference") + # print("indexed_reference") self.index = self.index.generate(context) return self def type_conv(self: behav.TypeConv, context): - print("type_conv") + # print("type_conv") self.expr = self.expr.generate(context) return self def callable_(self: behav.Callable, context): - print("callable_") + # print("callable_") self.args = [stmt.generate(context) for stmt in self.args] return self def procedure_call(self: behav.ProcedureCall, context): - print("procedure_call") + # print("procedure_call") self.args = [stmt.generate(context) for stmt in self.args] return self def group(self: behav.Group, context): - print("group") + # print("group") self.expr = self.expr.generate(context) if isinstance(self.expr, behav.IntLiteral): return self.expr @@ -213,5 +211,5 @@ def group(self: behav.Group, context): def break_(self: behav.Break, context): - print("break_") + # print("break_") return self From 64fa03d85c8b8e5d751512870151633ce26d8c27 Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Wed, 15 Apr 2026 17:30:39 +0200 Subject: [PATCH 18/24] remove redundant warnings code from etiss writer --- m2isar/backends/etiss/architecture_writer.py | 2 +- m2isar/backends/etiss/instruction_generator.py | 13 ++++++------- m2isar/backends/etiss/instruction_transform.py | 17 ----------------- m2isar/backends/etiss/instruction_utils.py | 10 ++-------- m2isar/backends/etiss/instruction_writer.py | 11 +++++------ m2isar/backends/etiss/writer.py | 15 ++------------- 6 files changed, 16 insertions(+), 52 deletions(-) diff --git a/m2isar/backends/etiss/architecture_writer.py b/m2isar/backends/etiss/architecture_writer.py index bc69f8f7..6bb671d3 100644 --- a/m2isar/backends/etiss/architecture_writer.py +++ b/m2isar/backends/etiss/architecture_writer.py @@ -201,7 +201,7 @@ def write_arch_specific_cpp(core: arch.CoreDef, start_time: str, output_path: pa error_instr._size = bitsize # pylint: disable=protected-access error_fields = generate_fields(32, error_instr) - error_callbacks[bitsize] = generate_instruction_callback(core, error_instr, error_fields, True, BlockEndType.NONE, False, None) + error_callbacks[bitsize] = generate_instruction_callback(core, error_instr, error_fields, True, BlockEndType.NONE, False) logger.info("writing architecture specific file") diff --git a/m2isar/backends/etiss/instruction_generator.py b/m2isar/backends/etiss/instruction_generator.py index 0700bb15..69a8a268 100644 --- a/m2isar/backends/etiss/instruction_generator.py +++ b/m2isar/backends/etiss/instruction_generator.py @@ -15,7 +15,6 @@ from ...metamodel import arch, behav, patch_model from . import BlockEndType, instruction_transform, instruction_utils from .templates import template_dir -from ...warnings import WarningsInfo logger = logging.getLogger("instruction_generator") @@ -23,7 +22,7 @@ def generate_arg_str(arg: arch.FnParam): arg_name = f" {arg.name}" if arg.name is not None else "" return f'{instruction_utils.data_type_map[arg.data_type]}{arg.actual_size}{arg_name}' -def generate_functions(core: arch.CoreDef, static_scalars: bool, decls_only: bool, generate_coverage: bool, warnings_info: WarningsInfo): +def generate_functions(core: arch.CoreDef, static_scalars: bool, decls_only: bool, generate_coverage: bool): """Return a generator object to generate function behavior code. Uses function definitions in the core object. """ @@ -48,7 +47,7 @@ def generate_functions(core: arch.CoreDef, static_scalars: bool, decls_only: boo # set up a transformer context and generate code context = instruction_utils.TransformerContext(core.constants, core.memories, core.memory_aliases, fn_def.args, fn_def.attributes, - core.functions, 0, core_default_width, core_name, static_scalars, core.intrinsics, generate_coverage, True, warnings_info) + core.functions, 0, core_default_width, core_name, static_scalars, core.intrinsics, generate_coverage, True) logger.debug("generating code for %s", fn_name) @@ -140,7 +139,7 @@ def generate_fields(core_default_width, instr_def: arch.Instruction): return (fields_code, asm_printer_code, seen_fields, enc_idx) -def generate_instruction_callback(core: arch.CoreDef, instr_def: arch.Instruction, fields, static_scalars: bool, block_end_on: BlockEndType, generate_coverage: bool, warnings_info: WarningsInfo): +def generate_instruction_callback(core: arch.CoreDef, instr_def: arch.Instruction, fields, static_scalars: bool, block_end_on: BlockEndType, generate_coverage: bool): patch_model(instruction_transform) instr_name = instr_def.name @@ -152,7 +151,7 @@ def generate_instruction_callback(core: arch.CoreDef, instr_def: arch.Instructio callback_template = Template(filename=str(template_dir/'etiss_instruction_callback.mako')) context = instruction_utils.TransformerContext(core.constants, core.memories, core.memory_aliases, instr_def.fields, instr_def.attributes, - core.functions, enc_idx, core_default_width, core_name, static_scalars, core.intrinsics, generate_coverage, False, warnings_info) + core.functions, enc_idx, core_default_width, core_name, static_scalars, core.intrinsics, generate_coverage, False) # force a block end if necessary if ((arch.InstrAttribute.NO_CONT in instr_def.attributes @@ -187,7 +186,7 @@ def generate_instruction_callback(core: arch.CoreDef, instr_def: arch.Instructio return callback_str -def generate_instructions(core: arch.CoreDef, static_scalars: bool, block_end_on: BlockEndType, generate_coverage: bool, warnings_info: WarningsInfo): +def generate_instructions(core: arch.CoreDef, static_scalars: bool, block_end_on: BlockEndType, generate_coverage: bool): """Return a generator object to generate instruction behavior code. Uses instruction definitions in the core object. """ @@ -231,7 +230,7 @@ def generate_instructions(core: arch.CoreDef, static_scalars: bool, block_end_on instr_def.operation = new_op instr_def.throws = True - callback_str = generate_instruction_callback(core, instr_def, fields, static_scalars, block_end_on, generate_coverage, warnings_info) + callback_str = generate_instruction_callback(core, instr_def, fields, static_scalars, block_end_on, generate_coverage) # render code for whole instruction templ_str = instr_template.render( diff --git a/m2isar/backends/etiss/instruction_transform.py b/m2isar/backends/etiss/instruction_transform.py index 20b0c7a2..0e0d62c5 100644 --- a/m2isar/backends/etiss/instruction_transform.py +++ b/m2isar/backends/etiss/instruction_transform.py @@ -471,11 +471,6 @@ def assignment(self: behav.Assignment, context: TransformerContext): context.affected_regs.update(target.regs_affected) context.dependent_regs.update(expr.regs_affected) - # TODO: move to parser! - # if target.size < expr.size and not context.ignore_trunc_warnings: - if target.size < expr.size: - context.emit_warning(f"Implicit truncation {expr.size} -> {target.size} found", "implicit-trunc", logger=logger, line_info=self.line_info) - if not target.is_mem_access and not expr.is_mem_access: if target.actual_size > target.size: if target.signed: @@ -530,16 +525,6 @@ def binary_operation(self: behav.BinaryOperation, context: TransformerContext): left = self.left.generate(context) op = self.op right = self.right.generate(context) - if op.value in ["<<", ">>", ">>>"] and right.signed: - context.emit_warning(f"Shift by signed amount", "shift-signed", logger=logger, line_info=self.line_info) - if op.value in ["<", "<=", ">", ">=", "==", "!="] and left.signed != right.signed: - # TODO: handle unsigned < 0 - if left.static and left.is_literal and left.code == "0": - pass - elif right.static and right.is_literal and right.code == "0": - pass - else: - context.emit_warning(f"Signed vs. unsigned comparison", "sign-compare", logger=logger, line_info=self.line_info) # convert staticness if needed if not left.static and right.static and not right.is_literal: @@ -547,8 +532,6 @@ def binary_operation(self: behav.BinaryOperation, context: TransformerContext): if not right.static and left.static and not left.is_literal: left.code = context.make_static(left.code, left.signed) - if op.value == "<<" and left.size <= right.size: - context.emit_warning(f"Shift count overflow for << operation ({left.size} vs. {right.size})", "shift-overflow", logger=logger, line_info=self.line_info) c = CodeString(f'{left.code} {op.value} {right.code}', left.static and right.static, left.size if left.size > right.size else right.size, left.signed or right.signed, set.union(left.regs_affected, right.regs_affected), [self.line_info] + left.line_infos + right.line_infos) # keep track of any memory accesses diff --git a/m2isar/backends/etiss/instruction_utils.py b/m2isar/backends/etiss/instruction_utils.py index 8829452e..db57ec06 100644 --- a/m2isar/backends/etiss/instruction_utils.py +++ b/m2isar/backends/etiss/instruction_utils.py @@ -17,7 +17,6 @@ from ...metamodel.code_info import LineInfo from ...metamodel.utils import StaticType from . import replacements -from ...warnings import WarningsManager, WarningsInfo data_type_map = { arch.DataType.S: 'etiss_int', @@ -135,19 +134,14 @@ def format(self, mapping={}, **kwargs): setattr(self, name, formatted) -class EtissWriterWarningsManager(WarningsManager): - pass - - -class TransformerContext(EtissWriterWarningsManager): +class TransformerContext: """Track miscellaneous information throughout the code generation process. Also provides helper functions for staticness conversion etc. """ def __init__(self, constants: "dict[str, arch.Constant]", memories: "dict[str, arch.Memory]", memory_aliases: "dict[str, arch.Memory]", fields: "dict[str, arch.BitFieldDescr]", attributes: "list[arch.InstrAttribute]", functions: "dict[str, arch.Function]", - instr_size: int, native_size: int, arch_name: str, static_scalars: bool, intrinsics, generate_coverage: bool, ignore_static: bool = False, warnings_info: WarningsInfo = None): - super().__init__(warnings_info) + instr_size: int, native_size: int, arch_name: str, static_scalars: bool, intrinsics, generate_coverage: bool, ignore_static: bool = False): self.constants = constants self.memories = memories diff --git a/m2isar/backends/etiss/instruction_writer.py b/m2isar/backends/etiss/instruction_writer.py index 0a9326fa..d852f062 100644 --- a/m2isar/backends/etiss/instruction_writer.py +++ b/m2isar/backends/etiss/instruction_writer.py @@ -18,11 +18,10 @@ from . import BlockEndType from .instruction_generator import generate_functions, generate_instructions from .templates import template_dir -from ...warnings import WarningsInfo logger = logging.getLogger("instruction_writer") -def write_functions(core: arch.CoreDef, start_time: str, output_path: pathlib.Path, static_scalars: bool, generate_coverage: bool, warnings_info: WarningsInfo): +def write_functions(core: arch.CoreDef, start_time: str, output_path: pathlib.Path, static_scalars: bool, generate_coverage: bool): """Generate and write the {CoreName}Funcs.h file for ETISS.""" fn_set_header_template = Template(filename=str(template_dir/'etiss_function_set_header.mako')) @@ -45,7 +44,7 @@ def write_functions(core: arch.CoreDef, start_time: str, output_path: pathlib.Pa funcs_f.write(" // clang-format off\n") # generate and write function declarations - for fn_name, templ_str in generate_functions(core, static_scalars, True, generate_coverage, warnings_info): + for fn_name, templ_str in generate_functions(core, static_scalars, True, generate_coverage): logger.debug("writing function decl %s", fn_name) funcs_f.write(templ_str) @@ -64,13 +63,13 @@ def write_functions(core: arch.CoreDef, start_time: str, output_path: pathlib.Pa funcs_f.write("// clang-format off\n") # generate and write function definitions - for fn_name, templ_str in generate_functions(core, static_scalars, False, generate_coverage, warnings_info): + for fn_name, templ_str in generate_functions(core, static_scalars, False, generate_coverage): logger.debug("writing function def %s", fn_name) funcs_f.write(templ_str) funcs_f.write("// clang-format on\n") def write_instructions(core: arch.CoreDef, start_time: str, output_path: pathlib.Path, separate: bool, static_scalars: bool, - block_end_on: BlockEndType, generate_coverage: bool, warnings_info: WarningsInfo): + block_end_on: BlockEndType, generate_coverage: bool): """Generate and write the instruction model C++ files for ETISS.""" instr_set_template = Template(filename=str(template_dir/'etiss_instruction_set.mako')) @@ -104,7 +103,7 @@ def write_instructions(core: arch.CoreDef, start_time: str, output_path: pathlib out_f.write(instr_set_str) # generate instruction behavior models - for instr_name, _, ext_name, templ_str in generate_instructions(core, static_scalars, block_end_on, generate_coverage, warnings_info): + for instr_name, _, ext_name, templ_str in generate_instructions(core, static_scalars, block_end_on, generate_coverage): logger.debug("writing instruction %s", instr_name) outfiles.get(ext_name, outfiles['default']).write(templ_str) for outfile in outfiles.values(): diff --git a/m2isar/backends/etiss/writer.py b/m2isar/backends/etiss/writer.py index 2ed6723d..05074c86 100755 --- a/m2isar/backends/etiss/writer.py +++ b/m2isar/backends/etiss/writer.py @@ -26,16 +26,6 @@ write_arch_specific_header, write_arch_struct) from .instruction_writer import write_functions, write_instructions -from ...warnings import add_warnings_flags - -ETISS_WRITER_WARNINGS = { - 'implicit-trunc', - 'shift-overflow', - 'shift-signed', - 'implicit-extend', - 'sign-compare', - 'unused-value', -} # TODO: not required anymore for Python >= v3.9 @@ -96,7 +86,6 @@ def setup(): help="Force end translation blocks on no instructions, uncoditional jumps or all jumps.") parser.add_argument("--coverage", action=BooleanOptionalAction, default=False, help="Generate coverage tracking code into model.") parser.add_argument("--log", default="info", choices=["critical", "error", "warning", "info", "debug"]) - add_warnings_flags(parser, ETISS_WRITER_WARNINGS, ETISS_WRITER_WARNINGS) args = parser.parse_args() # configure logging @@ -183,8 +172,8 @@ def main(): write_arch_lib(core, start_time, output_path) write_arch_cmake(core, start_time, output_path, args.separate) write_arch_gdbcore(core, start_time, output_path) - write_functions(core, start_time, output_path, args.static_scalars, args.coverage, args.warnings) - write_instructions(core, start_time, output_path, args.separate, args.static_scalars, BlockEndType[args.block_end_on.upper()], args.coverage, args.warnings) + write_functions(core, start_time, output_path, args.static_scalars, args.coverage) + write_instructions(core, start_time, output_path, args.separate, args.static_scalars, BlockEndType[args.block_end_on.upper()], args.coverage) with open(output_path / "coverage.csv", "w") as f: for c_id, c_info in sorted(CodeInfoTracker.tracker[core_name].items()): From 93834489ef72d4008a020e1a6104e3ccbbec5021 Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Wed, 15 Apr 2026 17:31:29 +0200 Subject: [PATCH 19/24] remove print --- m2isar/frontends/coredsl2/parser.py | 1 - 1 file changed, 1 deletion(-) diff --git a/m2isar/frontends/coredsl2/parser.py b/m2isar/frontends/coredsl2/parser.py index f3bda456..9e2a4ac7 100644 --- a/m2isar/frontends/coredsl2/parser.py +++ b/m2isar/frontends/coredsl2/parser.py @@ -264,7 +264,6 @@ def main(): CodeInfoBase.database ) - print("args.validate", args.validate) if args.validate: logger.info("Running type inference") model_obj = infer_types(model_obj) From aa4a9b90ba5cd158467a8afa2b048307a339be9b Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Wed, 15 Apr 2026 17:32:07 +0200 Subject: [PATCH 20/24] load_model cleanup --- m2isar/metamodel/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/m2isar/metamodel/__init__.py b/m2isar/metamodel/__init__.py index 55c0b155..0396add7 100644 --- a/m2isar/metamodel/__init__.py +++ b/m2isar/metamodel/__init__.py @@ -102,8 +102,6 @@ def load_model( logger = logging.getLogger("load_model") logger.debug("loading model: %s", str(model_path)) with open(model_path, "rb") as f: - # models: "dict[str, arch.CoreDef]" = pickle.load(f) - # sets: "dict[str, arch.InstructionSet]" = pickle.load(f) model_obj: M2Model = pickle.load(f) assert isinstance(model_obj, M2Model), "Expected M2Model" required_version = M2_METAMODEL_VERSION From ff3b86707b299e68b80d859cb4c9c5d7d6b0be5c Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Wed, 15 Apr 2026 17:33:12 +0200 Subject: [PATCH 21/24] validate_behav: cleanup visitor --- m2isar/transforms/validate_behav/visitor.py | 39 --------------------- 1 file changed, 39 deletions(-) diff --git a/m2isar/transforms/validate_behav/visitor.py b/m2isar/transforms/validate_behav/visitor.py index 3f939c35..8591d3fa 100644 --- a/m2isar/transforms/validate_behav/visitor.py +++ b/m2isar/transforms/validate_behav/visitor.py @@ -31,60 +31,42 @@ def operation(self: behav.Operation, context): - # print("operation", operation) statements = [] for stmt in self.statements: - # try: temp = stmt.generate(context) if isinstance(temp, list): statements.extend(temp) else: statements.append(temp) - # except (NotImplementedError, ValueError): - # print(f"cant simplify {stmt}") self.statements = statements return self def binary_operation(self: behav.BinaryOperation, context): - # print("binary_operation") self.left = self.left.generate(context) op = self.op self.right = self.right.generate(context) - # print("self.left", self.left) - # print("op", op) - # print("self.right", self.right) assert self.left.inferred_type is not None assert self.right.inferred_type is not None if op.value in ["|", "&", "^"] and self.left.inferred_type.width != self.right.inferred_type.width: context.emit_warning(f"Bitwise operations with differently size operands are discouraged.", "bit-op-missmatch", logger=logger, line_info=self.line_info) - # input("!!") - # print("self.left.inferred_type", self.left.inferred_type) - # print("self.right.inferred_type", self.right.inferred_type) if op.value in ["<<", ">>", ">>>"] and self.right.inferred_type.signed: context.emit_warning(f"Shift by signed amount", "shift-signed", logger=logger, line_info=self.line_info) - # input("!!5") if op.value in ["<", "<=", ">", ">=", "==", "!="] and self.left.inferred_type.signed != self.right.inferred_type.signed: - # TODO: handle unsigned < 0 - # print("self.left", self.left, dir(self.left), self.left.inferred_type) - # print("self.right", self.right, dir(self.right), self.right.inferred_type) if isinstance(self.left, behav.IntLiteral) and self.left.value == 0: pass if isinstance(self.right, behav.IntLiteral) and self.right.value == 0: pass else: context.emit_warning(f"Signed vs. unsigned comparison", "sign-compare", logger=logger, line_info=self.line_info) - # input("!!4") if op.value == "<<" and self.left.inferred_type.width <= self.right.inferred_type.width: context.emit_warning(f"Shift count overflow for << operation ({self.left.inferred_type.width} vs. {self.right.inferred_type.width})", "shift-overflow", logger=logger, line_info=self.line_info) - # input("!!6") return self def slice_operation(self: behav.SliceOperation, context): - # print("slice_operation") self.expr = self.expr.generate(context) self.left = self.left.generate(context) self.right = self.right.generate(context) @@ -92,46 +74,36 @@ def slice_operation(self: behav.SliceOperation, context): def concat_operation(self: behav.ConcatOperation, context): - # print("concat_coperation") self.left = self.left.generate(context) self.right = self.right.generate(context) return self def number_literal(self: behav.IntLiteral, context): - # print("number_literal") return self def int_literal(self: behav.IntLiteral, context): - # print("int_literal") return self def scalar_definition(self: behav.ScalarDefinition, context): - # print("scalar_definition") return self def assignment(self: behav.Assignment, context): - # print("assignment", self) self.target = self.target.generate(context) self.expr = self.expr.generate(context) - # print("self.target", self.target) - # print("self.expr", self.expr) assert self.target.inferred_type is not None assert self.expr.inferred_type is not None if self.target.inferred_type.width < self.expr.inferred_type.width: context.emit_warning(f"Implicit truncation {self.expr.inferred_type.width} -> {self.target.inferred_type.width} found", "implicit-trunc", logger=logger, line_info=self.line_info) - # input("!!2") if self.target.inferred_type.width > self.expr.inferred_type.width: context.emit_warning(f"Implicit extend {self.expr.inferred_type.width} -> {self.target.inferred_type.width} found", "implicit-extend", logger=logger, line_info=self.line_info) - # input("!!3") return self def conditional(self: behav.Conditional, context): - # print("conditional") self.conds = [x.generate(context) for x in self.conds] stmts = [] for stmt in self.stmts: @@ -145,14 +117,12 @@ def conditional(self: behav.Conditional, context): def loop(self: behav.Loop, context): - # print("loop") self.cond = self.cond.generate(context) self.stmts = [x.generate(context) for x in self.stmts] return self def ternary(self: behav.Ternary, context): - # print("ternary") self.cond = self.cond.generate(context) self.then_expr = self.then_expr.generate(context) self.else_expr = self.else_expr.generate(context) @@ -161,49 +131,41 @@ def ternary(self: behav.Ternary, context): def return_(self: behav.Return, context): - # print("return_") if self.expr is not None: self.expr = self.expr.generate(context) return self def unary_operation(self: behav.UnaryOperation, context): - # print("unary_operation") self.right = self.right.generate(context) return self def named_reference(self: behav.NamedReference, context): - # print("named_reference", self) return self def indexed_reference(self: behav.IndexedReference, context): - # print("indexed_reference") self.index = self.index.generate(context) return self def type_conv(self: behav.TypeConv, context): - # print("type_conv") self.expr = self.expr.generate(context) return self def callable_(self: behav.Callable, context): - # print("callable_") self.args = [stmt.generate(context) for stmt in self.args] return self def procedure_call(self: behav.ProcedureCall, context): - # print("procedure_call") self.args = [stmt.generate(context) for stmt in self.args] return self def group(self: behav.Group, context): - # print("group") self.expr = self.expr.generate(context) if isinstance(self.expr, behav.IntLiteral): return self.expr @@ -211,5 +173,4 @@ def group(self: behav.Group, context): def break_(self: behav.Break, context): - # print("break_") return self From da1b076384cd409357df29dbf2feb9f5e66870f5 Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Wed, 15 Apr 2026 17:35:50 +0200 Subject: [PATCH 22/24] coredsl parser: expose --infer-types (on by default) --- m2isar/frontends/coredsl2/parser.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/m2isar/frontends/coredsl2/parser.py b/m2isar/frontends/coredsl2/parser.py index 9e2a4ac7..1052d525 100644 --- a/m2isar/frontends/coredsl2/parser.py +++ b/m2isar/frontends/coredsl2/parser.py @@ -34,7 +34,8 @@ def main(): parser.add_argument("top_level", help="The top-level CoreDSL file.") parser.add_argument("--log", default="info", choices=["critical", "error", "warning", "info", "debug"]) parser.add_argument("-I", dest="includes", action="append", default=[], help="Extra include directories") - parser.add_argument('--validate', action=BooleanOptionalAction, default=False, help="Run type inference and validator after parsing.") + parser.add_argument('--infer-types', action=BooleanOptionalAction, default=True, help="Run type inference after parsing.") + parser.add_argument('--validate', action=BooleanOptionalAction, default=False, help="Run validator after parsing.") add_warnings_flags(parser, KNOWN_WARNINGS, KNOWN_WARNINGS) # only if --validate args = parser.parse_args() @@ -264,9 +265,10 @@ def main(): CodeInfoBase.database ) - if args.validate: + if args.infer_types or args.validate: logger.info("Running type inference") model_obj = infer_types(model_obj) + if args.validate: logger.info("Running validator") warnings_info = args.warnings validate_behav(model_obj, warnings_info) From 611fea16d4c5274de44cbef28f3ca1d803526ea3 Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Wed, 15 Apr 2026 17:36:11 +0200 Subject: [PATCH 23/24] infer_types: cleanup --- m2isar/transforms/infer_types/visitor.py | 64 ++++++++++++------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/m2isar/transforms/infer_types/visitor.py b/m2isar/transforms/infer_types/visitor.py index 5d8297f0..e2aee579 100644 --- a/m2isar/transforms/infer_types/visitor.py +++ b/m2isar/transforms/infer_types/visitor.py @@ -31,7 +31,7 @@ def operation(self: behav.Operation, context): - print("operation", operation) + # print("operation", operation) statements = [] for stmt in self.statements: # try: @@ -48,17 +48,17 @@ def operation(self: behav.Operation, context): def binary_operation(self: behav.BinaryOperation, context): - print("binary_operation") - print("self.op.value", self.op.value) + # print("binary_operation") + # print("self.op.value", self.op.value) self.left = self.left.generate(context) self.right = self.right.generate(context) - print("self.left", self.left) - print("self.right", self.right) + # print("self.left", self.left) + # print("self.right", self.right) - print("self.left.inferred_type", self.left.inferred_type) - print("self.right.inferred_type", self.right.inferred_type) - print("self.inferred_type_", self.inferred_type) + # print("self.left.inferred_type", self.left.inferred_type) + # print("self.right.inferred_type", self.right.inferred_type) + # print("self.inferred_type_", self.inferred_type) # see: https://github.com/Minres/CoreDSL/wiki/Expressions#arithmetic-type-rules if self.op.value in ["+", "-", "*", "/", "%", "|", "&", "^", "<<", ">>"]: @@ -127,7 +127,7 @@ def binary_operation(self: behav.BinaryOperation, context): elif self.op.value in ["<", ">", "==", "!=", ">=", "<="]: self.inferred_type = arch.IntegerType(1, False, None) # unsigned<1> / bool # print("sit", self.inferred_type.width) - print("self.inferred_type", self.inferred_type) + # print("self.inferred_type", self.inferred_type) assert self.inferred_type is not None # input("!x!") @@ -135,7 +135,7 @@ def binary_operation(self: behav.BinaryOperation, context): def slice_operation(self: behav.SliceOperation, context): - print("slice_operation") + # print("slice_operation") self.expr = self.expr.generate(context) self.left = self.left.generate(context) self.right = self.right.generate(context) @@ -170,7 +170,7 @@ def slice_operation(self: behav.SliceOperation, context): def concat_operation(self: behav.ConcatOperation, context): - print("concat_coperation") + # print("concat_coperation") self.left = self.left.generate(context) self.right = self.right.generate(context) # print("self", self) @@ -194,7 +194,7 @@ def concat_operation(self: behav.ConcatOperation, context): def number_literal(self: behav.IntLiteral, context): - print("number_literal") + # print("number_literal") if isinstance(self, behav.IntLiteral): bit_size = self.bit_size signed = self.signed @@ -204,7 +204,7 @@ def number_literal(self: behav.IntLiteral, context): def int_literal(self: behav.IntLiteral, context): - print("int_literal") + # print("int_literal") # type inference bit_size = self.bit_size @@ -216,7 +216,7 @@ def int_literal(self: behav.IntLiteral, context): def scalar_definition(self: behav.ScalarDefinition, context): - print("scalar_definition") + # print("scalar_definition") # type inference # print("scalar_definition", self, dir(self), self.scalar, self.scalar.size, self.scalar.data_type) signed = self.scalar.data_type == arch.DataType.S @@ -226,7 +226,7 @@ def scalar_definition(self: behav.ScalarDefinition, context): def assignment(self: behav.Assignment, context): - print("assignment", self) + # print("assignment", self) # print("at_", self.target) # print("ae_", self.expr) self.target = self.target.generate(context) @@ -249,7 +249,7 @@ def assignment(self: behav.Assignment, context): def conditional(self: behav.Conditional, context): - print("conditional") + # print("conditional") self.conds = [x.generate(context) for x in self.conds] # self.stmts = [[y.generate(context) for y in x] for x in self.stmts] stmts = [] @@ -265,7 +265,7 @@ def conditional(self: behav.Conditional, context): def loop(self: behav.Loop, context): - print("loop") + # print("loop") self.cond = self.cond.generate(context) self.stmts = [x.generate(context) for x in self.stmts] @@ -273,7 +273,7 @@ def loop(self: behav.Loop, context): def ternary(self: behav.Ternary, context): - print("ternary") + # print("ternary") self.cond = self.cond.generate(context) self.then_expr = self.then_expr.generate(context) @@ -302,7 +302,7 @@ def ternary(self: behav.Ternary, context): def return_(self: behav.Return, context): - print("return_") + # print("return_") if self.expr is not None: self.expr = self.expr.generate(context) @@ -310,7 +310,7 @@ def return_(self: behav.Return, context): def unary_operation(self: behav.UnaryOperation, context): - print("unary_operation") + # print("unary_operation") self.right = self.right.generate(context) @@ -334,7 +334,7 @@ def unary_operation(self: behav.UnaryOperation, context): def named_reference(self: behav.NamedReference, context): - print("named_reference", self) + # print("named_reference", self) # print("dir", dir(self)) # print("self.reference", self.reference) reference = self.reference @@ -389,7 +389,7 @@ def named_reference(self: behav.NamedReference, context): def indexed_reference(self: behav.IndexedReference, context): - print("indexed_reference") + # print("indexed_reference") self.index = self.index.generate(context) # type inference @@ -407,9 +407,9 @@ def indexed_reference(self: behav.IndexedReference, context): def type_conv(self: behav.TypeConv, context): - print("type_conv") + # print("type_conv") self.expr = self.expr.generate(context) - print("self.expr", self.expr) + # print("self.expr", self.expr) ty = self.expr.inferred_type if ty is None: @@ -429,12 +429,12 @@ def type_conv(self: behav.TypeConv, context): def callable_(self: behav.Callable, context): - print("callable_") - print("self", self) - print("dir(self)", dir(self)) - print("self.ref_or_name", self.ref_or_name) + # print("callable_") + # print("self", self) + # print("dir(self)", dir(self)) + # print("self.ref_or_name", self.ref_or_name) if isinstance(self.ref_or_name, arch.Function): - print("dir(self.ref_or_name)", dir(self.ref_or_name)) + # print("dir(self.ref_or_name)", dir(self.ref_or_name)) assert self.ref_or_name.data_type in [arch.DataType.U, arch.DataType.S] signed = self.ref_or_name.data_type == arch.DataType.S width = self.ref_or_name.size @@ -446,14 +446,14 @@ def callable_(self: behav.Callable, context): def procedure_call(self: behav.ProcedureCall, context): - print("procedure_call") + # print("procedure_call") self.args = [stmt.generate(context) for stmt in self.args] return self def group(self: behav.Group, context): - print("group") + # print("group") self.expr = self.expr.generate(context) if isinstance(self.expr, behav.IntLiteral): @@ -466,5 +466,5 @@ def group(self: behav.Group, context): def break_(self: behav.Break, context): - print("break_") + # print("break_") return self From 0a15f88abc093de45816e686a1f313393e24420a Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Wed, 15 Apr 2026 17:38:00 +0200 Subject: [PATCH 24/24] infer_types: cleanup prints --- m2isar/transforms/infer_types/visitor.py | 103 ----------------------- 1 file changed, 103 deletions(-) diff --git a/m2isar/transforms/infer_types/visitor.py b/m2isar/transforms/infer_types/visitor.py index e2aee579..948c380e 100644 --- a/m2isar/transforms/infer_types/visitor.py +++ b/m2isar/transforms/infer_types/visitor.py @@ -31,34 +31,21 @@ def operation(self: behav.Operation, context): - # print("operation", operation) statements = [] for stmt in self.statements: - # try: temp = stmt.generate(context) if isinstance(temp, list): statements.extend(temp) else: statements.append(temp) - # except (NotImplementedError, ValueError): - # print(f"cant simplify {stmt}") self.statements = statements return self def binary_operation(self: behav.BinaryOperation, context): - # print("binary_operation") - # print("self.op.value", self.op.value) - self.left = self.left.generate(context) self.right = self.right.generate(context) - # print("self.left", self.left) - # print("self.right", self.right) - - # print("self.left.inferred_type", self.left.inferred_type) - # print("self.right.inferred_type", self.right.inferred_type) - # print("self.inferred_type_", self.inferred_type) # see: https://github.com/Minres/CoreDSL/wiki/Expressions#arithmetic-type-rules if self.op.value in ["+", "-", "*", "/", "%", "|", "&", "^", "<<", ">>"]: @@ -126,23 +113,15 @@ def binary_operation(self: behav.BinaryOperation, context): self.inferred_type = arch.IntegerType(1, False, None) # unsigned<1> / bool elif self.op.value in ["<", ">", "==", "!=", ">=", "<="]: self.inferred_type = arch.IntegerType(1, False, None) # unsigned<1> / bool - # print("sit", self.inferred_type.width) - # print("self.inferred_type", self.inferred_type) assert self.inferred_type is not None - # input("!x!") return self def slice_operation(self: behav.SliceOperation, context): - # print("slice_operation") self.expr = self.expr.generate(context) self.left = self.left.generate(context) self.right = self.right.generate(context) - # print("self.expr", self.expr) - # print("self.left", self.left) - # print("self.right", self.right) - # input("slice") # type inference if self.expr.inferred_type is None: @@ -163,23 +142,13 @@ def slice_operation(self: behav.SliceOperation, context): ty_ = copy(ty) ty_._width = width self.inferred_type = ty_ - # print("sit", ty) - # input("*") return self def concat_operation(self: behav.ConcatOperation, context): - # print("concat_coperation") self.left = self.left.generate(context) self.right = self.right.generate(context) - # print("self", self) - # print("dir(self)", dir(self)) - # print("self.left", self.left) - # print("dir(self.left)", dir(self.left)) - # print("self.right", self.right) - # print("dir(self.right)", dir(self.right)) - # input("!") if self.left.inferred_type is None: logger.warning("Concat Operation needs inferred type. Skipping...") return self @@ -194,7 +163,6 @@ def concat_operation(self: behav.ConcatOperation, context): def number_literal(self: behav.IntLiteral, context): - # print("number_literal") if isinstance(self, behav.IntLiteral): bit_size = self.bit_size signed = self.signed @@ -204,7 +172,6 @@ def number_literal(self: behav.IntLiteral, context): def int_literal(self: behav.IntLiteral, context): - # print("int_literal") # type inference bit_size = self.bit_size @@ -216,9 +183,7 @@ def int_literal(self: behav.IntLiteral, context): def scalar_definition(self: behav.ScalarDefinition, context): - # print("scalar_definition") # type inference - # print("scalar_definition", self, dir(self), self.scalar, self.scalar.size, self.scalar.data_type) signed = self.scalar.data_type == arch.DataType.S width = self.scalar.size self.inferred_type = arch.IntegerType(width, signed, None) @@ -226,9 +191,6 @@ def scalar_definition(self: behav.ScalarDefinition, context): def assignment(self: behav.Assignment, context): - # print("assignment", self) - # print("at_", self.target) - # print("ae_", self.expr) self.target = self.target.generate(context) self.expr = self.expr.generate(context) @@ -236,20 +198,12 @@ def assignment(self: behav.Assignment, context): # self.target.scalar.value = self.expr.value # type inference - # print("at", self.target) - # print("ae", self.expr) - # print("at1", self.target.inferred_type) - # print("ae1", self.expr.inferred_type) - # print("at2", self.target.inferred_type.width) - # print("ae2", self.expr.inferred_type.width) - # input("ccc") self.inferred_type = None return self def conditional(self: behav.Conditional, context): - # print("conditional") self.conds = [x.generate(context) for x in self.conds] # self.stmts = [[y.generate(context) for y in x] for x in self.stmts] stmts = [] @@ -265,7 +219,6 @@ def conditional(self: behav.Conditional, context): def loop(self: behav.Loop, context): - # print("loop") self.cond = self.cond.generate(context) self.stmts = [x.generate(context) for x in self.stmts] @@ -273,18 +226,11 @@ def loop(self: behav.Loop, context): def ternary(self: behav.Ternary, context): - # print("ternary") self.cond = self.cond.generate(context) self.then_expr = self.then_expr.generate(context) self.else_expr = self.else_expr.generate(context) - # print("ste", self.then_expr) - # print("see", self.else_expr) - # print("ste1", self.then_expr.inferred_type) - # print("see1", self.else_expr.inferred_type) - # print("ste2", self.then_expr.inferred_type.width) - # print("see2", self.else_expr.inferred_type.width) # TODO then_ty = self.then_expr.inferred_type else_ty = self.else_expr.inferred_type @@ -293,16 +239,12 @@ def ternary(self: behav.Ternary, context): wt = then_ty.width we = else_ty.width wr = max(wt, we) - # print("wr", wr) - # input("o") self.inferred_type = arch.IntegerType(wr, True, None) - # input("ppp") return self def return_(self: behav.Return, context): - # print("return_") if self.expr is not None: self.expr = self.expr.generate(context) @@ -310,14 +252,9 @@ def return_(self: behav.Return, context): def unary_operation(self: behav.UnaryOperation, context): - # print("unary_operation") self.right = self.right.generate(context) - # print("sr", self.right) - # print("sr1", self.right.inferred_type) - # print("sr2", self.right.inferred_type.width) - # input("!") if self.right.inferred_type: w1 = self.right.inferred_type.width if self.op.value == "-": @@ -334,24 +271,16 @@ def unary_operation(self: behav.UnaryOperation, context): def named_reference(self: behav.NamedReference, context): - # print("named_reference", self) - # print("dir", dir(self)) - # print("self.reference", self.reference) reference = self.reference # type inference # self.infered_type = ? if isinstance(reference, arch.BitFieldDescr): - # print("BITFIELD", reference) - # print("self.reference", self.reference) - # print("self.reference.data_type", self.reference.data_type) assert self.reference.data_type in [arch.DataType.U, arch.DataType.S] ty = arch.IntegerType(reference.size, reference.data_type == arch.DataType.S, None) - # print("ty", ty) self.inferred_type = ty elif isinstance(reference, arch.Scalar): - # print("SCALAR", reference) dt = reference.data_type sz = reference.size assert dt in [arch.DataType.U, arch.DataType.S] @@ -359,37 +288,19 @@ def named_reference(self: behav.NamedReference, context): ty = arch.IntegerType(sz, signed, None) self.inferred_type = ty elif isinstance(reference, arch.Memory): - # print("MEMORY", reference) self.inferred_type = arch.IntegerType(reference.size, False, None) - # print("dir(reference)", dir(reference)) - # input("%%%%%") elif isinstance(reference, arch.Intrinsic): - # print("INTRIN", reference) - # print("dir(reference)", dir(reference)) - # print("reference.size", reference.size) - # print("reference.data_type", reference.data_type) assert self.reference.data_type in [arch.DataType.U, arch.DataType.S] self.inferred_type = arch.IntegerType(reference.size, reference.data_type == arch.DataType.S, None) elif isinstance(reference, arch.Constant): - # print("CONST", reference) - # print("dir(reference)", dir(reference)) - # print("reference.size", reference.size) - # print("reference.signed", reference.signed) self.inferred_type = arch.IntegerType(reference.size, reference.signed, None) else: - # print("ELSE", reference) - # print("reference.size", reference.size) - # print("reference.data_type", reference.data_type) assert False, "Unhandled reference" - # print("self.inferred_type", self.inferred_type) - # input("222") - return self def indexed_reference(self: behav.IndexedReference, context): - # print("indexed_reference") self.index = self.index.generate(context) # type inference @@ -400,21 +311,16 @@ def indexed_reference(self: behav.IndexedReference, context): ty_ = arch.IntegerType(size, ty == arch.DataType.S, None) self.inferred_type = ty_ - # print("self.inferred_type", self.inferred_type) - # input("111") return self def type_conv(self: behav.TypeConv, context): - # print("type_conv") self.expr = self.expr.generate(context) - # print("self.expr", self.expr) ty = self.expr.inferred_type if ty is None: logger.warning("Type conv needs inferred type. Skipping...") - input("!!@@") return self assert isinstance(ty, arch.IntegerType) assert self.data_type in [arch.DataType.U, arch.DataType.S] @@ -429,31 +335,23 @@ def type_conv(self: behav.TypeConv, context): def callable_(self: behav.Callable, context): - # print("callable_") - # print("self", self) - # print("dir(self)", dir(self)) - # print("self.ref_or_name", self.ref_or_name) if isinstance(self.ref_or_name, arch.Function): - # print("dir(self.ref_or_name)", dir(self.ref_or_name)) assert self.ref_or_name.data_type in [arch.DataType.U, arch.DataType.S] signed = self.ref_or_name.data_type == arch.DataType.S width = self.ref_or_name.size self.inferred_type = arch.IntegerType(width, signed, None) - # print("self.inferred_type", self.inferred_type) self.args = [stmt.generate(context) for stmt in self.args] return self def procedure_call(self: behav.ProcedureCall, context): - # print("procedure_call") self.args = [stmt.generate(context) for stmt in self.args] return self def group(self: behav.Group, context): - # print("group") self.expr = self.expr.generate(context) if isinstance(self.expr, behav.IntLiteral): @@ -466,5 +364,4 @@ def group(self: behav.Group, context): def break_(self: behav.Break, context): - # print("break_") return self