Path: blob/21.2-virgl/src/freedreno/isa/encode.py
4564 views
#1# Copyright © 2020 Google, Inc.2#3# Permission is hereby granted, free of charge, to any person obtaining a4# copy of this software and associated documentation files (the "Software"),5# to deal in the Software without restriction, including without limitation6# the rights to use, copy, modify, merge, publish, distribute, sublicense,7# and/or sell copies of the Software, and to permit persons to whom the8# Software is furnished to do so, subject to the following conditions:9#10# The above copyright notice and this permission notice (including the next11# paragraph) shall be included in all copies or substantial portions of the12# Software.13#14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20# IN THE SOFTWARE.2122from mako.template import Template23from isa import ISA, BitSetDerivedField, BitSetAssertField24import sys25import re2627# Encoding is driven by the display template that would be used28# to decode any given instruction, essentially working backwards29# from the decode case. (Or put another way, the decoded bitset30# should contain enough information to re-encode it again.)31#32# In the xml, we can have multiple override cases per bitset,33# which can override display template and/or fields. Iterating34# all this from within the template is messy, so use helpers35# outside of the template for this.36#37# The hierarchy of iterators for encoding is:38#39# // First level - Case() (s.bitset_cases() iterator)40# if (caseA.expression()) { // maps to <override/> in xml41# // Second level - DisplayField() (case.display_fields() iterator)42# ... encode field A ...43# ... encode field B ...44#45# // Third level - each display field can be resolved in potentially46# // resolved by multiple different overrides, you can end up with47# // an if/else ladder for an individual display field48# if (field_c_case1.expression()) {49# ... encode field C ...50# } else if (field_c_case2.expression() {51# ... encode field C ...52# } else {53# }54#55# } else if (caseB.expression())(56# } else { // maps to the default case in bitset, ie. outside <override/>57# }585960# Represents a concrete field, ie. a field can be overriden61# by an override, so the exact choice to encode a given field62# in a bitset may be conditional63class FieldCase(object):64def __init__(self, field, case):65self.field = field66self.expr = None67if case.expr is not None:68self.expr = isa.expressions[case.expr]6970class AssertField(object):71def __init__(self, field, case):72self.field = field73self.expr = None74if case.expr is not None:75self.expr = isa.expressions[case.expr]7677# Represents a field to be encoded:78class DisplayField(object):79def __init__(self, bitset, case, name):80self.bitset = bitset # leaf bitset81self.case = case82self.name = name8384def fields(self, bitset=None):85if bitset is None:86bitset = self.bitset87# resolving the various cases for encoding a given88# field is similar to resolving the display template89# string90for case in bitset.cases:91if case.expr is not None:92expr = bitset.isa.expressions[case.expr]93self.case.append_expr_fields(expr)94if self.name in case.fields:95field = case.fields[self.name]96# For bitset fields, the bitset type could reference97# fields in this (the containing) bitset, in addition98# to the ones which are directly used to encode the99# field itself.100if field.get_c_typename() == 'TYPE_BITSET':101for param in field.params:102self.case.append_field(param[0])103# For derived fields, we want to consider any other104# fields that are referenced by the expr105if isinstance(field, BitSetDerivedField):106expr = bitset.isa.expressions[field.expr]107self.case.append_expr_fields(expr)108elif not isinstance(field, BitSetAssertField):109yield FieldCase(field, case)110# if we've found an unconditional case specifying111# the named field, we are done112if case.expr is None:113return114if bitset.extends is not None:115yield from self.fields(isa.bitsets[bitset.extends])116117# Represents an if/else case in bitset encoding which has a display118# template string:119class Case(object):120def __init__(self, bitset, case):121self.bitset = bitset # leaf bitset122self.case = case123self.expr = None124if case.expr is not None:125self.expr = isa.expressions[case.expr]126self.fieldnames = re.findall(r"{([a-zA-Z0-9_]+)}", case.display)127self.append_forced(bitset)128129# Handle fields which don't appear in display template but have130# force="true"131def append_forced(self, bitset):132if bitset.encode is not None:133for name, val in bitset.encode.forced.items():134self.append_field(name)135if bitset.extends is not None:136self.append_forced(isa.bitsets[bitset.extends])137138# In the process of resolving a field, we might discover additional139# fields that need resolving:140#141# a) a derived field which maps to one or more other concrete fields142# b) a bitset field, which may be "parameterized".. for example a143# #multisrc field which refers back to SRC1_R/SRC2_R outside of144# the range of bits covered by the #multisrc field itself145def append_field(self, fieldname):146if fieldname not in self.fieldnames:147self.fieldnames.append(fieldname)148149def append_expr_fields(self, expr):150for fieldname in expr.fieldnames:151self.append_field(fieldname)152153def display_fields(self):154for fieldname in self.fieldnames:155yield DisplayField(self.bitset, self, fieldname)156157def assert_cases(self, bitset=None):158if bitset is None:159bitset = self.bitset160for case in bitset.cases:161for name, field in case.fields.items():162if field.get_c_typename() == 'TYPE_ASSERT':163yield AssertField(field, case)164if bitset.extends is not None:165yield from self.assert_cases(isa.bitsets[bitset.extends])166167# State and helpers used by the template:168class State(object):169def __init__(self, isa):170self.isa = isa171self.warned_missing_extractors = []172173def bitset_cases(self, bitset, leaf_bitset=None):174if leaf_bitset is None:175leaf_bitset = bitset;176for case in bitset.cases:177if case.display is None:178# if this is the last case (ie. case.expr is None)179# then we need to go up the inheritance chain:180if case.expr is None and bitset.extends is not None:181parent_bitset = isa.bitsets[bitset.extends]182yield from self.bitset_cases(parent_bitset, leaf_bitset)183continue;184yield Case(leaf_bitset, case)185186# Find unique bitset remap/parameter names, to generate a struct187# used to pass "parameters" to bitset fields:188def unique_param_names(self):189unique_names = []190for root in self.encode_roots():191for leaf in self.encode_leafs(root):192for case in s.bitset_cases(leaf):193for df in case.display_fields():194for f in df.fields():195if f.field.get_c_typename() == 'TYPE_BITSET':196for param in f.field.params:197target_name = param[1]198if target_name not in unique_names:199yield target_name200unique_names.append(target_name)201202def case_name(self, bitset, name):203return bitset.encode.case_prefix + name.upper().replace('.', '_').replace('-', '_').replace('#', '')204205def encode_roots(self):206for name, root in self.isa.roots.items():207if root.encode is None:208continue209yield root210211def encode_leafs(self, root):212for name, leaf in self.isa.leafs.items():213if leaf.get_root() != root:214continue215yield leaf216217# expressions used in a bitset (case or field or recursively parent bitsets)218def bitset_used_exprs(self, bitset):219for case in bitset.cases:220if case.expr:221yield self.isa.expressions[case.expr]222for name, field in case.fields.items():223if isinstance(field, BitSetDerivedField):224yield self.isa.expressions[field.expr]225if bitset.extends is not None:226yield from self.bitset_used_exprs(self.isa.bitsets[bitset.extends])227228def extractor_impl(self, bitset, name):229if bitset.encode is not None:230if name in bitset.encode.maps:231return bitset.encode.maps[name]232if bitset.extends is not None:233return self.extractor_impl(self.isa.bitsets[bitset.extends], name)234return None235236# Default fallback when no mapping is defined, simply to avoid237# having to deal with encoding at the same time as r/e new238# instruction decoding.. but we can at least print warnings:239def extractor_fallback(self, bitset, name):240extr_name = bitset.name + '.' + name241if extr_name not in self.warned_missing_extractors:242print('WARNING: no encode mapping for {}.{}'.format(bitset.name, name))243self.warned_missing_extractors.append(extr_name)244return '0 /* XXX */'245246def extractor(self, bitset, name):247extr = self.extractor_impl(bitset, name)248if extr is not None:249return extr250return self.extractor_fallback(bitset, name)251252# In the special case of needing to access a field with bitset type253# for an expr, we need to encode the field so we end up with an254# integer, and not some pointer to a thing that will be encoded to255# an integer256def expr_extractor(self, bitset, name, p):257extr = self.extractor_impl(bitset, name)258field = self.resolve_simple_field(bitset, name)259if isinstance(field, BitSetDerivedField):260expr = self.isa.expressions[field.expr]261return self.expr_name(bitset.get_root(), expr) + '(s, p, src)'262if extr is None:263if name in self.unique_param_names():264extr = 'p->' + name265else:266extr = self.extractor_fallback(bitset, name)267if field and field.get_c_typename() == 'TYPE_BITSET':268extr = 'encode' + isa.roots[field.type].get_c_name() + '(s, ' + p + ', ' + extr + ')'269return extr270271# A limited resolver for field type which doesn't properly account for272# overrides. In particular, if a field is defined differently in multiple273# different cases, this just blindly picks the last one.274#275# TODO to do this properly, I don't think there is an alternative than276# to emit code which evaluates the case.expr277def resolve_simple_field(self, bitset, name):278field = None279for case in bitset.cases:280if name in case.fields:281field = case.fields[name]282if field is not None:283return field284if bitset.extends is not None:285return self.resolve_simple_field(isa.bitsets[bitset.extends], name)286return None287288def encode_type(self, bitset):289if bitset.encode is not None:290if bitset.encode.type is not None:291return bitset.encode.type292if bitset.extends is not None:293return self.encode_type(isa.bitsets[bitset.extends])294return None295296def expr_name(self, root, expr):297return root.get_c_name() + '_' + expr.get_c_name()298299def has_jmp(self, instructions):300# I'm sure there is some clever more pythony way to do this:301for instr in instructions:302if instr[0] == 'JMP':303return True304return False305306template = """\307/* Copyright (C) 2020 Google, Inc.308*309* Permission is hereby granted, free of charge, to any person obtaining a310* copy of this software and associated documentation files (the "Software"),311* to deal in the Software without restriction, including without limitation312* the rights to use, copy, modify, merge, publish, distribute, sublicense,313* and/or sell copies of the Software, and to permit persons to whom the314* Software is furnished to do so, subject to the following conditions:315*316* The above copyright notice and this permission notice (including the next317* paragraph) shall be included in all copies or substantial portions of the318* Software.319*320* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR321* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,322* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL323* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER324* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING325* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS326* IN THE SOFTWARE.327*/328329#include <stdbool.h>330#include <stdint.h>331332<%333isa = s.isa334%>335336/**337* Opaque type from the PoV of generated code, but allows state to be passed338* thru to the hand written helpers used by the generated code.339*/340struct encode_state;341342struct bitset_params;343344static uint64_t345pack_field(unsigned low, unsigned high, uint64_t val)346{347val &= ((UINT64_C(1) << (1 + high - low)) - 1);348return val << low;349}350351/*352* Forward-declarations (so we don't have to figure out which order to353* emit various encoders when they have reference each other)354*/355356%for root in s.encode_roots():357static uint64_t encode${root.get_c_name()}(struct encode_state *s, struct bitset_params *p, ${root.encode.type} src);358%endfor359360## TODO before the expr evaluators, we should generate extract_FOO() for361## derived fields.. which probably also need to be in the context of the362## respective root so they take the correct src arg??363364/*365* Expression evaluators:366*/367368struct bitset_params {369%for name in s.unique_param_names():370int64_t ${name};371%endfor372};373374#define push(v) do { \375assert(sp < ARRAY_SIZE(stack)); \376stack[sp] = (v); \377sp++; \378} while (0)379#define peek() ({ \380assert(sp < ARRAY_SIZE(stack)); \381stack[sp - 1]; \382})383#define pop() ({ \384assert(sp > 0); \385--sp; \386stack[sp]; \387})388389<%def name="render_expr(leaf, expr)">390static inline int64_t391${s.expr_name(leaf.get_root(), expr)}(struct encode_state *s, struct bitset_params *p, ${leaf.get_root().encode.type} src)392{393% for fieldname in expr.fieldnames:394int64_t ${fieldname};395% endfor396% for fieldname in expr.fieldnames:397<% field = s.resolve_simple_field(leaf, fieldname) %>398% if field is not None and field.get_c_typename() == 'TYPE_BITSET':399{ ${encode_params(leaf, field)}400${fieldname} = ${s.expr_extractor(leaf, fieldname, '&bp')};401}402% else:403${fieldname} = ${s.expr_extractor(leaf, fieldname, 'p')};404% endif405% endfor406return ${expr.expr};407}408</%def>409410## note, we can't just iterate all the expressions, but we need to find411## the context in which they are used to know the correct src type412413%for root in s.encode_roots():414<%415rendered_exprs = []416%>417% for leaf in s.encode_leafs(root):418% for expr in s.bitset_used_exprs(leaf):419<%420if expr in rendered_exprs:421continue422rendered_exprs.append(expr)423%>424${render_expr(leaf, expr)}425% endfor426% endfor427%endfor428429#undef pop430#undef peek431#undef push432433434<%def name="case_pre(root, expr)">435%if expr is not None:436if (${s.expr_name(root, expr)}(s, p, src)) {437%else:438{439%endif440</%def>441442<%def name="case_post(root, expr)">443%if expr is not None:444} else445%else:446}447%endif448</%def>449450<%def name="encode_params(leaf, field)">451struct bitset_params bp = {452%for param in field.params:453.${param[1]} = ${s.expr_extractor(leaf, param[0], 'p')}, /* ${param[0]} */454%endfor455};456</%def>457458<%def name="encode_bitset(root, leaf)">459uint64_t fld, val = ${hex(leaf.get_pattern().match)};460(void)fld;461<% visited_exprs = [] %>462%for case in s.bitset_cases(leaf):463<%464if case.expr is not None:465visited_exprs.append(case.expr)466%>467${case_pre(root, case.expr)}468% for df in case.display_fields():469% for f in df.fields():470<%471# simplify the control flow a bit to give the compiler a bit472# less to clean up473expr = f.expr474if expr == case.expr:475# Don't need to evaluate the same condition twice:476expr = None477elif expr in visited_exprs:478# We are in an 'else'/'else-if' leg that we wouldn't479# go down due to passing an earlier if()480continue481%>482${case_pre(root, expr)}483% if f.field.get_c_typename() == 'TYPE_BITSET':484{ ${encode_params(leaf, f.field)}485fld = encode${isa.roots[f.field.type].get_c_name()}(s, &bp, ${s.extractor(leaf, f.field.name)}); }486% else:487fld = ${s.extractor(leaf, f.field.name)};488% endif489val |= pack_field(${f.field.low}, ${f.field.high}, fld); /* ${f.field.name} */490${case_post(root, expr)}491% endfor492% endfor493494% for f in case.assert_cases():495<%496# simplify the control flow a bit to give the compiler a bit497# less to clean up498expr = f.expr499if expr == case.expr:500# Don't need to evaluate the same condition twice:501expr = None502elif expr in visited_exprs:503# We are in an 'else'/'else-if' leg that we wouldn't504# go down due to passing an earlier if()505continue506%>507${case_pre(root, expr)}508val |= pack_field(${f.field.low}, ${f.field.high}, ${f.field.val});509${case_post(root, None)}510% endfor511{} /* in case no unconditional field to close out last '} else' */512${case_post(root, case.expr)}513%endfor514return val;515</%def>516517/*518* The actual encoder definitions519*/520521%for root in s.encode_roots():522523static uint64_t524encode${root.get_c_name()}(struct encode_state *s, struct bitset_params *p, ${root.encode.type} src)525{526% if root.encode.case_prefix is not None:527switch (${root.get_c_name()}_case(s, src)) {528% for leaf in s.encode_leafs(root):529case ${s.case_name(root, leaf.name)}: {530${encode_bitset(root, leaf)}531}532% endfor533default:534/* Note that we need the default case, because there are535* instructions which we never expect to be encoded, (ie.536* meta/macro instructions) as they are removed/replace537* in earlier stages of the compiler.538*/539break;540}541mesa_loge("Unhandled ${root.name} encode case: 0x%x\\n", ${root.get_c_name()}_case(s, src));542return 0;543% else: # single case bitset, no switch544% for leaf in s.encode_leafs(root):545${encode_bitset(root, leaf)}546% endfor547% endif548}549550%endfor551552"""553554xml = sys.argv[1]555dst = sys.argv[2]556557isa = ISA(xml)558s = State(isa)559560with open(dst, 'wb') as f:561f.write(Template(template, output_encoding='utf-8').render(s=s))562563564