Path: blob/21.2-virgl/src/intel/genxml/gen_pack_header.py
7095 views
#encoding=utf-812from __future__ import (3absolute_import, division, print_function, unicode_literals4)5import argparse6import ast7import xml.parsers.expat8import re9import sys10import copy11import textwrap12from util import *1314license = """/*15* Copyright (C) 2016 Intel Corporation16*17* Permission is hereby granted, free of charge, to any person obtaining a18* copy of this software and associated documentation files (the "Software"),19* to deal in the Software without restriction, including without limitation20* the rights to use, copy, modify, merge, publish, distribute, sublicense,21* and/or sell copies of the Software, and to permit persons to whom the22* Software is furnished to do so, subject to the following conditions:23*24* The above copyright notice and this permission notice (including the next25* paragraph) shall be included in all copies or substantial portions of the26* Software.27*28* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR29* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,30* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL31* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER32* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING33* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS34* IN THE SOFTWARE.35*/36"""3738pack_header = """%(license)s3940/* Instructions, enums and structures for %(platform)s.41*42* This file has been generated, do not hand edit.43*/4445#ifndef %(guard)s46#define %(guard)s4748#include <stdio.h>49#include <stdint.h>50#include <stdbool.h>51#include <assert.h>52#include <math.h>5354#ifndef __gen_validate_value55#define __gen_validate_value(x)56#endif5758#ifndef __intel_field_functions59#define __intel_field_functions6061#ifdef NDEBUG62#define NDEBUG_UNUSED __attribute__((unused))63#else64#define NDEBUG_UNUSED65#endif6667union __intel_value {68float f;69uint32_t dw;70};7172static inline __attribute__((always_inline)) uint64_t73__gen_mbo(uint32_t start, uint32_t end)74{75return (~0ull >> (64 - (end - start + 1))) << start;76}7778static inline __attribute__((always_inline)) uint64_t79__gen_uint(uint64_t v, uint32_t start, NDEBUG_UNUSED uint32_t end)80{81__gen_validate_value(v);8283#ifndef NDEBUG84const int width = end - start + 1;85if (width < 64) {86const uint64_t max = (1ull << width) - 1;87assert(v <= max);88}89#endif9091return v << start;92}9394static inline __attribute__((always_inline)) uint64_t95__gen_sint(int64_t v, uint32_t start, uint32_t end)96{97const int width = end - start + 1;9899__gen_validate_value(v);100101#ifndef NDEBUG102if (width < 64) {103const int64_t max = (1ll << (width - 1)) - 1;104const int64_t min = -(1ll << (width - 1));105assert(min <= v && v <= max);106}107#endif108109const uint64_t mask = ~0ull >> (64 - width);110111return (v & mask) << start;112}113114static inline __attribute__((always_inline)) uint64_t115__gen_offset(uint64_t v, NDEBUG_UNUSED uint32_t start, NDEBUG_UNUSED uint32_t end)116{117__gen_validate_value(v);118#ifndef NDEBUG119uint64_t mask = (~0ull >> (64 - (end - start + 1))) << start;120121assert((v & ~mask) == 0);122#endif123124return v;125}126127static inline __attribute__((always_inline)) uint64_t128__gen_address(__gen_user_data *data, void *location,129__gen_address_type address, uint32_t delta,130__attribute__((unused)) uint32_t start, uint32_t end)131{132uint64_t addr_u64 = __gen_combine_address(data, location, address, delta);133if (end == 31) {134return addr_u64;135} else if (end < 63) {136const unsigned shift = 63 - end;137return (addr_u64 << shift) >> shift;138} else {139return addr_u64;140}141}142143static inline __attribute__((always_inline)) uint32_t144__gen_float(float v)145{146__gen_validate_value(v);147return ((union __intel_value) { .f = (v) }).dw;148}149150static inline __attribute__((always_inline)) uint64_t151__gen_sfixed(float v, uint32_t start, uint32_t end, uint32_t fract_bits)152{153__gen_validate_value(v);154155const float factor = (1 << fract_bits);156157#ifndef NDEBUG158const float max = ((1 << (end - start)) - 1) / factor;159const float min = -(1 << (end - start)) / factor;160assert(min <= v && v <= max);161#endif162163const int64_t int_val = llroundf(v * factor);164const uint64_t mask = ~0ull >> (64 - (end - start + 1));165166return (int_val & mask) << start;167}168169static inline __attribute__((always_inline)) uint64_t170__gen_ufixed(float v, uint32_t start, NDEBUG_UNUSED uint32_t end, uint32_t fract_bits)171{172__gen_validate_value(v);173174const float factor = (1 << fract_bits);175176#ifndef NDEBUG177const float max = ((1 << (end - start + 1)) - 1) / factor;178const float min = 0.0f;179assert(min <= v && v <= max);180#endif181182const uint64_t uint_val = llroundf(v * factor);183184return uint_val << start;185}186187#ifndef __gen_address_type188#error #define __gen_address_type before including this file189#endif190191#ifndef __gen_user_data192#error #define __gen_combine_address before including this file193#endif194195#undef NDEBUG_UNUSED196197#endif198199"""200201def num_from_str(num_str):202if num_str.lower().startswith('0x'):203return int(num_str, base=16)204205assert not num_str.startswith('0'), 'octals numbers not allowed'206return int(num_str)207208class Field(object):209ufixed_pattern = re.compile(r"u(\d+)\.(\d+)")210sfixed_pattern = re.compile(r"s(\d+)\.(\d+)")211212def __init__(self, parser, attrs):213self.parser = parser214if "name" in attrs:215self.name = safe_name(attrs["name"])216self.start = int(attrs["start"])217self.end = int(attrs["end"])218self.type = attrs["type"]219220assert self.start <= self.end, \221'field {} has end ({}) < start ({})'.format(self.name, self.end,222self.start)223if self.type == 'bool':224assert self.end == self.start, \225'bool field ({}) is too wide'.format(self.name)226227if "prefix" in attrs:228self.prefix = attrs["prefix"]229else:230self.prefix = None231232if "default" in attrs:233# Base 0 recognizes 0x, 0o, 0b prefixes in addition to decimal ints.234self.default = int(attrs["default"], base=0)235else:236self.default = None237238ufixed_match = Field.ufixed_pattern.match(self.type)239if ufixed_match:240self.type = 'ufixed'241self.fractional_size = int(ufixed_match.group(2))242243sfixed_match = Field.sfixed_pattern.match(self.type)244if sfixed_match:245self.type = 'sfixed'246self.fractional_size = int(sfixed_match.group(2))247248def is_builtin_type(self):249builtins = [ 'address', 'bool', 'float', 'ufixed',250'offset', 'sfixed', 'offset', 'int', 'uint', 'mbo' ]251return self.type in builtins252253def is_struct_type(self):254return self.type in self.parser.structs255256def is_enum_type(self):257return self.type in self.parser.enums258259def emit_template_struct(self, dim):260if self.type == 'address':261type = '__gen_address_type'262elif self.type == 'bool':263type = 'bool'264elif self.type == 'float':265type = 'float'266elif self.type == 'ufixed':267type = 'float'268elif self.type == 'sfixed':269type = 'float'270elif self.type == 'uint' and self.end - self.start > 32:271type = 'uint64_t'272elif self.type == 'offset':273type = 'uint64_t'274elif self.type == 'int':275type = 'int32_t'276elif self.type == 'uint':277type = 'uint32_t'278elif self.is_struct_type():279type = 'struct ' + self.parser.gen_prefix(safe_name(self.type))280elif self.is_enum_type():281type = 'enum ' + self.parser.gen_prefix(safe_name(self.type))282elif self.type == 'mbo':283return284else:285print("#error unhandled type: %s" % self.type)286return287288print(" %-36s %s%s;" % (type, self.name, dim))289290prefix = ""291if self.values and self.default is None:292if self.prefix:293prefix = self.prefix + "_"294295for value in self.values:296print("#define %-40s %d" % (prefix + value.name, value.value))297298class Group(object):299def __init__(self, parser, parent, start, count, size):300self.parser = parser301self.parent = parent302self.start = start303self.count = count304self.size = size305self.fields = []306307def emit_template_struct(self, dim):308if self.count == 0:309print(" /* variable length fields follow */")310else:311if self.count > 1:312dim = "%s[%d]" % (dim, self.count)313314for field in self.fields:315field.emit_template_struct(dim)316317class DWord:318def __init__(self):319self.size = 32320self.fields = []321self.address = None322323def collect_dwords(self, dwords, start, dim):324for field in self.fields:325if isinstance(field, Group):326if field.count == 1:327field.collect_dwords(dwords, start + field.start, dim)328else:329for i in range(field.count):330field.collect_dwords(dwords,331start + field.start + i * field.size,332"%s[%d]" % (dim, i))333continue334335index = (start + field.start) // 32336if not index in dwords:337dwords[index] = self.DWord()338339clone = copy.copy(field)340clone.start = clone.start + start341clone.end = clone.end + start342clone.dim = dim343dwords[index].fields.append(clone)344345if field.type == "address":346# assert dwords[index].address == None347dwords[index].address = clone348349# Coalesce all the dwords covered by this field. The two cases we350# handle are where multiple fields are in a 64 bit word (typically351# and address and a few bits) or where a single struct field352# completely covers multiple dwords.353while index < (start + field.end) // 32:354if index + 1 in dwords and not dwords[index] == dwords[index + 1]:355dwords[index].fields.extend(dwords[index + 1].fields)356dwords[index].size = 64357dwords[index + 1] = dwords[index]358index = index + 1359360def collect_dwords_and_length(self):361dwords = {}362self.collect_dwords(dwords, 0, "")363364# Determine number of dwords in this group. If we have a size, use365# that, since that'll account for MBZ dwords at the end of a group366# (like dword 8 on BDW+ 3DSTATE_HS). Otherwise, use the largest dword367# index we've seen plus one.368if self.size > 0:369length = self.size // 32370elif dwords:371length = max(dwords.keys()) + 1372else:373length = 0374375return (dwords, length)376377def emit_pack_function(self, dwords, length):378for index in range(length):379# Handle MBZ dwords380if not index in dwords:381print("")382print(" dw[%d] = 0;" % index)383continue384385# For 64 bit dwords, we aliased the two dword entries in the dword386# dict it occupies. Now that we're emitting the pack function,387# skip the duplicate entries.388dw = dwords[index]389if index > 0 and index - 1 in dwords and dw == dwords[index - 1]:390continue391392# Special case: only one field and it's a struct at the beginning393# of the dword. In this case we pack directly into the394# destination. This is the only way we handle embedded structs395# larger than 32 bits.396if len(dw.fields) == 1:397field = dw.fields[0]398name = field.name + field.dim399if field.is_struct_type() and field.start % 32 == 0:400print("")401print(" %s_pack(data, &dw[%d], &values->%s);" %402(self.parser.gen_prefix(safe_name(field.type)), index, name))403continue404405# Pack any fields of struct type first so we have integer values406# to the dword for those fields.407field_index = 0408for field in dw.fields:409if isinstance(field, Field) and field.is_struct_type():410name = field.name + field.dim411print("")412print(" uint32_t v%d_%d;" % (index, field_index))413print(" %s_pack(data, &v%d_%d, &values->%s);" %414(self.parser.gen_prefix(safe_name(field.type)), index, field_index, name))415field_index = field_index + 1416417print("")418dword_start = index * 32419if dw.address == None:420address_count = 0421else:422address_count = 1423424if dw.size == 32 and dw.address == None:425v = None426print(" dw[%d] =" % index)427elif len(dw.fields) > address_count:428v = "v%d" % index429print(" const uint%d_t %s =" % (dw.size, v))430else:431v = "0"432433field_index = 0434non_address_fields = []435for field in dw.fields:436if field.type != "mbo":437name = field.name + field.dim438439if field.type == "mbo":440non_address_fields.append("__gen_mbo(%d, %d)" % \441(field.start - dword_start, field.end - dword_start))442elif field.type == "address":443pass444elif field.type == "uint":445non_address_fields.append("__gen_uint(values->%s, %d, %d)" % \446(name, field.start - dword_start, field.end - dword_start))447elif field.is_enum_type():448non_address_fields.append("__gen_uint(values->%s, %d, %d)" % \449(name, field.start - dword_start, field.end - dword_start))450elif field.type == "int":451non_address_fields.append("__gen_sint(values->%s, %d, %d)" % \452(name, field.start - dword_start, field.end - dword_start))453elif field.type == "bool":454non_address_fields.append("__gen_uint(values->%s, %d, %d)" % \455(name, field.start - dword_start, field.end - dword_start))456elif field.type == "float":457non_address_fields.append("__gen_float(values->%s)" % name)458elif field.type == "offset":459non_address_fields.append("__gen_offset(values->%s, %d, %d)" % \460(name, field.start - dword_start, field.end - dword_start))461elif field.type == 'ufixed':462non_address_fields.append("__gen_ufixed(values->%s, %d, %d, %d)" % \463(name, field.start - dword_start, field.end - dword_start, field.fractional_size))464elif field.type == 'sfixed':465non_address_fields.append("__gen_sfixed(values->%s, %d, %d, %d)" % \466(name, field.start - dword_start, field.end - dword_start, field.fractional_size))467elif field.is_struct_type():468non_address_fields.append("__gen_uint(v%d_%d, %d, %d)" % \469(index, field_index, field.start - dword_start, field.end - dword_start))470field_index = field_index + 1471else:472non_address_fields.append("/* unhandled field %s, type %s */\n" % \473(name, field.type))474475if non_address_fields:476print(" |\n".join(" " + f for f in non_address_fields) + ";")477478if dw.size == 32:479if dw.address:480print(" dw[%d] = __gen_address(data, &dw[%d], values->%s, %s, %d, %d);" %481(index, index, dw.address.name + field.dim, v,482dw.address.start - dword_start, dw.address.end - dword_start))483continue484485if dw.address:486v_address = "v%d_address" % index487print(" const uint64_t %s =\n __gen_address(data, &dw[%d], values->%s, %s, %d, %d);" %488(v_address, index, dw.address.name + field.dim, v,489dw.address.start - dword_start, dw.address.end - dword_start))490if len(dw.fields) > address_count:491print(" dw[%d] = %s;" % (index, v_address))492print(" dw[%d] = (%s >> 32) | (%s >> 32);" % (index + 1, v_address, v))493continue494else:495v = v_address496print(" dw[%d] = %s;" % (index, v))497print(" dw[%d] = %s >> 32;" % (index + 1, v))498499class Value(object):500def __init__(self, attrs):501self.name = safe_name(attrs["name"])502self.value = ast.literal_eval(attrs["value"])503504class Parser(object):505def __init__(self):506self.parser = xml.parsers.expat.ParserCreate()507self.parser.StartElementHandler = self.start_element508self.parser.EndElementHandler = self.end_element509510self.instruction = None511self.structs = {}512# Set of enum names we've seen.513self.enums = set()514self.registers = {}515516def gen_prefix(self, name):517if name[0] == "_":518return 'GFX%s%s' % (self.gen, name)519return 'GFX%s_%s' % (self.gen, name)520521def gen_guard(self):522return self.gen_prefix("PACK_H")523524def start_element(self, name, attrs):525if name == "genxml":526self.platform = attrs["name"]527self.gen = attrs["gen"].replace('.', '')528print(pack_header % {'license': license, 'platform': self.platform, 'guard': self.gen_guard()})529elif name in ("instruction", "struct", "register"):530if name == "instruction":531self.instruction = safe_name(attrs["name"])532self.length_bias = int(attrs["bias"])533if "engine" in attrs:534self.instruction_engines = set(attrs["engine"].split('|'))535else:536# When an instruction doesn't have the engine specified,537# it is considered to be for all engines, so 'None' is used538# to signify that the instruction belongs to all engines.539self.instruction_engines = None540elif name == "struct":541self.struct = safe_name(attrs["name"])542self.structs[attrs["name"]] = 1543elif name == "register":544self.register = safe_name(attrs["name"])545self.reg_num = num_from_str(attrs["num"])546self.registers[attrs["name"]] = 1547if "length" in attrs:548self.length = int(attrs["length"])549size = self.length * 32550else:551self.length = None552size = 0553self.group = Group(self, None, 0, 1, size)554555elif name == "group":556group = Group(self, self.group,557int(attrs["start"]), int(attrs["count"]), int(attrs["size"]))558self.group.fields.append(group)559self.group = group560elif name == "field":561self.group.fields.append(Field(self, attrs))562self.values = []563elif name == "enum":564self.values = []565self.enum = safe_name(attrs["name"])566self.enums.add(attrs["name"])567if "prefix" in attrs:568self.prefix = safe_name(attrs["prefix"])569else:570self.prefix= None571elif name == "value":572self.values.append(Value(attrs))573574def end_element(self, name):575if name == "instruction":576self.emit_instruction()577self.instruction = None578self.group = None579elif name == "struct":580self.emit_struct()581self.struct = None582self.group = None583elif name == "register":584self.emit_register()585self.register = None586self.reg_num = None587self.group = None588elif name == "group":589self.group = self.group.parent590elif name == "field":591self.group.fields[-1].values = self.values592elif name == "enum":593self.emit_enum()594self.enum = None595elif name == "genxml":596print('#endif /* %s */' % self.gen_guard())597598def emit_template_struct(self, name, group):599print("struct %s {" % self.gen_prefix(name))600group.emit_template_struct("")601print("};\n")602603def emit_pack_function(self, name, group):604name = self.gen_prefix(name)605print(textwrap.dedent("""\606static inline __attribute__((always_inline)) void607%s_pack(__attribute__((unused)) __gen_user_data *data,608%s__attribute__((unused)) void * restrict dst,609%s__attribute__((unused)) const struct %s * restrict values)610{""") % (name, ' ' * len(name), ' ' * len(name), name))611612(dwords, length) = group.collect_dwords_and_length()613if length:614# Cast dst to make header C++ friendly615print(" uint32_t * restrict dw = (uint32_t * restrict) dst;")616617group.emit_pack_function(dwords, length)618619print("}\n")620621def emit_instruction(self):622name = self.instruction623if self.instruction_engines and not self.instruction_engines & self.engines:624return625626if not self.length is None:627print('#define %-33s %6d' %628(self.gen_prefix(name + "_length"), self.length))629print('#define %-33s %6d' %630(self.gen_prefix(name + "_length_bias"), self.length_bias))631632default_fields = []633for field in self.group.fields:634if not isinstance(field, Field):635continue636if field.default is None:637continue638639if field.is_builtin_type():640default_fields.append(" .%-35s = %6d" % (field.name, field.default))641else:642# Default values should not apply to structures643assert field.is_enum_type()644default_fields.append(" .%-35s = (enum %s) %6d" % (field.name, self.gen_prefix(safe_name(field.type)), field.default))645646if default_fields:647print('#define %-40s\\' % (self.gen_prefix(name + '_header')))648print(", \\\n".join(default_fields))649print('')650651self.emit_template_struct(self.instruction, self.group)652653self.emit_pack_function(self.instruction, self.group)654655def emit_register(self):656name = self.register657if not self.reg_num is None:658print('#define %-33s 0x%04x' %659(self.gen_prefix(name + "_num"), self.reg_num))660661if not self.length is None:662print('#define %-33s %6d' %663(self.gen_prefix(name + "_length"), self.length))664665self.emit_template_struct(self.register, self.group)666self.emit_pack_function(self.register, self.group)667668def emit_struct(self):669name = self.struct670if not self.length is None:671print('#define %-33s %6d' %672(self.gen_prefix(name + "_length"), self.length))673674self.emit_template_struct(self.struct, self.group)675self.emit_pack_function(self.struct, self.group)676677def emit_enum(self):678print('enum %s {' % self.gen_prefix(self.enum))679for value in self.values:680if self.prefix:681name = self.prefix + "_" + value.name682else:683name = value.name684print(' %-36s = %6d,' % (name.upper(), value.value))685print('};\n')686687def parse(self, filename):688file = open(filename, "rb")689self.parser.ParseFile(file)690file.close()691692def parse_args():693p = argparse.ArgumentParser()694p.add_argument('xml_source', metavar='XML_SOURCE',695help="Input xml file")696p.add_argument('--engines', nargs='?', type=str, default='render',697help="Comma-separated list of engines whose instructions should be parsed (default: %(default)s)")698699pargs = p.parse_args()700701if pargs.engines is None:702print("No engines specified")703sys.exit(1)704705return pargs706707def main():708pargs = parse_args()709710input_file = pargs.xml_source711engines = pargs.engines.split(',')712valid_engines = [ 'render', 'blitter', 'video' ]713if set(engines) - set(valid_engines):714print("Invalid engine specified, valid engines are:\n")715for e in valid_engines:716print("\t%s" % e)717sys.exit(1)718719p = Parser()720p.engines = set(engines)721p.parse(input_file)722723if __name__ == '__main__':724main()725726727