mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-06-09 23:08:18 +02:00
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:
parent
8b59d133ec
commit
068ea94ca3
2 changed files with 228 additions and 1 deletions
217
src/intel/compiler/gen/gen_inst_info.py
Executable file
217
src/intel/compiler/gen/gen_inst_info.py
Executable 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()
|
||||
|
|
@ -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'],
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue