xref: /aosp_15_r20/external/mesa3d/src/panfrost/compiler/bifrost_isa.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker#
2*61046927SAndroid Build Coastguard Worker# Copyright (C) 2020 Collabora, Ltd.
3*61046927SAndroid Build Coastguard Worker#
4*61046927SAndroid Build Coastguard Worker# Permission is hereby granted, free of charge, to any person obtaining a
5*61046927SAndroid Build Coastguard Worker# copy of this software and associated documentation files (the "Software"),
6*61046927SAndroid Build Coastguard Worker# to deal in the Software without restriction, including without limitation
7*61046927SAndroid Build Coastguard Worker# the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*61046927SAndroid Build Coastguard Worker# and/or sell copies of the Software, and to permit persons to whom the
9*61046927SAndroid Build Coastguard Worker# Software is furnished to do so, subject to the following conditions:
10*61046927SAndroid Build Coastguard Worker#
11*61046927SAndroid Build Coastguard Worker# The above copyright notice and this permission notice (including the next
12*61046927SAndroid Build Coastguard Worker# paragraph) shall be included in all copies or substantial portions of the
13*61046927SAndroid Build Coastguard Worker# Software.
14*61046927SAndroid Build Coastguard Worker#
15*61046927SAndroid Build Coastguard Worker# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*61046927SAndroid Build Coastguard Worker# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*61046927SAndroid Build Coastguard Worker# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18*61046927SAndroid Build Coastguard Worker# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*61046927SAndroid Build Coastguard Worker# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*61046927SAndroid Build Coastguard Worker# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21*61046927SAndroid Build Coastguard Worker# IN THE SOFTWARE.
22*61046927SAndroid Build Coastguard Worker
23*61046927SAndroid Build Coastguard Worker# Useful for autogeneration
24*61046927SAndroid Build Coastguard WorkerCOPYRIGHT = """/*
25*61046927SAndroid Build Coastguard Worker * Copyright (C) 2020 Collabora, Ltd.
26*61046927SAndroid Build Coastguard Worker *
27*61046927SAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining a
28*61046927SAndroid Build Coastguard Worker * copy of this software and associated documentation files (the "Software"),
29*61046927SAndroid Build Coastguard Worker * to deal in the Software without restriction, including without limitation
30*61046927SAndroid Build Coastguard Worker * the rights to use, copy, modify, merge, publish, distribute, sublicense,
31*61046927SAndroid Build Coastguard Worker * and/or sell copies of the Software, and to permit persons to whom the
32*61046927SAndroid Build Coastguard Worker * Software is furnished to do so, subject to the following conditions:
33*61046927SAndroid Build Coastguard Worker *
34*61046927SAndroid Build Coastguard Worker * The above copyright notice and this permission notice (including the next
35*61046927SAndroid Build Coastguard Worker * paragraph) shall be included in all copies or substantial portions of the
36*61046927SAndroid Build Coastguard Worker * Software.
37*61046927SAndroid Build Coastguard Worker *
38*61046927SAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39*61046927SAndroid Build Coastguard Worker * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40*61046927SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
41*61046927SAndroid Build Coastguard Worker * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42*61046927SAndroid Build Coastguard Worker * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43*61046927SAndroid Build Coastguard Worker * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
44*61046927SAndroid Build Coastguard Worker * SOFTWARE.
45*61046927SAndroid Build Coastguard Worker */
46*61046927SAndroid Build Coastguard Worker
47*61046927SAndroid Build Coastguard Worker/* Autogenerated file, do not edit */
48*61046927SAndroid Build Coastguard Worker
49*61046927SAndroid Build Coastguard Worker"""
50*61046927SAndroid Build Coastguard Worker
51*61046927SAndroid Build Coastguard Worker# Parse instruction set XML into a normalized form for processing
52*61046927SAndroid Build Coastguard Worker
53*61046927SAndroid Build Coastguard Workerimport xml.etree.ElementTree as ET
54*61046927SAndroid Build Coastguard Workerimport copy
55*61046927SAndroid Build Coastguard Workerimport itertools
56*61046927SAndroid Build Coastguard Workerfrom collections import OrderedDict
57*61046927SAndroid Build Coastguard Worker
58*61046927SAndroid Build Coastguard Workerdef parse_cond(cond, aliased = False):
59*61046927SAndroid Build Coastguard Worker    if cond.tag == 'reserved':
60*61046927SAndroid Build Coastguard Worker        return None
61*61046927SAndroid Build Coastguard Worker
62*61046927SAndroid Build Coastguard Worker    if cond.attrib.get('alias', False) and not aliased:
63*61046927SAndroid Build Coastguard Worker        return ['alias', parse_cond(cond, True)]
64*61046927SAndroid Build Coastguard Worker
65*61046927SAndroid Build Coastguard Worker    if 'left' in cond.attrib:
66*61046927SAndroid Build Coastguard Worker        return [cond.tag, cond.attrib['left'], cond.attrib['right']]
67*61046927SAndroid Build Coastguard Worker    else:
68*61046927SAndroid Build Coastguard Worker        return [cond.tag] + [parse_cond(x) for x in cond.findall('*')]
69*61046927SAndroid Build Coastguard Worker
70*61046927SAndroid Build Coastguard Workerdef parse_exact(obj):
71*61046927SAndroid Build Coastguard Worker    return [int(obj.attrib['mask'], 0), int(obj.attrib['exact'], 0)]
72*61046927SAndroid Build Coastguard Worker
73*61046927SAndroid Build Coastguard Workerdef parse_derived(obj):
74*61046927SAndroid Build Coastguard Worker    out = []
75*61046927SAndroid Build Coastguard Worker
76*61046927SAndroid Build Coastguard Worker    for deriv in obj.findall('derived'):
77*61046927SAndroid Build Coastguard Worker        loc = [int(deriv.attrib['start']), int(deriv.attrib['size'])]
78*61046927SAndroid Build Coastguard Worker        count = 1 << loc[1]
79*61046927SAndroid Build Coastguard Worker
80*61046927SAndroid Build Coastguard Worker        opts = [parse_cond(d) for d in deriv.findall('*')]
81*61046927SAndroid Build Coastguard Worker        default = [None] * count
82*61046927SAndroid Build Coastguard Worker        opts_fit = (opts + default)[0:count]
83*61046927SAndroid Build Coastguard Worker
84*61046927SAndroid Build Coastguard Worker        out.append([loc, opts_fit])
85*61046927SAndroid Build Coastguard Worker
86*61046927SAndroid Build Coastguard Worker    return out
87*61046927SAndroid Build Coastguard Worker
88*61046927SAndroid Build Coastguard Workerdef parse_modifiers(obj, include_pseudo):
89*61046927SAndroid Build Coastguard Worker    out = []
90*61046927SAndroid Build Coastguard Worker
91*61046927SAndroid Build Coastguard Worker    for mod in obj.findall('mod'):
92*61046927SAndroid Build Coastguard Worker        if mod.attrib.get('pseudo', False) and not include_pseudo:
93*61046927SAndroid Build Coastguard Worker            continue
94*61046927SAndroid Build Coastguard Worker
95*61046927SAndroid Build Coastguard Worker        name = mod.attrib['name']
96*61046927SAndroid Build Coastguard Worker        start = mod.attrib.get('start', None)
97*61046927SAndroid Build Coastguard Worker        size = int(mod.attrib['size'])
98*61046927SAndroid Build Coastguard Worker
99*61046927SAndroid Build Coastguard Worker        if start is not None:
100*61046927SAndroid Build Coastguard Worker            start = int(start)
101*61046927SAndroid Build Coastguard Worker
102*61046927SAndroid Build Coastguard Worker        opts = [x.text if x.tag == 'opt' else x.tag for x in mod.findall('*')]
103*61046927SAndroid Build Coastguard Worker
104*61046927SAndroid Build Coastguard Worker        if len(opts) == 0:
105*61046927SAndroid Build Coastguard Worker            if 'opt' in mod.attrib:
106*61046927SAndroid Build Coastguard Worker                opts = ['none', mod.attrib['opt']]
107*61046927SAndroid Build Coastguard Worker
108*61046927SAndroid Build Coastguard Worker        # Find suitable default
109*61046927SAndroid Build Coastguard Worker        default = mod.attrib.get('default', 'none' if 'none' in opts else None)
110*61046927SAndroid Build Coastguard Worker
111*61046927SAndroid Build Coastguard Worker        # Pad out as reserved
112*61046927SAndroid Build Coastguard Worker        count = (1 << size)
113*61046927SAndroid Build Coastguard Worker        opts = (opts + (['reserved'] * count))[0:count]
114*61046927SAndroid Build Coastguard Worker        out.append([[name, start, size], default, opts])
115*61046927SAndroid Build Coastguard Worker
116*61046927SAndroid Build Coastguard Worker    return out
117*61046927SAndroid Build Coastguard Worker
118*61046927SAndroid Build Coastguard Workerdef parse_copy(enc, existing):
119*61046927SAndroid Build Coastguard Worker    for node in enc.findall('copy'):
120*61046927SAndroid Build Coastguard Worker        name = node.get('name')
121*61046927SAndroid Build Coastguard Worker        for ex in existing:
122*61046927SAndroid Build Coastguard Worker            if ex[0][0] == name:
123*61046927SAndroid Build Coastguard Worker                ex[0][1] = node.get('start')
124*61046927SAndroid Build Coastguard Worker
125*61046927SAndroid Build Coastguard Workermod_names = {
126*61046927SAndroid Build Coastguard Worker    'cmp'     : [['cmpf', None, None], None, ['eq', 'gt', 'ge', 'ne', 'lt', 'le', 'gtlt', 'total']],
127*61046927SAndroid Build Coastguard Worker    # FIXME: Valhall can accept any integer comparision, but the old IR generator only generated
128*61046927SAndroid Build Coastguard Worker    #   gt and ge, and left out lt and le. For now follow the old way so we can compare generated files,
129*61046927SAndroid Build Coastguard Worker    #   but we should switch over to the proper way once everything is working
130*61046927SAndroid Build Coastguard Worker#    'cmpfi'    : [['cmpf', None, None], None, ['eq', 'ne', 'gt', 'ge', 'lt', 'le']],
131*61046927SAndroid Build Coastguard Worker    'cmpfi'     : [['cmpf', None, None], None, ['eq', 'ne', 'gt', 'ge']],
132*61046927SAndroid Build Coastguard Worker    'eq'        : [['cmpf', None, None], 'ne', ['eq', 'ne']],
133*61046927SAndroid Build Coastguard Worker    'dimension' : [['dimension', None, None], None, ['1d', '2d', '3d', 'cube']],
134*61046927SAndroid Build Coastguard Worker    'fetch_component' : [['fetch_component', None, None], None, ['gather4_r', 'gather4_g', 'gather4_b', 'gather4_a']],
135*61046927SAndroid Build Coastguard Worker    'lod_mode': [['va_lod_mode', None, None], 'zero_lod', ['zero_lod', 'computed_lod', 'explicit', 'computed_bias', 'grdesc']],
136*61046927SAndroid Build Coastguard Worker    'regfmt'  : [['register_format', None, None], None, ['f16', 'f32', 's32', 'u32', 's16', 'u16', 'f64', 'i64', 'auto']],
137*61046927SAndroid Build Coastguard Worker    'result_type' : [['result_type', None, None], None, ['i1', 'f1', 'm1']],
138*61046927SAndroid Build Coastguard Worker    'sample'  : [['sample', None, None], 'none', ['center', 'centroid', 'sample', 'explicit', 'none']],
139*61046927SAndroid Build Coastguard Worker    'update'  : [['update', None, None], None, ['store', 'retrieve', 'conditional', 'clobber']],
140*61046927SAndroid Build Coastguard Worker    'vecsize' : [['vecsize', None, None], 'none', ['none', 'v2', 'v3', 'v4']],
141*61046927SAndroid Build Coastguard Worker    'source_format' : [['source_format', None, None], None, ['flat32', 'flat16', 'f32', 'f16']],
142*61046927SAndroid Build Coastguard Worker
143*61046927SAndroid Build Coastguard Worker    'array_enable': [['array_enable', None, None], 'none', ['none', 'array_enable']],
144*61046927SAndroid Build Coastguard Worker    'integer_coordinates': [['integer_coordinates', None, None], 'none', ['none', 'integer_coordinates']],
145*61046927SAndroid Build Coastguard Worker    'shadow'      : [['shadow', None, None], 'none', ['none', 'shadow']],
146*61046927SAndroid Build Coastguard Worker    'skip'        : [['skip', None, None], 'none', ['none', 'skip']],
147*61046927SAndroid Build Coastguard Worker    'texel_offset': [['texel_offset', None, None], 'none', ['none', 'texel_offset']],
148*61046927SAndroid Build Coastguard Worker    'wide_indices': [['wide_indices', None, None], 'none', ['none', 'wide_indices']],
149*61046927SAndroid Build Coastguard Worker    'write_mask' : [['write_mask', None, None], 'none', ['none', 'r', 'g', 'rg', 'b', 'rb', 'gb', 'rgb', 'a', 'ra', 'ga', 'rga', 'ba', 'rba', 'gba', 'rgba']]
150*61046927SAndroid Build Coastguard Worker    }
151*61046927SAndroid Build Coastguard Worker
152*61046927SAndroid Build Coastguard Workerdef parse_instruction(ins, include_pseudo):
153*61046927SAndroid Build Coastguard Worker    common = {
154*61046927SAndroid Build Coastguard Worker            'srcs': [],
155*61046927SAndroid Build Coastguard Worker            'modifiers': [],
156*61046927SAndroid Build Coastguard Worker            'immediates': [],
157*61046927SAndroid Build Coastguard Worker            'swaps': [],
158*61046927SAndroid Build Coastguard Worker            'derived': [],
159*61046927SAndroid Build Coastguard Worker            'staging': ins.attrib.get('staging', '').split('=')[0],
160*61046927SAndroid Build Coastguard Worker            'staging_count': ins.attrib.get('staging', '=0').split('=')[1],
161*61046927SAndroid Build Coastguard Worker            'dests': int(ins.attrib.get('dests', '1')),
162*61046927SAndroid Build Coastguard Worker            'variable_dests': ins.attrib.get('variable_dests', False),
163*61046927SAndroid Build Coastguard Worker            'variable_srcs': ins.attrib.get('variable_srcs', False),
164*61046927SAndroid Build Coastguard Worker            'unused': ins.attrib.get('unused', False),
165*61046927SAndroid Build Coastguard Worker            'pseudo': ins.attrib.get('pseudo', False),
166*61046927SAndroid Build Coastguard Worker            'message': ins.attrib.get('message', 'none'),
167*61046927SAndroid Build Coastguard Worker            'last': ins.attrib.get('last', False),
168*61046927SAndroid Build Coastguard Worker            'table': ins.attrib.get('table', False),
169*61046927SAndroid Build Coastguard Worker    }
170*61046927SAndroid Build Coastguard Worker
171*61046927SAndroid Build Coastguard Worker    if 'exact' in ins.attrib:
172*61046927SAndroid Build Coastguard Worker        common['exact'] = parse_exact(ins)
173*61046927SAndroid Build Coastguard Worker
174*61046927SAndroid Build Coastguard Worker    extra_modifiers=[]
175*61046927SAndroid Build Coastguard Worker    src_num = 0
176*61046927SAndroid Build Coastguard Worker    for src in ins.findall('src'):
177*61046927SAndroid Build Coastguard Worker        if src.attrib.get('pseudo', False) and not include_pseudo:
178*61046927SAndroid Build Coastguard Worker            continue
179*61046927SAndroid Build Coastguard Worker
180*61046927SAndroid Build Coastguard Worker        mask = int(src.attrib['mask'], 0) if ('mask' in src.attrib) else 0xFF
181*61046927SAndroid Build Coastguard Worker        if src.attrib.get('start') is not None:
182*61046927SAndroid Build Coastguard Worker            common['srcs'].append([int(src.attrib['start'], 0), mask])
183*61046927SAndroid Build Coastguard Worker        else:
184*61046927SAndroid Build Coastguard Worker            common['srcs'].append([src_num*3, mask])
185*61046927SAndroid Build Coastguard Worker        if src.attrib.get('absneg', False):
186*61046927SAndroid Build Coastguard Worker            extra_modifiers.append([['neg'+str(src_num), '0', '1'], 'neg',['none', 'neg']])
187*61046927SAndroid Build Coastguard Worker            extra_modifiers.append([['abs'+str(src_num), '0', '1'], 'abs',['none', 'abs']])
188*61046927SAndroid Build Coastguard Worker        src_num += 1
189*61046927SAndroid Build Coastguard Worker
190*61046927SAndroid Build Coastguard Worker    for imm in ins.findall('immediate'):
191*61046927SAndroid Build Coastguard Worker        if imm.attrib.get('pseudo', False) and not include_pseudo:
192*61046927SAndroid Build Coastguard Worker            continue
193*61046927SAndroid Build Coastguard Worker
194*61046927SAndroid Build Coastguard Worker        start = int(imm.attrib['start']) if 'start' in imm.attrib else None
195*61046927SAndroid Build Coastguard Worker        common['immediates'].append([imm.attrib['name'], start, int(imm.attrib['size'])])
196*61046927SAndroid Build Coastguard Worker
197*61046927SAndroid Build Coastguard Worker    # FIXME valhall ISA.xml uses <imm/> instead of <immediate/>
198*61046927SAndroid Build Coastguard Worker    for imm in ins.findall('imm'):
199*61046927SAndroid Build Coastguard Worker        if imm.attrib.get('pseudo', False) and not include_pseudo:
200*61046927SAndroid Build Coastguard Worker            continue
201*61046927SAndroid Build Coastguard Worker
202*61046927SAndroid Build Coastguard Worker        base_name = imm.attrib['name']
203*61046927SAndroid Build Coastguard Worker        name = imm.attrib.get('ir_name', base_name)
204*61046927SAndroid Build Coastguard Worker        if not name:
205*61046927SAndroid Build Coastguard Worker            continue
206*61046927SAndroid Build Coastguard Worker
207*61046927SAndroid Build Coastguard Worker        start = int(imm.attrib['start']) if 'start' in imm.attrib else None
208*61046927SAndroid Build Coastguard Worker        common['immediates'].append([name, start, int(imm.attrib['size'])])
209*61046927SAndroid Build Coastguard Worker
210*61046927SAndroid Build Coastguard Worker    staging_read = False
211*61046927SAndroid Build Coastguard Worker    staging_write = False
212*61046927SAndroid Build Coastguard Worker    for sr in ins.findall('sr'):
213*61046927SAndroid Build Coastguard Worker        if sr.attrib.get('read', False):
214*61046927SAndroid Build Coastguard Worker            staging_read = True
215*61046927SAndroid Build Coastguard Worker        if sr.attrib.get('write', False):
216*61046927SAndroid Build Coastguard Worker            staging_write = True
217*61046927SAndroid Build Coastguard Worker
218*61046927SAndroid Build Coastguard Worker    if staging_read:
219*61046927SAndroid Build Coastguard Worker        common['staging'] = 'r'
220*61046927SAndroid Build Coastguard Worker    if staging_write:
221*61046927SAndroid Build Coastguard Worker        common['staging'] += 'w'
222*61046927SAndroid Build Coastguard Worker    for sr in ins.findall('sr_count'):
223*61046927SAndroid Build Coastguard Worker        size = sr.attrib.get('count', 'sr_count')
224*61046927SAndroid Build Coastguard Worker        common['staging_count'] = size
225*61046927SAndroid Build Coastguard Worker
226*61046927SAndroid Build Coastguard Worker    for m in ins.findall('*'):
227*61046927SAndroid Build Coastguard Worker        name = m.tag
228*61046927SAndroid Build Coastguard Worker        if name == 'cmp':
229*61046927SAndroid Build Coastguard Worker            if m.attrib.get('int_only', False):
230*61046927SAndroid Build Coastguard Worker                name = 'cmpfi'
231*61046927SAndroid Build Coastguard Worker            elif m.attrib.get('eqne_only', False):
232*61046927SAndroid Build Coastguard Worker                name = 'cmpfeq'
233*61046927SAndroid Build Coastguard Worker        if name == 'va_mod':
234*61046927SAndroid Build Coastguard Worker            name = m.attrib.get('name', '')
235*61046927SAndroid Build Coastguard Worker        if name in mod_names:
236*61046927SAndroid Build Coastguard Worker            extra_modifiers.append(mod_names[name])
237*61046927SAndroid Build Coastguard Worker
238*61046927SAndroid Build Coastguard Worker    common['derived'] = parse_derived(ins)
239*61046927SAndroid Build Coastguard Worker    common['modifiers'] = parse_modifiers(ins, include_pseudo) + extra_modifiers
240*61046927SAndroid Build Coastguard Worker
241*61046927SAndroid Build Coastguard Worker    for swap in ins.findall('swap'):
242*61046927SAndroid Build Coastguard Worker        lr = [int(swap.get('left')), int(swap.get('right'))]
243*61046927SAndroid Build Coastguard Worker        cond = parse_cond(swap.findall('*')[0])
244*61046927SAndroid Build Coastguard Worker        rewrites = {}
245*61046927SAndroid Build Coastguard Worker
246*61046927SAndroid Build Coastguard Worker        for rw in swap.findall('rewrite'):
247*61046927SAndroid Build Coastguard Worker            mp = {}
248*61046927SAndroid Build Coastguard Worker
249*61046927SAndroid Build Coastguard Worker            for m in rw.findall('map'):
250*61046927SAndroid Build Coastguard Worker                mp[m.attrib['from']] = m.attrib['to']
251*61046927SAndroid Build Coastguard Worker
252*61046927SAndroid Build Coastguard Worker            rewrites[rw.attrib['name']] = mp
253*61046927SAndroid Build Coastguard Worker
254*61046927SAndroid Build Coastguard Worker        common['swaps'].append([lr, cond, rewrites])
255*61046927SAndroid Build Coastguard Worker
256*61046927SAndroid Build Coastguard Worker    encodings = ins.findall('encoding')
257*61046927SAndroid Build Coastguard Worker    variants = []
258*61046927SAndroid Build Coastguard Worker
259*61046927SAndroid Build Coastguard Worker    if len(encodings) == 0:
260*61046927SAndroid Build Coastguard Worker        variants = [[None, common]]
261*61046927SAndroid Build Coastguard Worker    else:
262*61046927SAndroid Build Coastguard Worker        for enc in encodings:
263*61046927SAndroid Build Coastguard Worker            variant = copy.deepcopy(common)
264*61046927SAndroid Build Coastguard Worker            assert(len(variant['derived']) == 0)
265*61046927SAndroid Build Coastguard Worker
266*61046927SAndroid Build Coastguard Worker            variant['exact'] = parse_exact(enc)
267*61046927SAndroid Build Coastguard Worker            variant['derived'] = parse_derived(enc)
268*61046927SAndroid Build Coastguard Worker            parse_copy(enc, variant['modifiers'])
269*61046927SAndroid Build Coastguard Worker
270*61046927SAndroid Build Coastguard Worker            cond = parse_cond(enc.findall('*')[0])
271*61046927SAndroid Build Coastguard Worker            variants.append([cond, variant])
272*61046927SAndroid Build Coastguard Worker
273*61046927SAndroid Build Coastguard Worker    return variants
274*61046927SAndroid Build Coastguard Worker
275*61046927SAndroid Build Coastguard Workerdef ins_name(ins, group = False):
276*61046927SAndroid Build Coastguard Worker    # a historical artifact: the first character of the name should contain
277*61046927SAndroid Build Coastguard Worker    # a single character tag to indicate the unit: '+' for add, '*' for fma
278*61046927SAndroid Build Coastguard Worker    # bifrost has only those two units, valhall has others but for those
279*61046927SAndroid Build Coastguard Worker    # it doesn't matter (pretend they are '+')
280*61046927SAndroid Build Coastguard Worker    if not group:
281*61046927SAndroid Build Coastguard Worker        group = ins
282*61046927SAndroid Build Coastguard Worker
283*61046927SAndroid Build Coastguard Worker    base_name = ins.attrib['name']
284*61046927SAndroid Build Coastguard Worker    if group.attrib['unit'] == 'fma':
285*61046927SAndroid Build Coastguard Worker        tagged_name = '*' + base_name
286*61046927SAndroid Build Coastguard Worker    else:
287*61046927SAndroid Build Coastguard Worker        tagged_name = '+' + base_name
288*61046927SAndroid Build Coastguard Worker    return tagged_name
289*61046927SAndroid Build Coastguard Worker
290*61046927SAndroid Build Coastguard Workerdef parse_instructions(xml, include_unused = False, include_pseudo = False):
291*61046927SAndroid Build Coastguard Worker    final = {}
292*61046927SAndroid Build Coastguard Worker
293*61046927SAndroid Build Coastguard Worker    # look at groups of instructions
294*61046927SAndroid Build Coastguard Worker    groups = ET.parse(xml).getroot().findall('group')
295*61046927SAndroid Build Coastguard Worker    for gr in groups:
296*61046927SAndroid Build Coastguard Worker        if gr.attrib.get('unused', False) and not include_unused:
297*61046927SAndroid Build Coastguard Worker            continue
298*61046927SAndroid Build Coastguard Worker        if gr.attrib.get('pseudo', False) and not include_pseudo:
299*61046927SAndroid Build Coastguard Worker            continue
300*61046927SAndroid Build Coastguard Worker        group_base = parse_instruction(gr, include_pseudo)
301*61046927SAndroid Build Coastguard Worker        for ins in gr.findall('ins'):
302*61046927SAndroid Build Coastguard Worker            parsed = copy.deepcopy(group_base)
303*61046927SAndroid Build Coastguard Worker            tagged_name = ins_name(ins, gr)
304*61046927SAndroid Build Coastguard Worker            final[tagged_name] = parsed
305*61046927SAndroid Build Coastguard Worker
306*61046927SAndroid Build Coastguard Worker    # now look at individual instructions
307*61046927SAndroid Build Coastguard Worker    instructions = ET.parse(xml).getroot().findall('ins')
308*61046927SAndroid Build Coastguard Worker
309*61046927SAndroid Build Coastguard Worker    for ins in instructions:
310*61046927SAndroid Build Coastguard Worker        parsed = parse_instruction(ins, include_pseudo)
311*61046927SAndroid Build Coastguard Worker
312*61046927SAndroid Build Coastguard Worker        # Some instructions are for useful disassembly only and can be stripped
313*61046927SAndroid Build Coastguard Worker        # out of the compiler, particularly useful for release builds
314*61046927SAndroid Build Coastguard Worker        if parsed[0][1]["unused"] and not include_unused:
315*61046927SAndroid Build Coastguard Worker            continue
316*61046927SAndroid Build Coastguard Worker
317*61046927SAndroid Build Coastguard Worker        # On the other hand, some instructions are only for the IR, not disassembly
318*61046927SAndroid Build Coastguard Worker        if parsed[0][1]["pseudo"] and not include_pseudo:
319*61046927SAndroid Build Coastguard Worker            continue
320*61046927SAndroid Build Coastguard Worker
321*61046927SAndroid Build Coastguard Worker        tagged_name = ins_name(ins)
322*61046927SAndroid Build Coastguard Worker        final[tagged_name] = parsed
323*61046927SAndroid Build Coastguard Worker
324*61046927SAndroid Build Coastguard Worker    return final
325*61046927SAndroid Build Coastguard Worker
326*61046927SAndroid Build Coastguard Worker# Expand out an opcode name to something C-escaped
327*61046927SAndroid Build Coastguard Worker
328*61046927SAndroid Build Coastguard Workerdef opname_to_c(name):
329*61046927SAndroid Build Coastguard Worker    return name.lower().replace('*', 'fma_').replace('+', 'add_').replace('.', '_')
330*61046927SAndroid Build Coastguard Worker
331*61046927SAndroid Build Coastguard Worker# Expand out distinct states to distrinct instructions, with a placeholder
332*61046927SAndroid Build Coastguard Worker# condition for instructions with a single state
333*61046927SAndroid Build Coastguard Worker
334*61046927SAndroid Build Coastguard Workerdef expand_states(instructions):
335*61046927SAndroid Build Coastguard Worker    out = {}
336*61046927SAndroid Build Coastguard Worker
337*61046927SAndroid Build Coastguard Worker    for ins in instructions:
338*61046927SAndroid Build Coastguard Worker        c = instructions[ins]
339*61046927SAndroid Build Coastguard Worker
340*61046927SAndroid Build Coastguard Worker        for ((test, desc), i) in zip(c, range(len(c))):
341*61046927SAndroid Build Coastguard Worker            # Construct a name for the state
342*61046927SAndroid Build Coastguard Worker            name = ins + (('.' + str(i)) if len(c) > 1 else '')
343*61046927SAndroid Build Coastguard Worker
344*61046927SAndroid Build Coastguard Worker            out[name] = (ins, test if test is not None else [], desc)
345*61046927SAndroid Build Coastguard Worker
346*61046927SAndroid Build Coastguard Worker    return out
347*61046927SAndroid Build Coastguard Worker
348*61046927SAndroid Build Coastguard Worker# Drop keys used for packing to simplify IR representation, so we can check for
349*61046927SAndroid Build Coastguard Worker# equivalence easier
350*61046927SAndroid Build Coastguard Worker
351*61046927SAndroid Build Coastguard Workerdef simplify_to_ir(ins):
352*61046927SAndroid Build Coastguard Worker    return {
353*61046927SAndroid Build Coastguard Worker            'staging': ins['staging'],
354*61046927SAndroid Build Coastguard Worker            'srcs': len(ins['srcs']),
355*61046927SAndroid Build Coastguard Worker            'dests': ins['dests'],
356*61046927SAndroid Build Coastguard Worker            'variable_dests': ins['variable_dests'],
357*61046927SAndroid Build Coastguard Worker            'variable_srcs': ins['variable_srcs'],
358*61046927SAndroid Build Coastguard Worker            'modifiers': [[m[0][0], m[2]] for m in ins['modifiers']],
359*61046927SAndroid Build Coastguard Worker            'immediates': [m[0] for m in ins['immediates']]
360*61046927SAndroid Build Coastguard Worker        }
361*61046927SAndroid Build Coastguard Worker
362*61046927SAndroid Build Coastguard Worker# Converstions to integers default to rounding-to-zero
363*61046927SAndroid Build Coastguard Worker# All other opcodes default to rounding to nearest even
364*61046927SAndroid Build Coastguard Workerdef default_round_to_zero(name):
365*61046927SAndroid Build Coastguard Worker    # 8-bit int to float is exact
366*61046927SAndroid Build Coastguard Worker    subs = ['_TO_U', '_TO_S', '_TO_V2U', '_TO_V2S', '_TO_V4U', '_TO_V4S']
367*61046927SAndroid Build Coastguard Worker    return any([x in name for x in subs])
368*61046927SAndroid Build Coastguard Worker
369*61046927SAndroid Build Coastguard Workerdef combine_ir_variants(instructions, key):
370*61046927SAndroid Build Coastguard Worker    seen = [op for op in instructions.keys() if op[1:] == key]
371*61046927SAndroid Build Coastguard Worker    variant_objs = [[simplify_to_ir(Q[1]) for Q in instructions[x]] for x in seen]
372*61046927SAndroid Build Coastguard Worker    variants = sum(variant_objs, [])
373*61046927SAndroid Build Coastguard Worker
374*61046927SAndroid Build Coastguard Worker    # Accumulate modifiers across variants
375*61046927SAndroid Build Coastguard Worker    modifiers = {}
376*61046927SAndroid Build Coastguard Worker
377*61046927SAndroid Build Coastguard Worker    for s in variants[0:]:
378*61046927SAndroid Build Coastguard Worker        # Check consistency
379*61046927SAndroid Build Coastguard Worker        assert(s['srcs'] == variants[0]['srcs'])
380*61046927SAndroid Build Coastguard Worker        assert(s['dests'] == variants[0]['dests'])
381*61046927SAndroid Build Coastguard Worker        assert(s['immediates'] == variants[0]['immediates'])
382*61046927SAndroid Build Coastguard Worker        assert(s['staging'] == variants[0]['staging'])
383*61046927SAndroid Build Coastguard Worker
384*61046927SAndroid Build Coastguard Worker        for name, opts in s['modifiers']:
385*61046927SAndroid Build Coastguard Worker            if name not in modifiers:
386*61046927SAndroid Build Coastguard Worker                modifiers[name] = copy.deepcopy(opts)
387*61046927SAndroid Build Coastguard Worker            else:
388*61046927SAndroid Build Coastguard Worker                modifiers[name] += opts
389*61046927SAndroid Build Coastguard Worker
390*61046927SAndroid Build Coastguard Worker    # Great, we've checked srcs/immediates are consistent and we've summed over
391*61046927SAndroid Build Coastguard Worker    # modifiers
392*61046927SAndroid Build Coastguard Worker    return {
393*61046927SAndroid Build Coastguard Worker            'key': key,
394*61046927SAndroid Build Coastguard Worker            'srcs': variants[0]['srcs'],
395*61046927SAndroid Build Coastguard Worker            'dests': variants[0]['dests'],
396*61046927SAndroid Build Coastguard Worker            'variable_dests': variants[0]['variable_dests'],
397*61046927SAndroid Build Coastguard Worker            'variable_srcs': variants[0]['variable_srcs'],
398*61046927SAndroid Build Coastguard Worker            'staging': variants[0]['staging'],
399*61046927SAndroid Build Coastguard Worker            'immediates': sorted(variants[0]['immediates']),
400*61046927SAndroid Build Coastguard Worker            'modifiers': modifiers,
401*61046927SAndroid Build Coastguard Worker            'v': len(variants),
402*61046927SAndroid Build Coastguard Worker            'ir': variants,
403*61046927SAndroid Build Coastguard Worker            'rtz': default_round_to_zero(key)
404*61046927SAndroid Build Coastguard Worker        }
405*61046927SAndroid Build Coastguard Worker
406*61046927SAndroid Build Coastguard Worker# Partition instructions to mnemonics, considering units and variants
407*61046927SAndroid Build Coastguard Worker# equivalent.
408*61046927SAndroid Build Coastguard Worker
409*61046927SAndroid Build Coastguard Workerdef partition_mnemonics(instructions):
410*61046927SAndroid Build Coastguard Worker    key_func = lambda x: x[1:]
411*61046927SAndroid Build Coastguard Worker    sorted_instrs = sorted(instructions.keys(), key = key_func)
412*61046927SAndroid Build Coastguard Worker    partitions = itertools.groupby(sorted_instrs, key_func)
413*61046927SAndroid Build Coastguard Worker    return { k: combine_ir_variants(instructions, k) for k, v in partitions }
414*61046927SAndroid Build Coastguard Worker
415*61046927SAndroid Build Coastguard Worker# Generate modifier lists, by accumulating all the possible modifiers, and
416*61046927SAndroid Build Coastguard Worker# deduplicating thus assigning canonical enum values. We don't try _too_ hard
417*61046927SAndroid Build Coastguard Worker# to be clever, but by preserving as much of the original orderings as
418*61046927SAndroid Build Coastguard Worker# possible, later instruction encoding is simplified a bit.  Probably a micro
419*61046927SAndroid Build Coastguard Worker# optimization but we have to pick _some_ ordering, might as well choose the
420*61046927SAndroid Build Coastguard Worker# most convenient.
421*61046927SAndroid Build Coastguard Worker#
422*61046927SAndroid Build Coastguard Worker# THIS MUST BE DETERMINISTIC
423*61046927SAndroid Build Coastguard Worker
424*61046927SAndroid Build Coastguard Workerdef order_modifiers(ir_instructions):
425*61046927SAndroid Build Coastguard Worker    out = {}
426*61046927SAndroid Build Coastguard Worker
427*61046927SAndroid Build Coastguard Worker    # modifier name -> (list of option strings)
428*61046927SAndroid Build Coastguard Worker    modifier_lists = {}
429*61046927SAndroid Build Coastguard Worker
430*61046927SAndroid Build Coastguard Worker    for ins in sorted(ir_instructions):
431*61046927SAndroid Build Coastguard Worker        modifiers = ir_instructions[ins]["modifiers"]
432*61046927SAndroid Build Coastguard Worker
433*61046927SAndroid Build Coastguard Worker        for name in modifiers:
434*61046927SAndroid Build Coastguard Worker            name_ = name[0:-1] if name[-1] in "0123" else name
435*61046927SAndroid Build Coastguard Worker
436*61046927SAndroid Build Coastguard Worker            if name_ not in modifier_lists:
437*61046927SAndroid Build Coastguard Worker                modifier_lists[name_] = copy.deepcopy(modifiers[name])
438*61046927SAndroid Build Coastguard Worker            else:
439*61046927SAndroid Build Coastguard Worker                modifier_lists[name_] += modifiers[name]
440*61046927SAndroid Build Coastguard Worker
441*61046927SAndroid Build Coastguard Worker    for mod in modifier_lists:
442*61046927SAndroid Build Coastguard Worker        lst = list(OrderedDict.fromkeys(modifier_lists[mod]))
443*61046927SAndroid Build Coastguard Worker
444*61046927SAndroid Build Coastguard Worker        # Ensure none is false for booleans so the builder makes sense
445*61046927SAndroid Build Coastguard Worker        if len(lst) == 2 and lst[1] == "none":
446*61046927SAndroid Build Coastguard Worker            lst.reverse()
447*61046927SAndroid Build Coastguard Worker        elif mod == "table":
448*61046927SAndroid Build Coastguard Worker            # We really need a zero sentinel to materialize DTSEL
449*61046927SAndroid Build Coastguard Worker            assert(lst[2] == "none")
450*61046927SAndroid Build Coastguard Worker            lst[2] = lst[0]
451*61046927SAndroid Build Coastguard Worker            lst[0] = "none"
452*61046927SAndroid Build Coastguard Worker
453*61046927SAndroid Build Coastguard Worker        out[mod] = lst
454*61046927SAndroid Build Coastguard Worker
455*61046927SAndroid Build Coastguard Worker    return out
456*61046927SAndroid Build Coastguard Worker
457*61046927SAndroid Build Coastguard Worker# Count sources for a simplified (IR) instruction, including a source for a
458*61046927SAndroid Build Coastguard Worker# staging register if necessary
459*61046927SAndroid Build Coastguard Workerdef src_count(op):
460*61046927SAndroid Build Coastguard Worker    staging = 1 if (op["staging"] in ["r", "rw"]) else 0
461*61046927SAndroid Build Coastguard Worker    return op["srcs"] + staging
462*61046927SAndroid Build Coastguard Worker
463*61046927SAndroid Build Coastguard Worker# Parses out the size part of an opocde name
464*61046927SAndroid Build Coastguard Workerdef typesize(opcode):
465*61046927SAndroid Build Coastguard Worker    if opcode[-3:] == '128':
466*61046927SAndroid Build Coastguard Worker        return 128
467*61046927SAndroid Build Coastguard Worker    if opcode[-2:] == '48':
468*61046927SAndroid Build Coastguard Worker        return 48
469*61046927SAndroid Build Coastguard Worker    elif opcode[-1] == '8':
470*61046927SAndroid Build Coastguard Worker        return 8
471*61046927SAndroid Build Coastguard Worker    else:
472*61046927SAndroid Build Coastguard Worker        try:
473*61046927SAndroid Build Coastguard Worker            return int(opcode[-2:])
474*61046927SAndroid Build Coastguard Worker        except:
475*61046927SAndroid Build Coastguard Worker            return 32
476