From 068ea94ca3c14c604c39fb327d43bfc6d1ff43b4 Mon Sep 17 00:00:00 2001 From: Jordan Justen Date: Wed, 25 Mar 2026 02:20:46 -0700 Subject: [PATCH] intel/gen: Add gen_inst_info.py script to generate C++ headers Signed-off-by: Jordan Justen Acked-by: Caio Oliveira Part-of: --- src/intel/compiler/gen/gen_inst_info.py | 217 ++++++++++++++++++++++++ src/intel/compiler/gen/meson.build | 12 +- 2 files changed, 228 insertions(+), 1 deletion(-) create mode 100755 src/intel/compiler/gen/gen_inst_info.py diff --git a/src/intel/compiler/gen/gen_inst_info.py b/src/intel/compiler/gen/gen_inst_info.py new file mode 100755 index 00000000000..6674f8a4bd0 --- /dev/null +++ b/src/intel/compiler/gen/gen_inst_info.py @@ -0,0 +1,217 @@ +#!/usr/bin/env python3 +# Copyright © 2025 Intel Corporation +# SPDX-License-Identifier: MIT + +import argparse +import copy +import ctypes +import enum +import fcntl +import json +import pathlib +import os +import re +import sys + + + +H_TEMPLATE = """\ +/* + * Copyright © 2026 Intel Corporation + * SPDX-License-Identifier: MIT + * + * Autogenerated file, do not edit! + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus + +<%def name="comma_join(l)">${', '.join([str(i) for i in l])} + +struct gen_encoding_${info.name.lower()} { + static constexpr gen_encoding_type TYPE = GEN_ENCODING_${info.name.upper()}; + +% for (i, r) in info.fields.items(): + FIELD(${i}, ${comma_join(r)}); +% endfor +% for (i, r) in info.compact_fields.items(): + FIELD(C_${i}, ${comma_join(r)}); +% endfor +% for (i, r) in info.sub_fields.items(): + SUB_FIELD(${i}, ${comma_join(r)}); +% endfor + + static constexpr std::array gen_to_description = + []() constexpr { + std::array r; +% for (op, brw) in info.gen_op_to_brw.items(): + r[GEN_OP_${op}] = gen_inst_description(GEN_OP_${op}, ${brw}); +% endfor + return r; + }(); + + static constexpr std::array hw_to_description = + []() constexpr { + std::array r; +% for (op, brw) in info.gen_op_to_brw.items(): + r[${brw}] = gen_inst_description(GEN_OP_${op}, ${brw}); +% endfor + return r; + }(); +}; + +#endif + +#ifdef __cplusplus +} +#endif +""" + + +class InstructionInfo: + + def __init__(self, raw_info, name): + self.name = name + self.imported = set() + self.target = self.__init_with_inheritance(raw_info, name) + assert name in self.imported + + def __init_with_inheritance(self, raw_info, name): + assert name in raw_info + import_name = raw_info[name].get('import') + if import_name: + assert import_name not in self.imported + self.imported.add(import_name) + base = self.__init_with_inheritance(raw_info, import_name) + else: + base = dict() + + def find_dicts(d): + return set({ k for k, v in d.items() if isinstance(v, dict) }) + + new_target = copy.deepcopy(raw_info[name]) + + # Drop all comment items. (object key names that start with a '#') + for d in find_dicts(new_target): + new_target[d] = { k: v for k, v + in new_target[d].items() + if not k.startswith('#') } + + if import_name: + needed = find_dicts(new_target) - find_dicts(base) + base.update({ k: {} for k in needed }) + needed = find_dicts(base) - find_dicts(new_target) + new_target.update({ k: {} for k in needed }) + # Merge imported fields, but prefer current version + dicts = find_dicts(new_target) + for d in dicts: + old_only = { k: v for k, v in base[d].items() + if k not in new_target[d] } + assert len(set(old_only.keys()).intersection(set(new_target[d].keys()))) == 0 + new_target[d].update(old_only) + + required_infos = ('fields', 'sub-fields', 'compact-fields', + 'gen-op-to-brw') + for info in required_infos: + if info not in new_target: + new_target[info] = {} + + # Drop all items that are None (null in json) + for d in find_dicts(new_target): + new_target[d] = { k: v for k, v in new_target[d].items() + if v is not None } + + self.imported.add(name) + return new_target + + def __getattr__(self, name): + dashed_name = name.replace('_', '-') + if dashed_name in self.target: + return self.target[dashed_name] + raise AttributeError + + def for_mako(self): + return self.target + +class GenInstructionSources: + + def __init__(self, args): + self.args = args + self.raw_info = {} + for in_json in self.args.json: + in_json = pathlib.Path(in_json) + assert in_json.is_file() + self.outdir = pathlib.Path(args.output_dir) + assert self.outdir.is_dir() + with open(in_json, 'r', encoding='utf8') as json_file: + new_info = json.load(json_file) + # Make sure there is no overlap in json input + assert all({k not in self.raw_info for k in new_info.keys()}) + self.raw_info.update(new_info) + + import mako.template + self.h_template = mako.template.Template(H_TEMPLATE) + + def gen(self): + gen_count = 0 + if self.args.cpp: + gen_count += self.gen_cpp_headers() + if gen_count == 0: + print("info: No sources specified to be generated") + return gen_count > 0 + + def gen_cpp_header(self, name): + info = InstructionInfo(self.raw_info, name) + template_input = { + "info": info, + } + filename = self.outdir / f'gen_info_{name.lower()}.h' + with open(filename, 'w', encoding='utf8') as h: + try: + print('Generating', filename) + h.write(self.h_template.render(**template_input)) + except: + import mako.exceptions + print(mako.exceptions.text_error_template().render()) + raise + return True + + def gen_cpp_headers(self): + count = 0 + names = list(self.raw_info.keys()) + for name in names: + if self.gen_cpp_header(name): + count += 1 + return count + +class GenInstructionsApp: + + def __init__(self): + self.parse_args() + self.gen_sources = GenInstructionSources(self.args) + sys.exit(0 if self.gen_sources.gen() else 1) + + def parse_args(self): + p = argparse.ArgumentParser() + p.add_argument("-v", "--verbose", action="count", default=0, + help="Enable verbose output") + p.add_argument("--json", action="append", default=[], + help="Input json describing the target") + p.add_argument("--output-dir", required=True, + help="Output directory for generated files") + p.add_argument("--cpp", action="store_true", default=False, + help="Generate C++ headers") + + a = p.parse_args() + + self.args = a + self.verbose = a.verbose + + +if __name__ == "__main__": + GenInstructionsApp() diff --git a/src/intel/compiler/gen/meson.build b/src/intel/compiler/gen/meson.build index 51ac39d7d24..96cddf0f13d 100644 --- a/src/intel/compiler/gen/meson.build +++ b/src/intel/compiler/gen/meson.build @@ -17,9 +17,19 @@ libintel_compiler_gen_files = files( 'gen_validate.cpp', ) +gen_gen_srcs = custom_target('gen_info_*.h', + input : ['gen_inst_info.py', + 'pre_xe.json', 'xe.json'], + output : ['gen_info_pre_xe.h', 'gen_info_xe.h', + 'gen_info_xe2.h'], + command : [prog_python, + '@INPUT0@', + '--json=@INPUT1@', '--json=@INPUT2@', + '--output-dir=@OUTDIR@', '--cpp']) + libintel_compiler_gen = static_library( 'intel_compiler_gen', - libintel_compiler_gen_files, + [libintel_compiler_gen_files, gen_gen_srcs], include_directories : [inc_include, inc_src, inc_intel, inc_intel_compiler], c_args : [no_override_init_args], cpp_args : ['-Werror=vla'],