blob: 029ecf30f1376e395b5641949126b817a00e9c62 [file] [log] [blame]
#!/bin/env python
COPYRIGHT = """\
/*
* Copyright 2021 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
"""
import argparse
import os.path
import re
import sys
from grl_parser import parse_grl_file
class Writer(object):
def __init__(self, file):
self._file = file
self._indent = 0
self._new_line = True
def push_indent(self, levels=4):
self._indent += levels
def pop_indent(self, levels=4):
self._indent -= levels
def write(self, s, *fmt):
if self._new_line:
s = '\n' + s
self._new_line = False
if s.endswith('\n'):
self._new_line = True
s = s[:-1]
if fmt:
s = s.format(*fmt)
self._file.write(s.replace('\n', '\n' + ' ' * self._indent))
# Internal Representation
class Value(object):
def __init__(self, name=None, zone=None):
self.name = name
self._zone = zone
self.live = False
@property
def zone(self):
assert self._zone is not None
return self._zone
def is_reg(self):
return False
def c_val(self):
if not self.name:
print(self)
assert self.name
return self.name
def c_cpu_val(self):
assert self.zone == 'cpu'
return self.c_val()
def c_gpu_val(self):
if self.zone == 'gpu':
return self.c_val()
else:
return 'mi_imm({})'.format(self.c_cpu_val())
class Constant(Value):
def __init__(self, value):
super().__init__(zone='cpu')
self.value = value
def c_val(self):
if self.value < 100:
return str(self.value)
elif self.value < (1 << 32):
return '0x{:x}u'.format(self.value)
else:
return '0x{:x}ull'.format(self.value)
class Register(Value):
def __init__(self, name):
super().__init__(name=name, zone='gpu')
def is_reg(self):
return True
class FixedGPR(Register):
def __init__(self, num):
super().__init__('REG{}'.format(num))
self.num = num
def write_c(self, w):
w.write('UNUSED struct mi_value {} = mi_reserve_gpr(&b, {});\n',
self.name, self.num)
class GroupSizeRegister(Register):
def __init__(self, comp):
super().__init__('DISPATCHDIM_' + 'XYZ'[comp])
self.comp = comp
class Member(Value):
def __init__(self, value, member):
super().__init__(zone=value.zone)
self.value = value
self.member = member
def is_reg(self):
return self.value.is_reg()
def c_val(self):
c_val = self.value.c_val()
if self.zone == 'gpu':
assert isinstance(self.value, Register)
if self.member == 'hi':
return 'mi_value_half({}, true)'.format(c_val)
elif self.member == 'lo':
return 'mi_value_half({}, false)'.format(c_val)
else:
assert False, 'Invalid member: {}'.format(self.member)
else:
return '.'.join([c_val, self.member])
class OffsetOf(Value):
def __init__(self, mk, expr):
super().__init__(zone='cpu')
assert isinstance(expr, tuple) and expr[0] == 'member'
self.type = mk.m.get_type(expr[1])
self.field = expr[2]
def c_val(self):
return 'offsetof({}, {})'.format(self.type.c_name, self.field)
class Scope(object):
def __init__(self, m, mk, parent):
self.m = m
self.mk = mk
self.parent = parent
self.defs = {}
def add_def(self, d, name=None):
if name is None:
name = d.name
assert name not in self.defs
self.defs[name] = d
def get_def(self, name):
if name in self.defs:
return self.defs[name]
assert self.parent, 'Unknown definition: "{}"'.format(name)
return self.parent.get_def(name)
class Statement(object):
def __init__(self, srcs=[]):
assert isinstance(srcs, (list, tuple))
self.srcs = list(srcs)
class SSAStatement(Statement, Value):
_count = 0
def __init__(self, zone, srcs):
Statement.__init__(self, srcs)
Value.__init__(self, None, zone)
self.c_name = '_tmp{}'.format(SSAStatement._count)
SSAStatement._count += 1
def c_val(self):
return self.c_name
def write_c_refs(self, w):
assert self.zone == 'gpu'
assert self.uses > 0
if self.uses > 1:
w.write('mi_value_add_refs(&b, {}, {});\n',
self.c_name, self.uses - 1)
class Half(SSAStatement):
def __init__(self, value, half):
assert half in ('hi', 'lo')
super().__init__(None, [value])
self.half = half
@property
def zone(self):
return self.srcs[0].zone
def write_c(self, w):
assert self.half in ('hi', 'lo')
if self.zone == 'cpu':
if self.half == 'hi':
w.write('uint32_t {} = (uint64_t)({}) >> 32;\n',
self.c_name, self.srcs[0].c_cpu_val())
else:
w.write('uint32_t {} = {};\n',
self.c_name, self.srcs[0].c_cpu_val())
else:
if self.half == 'hi':
w.write('struct mi_value {} = mi_value_half({}, true);\n',
self.c_name, self.srcs[0].c_gpu_val())
else:
w.write('struct mi_value {} = mi_value_half({}, false);\n',
self.c_name, self.srcs[0].c_gpu_val())
self.write_c_refs(w)
class Expression(SSAStatement):
def __init__(self, mk, op, *srcs):
super().__init__(None, srcs)
self.op = op
@property
def zone(self):
zone = 'cpu'
for s in self.srcs:
if s.zone == 'gpu':
zone = 'gpu'
return zone
def write_c(self, w):
if self.zone == 'cpu':
w.write('uint64_t {} = ', self.c_name)
c_cpu_vals = [s.c_cpu_val() for s in self.srcs]
if len(self.srcs) == 1:
w.write('({} {})', self.op, c_cpu_vals[0])
elif len(self.srcs) == 2:
w.write('({} {} {})', c_cpu_vals[0], self.op, c_cpu_vals[1])
else:
assert len(self.srcs) == 3 and op == '?'
w.write('({} ? {} : {})', *c_cpu_vals)
w.write(';\n')
return
w.write('struct mi_value {} = ', self.c_name)
if self.op == '~':
w.write('mi_inot(&b, {});\n', self.srcs[0].c_gpu_val())
elif self.op == '+':
w.write('mi_iadd(&b, {}, {});\n',
self.srcs[0].c_gpu_val(), self.srcs[1].c_gpu_val())
elif self.op == '-':
w.write('mi_isub(&b, {}, {});\n',
self.srcs[0].c_gpu_val(), self.srcs[1].c_gpu_val())
elif self.op == '&':
w.write('mi_iand(&b, {}, {});\n',
self.srcs[0].c_gpu_val(), self.srcs[1].c_gpu_val())
elif self.op == '|':
w.write('mi_ior(&b, {}, {});\n',
self.srcs[0].c_gpu_val(), self.srcs[1].c_gpu_val())
elif self.op == '<<':
if self.srcs[1].zone == 'cpu':
w.write('mi_ishl_imm(&b, {}, {});\n',
self.srcs[0].c_gpu_val(), self.srcs[1].c_cpu_val())
else:
w.write('mi_ishl(&b, {}, {});\n',
self.srcs[0].c_gpu_val(), self.srcs[1].c_gpu_val())
elif self.op == '>>':
if self.srcs[1].zone == 'cpu':
w.write('mi_ushr_imm(&b, {}, {});\n',
self.srcs[0].c_gpu_val(), self.srcs[1].c_cpu_val())
else:
w.write('mi_ushr(&b, {}, {});\n',
self.srcs[0].c_gpu_val(), self.srcs[1].c_gpu_val())
elif self.op == '==':
w.write('mi_ieq(&b, {}, {});\n',
self.srcs[0].c_gpu_val(), self.srcs[1].c_gpu_val())
elif self.op == '<':
w.write('mi_ult(&b, {}, {});\n',
self.srcs[0].c_gpu_val(), self.srcs[1].c_gpu_val())
elif self.op == '>':
w.write('mi_ult(&b, {}, {});\n',
self.srcs[1].c_gpu_val(), self.srcs[0].c_gpu_val())
elif self.op == '<=':
w.write('mi_uge(&b, {}, {});\n',
self.srcs[1].c_gpu_val(), self.srcs[0].c_gpu_val())
else:
assert False, 'Unknown expression opcode: {}'.format(self.op)
self.write_c_refs(w)
class StoreReg(Statement):
def __init__(self, mk, reg, value):
super().__init__([mk.load_value(value)])
self.reg = mk.parse_value(reg)
assert self.reg.is_reg()
def write_c(self, w):
value = self.srcs[0]
w.write('mi_store(&b, {}, {});\n',
self.reg.c_gpu_val(), value.c_gpu_val())
class LoadMem(SSAStatement):
def __init__(self, mk, bit_size, addr):
super().__init__('gpu', [mk.load_value(addr)])
self.bit_size = bit_size
def write_c(self, w):
addr = self.srcs[0]
w.write('struct mi_value {} = ', self.c_name)
if addr.zone == 'cpu':
w.write('mi_mem{}(anv_address_from_u64({}));\n',
self.bit_size, addr.c_cpu_val())
else:
assert self.bit_size == 64
w.write('mi_load_mem64_offset(&b, anv_address_from_u64(0), {});\n',
addr.c_gpu_val())
self.write_c_refs(w)
class StoreMem(Statement):
def __init__(self, mk, bit_size, addr, src):
super().__init__([mk.load_value(addr), mk.load_value(src)])
self.bit_size = bit_size
def write_c(self, w):
addr, data = tuple(self.srcs)
if addr.zone == 'cpu':
w.write('mi_store(&b, mi_mem{}(anv_address_from_u64({})), {});\n',
self.bit_size, addr.c_cpu_val(), data.c_gpu_val())
else:
assert self.bit_size == 64
w.write('mi_store_mem64_offset(&b, anv_address_from_u64(0), {}, {});\n',
addr.c_gpu_val(), data.c_gpu_val())
class GoTo(Statement):
def __init__(self, mk, target_id, cond=None, invert=False):
cond = [mk.load_value(cond)] if cond is not None else []
super().__init__(cond)
self.target_id = target_id
self.invert = invert
self.mk = mk
def write_c(self, w):
# Now that we've parsed the entire metakernel, we can look up the
# actual target from the id
target = self.mk.get_goto_target(self.target_id)
if self.srcs:
cond = self.srcs[0]
if self.invert:
w.write('mi_goto_if(&b, mi_inot(&b, {}), &{});\n', cond.c_gpu_val(), target.c_name)
else:
w.write('mi_goto_if(&b, {}, &{});\n', cond.c_gpu_val(), target.c_name)
else:
w.write('mi_goto(&b, &{});\n', target.c_name)
class GoToTarget(Statement):
def __init__(self, mk, name):
super().__init__()
self.name = name
self.c_name = '_goto_target_' + name
self.goto_tokens = []
mk = mk.add_goto_target(self)
def write_decl(self, w):
w.write('struct mi_goto_target {} = MI_GOTO_TARGET_INIT;\n',
self.c_name)
def write_c(self, w):
w.write('mi_goto_target(&b, &{});\n', self.c_name)
class Dispatch(Statement):
def __init__(self, mk, kernel, group_size, args, postsync):
if group_size is None:
srcs = [mk.scope.get_def('DISPATCHDIM_{}'.format(d)) for d in 'XYZ']
else:
srcs = [mk.load_value(s) for s in group_size]
srcs += [mk.load_value(a) for a in args]
super().__init__(srcs)
self.kernel = mk.m.kernels[kernel]
self.indirect = group_size is None
self.postsync = postsync
def write_c(self, w):
w.write('{\n')
w.push_indent()
group_size = self.srcs[:3]
args = self.srcs[3:]
if not self.indirect:
w.write('const uint32_t _group_size[3] = {{ {}, {}, {} }};\n',
*[s.c_cpu_val() for s in group_size])
gs = '_group_size'
else:
gs = 'NULL'
w.write('const struct anv_kernel_arg _args[] = {\n')
w.push_indent()
for arg in args:
w.write('{{ .u64 = {} }},\n', arg.c_cpu_val())
w.pop_indent()
w.write('};\n')
w.write('genX(grl_dispatch)(cmd_buffer, {},\n', self.kernel.c_name)
w.write(' {}, ARRAY_SIZE(_args), _args);\n', gs)
w.pop_indent()
w.write('}\n')
class SemWait(Statement):
def __init__(self, scope, wait):
super().__init__()
self.wait = wait
class Control(Statement):
def __init__(self, scope, wait):
super().__init__()
self.wait = wait
def write_c(self, w):
w.write('cmd_buffer->state.pending_pipe_bits |=\n')
w.write(' ANV_PIPE_CS_STALL_BIT |\n')
w.write(' ANV_PIPE_DATA_CACHE_FLUSH_BIT |\n')
w.write(' ANV_PIPE_UNTYPED_DATAPORT_CACHE_FLUSH_BIT;\n')
w.write('genX(cmd_buffer_apply_pipe_flushes)(cmd_buffer);\n')
TYPE_REMAPS = {
'dword' : 'uint32_t',
'qword' : 'uint64_t',
}
class Module(object):
def __init__(self, grl_dir, elems):
assert isinstance(elems[0], tuple)
assert elems[0][0] == 'module-name'
self.grl_dir = grl_dir
self.name = elems[0][1]
self.kernels = {}
self.structs = {}
self.constants = []
self.metakernels = []
self.regs = {}
scope = Scope(self, None, None)
for e in elems[1:]:
if e[0] == 'kernel':
k = Kernel(self, *e[1:])
assert k.name not in self.kernels
self.kernels[k.name] = k
elif e[0] == 'kernel-module':
m = KernelModule(self, *e[1:])
for k in m.kernels:
assert k.name not in self.kernels
self.kernels[k.name] = k
elif e[0] == 'struct':
s = Struct(self, *e[1:])
assert s.name not in self.kernels
self.structs[s.name] = s
elif e[0] == 'named-constant':
c = NamedConstant(*e[1:])
scope.add_def(c)
self.constants.append(c)
elif e[0] == 'meta-kernel':
mk = MetaKernel(self, scope, *e[1:])
self.metakernels.append(mk)
elif e[0] == 'import':
assert e[2] == 'struct'
self.import_struct(e[1], e[3])
else:
assert False, 'Invalid module-level token: {}'.format(t[0])
def import_struct(self, filename, struct_name):
elems = parse_grl_file(os.path.join(self.grl_dir, filename), [])
assert elems
for e in elems[1:]:
if e[0] == 'struct' and e[1] == struct_name:
s = Struct(self, *e[1:])
assert s.name not in self.kernels
self.structs[s.name] = s
return
assert False, "Struct {0} not found in {1}".format(struct_name, filename)
def get_type(self, name):
if name in self.structs:
return self.structs[name]
return BasicType(TYPE_REMAPS.get(name, name))
def get_fixed_gpr(self, num):
assert isinstance(num, int)
if num in self.regs:
return self.regs[num]
reg = FixedGPR(num)
self.regs[num] = reg
return reg
def optimize(self):
progress = True
while progress:
progress = False
# Copy Propagation
for mk in self.metakernels:
if mk.opt_copy_prop():
progress = True
# Dead Code Elimination
for r in self.regs.values():
r.live = False
for c in self.constants:
c.live = False
for mk in self.metakernels:
mk.opt_dead_code1()
for mk in self.metakernels:
if mk.opt_dead_code2():
progress = True
for n in list(self.regs.keys()):
if not self.regs[n].live:
del self.regs[n]
progress = True
self.constants = [c for c in self.constants if c.live]
def compact_regs(self):
old_regs = self.regs
self.regs = {}
for i, reg in enumerate(old_regs.values()):
reg.num = i
self.regs[i] = reg
def write_h(self, w):
for s in self.structs.values():
s.write_h(w)
for mk in self.metakernels:
mk.write_h(w)
def write_c(self, w):
for c in self.constants:
c.write_c(w)
for mk in self.metakernels:
mk.write_c(w)
class Kernel(object):
def __init__(self, m, name, ann):
self.name = name
self.source_file = ann['source']
self.kernel_name = self.source_file.replace('/', '_')[:-3].upper()
self.entrypoint = ann['kernelFunction']
assert self.source_file.endswith('.cl')
self.c_name = '_'.join([
'GRL_CL_KERNEL',
self.kernel_name,
self.entrypoint.upper(),
])
class KernelModule(object):
def __init__(self, m, name, source, kernels):
self.name = name
self.kernels = []
self.libraries = []
for k in kernels:
if k[0] == 'kernel':
k[2]['source'] = source
self.kernels.append(Kernel(m, *k[1:]))
elif k[0] == 'library':
# Skip this for now.
pass
class BasicType(object):
def __init__(self, name):
self.name = name
self.c_name = name
class Struct(object):
def __init__(self, m, name, fields, align):
assert align == 0
self.name = name
self.c_name = 'struct ' + '_'.join(['grl', m.name, self.name])
self.fields = [(m.get_type(t), n) for t, n in fields]
def write_h(self, w):
w.write('{} {{\n', self.c_name)
w.push_indent()
for f in self.fields:
w.write('{} {};\n', f[0].c_name, f[1])
w.pop_indent()
w.write('};\n')
class NamedConstant(Value):
def __init__(self, name, value):
super().__init__(name, 'cpu')
self.name = name
self.value = Constant(value)
self.written = False
def set_module(self, m):
pass
def write_c(self, w):
if self.written:
return
w.write('static const uint64_t {} = {};\n',
self.name, self.value.c_val())
self.written = True
class MetaKernelParameter(Value):
def __init__(self, mk, type, name):
super().__init__(name, 'cpu')
self.type = mk.m.get_type(type)
class MetaKernel(object):
def __init__(self, m, m_scope, name, params, ann, statements):
self.m = m
self.name = name
self.c_name = '_'.join(['grl', m.name, self.name])
self.goto_targets = {}
self.num_tmps = 0
mk_scope = Scope(m, self, m_scope)
self.params = [MetaKernelParameter(self, *p) for p in params]
for p in self.params:
mk_scope.add_def(p)
mk_scope.add_def(GroupSizeRegister(0), name='DISPATCHDIM_X')
mk_scope.add_def(GroupSizeRegister(1), name='DISPATCHDIM_Y')
mk_scope.add_def(GroupSizeRegister(2), name='DISPATCHDIM_Z')
self.statements = []
self.parse_stmt(mk_scope, statements)
self.scope = None
def get_tmp(self):
tmpN = '_tmp{}'.format(self.num_tmps)
self.num_tmps += 1
return tmpN
def add_stmt(self, stmt):
self.statements.append(stmt)
return stmt
def parse_value(self, v):
if isinstance(v, Value):
return v
elif isinstance(v, str):
if re.match(r'REG\d+', v):
return self.m.get_fixed_gpr(int(v[3:]))
else:
return self.scope.get_def(v)
elif isinstance(v, int):
return Constant(v)
elif isinstance(v, tuple):
if v[0] == 'member':
return Member(self.parse_value(v[1]), v[2])
elif v[0] == 'offsetof':
return OffsetOf(self, v[1])
else:
op = v[0]
srcs = [self.parse_value(s) for s in v[1:]]
return self.add_stmt(Expression(self, op, *srcs))
else:
assert False, 'Invalid value: {}'.format(v[0])
def load_value(self, v):
v = self.parse_value(v)
if isinstance(v, Member) and v.zone == 'gpu':
v = self.add_stmt(Half(v.value, v.member))
return v
def parse_stmt(self, scope, s):
self.scope = scope
if isinstance(s, list):
subscope = Scope(self.m, self, scope)
for stmt in s:
self.parse_stmt(subscope, stmt)
elif s[0] == 'define':
scope.add_def(self.parse_value(s[2]), name=s[1])
elif s[0] == 'assign':
self.add_stmt(StoreReg(self, *s[1:]))
elif s[0] == 'dispatch':
self.add_stmt(Dispatch(self, *s[1:]))
elif s[0] == 'load-dword':
v = self.add_stmt(LoadMem(self, 32, s[2]))
self.add_stmt(StoreReg(self, s[1], v))
elif s[0] == 'load-qword':
v = self.add_stmt(LoadMem(self, 64, s[2]))
self.add_stmt(StoreReg(self, s[1], v))
elif s[0] == 'store-dword':
self.add_stmt(StoreMem(self, 32, *s[1:]))
elif s[0] == 'store-qword':
self.add_stmt(StoreMem(self, 64, *s[1:]))
elif s[0] == 'goto':
self.add_stmt(GoTo(self, s[1]))
elif s[0] == 'goto-if':
self.add_stmt(GoTo(self, s[1], s[2]))
elif s[0] == 'goto-if-not':
self.add_stmt(GoTo(self, s[1], s[2], invert=True))
elif s[0] == 'label':
self.add_stmt(GoToTarget(self, s[1]))
elif s[0] == 'control':
self.add_stmt(Control(self, s[1]))
elif s[0] == 'sem-wait-while':
self.add_stmt(Control(self, s[1]))
else:
assert False, 'Invalid statement: {}'.format(s[0])
def add_goto_target(self, t):
assert t.name not in self.goto_targets
self.goto_targets[t.name] = t
def get_goto_target(self, name):
return self.goto_targets[name]
def opt_copy_prop(self):
progress = False
copies = {}
for stmt in self.statements:
for i in range(len(stmt.srcs)):
src = stmt.srcs[i]
if isinstance(src, FixedGPR) and src.num in copies:
stmt.srcs[i] = copies[src.num]
progress = True
if isinstance(stmt, StoreReg):
reg = stmt.reg
if isinstance(reg, Member):
reg = reg.value
if isinstance(reg, FixedGPR):
copies.pop(reg.num, None)
if not stmt.srcs[0].is_reg():
copies[reg.num] = stmt.srcs[0]
elif isinstance(stmt, (GoTo, GoToTarget)):
copies = {}
return progress
def opt_dead_code1(self):
for stmt in self.statements:
# Mark every register which is read as live
for src in stmt.srcs:
if isinstance(src, Register):
src.live = True
# Initialize every SSA statement to dead
if isinstance(stmt, SSAStatement):
stmt.live = False
def opt_dead_code2(self):
def yield_live(statements):
gprs_read = set(self.m.regs.keys())
for stmt in statements:
if isinstance(stmt, SSAStatement):
if not stmt.live:
continue
elif isinstance(stmt, StoreReg):
reg = stmt.reg
if isinstance(reg, Member):
reg = reg.value
if not stmt.reg.live:
continue
if isinstance(reg, FixedGPR):
if reg.num in gprs_read:
gprs_read.remove(reg.num)
else:
continue
elif isinstance(stmt, (GoTo, GoToTarget)):
gprs_read = set(self.m.regs.keys())
for src in stmt.srcs:
src.live = True
if isinstance(src, FixedGPR):
gprs_read.add(src.num)
yield stmt
old_stmt_list = self.statements
old_stmt_list.reverse()
self.statements = list(yield_live(old_stmt_list))
self.statements.reverse()
return len(self.statements) != len(old_stmt_list)
def count_ssa_value_uses(self):
for stmt in self.statements:
if isinstance(stmt, SSAStatement):
stmt.uses = 0
for src in stmt.srcs:
if isinstance(src, SSAStatement):
src.uses += 1
def write_h(self, w):
w.write('void\n')
w.write('genX({})(\n', self.c_name)
w.push_indent()
w.write('struct anv_cmd_buffer *cmd_buffer')
for p in self.params:
w.write(',\n{} {}', p.type.c_name, p.name)
w.write(');\n')
w.pop_indent()
def write_c(self, w):
w.write('void\n')
w.write('genX({})(\n', self.c_name)
w.push_indent()
w.write('struct anv_cmd_buffer *cmd_buffer')
for p in self.params:
w.write(',\n{} {}', p.type.c_name, p.name)
w.write(')\n')
w.pop_indent()
w.write('{\n')
w.push_indent()
w.write('struct mi_builder b;\n')
w.write('mi_builder_init(&b, cmd_buffer->device->info, &cmd_buffer->batch);\n')
w.write('\n')
for r in self.m.regs.values():
r.write_c(w)
w.write('\n')
for t in self.goto_targets.values():
t.write_decl(w)
w.write('\n')
self.count_ssa_value_uses()
for s in self.statements:
s.write_c(w)
w.pop_indent()
w.write('}\n')
HEADER_PROLOGUE = COPYRIGHT + '''
#include "anv_private.h"
#include "grl/genX_grl.h"
#ifndef {0}
#define {0}
#ifdef __cplusplus
extern "C" {{
#endif
'''
HEADER_EPILOGUE = '''
#ifdef __cplusplus
}}
#endif
#endif /* {0} */
'''
C_PROLOGUE = COPYRIGHT + '''
#include "{0}"
#include "genxml/gen_macros.h"
#include "genxml/genX_pack.h"
#include "genxml/gen_rt_pack.h"
/* We reserve :
* - GPR 14 for secondary command buffer returns
* - GPR 15 for conditional rendering
*/
#define MI_BUILDER_NUM_ALLOC_GPRS 14
#define __gen_get_batch_dwords anv_batch_emit_dwords
#define __gen_address_offset anv_address_add
#define __gen_get_batch_address(b, a) anv_batch_address(b, a)
#include "common/mi_builder.h"
#define MI_PREDICATE_RESULT mi_reg32(0x2418)
#define DISPATCHDIM_X mi_reg32(0x2500)
#define DISPATCHDIM_Y mi_reg32(0x2504)
#define DISPATCHDIM_Z mi_reg32(0x2508)
'''
def parse_libraries(filenames):
libraries = {}
for fname in filenames:
lib_package = parse_grl_file(fname, [])
for lib in lib_package:
assert lib[0] == 'library'
# Add the directory of the library so that CL files can be found.
lib[2].append(('path', os.path.dirname(fname)))
libraries[lib[1]] = lib
return libraries
def main():
argparser = argparse.ArgumentParser()
argparser.add_argument('--out-c', help='Output C file')
argparser.add_argument('--out-h', help='Output C file')
argparser.add_argument('--library', dest='libraries', action='append',
default=[], help='Libraries to include')
argparser.add_argument('grl', help="Input file")
args = argparser.parse_args()
grl_dir = os.path.dirname(args.grl)
libraries = parse_libraries(args.libraries)
ir = parse_grl_file(args.grl, libraries)
m = Module(grl_dir, ir)
m.optimize()
m.compact_regs()
with open(args.out_h, 'w') as f:
guard = os.path.splitext(os.path.basename(args.out_h))[0].upper()
w = Writer(f)
w.write(HEADER_PROLOGUE, guard)
m.write_h(w)
w.write(HEADER_EPILOGUE, guard)
with open(args.out_c, 'w') as f:
w = Writer(f)
w.write(C_PROLOGUE, os.path.basename(args.out_h))
m.write_c(w)
if __name__ == '__main__':
main()