#!/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/genX_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()