intel/gen: Add gen_inst_info.py script to generate C++ headers

Signed-off-by: Jordan Justen <jordan.l.justen@intel.com>
Acked-by: Caio Oliveira <caio.oliveira@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/41413>
This commit is contained in:
Jordan Justen 2026-03-25 02:20:46 -07:00 committed by Marge Bot
parent 8b59d133ec
commit 068ea94ca3
2 changed files with 228 additions and 1 deletions

View file

@ -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])}</%def>
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_inst_description, 128> gen_to_description =
[]() constexpr {
std::array<gen_inst_description, 128> 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<gen_inst_description, 128> hw_to_description =
[]() constexpr {
std::array<gen_inst_description, 128> 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()

View file

@ -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'],