# Copyright (c) 2025-2026 Advanced Micro Devices, Inc. # SPDX-License-Identifier: MIT """C++ file emission for generated ISA code.""" from __future__ import annotations import os import re import cgen from collections.abc import Sequence from datetime import datetime from typing import TextIO class CppFile: """A generated C++ file (.h or .cpp). Defines a common structure: copyright, includes, namespace, forward declarations, and source code objects. The top-level namespace is currently hardcoded to ``rocjitsu``. Namespace is configurable via ``CodegenConfig.namespace``. Attributes: name: File name without extension. out_path: Output directory for generated files. is_header: True if this is a header file. includes: List of (include_name, is_system_header) pairs. fwd_decls: Forward declarations within the namespace. src_code: Source code objects (strings or cgen objects). arch_name: ISA architecture name. replace_structs: If True, replace 'struct' with 'class' in output. file_name: File name with extension. """ @staticmethod def _prologue_comment() -> str: year = datetime.now().strftime('%Y') return ( f'// Copyright (c) 2025-{year} Advanced Micro Devices, Inc.\n' f'// SPDX-License-Identifier: MIT\n' f'//\n' f'// AUTO-GENERATED by the amdisa codegen pipeline. DO NOT EDIT.\n' f'// See lib/python/amdisa/README.md for regeneration instructions.\n\n' ) def __init__( self, name: str, out_path: str, is_header: bool, includes: list[tuple[str, bool]], fwd_decls: list[str], src_code: Sequence[object], arch_name: str, replace_structs: bool = False, ) -> None: self.name = name self.out_path = out_path self.is_header = is_header self.includes = includes self.fwd_decls = fwd_decls self.src_code = src_code self.arch_name = arch_name self.replace_structs = replace_structs self.file_name = self.name if self.is_header: self.file_name += '.h' include_guard_components = [s.upper() for s in self.name.split('_')] self.include_guard = ( f'ROCJITSU_ISA_ARCH_AMDGPU_{self.arch_name.upper()}_' + '_'.join(include_guard_components) + '_H_' ) else: self.file_name += '.cpp' def gen_prologue(self, f: TextIO) -> None: """Write copyright, include guard, includes, and namespace opener.""" f.write(CppFile._prologue_comment()) if self.is_header: f.write(f'#ifndef {self.include_guard}\n') f.write(f'#define {self.include_guard}\n\n') f.writelines([f'{cgen.Include(x[0], x[1])}\n' for x in self.includes]) f.write('\n') f.write('namespace rocjitsu {\n') f.writelines( [f'\n{cgen.Statement("class " + x)}' + '\n\n' for x in self.fwd_decls] ) f.write(f'namespace {self.arch_name} {{\n') f.write('\n') def gen_header(self, f: TextIO) -> None: """Write header body and closing guards.""" if self.replace_structs: f.writelines( [re.sub(r'^struct\s', 'class ', f'{e}\n\n') for e in self.src_code] ) else: f.writelines([f'{e}\n\n' for e in self.src_code]) f.write(f'}} // namespace {self.arch_name}\n}}' f' // namespace rocjitsu\n') f.write(f'\n#endif // {self.include_guard}\n') def gen_cpp(self, f: TextIO) -> None: """Write source file body and closing namespaces.""" f.writelines([f'{e}\n\n' for e in self.src_code]) f.write(f'}} // namespace {self.arch_name}' f'\n}} // namespace rocjitsu\n') def gen_code(self) -> None: """Generate the file (header or source).""" arch_out_path = os.path.join(self.out_path, self.arch_name) os.makedirs(arch_out_path, exist_ok=True) with open(os.path.join(arch_out_path, self.file_name), 'w') as f: self.gen_prologue(f) if self.is_header: self.gen_header(f) else: self.gen_cpp(f)