aboutsummaryrefslogtreecommitdiff
path: root/etc/compile-by-zinc/make-graph-with-reg.py
diff options
context:
space:
mode:
Diffstat (limited to 'etc/compile-by-zinc/make-graph-with-reg.py')
-rw-r--r--etc/compile-by-zinc/make-graph-with-reg.py292
1 files changed, 292 insertions, 0 deletions
diff --git a/etc/compile-by-zinc/make-graph-with-reg.py b/etc/compile-by-zinc/make-graph-with-reg.py
new file mode 100644
index 000000000..275f45e25
--- /dev/null
+++ b/etc/compile-by-zinc/make-graph-with-reg.py
@@ -0,0 +1,292 @@
+#!/usr/bin/env python
+from __future__ import with_statement
+from memoize import memoize
+import codecs, re, sys, os
+import subprocess
+
+LAMBDA = u'\u03bb'
+
+OP_NAMES = {'*':'MUL', '+':'ADD', '>>':'SHL', '<<':'SHR', '|':'OR', '&':'AND'}
+
+REGISTERS = tuple(['RAX', 'RBX', 'RCX', 'RDX', 'RSI', 'RDI', 'RBP', 'RSP']
+ + ['r%d' % i for i in range(8, 16)])
+REGISTER_COLORS = ['color="black"', 'color="white",fillcolor="black"', 'color="maroon"', 'color="green"', 'fillcolor="olive"',
+ 'color="navy"', 'color="purple"', 'fillcolor="teal"', 'fillcolor="silver"', 'fillcolor="gray"', 'fillcolor="red"',
+ 'fillcolor="lime"', 'fillcolor="yellow"', 'fillcolor="blue"', 'fillcolor="fuschia"', 'fillcolor="aqua"']
+REGISTER_COLORS = ['fillcolor="%s"' % c for c in 'aliceblue antiquewhite aquamarine azure beige bisque blue blueviolet brown cadetblue chartreuse cyan red gold deeppink darkorange'.split(' ')]
+COLOR_FOR_REGISTER = dict(zip(REGISTERS, REGISTER_COLORS))
+
+MAX_INSTRUCTION_WINDOW = 10000
+
+CORE_DATA = (('ADD_MUL', 2), ('MUL_CORE', 1), ('LEA_BW', 2))
+CORES = tuple(name for name, count in CORE_DATA)
+CORE_COUNT = dict(CORE_DATA)
+
+BITWISE_CORES = tuple({
+ 'core' : { 'name' : core_name , 'latency' : 1 },
+ 'latency' : 1
+ } for core_name in ('LEA_BW',))
+
+MODEL = {
+ '*': tuple({
+ 'core' : { 'name' : core_name , 'latency' : 1 },
+ 'latency' : 3
+ }
+ for core_name in ('ADD_MUL', 'MUL_CORE')),
+ '+': tuple({
+ 'core' : { 'name' : core_name , 'latency' : 1 },
+ 'latency' : 1
+ }
+ for core_name in ('ADD_MUL', 'LEA_BW')),
+ '>>': BITWISE_CORES,
+ '<<': BITWISE_CORES,
+ '|': BITWISE_CORES,
+ '&': BITWISE_CORES,
+ 'LOAD': tuple({
+ 'core' : { 'name' : core_name , 'latency' : 1 },
+ 'latency' : 1
+ } for core_name in REGISTERS),
+ 'STORE': tuple({
+ 'core' : { 'name' : core_name , 'latency' : 1 },
+ 'latency' : 1
+ } for core_name in REGISTERS)
+ }
+
+def get_lines(filename):
+ with codecs.open(filename, 'r', encoding='utf8') as f:
+ lines = f.read().replace('\r\n', '\n')
+ return [line.strip() for line in re.findall("%s '.*?[Rr]eturn [^\r\n]*" % LAMBDA, lines, flags=re.DOTALL)[0].split('\n')]
+
+def strip_casts(text):
+ return re.sub(r'\(u?int[0-9]*_t\)\s*\(?([^\)]*)\)?', r'\1', text)
+
+def parse_lines(lines):
+ lines = list(map(strip_casts, lines))
+ assert lines[0][:len(LAMBDA + ' ')] == LAMBDA + ' '
+ assert lines[0][-1] == ','
+ ret = {}
+ ret['vars'] = lines[0][len(LAMBDA + ' '):-1]
+ assert lines[-1][-1] == ')'
+ ret['return'] = lines[-1][:-1].replace('return ', '').replace('Return ', '')
+ ret['lines'] = []
+ for line in lines[1:-1]:
+ datatype, varname, arg1, op, arg2 = re.findall('^(u?int[0-9]*_t) ([^ ]*) = ([^ ]*) ([^ ]*) ([^ ]*);$', line)[0]
+ ret['lines'].append({'type':datatype, 'out':varname, 'op':op, 'args':(arg1, arg2), 'source':line})
+ print('Compiling %d lines in groups of %d...' % (len(ret['lines']), min(MAX_INSTRUCTION_WINDOW, len(ret['lines']))))
+ ret['lines'] = tuple(ret['lines'])
+ split_ret = []
+ for start in range(0, len(ret['lines']), MAX_INSTRUCTION_WINDOW):
+ cur_ret = dict(ret)
+ cur_ret['lines'] = ret['lines'][start:][:MAX_INSTRUCTION_WINDOW]
+ split_ret.append(cur_ret)
+ return tuple(split_ret)
+
+def get_var_names(input_data):
+ return tuple(line['out'] for line in input_data['lines'])
+
+def get_input_var_names(input_data):
+ return tuple(i for i in data['vars'].replace('%core', '').replace(',', ' ').replace('(', ' ').replace(')', ' ').replace("'", ' ').split(' ')
+ if i != '')
+
+def get_output_var_names(input_data):
+ return tuple(i for i in data['return'].replace(',', ' ').replace('(', ' ').replace(')', ' ').split(' ')
+ if i != '')
+
+def line_of_var(input_data, var):
+ retv = [line for line in input_data['lines'] if line['out'] == var]
+ if len(retv) > 0: return retv[0]
+ return {'out': var, 'args':tuple(), 'op': 'INPUT', 'type':'uint64_t'}
+
+def create_set(name, items):
+ ret = ''
+ ret += 'set of int: %s = 1..%d;\n' % (name, len(items))
+ for i, item in enumerate(items):
+ ret += '%s: %s = %d; ' % (name, item, i+1)
+ ret += 'array[%s] of string: %s_NAMES = ["' % (name, name)
+ ret += '", "'.join(items) + '"];\n'
+ ret += '\n'
+ return ret
+
+def make_data_dependencies(input_data):
+ input_var_names = get_input_var_names(input_data)
+ dependencies = dict((var, tuple()) for var in input_var_names)
+ for line in input_data['lines']:
+ dependencies[line['out']] = tuple(arg for arg in line['args']
+ if arg[0] not in '0123456789')
+ return dependencies
+def make_reverse_data_dependencies(dependencies):
+ ret = {}
+ for k, vs in dependencies.items():
+ for v in vs:
+ if v not in ret.keys(): ret[v] = []
+ ret[v].append(k)
+ for k in ret.keys():
+ ret[k] = tuple(ret[k])
+ return ret
+
+def make_reverse_data_dependencies(dependencies):
+ reverse_dependencies = dict((k, []) for k in dependencies.keys())
+ for k, v in dependencies.items():
+ for arg in v:
+ reverse_dependencies[arg].append(k)
+ return reverse_dependencies
+
+def backpropogate_one(input_data, dependencies, registers):
+ progressed = False
+ for var in registers.keys():
+ if len(dependencies[var]) == 1:
+ dep = dependencies[var][0]
+ if dep not in registers.keys():
+ line = line_of_var(input_data, dep)
+ if line['type'] == 'uint64_t' and ':' not in registers[var]:
+ registers[dep] = registers[var]
+ progressed = True
+ elif registers[dep] != registers[var] and registers[var] not in registers[dep].split(':') and len(dependencies[dep]) == 2:
+ for dep2, other_dep2 in (tuple(dependencies[dep]), tuple(reversed(dependencies[dep]))):
+ if dep2 in registers.keys(): continue
+ if other_dep2 in registers.keys() and registers[other_dep2] == registers[var]: continue
+ line = line_of_var(input_data, dep2)
+ other_line = line_of_var(input_data, other_dep2)
+ if line['type'] == 'uint64_t' and ':' not in registers[var] and (other_dep2 in registers.keys() or other_line['type'] != 'uint64_t'):
+ registers[dep2] = registers[var]
+ progressed = True
+ elif len(dependencies[var]) == 2:
+ for dep, other_dep in (tuple(dependencies[var]), tuple(reversed(dependencies[var]))):
+ if dep in registers.keys(): continue
+ if other_dep in registers.keys() and registers[other_dep] == registers[var]: continue
+ line = line_of_var(input_data, dep)
+ if line['type'] == 'uint64_t' and ':' not in registers[var] and len(dependencies[dep]) == 1 and dependencies[dep][0] in registers.keys():
+ registers[dep] = registers[var]
+ progressed = True
+ return progressed, registers
+def backpropogate_one_arbitrary(input_data, dependencies, registers):
+ progressed = False
+ for var in registers.keys():
+ if len(dependencies[var]) == 2:
+ for dep, other_dep in (tuple(dependencies[var]), tuple(reversed(dependencies[var]))):
+ if dep in registers.keys(): continue
+ if other_dep in registers.keys() and (registers[other_dep] == registers[var] or registers[var] in registers[other_dep].split(':')): continue
+ line = line_of_var(input_data, dep)
+ if line['type'] == 'uint64_t' and ':' not in registers[var]:
+ registers[dep] = registers[var]
+ progressed = True
+ elif line['type'] == 'uint128_t' and ':' in registers[var] and other_dep not in registers.keys():
+ registers[dep] = registers[var]
+ progressed = True
+ return progressed, registers
+def backpropogate_128(input_data, dependencies, reverse_dependencies, registers):
+ progressed = False
+ for var in registers.keys():
+ if len(dependencies[var]) == 1 and len(reverse_dependencies[dependencies[var][0]]) == 2:
+ var = dependencies[var][0]
+ if var in registers.keys(): continue
+ for dep, other_dep in (tuple(reverse_dependencies[var]), tuple(reversed(reverse_dependencies[var]))):
+ if dep not in registers.keys() or other_dep not in registers.keys(): continue
+ line = line_of_var(input_data, dep)
+ other_line = line_of_var(input_data, other_dep)
+ var_line = line_of_var(input_data, var)
+ if var_line['type'] == 'uint128_t' and line['type'] == 'uint64_t' and other_line['type'] == 'uint64_t' and line['op'] == '>>' and other_line['op'] == '&':
+ registers[var] = registers[dep] + ':' + registers[other_dep]
+ progressed = True
+ return progressed, registers
+def backpropogate_one128(input_data, dependencies, registers):
+ progressed = False
+ for var in registers.keys():
+ var_line = line_of_var(input_data, var)
+ if var_line['type'] != 'uint128_t': continue
+ if len(dependencies[var]) == 1:
+ dep = dependencies[var][0]
+ if dep not in registers.keys():
+ line = line_of_var(input_data, dep)
+ if line['type'] == 'uint128_t' and ':' in registers[var]:
+ registers[dep] = registers[var]
+ progressed = True
+ elif len(dependencies[var]) == 2:
+ for dep, other_dep in (tuple(dependencies[var]), tuple(reversed(dependencies[var]))):
+ if dep in registers.keys(): continue
+ if other_dep in registers.keys() and registers[other_dep] == registers[var]: continue
+ line = line_of_var(input_data, dep)
+ other_line = line_of_var(input_data, other_dep)
+ if line['type'] == 'uint128_t' and other_line['type'] == 'uint64_t' and other_dep not in registers.keys() and ':' in registers[var]:
+ registers[dep] = registers[var]
+ progressed = True
+ elif line['type'] == 'uint64_t' and other_line['type'] == 'uint64_t' and other_dep not in registers.keys() and ':' in registers[var] and var_line['op'] == '*':
+ registers[dep], registers[other_dep] = registers[var].split(':')
+ progressed = True
+ return progressed, registers
+def all_reverse_dependencies(reverse_dependencies, var_set):
+ ret = set(var_set)
+ for v in var_set:
+ ret = ret.union(set(reverse_dependencies[v]))
+ if len(ret) == len(set(var_set)): return ret
+ return all_reverse_dependencies(reverse_dependencies, ret)
+def unassigned_reverse_dependencies(reverse_dependencies, registers, var_set):
+ return set(v for v in all_reverse_dependencies(reverse_dependencies, var_set) if v not in registers.keys())
+def assign_one_new_reg(input_data, dependencies, reverse_dependencies, registers, new_reg):
+ for var in registers.keys():
+ var_line = line_of_var(input_data, var)
+ for dep in dependencies[var]:
+ if len(unassigned_reverse_dependencies(reverse_dependencies, registers, [dep])) == 1 and line_of_var(input_data, dep)['type'] == 'uint64_t':
+ registers[dep] = new_reg
+ return True, registers
+ return False, registers
+
+def assign_registers(input_data, dependencies):
+ reverse_dependencies = make_reverse_data_dependencies(dependencies)
+ registers = {}
+ registers_available = list(REGISTERS)
+ out_vars = get_output_var_names(input_data)
+ for var in out_vars:
+ registers[var] = registers_available.pop()
+ progressed = True
+ while progressed:
+ progressed, registers = backpropogate_one(input_data, dependencies, registers)
+ progressed1, progressed2 = True, True
+ while progressed1 or progressed2:
+ progressed1, registers = backpropogate_one(input_data, dependencies, registers)
+ progressed2, registers = backpropogate_one_arbitrary(input_data, dependencies, registers)
+ progressed5 = True
+ max_count = 7
+ c = 0
+ while c < max_count and progressed5:
+ progressed1, progressed2, did_progress = True, True, True
+ while progressed1 or progressed2 or did_progress:
+ progressed3, progressed4 = True, True
+ while progressed3 or progressed4:
+ progressed3, registers = backpropogate_128(input_data, dependencies, reverse_dependencies, registers)
+ progressed4, registers = backpropogate_one128(input_data, dependencies, registers)
+ did_progress = progressed3 or progressed4
+ progressed1, registers = backpropogate_one(input_data, dependencies, registers)
+ progressed2, registers = backpropogate_one_arbitrary(input_data, dependencies, registers)
+ c += 1
+ if c < max_count:
+ reg, registers_available = registers_available[-1], registers_available[:-1]
+ progressed5, registers = assign_one_new_reg(input_data, dependencies, reverse_dependencies, registers, reg)
+ return registers
+
+def print_dependencies(input_data, dependencies):
+ in_vars = get_input_var_names(input_data)
+ out_vars = get_output_var_names(input_data)
+ registers = assign_registers(input_data, dependencies)
+ body = (
+ ''.join(' %s [label="%s (%s)",%s];\n' % (var, var, reg, COLOR_FOR_REGISTER[reg.split(':')[0]]) for var, reg in registers.items()) +
+ ''.join(' in -> %s ;\n' % var for var in in_vars) +
+ ''.join(' %s -> out ;\n' % var for var in out_vars) +
+ ''.join(''.join(' %s -> %s ;\n' % (out_var, in_var) for out_var in sorted(dependencies[in_var]))
+ for in_var in sorted(dependencies.keys()))
+ )
+ return ('digraph G {\n' + body + '}\n')
+def adjust_bits(input_data, graph):
+ for line in input_data['lines']:
+ if line['type'] == 'uint128_t':
+ graph = graph.replace(line['out'], line['out'] + '_128')
+ return graph
+
+
+data_list = parse_lines(get_lines('femulDisplay.log'))
+for i, data in enumerate(data_list):
+ deps = adjust_bits(data, print_dependencies(data, make_data_dependencies(data)))
+ with codecs.open('femulData%d.dot' % i, 'w', encoding='utf8') as f:
+ f.write(deps)
+ for fmt in ('png', 'svg'):
+ subprocess.call(['dot', '-T%s' % fmt, 'femulData%d.dot' % i, '-o', 'femulData%d.%s' % (i, fmt)])