Skip to content

Commit

Permalink
Merge b8ad723 into 13b4725
Browse files Browse the repository at this point in the history
  • Loading branch information
leonardt committed Oct 9, 2018
2 parents 13b4725 + b8ad723 commit f49722e
Show file tree
Hide file tree
Showing 23 changed files with 579 additions and 205 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ A language for constructing hardware finite state machines using coroutines.

# Setup
```
pip install -r requirements.txt
pip install -e .
```

Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ git+git://github.com/phanrahan/magma.git#egg=magma
git+git://github.com/phanrahan/mantle.git#egg=mantle
git+git://github.com/phanrahan/loam.git#egg=loam
coreir
veriloggen
git+git://github.com/leonardt/veriloggen.git#egg=veriloggen
5 changes: 3 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
name='silica',
version='0.1-alpha',
description='',
packages=["silica"],
packages=["silica", "silica.cfg"],
install_requires=[
"fault==0.27"
"fault==0.27",
"python-constraint"
]
)
266 changes: 212 additions & 54 deletions silica/cfg/control_flow_graph.py

Large diffs are not rendered by default.

52 changes: 36 additions & 16 deletions silica/liveness.py → silica/cfg/liveness.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import ast
import silica.cfg.types as cfg_types
from .types import Yield, HeadBlock, Branch
import silica.ast_utils as ast_utils

class Analyzer(ast.NodeVisitor):
def __init__(self):
Expand All @@ -8,6 +9,9 @@ def __init__(self):
# self.return_values = set()

def visit_Call(self, node):
# if ast_utils.is_name(node.func) and node.func.id == "phi":
# # skip
# return
# Ignore function calls
for arg in node.args:
self.visit(arg)
Expand All @@ -23,6 +27,8 @@ def visit_Name(self, node):
self.gen.add(node.id)
else:
self.kill.add(node.id)
if node.id in self.gen:
self.gen.remove(node.id)

# def visit_Return(self, node):
# if isinstance(node, ast.Tuple):
Expand All @@ -34,31 +40,45 @@ def visit_Name(self, node):

def analyze(node):
analyzer = Analyzer()
if isinstance(node, cfg_types.Yield):
if isinstance(node, Yield):
analyzer.visit(node.value)
analyzer.gen = set(value for value in node.output_map.values())
if not node.terminal: # We only use assigments
analyzer.gen = set()
else:
analyzer.kill = set()
elif isinstance(node, cfg_types.HeadBlock):
# if not node.terminal: # We only use assigments
# analyzer.gen = set()
# else:
# analyzer.kill = set()
elif isinstance(node, HeadBlock):
for statement in node.initial_statements:
analyzer.visit(statement)
if hasattr(node, "initial_yield"):
analyzer.visit(node.initial_yield.value)
elif isinstance(node, cfg_types.Branch):
elif isinstance(node, Branch):
analyzer.visit(node.cond)
else:
for statement in node.statements:
analyzer.visit(statement)
return analyzer.gen, analyzer.kill

def do_analysis(block, seen=set()):
if block in seen:
return block.live_ins
seen.add(block)
block.gen, block.kill = analyze(block)
if not isinstance(block, Yield):
if isinstance(block, Branch):
true_live_ins = do_analysis(block.true_edge, seen)
false_live_ins = do_analysis(block.false_edge, seen)
block.live_outs = true_live_ins | false_live_ins
else:
block.live_outs = do_analysis(block.outgoing_edge[0], seen)
still_live = block.live_outs - block.kill
block.live_ins = block.gen | still_live
return block.live_ins

def liveness_analysis(cfg):
for path in cfg.paths_between_yields:
path[-1].live_outs = set()
for node in reversed(path):
node.gen, node.kill = analyze(node)
if node.next is not None:
node.live_outs = node.next.live_ins
still_live = node.live_outs - node.kill
node.live_ins = node.gen | still_live
for block in cfg.blocks:
if isinstance(block, (HeadBlock, Yield)):
block.live_outs = do_analysis(block.outgoing_edge[0])
block.gen, block.kill = analyze(block)
still_live = block.live_outs - block.kill
block.live_ins = still_live
21 changes: 14 additions & 7 deletions silica/cfg/ssa.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@


class SSAReplacer(ast.NodeTransformer):
def __init__(self):
def __init__(self, width_table):
self.width_table = width_table
self.id_counter = {}
self.phi_vars = {}
self.load_store_offset = {}
Expand Down Expand Up @@ -43,17 +44,22 @@ def visit_Assign(self, node):
node.targets[0].slice = self.visit(node.targets[0].slice)
store_offset = self.load_store_offset.get(node.targets[0].value.id, 0)
name = self.get_name(node.targets[0])
name += f"_{self.id_counter[name]}"
prev_name = name + f"_{self.id_counter[name] - store_offset}"
name += f"_{self.id_counter[name] + store_offset}"
index = self.get_index(node.targets[0])
if name not in self.array_stores:
self.array_stores[name, index] = 0
if (name, index) not in self.array_stores:
self.array_stores[name, index] = (0, prev_name)
num = 0
else:
self.array_stores[name, index] += 1
val = self.array_stores[name, index]
num = val[0] + 1
self.array_stores[name, index] = (num, val[1])
index_hash = "_".join(ast.dump(i) for i in index)
if index_hash not in self.index_map:
self.index_map[index_hash] = len(self.index_map)
node.targets[0].value.id += f"_{self.id_counter[node.targets[0].value.id]}_{self.array_stores[name, index]}_i{self.index_map[index_hash]}"
node.targets[0].value.id = f"{name}_si_tmp_val_{num}_i{self.index_map[index_hash]}"
node.targets[0] = node.targets[0].value
node.targets[0].ctx = ast.Store()
# self.increment_id(name)
# if name not in self.seen:
# self.increment_id(name)
Expand All @@ -80,4 +86,5 @@ def visit_Name(self, node):
# self.increment_id(node.id)
# self.seen.add(node.id)
store_offset = self.load_store_offset.get(node.id, 0)
return ast.Name(f"{node.id}_{self.id_counter[node.id] + store_offset}", ast.Store)
self.width_table[f"{node.id}_{self.id_counter[node.id]}"] = self.width_table[node.id]
return ast.Name(f"{node.id}_{self.id_counter[node.id] + store_offset}", ast.Store())
6 changes: 6 additions & 0 deletions silica/cfg/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class HeadBlock(Block):
def __init__(self):
super().__init__()
self.initial_statements = []
self.loads = {}

def add(self, stmt):
self.initial_statements.append(stmt)
Expand All @@ -44,6 +45,9 @@ def __init__(self):
def add(self, stmt):
self.statements.append(stmt)

def append(self, stmt):
self.statements.append(stmt)

def __iter__(self):
return iter(self.statements)

Expand All @@ -69,6 +73,8 @@ def __init__(self, value, output_map={}, array_stores_to_process=[]):
self.value = value
self.output_map = output_map
self.array_stores_to_process = array_stores_to_process
self.loads = {}
self.stores = {}

@property
def is_initial_yield(self):
Expand Down
42 changes: 23 additions & 19 deletions silica/compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from silica.cfg import ControlFlowGraph, BasicBlock, HeadBlock
from silica.cfg.control_flow_graph import render_paths_between_yields, build_state_info, render_fsm, get_constant
import silica.ast_utils as ast_utils
from silica.liveness import liveness_analysis
from silica.transformations import specialize_constants, replace_symbols, \
constant_fold, desugar_for_loops, specialize_evals, inline_yield_from_functions
from silica.visitors import collect_names
Expand Down Expand Up @@ -95,23 +94,21 @@ def compile(coroutine, file_name=None, mux_strategy="one-hot", output='verilog',
type_table = {}
TypeChecker(width_table, type_table).check(tree)
# DesugarArrays().run(tree)
cfg = ControlFlowGraph(tree)
for var in cfg.replacer.id_counter:
width = width_table[var]
for i in range(cfg.replacer.id_counter[var] + 1):
width_table[f"{var}_{i}"] = width
liveness_analysis(cfg)
cfg = ControlFlowGraph(tree, width_table, func_locals)
# cfg.render()
# render_paths_between_yields(cfg.paths)

if output == 'magma':
# NOTE: This is currently not maintained
return compile_magma(coroutine, file_name, mux_strategy, output)

registers = set()
registers |= cfg.registers
outputs = tuple()
for path in cfg.paths:
registers |= path[0].live_ins # Union
registers |= set(path[0].loads.values()) # Union
outputs += (collect_names(path[-1].value, ctx=ast.Load), )

assert all(outputs[1] == output for output in outputs[1:]), "Yield statements must all have the same outputs except for the first"
outputs = outputs[1]
states = cfg.states
Expand Down Expand Up @@ -166,9 +163,12 @@ def get_len(t):
width = width_table[var]
for i in range(cfg.replacer.id_counter[var] + 1):
if f"{var}_{i}" not in registers:
ctx.declare_wire(f"{var}_{i}", width)
if isinstance(width, MemoryType):
ctx.declare_wire(f"{var}_{i}", width.width, width.height)
else:
ctx.declare_wire(f"{var}_{i}", width)

for (name, index), value in cfg.replacer.array_stores.items():
for (name, index), (value, orig_value) in cfg.replacer.array_stores.items():
width = width_table[name]
if isinstance(width, MemoryType):
width = width.width
Expand All @@ -178,8 +178,10 @@ def get_len(t):
index_hash = "_".join(ast.dump(i) for i in index)
count = cfg.replacer.index_map[index_hash]
for i in range(count + 1):
var = name + f"_{value}_i{count}"
width_table[var] = width
var = name + f"_si_tmp_val_{value}_i{i}"
if var not in width_table:
width_table[var] = width
ctx.declare_wire(var, width)

# declare regs
for register in registers:
Expand All @@ -192,12 +194,14 @@ def get_len(t):
init_body = [ctx.assign(ctx.get_by_name(key), value) for key,value in initial_values.items() if value is not None]

if cfg.curr_yield_id > 1:
ctx.declare_reg("yield_state", (cfg.curr_yield_id - 1).bit_length())
yield_state_width = (cfg.curr_yield_id - 1).bit_length()
ctx.declare_reg("yield_state", yield_state_width)
ctx.declare_wire(f"yield_state_next", yield_state_width)
init_body.append(ctx.assign(ctx.get_by_name("yield_state"), 0))

if initial_basic_block:
for statement in states[0].statements:
verilog.process_statement(statement)
# if initial_basic_block:
# for statement in states[0].statements:
# verilog.process_statement(statement)
# init_body.append(ctx.translate(statement)) # TODO: redefinition bug?
# temp_var_promoter.visit(statement)

Expand All @@ -207,9 +211,9 @@ def get_len(t):
waddrs = {}
wdatas = {}
wens = {}
if initial_basic_block:
states = states[1:]
verilog.compile_states(ctx, states, cfg.curr_yield_id == 1, width_table, strategy)
# if initial_basic_block:
# states = states[1:]
verilog.compile_states(ctx, states, cfg.curr_yield_id == 1, width_table, registers, strategy)
# cfg.render()

with open(file_name, "w") as f:
Expand Down

0 comments on commit f49722e

Please sign in to comment.