├── .gitignore ├── README.md ├── coolname ├── __init__.py ├── __main__.py ├── config.py ├── control.py ├── coolname.py ├── fonts │ └── JetBrainsMono-Regular.ttf ├── fsm.py ├── gui.py ├── logger.py ├── memory.py ├── nodes.py ├── operator_.py └── sample_ir.py ├── data ├── divergence_atomic.dot ├── divergence_speculative.dot ├── prefix_sum_parallel.dot ├── prefix_sum_work_effective.dot ├── trmm_MEM.json ├── trmm_atomic_IR.dot └── trmm_speculative_IR.dot ├── header.png ├── requirements.txt └── run.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | /venv 3 | /.vscode -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | # \: a dataflow simulator. 6 | 7 | Abstract from thesis: 8 | > In recent developments, dataflow graphs are used to design highly parallel application-specific hardware (ASH). However, prototyping and optimizing these graphs - and the techniques used to construct them - is difficult as constructing and testing hardware circuits directly is expensive, both in time as cost. Currently, no model or tool exists to compare these graphs in terms of latency, energy and utilization. 9 | 10 | > In this thesis, we present \, a cycle-accurate, application-level static dataflow simulator, which can be used for analyzing high-level synthesis for application-specific hardware. Furthermore, we present and analyze several techniques and strategies to convert control dataflow graphs to pure dataflow graphs, and outline the possible challenges and limitations of this process. We validate the simulator - in terms of correctness and compliance to the static dataflow model - using controlled experiments in which we compare the execution of a dataflow graph using \, the execution of a conventional reference program and a manual simulation of the dataflow graph. 11 | 12 | > \ can be used as a tool to compare and optimize dataflow graphs for application-specific hardware by reporting performance metrics such as latency, energy and utilization. For ease of use, we also provide a GUI for the simulator, where the user can set input parameters, control the execution and gather performance results. 13 | 14 | 15 | ### Installation 16 | 17 | --- 18 | 19 | Tested for Python 3.8. 20 | ``` 21 | pip3 install -r requirements.txt 22 | ``` 23 | 24 | ### Usage 25 | 26 | --- 27 | 28 | From the GUI: 29 | ``` 30 | python3 run.py 31 | ``` 32 | 33 | Directly: 34 | ``` 35 | from coolname.gui import GUI 36 | from coolname.control import Simulation 37 | from coolname.logger import Logger 38 | from coolname.memory import DefaultMemorySimulator 39 | from coolname.nodes import IR 40 | 41 | # Load graph 42 | graph = IR.from_DOT('mygraph.dot') 43 | 44 | # Setup 45 | mem = DefaultMemorySimulator() 46 | logger = Logger() 47 | sim = Simulation(mem=mem, logger=logger) 48 | 49 | # Interact with memory: 50 | mem.store(2, 'a') 51 | mem.store(True, 'b', [0,0]) 52 | 53 | # Start 54 | sim.run() 55 | # or 56 | # sim.step() 57 | # or 58 | # sim.reset() 59 | 60 | # Statistics: 61 | sim.get_ipc_series() 62 | sim.get_end_statistics() 63 | ``` 64 | -------------------------------------------------------------------------------- /coolname/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffreyspaan/coolname/367db6afcab933d9dd494a49dbe51c75007fbd9f/coolname/__init__.py -------------------------------------------------------------------------------- /coolname/__main__.py: -------------------------------------------------------------------------------- 1 | 2 | from .coolname import main 3 | 4 | main() -------------------------------------------------------------------------------- /coolname/config.py: -------------------------------------------------------------------------------- 1 | from .operator_ import * 2 | import math 3 | 4 | class Config: 5 | class Latency: 6 | computation = { 7 | Operator.ADD: 1, 8 | Operator.SUB: 1, 9 | Operator.MUL: 3, 10 | Operator.DIV: 24, 11 | Operator.MOD: 24, 12 | Operator.LT: 1, 13 | Operator.LE: 1, 14 | Operator.GT: 1, 15 | Operator.GE: 1, 16 | Operator.EQ: 1, 17 | Operator.NE: 1, 18 | Operator.NEG: 0, 19 | Operator.NOT: 1 20 | } 21 | 22 | eta = 0 23 | 24 | mu_str = 'lambda n: math.log(n)' 25 | mu = eval(mu_str) 26 | 27 | mux_str = 'lambda n: math.log(n/4)' 28 | mux = eval(mux_str) 29 | 30 | combine_str = 'lambda n: math.log(n)/2' 31 | combine = eval(combine_str) 32 | 33 | xor_str = 'lambda n: math.log(n)/2' 34 | xor = eval(xor_str) 35 | 36 | mem_load = 8 37 | mem_store = 8 38 | communication = 1 39 | 40 | class Energy: 41 | computation = { 42 | Operator.ADD: 100, 43 | Operator.SUB: 100, 44 | Operator.MUL: 100, 45 | Operator.DIV: 100, 46 | Operator.MOD: 100, 47 | Operator.LT: 100, 48 | Operator.LE: 100, 49 | Operator.GT: 100, 50 | Operator.GE: 100, 51 | Operator.EQ: 100, 52 | Operator.NE: 100, 53 | Operator.NEG: 100, 54 | Operator.NOT: 100 55 | } 56 | 57 | eta = 100 58 | 59 | mu_str = 'lambda n: n*100' 60 | mu = eval(mu_str) 61 | 62 | mux_str = 'lambda n: n*100' 63 | mux = eval(mux_str) 64 | 65 | combine_str = 'lambda n: n*100' 66 | combine = eval(combine_str) 67 | 68 | xor_str = 'lambda n: n*100' 69 | xor = eval(xor_str) 70 | 71 | mem_load = 100 72 | mem_store = 100 73 | communication = 0 -------------------------------------------------------------------------------- /coolname/control.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from .config import * 4 | from .logger import * 5 | 6 | class Simulation: 7 | mem = None 8 | logger = None 9 | 10 | cycle = 0 11 | 12 | def __init__(self, graph=None, mem=None, logger=None): 13 | self.graph = graph 14 | 15 | Simulation.mem = mem 16 | Simulation.logger = logger 17 | 18 | self.stop_after = None 19 | self.halt_now = False 20 | 21 | self.busy_counter = 0 22 | self.start_time = 0 23 | self.end_time = 0 24 | 25 | self.ipc = [] 26 | 27 | def run(self): 28 | self.start_time = time.time() 29 | 30 | while not (self.soft_stop() or self.hard_stop()): 31 | self.step() 32 | 33 | if self.soft_stop(): 34 | # Account for soft stop extra unnecessary cycles. 35 | Simulation.cycle -= Config.Latency.communication 36 | self.ipc = self.ipc[:-Config.Latency.communication] 37 | 38 | self.end_time = time.time() 39 | 40 | def step(self): 41 | Simulation.cycle += 1 42 | 43 | for node in self.graph.nodes: 44 | node.step() 45 | 46 | self.was_busy() 47 | self.calc_ipc() 48 | 49 | def was_busy(self): 50 | if any([n.is_busy() for n in self.graph.nodes]): 51 | self.busy_counter = 0 52 | else: 53 | self.busy_counter += 1 54 | 55 | def hard_stop(self): 56 | if self.halt_now: 57 | return True 58 | 59 | if self.stop_after: 60 | if Simulation.cycle == self.stop_after: 61 | return True 62 | 63 | return False 64 | 65 | def soft_stop(self): 66 | return self.busy_counter == Config.Latency.communication 67 | 68 | def reset(self): 69 | Simulation.cycle = 0 70 | self.halt_now = False 71 | self.busy_counter = 0 72 | self.start_time = 0 73 | self.end_time = 0 74 | self.ipc = [] 75 | 76 | for node in self.graph.nodes: 77 | node.reset() 78 | 79 | for wire in self.graph.wires: 80 | wire.reset() 81 | 82 | def calc_ipc(self): 83 | self.ipc.append(sum([n.in_computation for n in self.graph.nodes])) 84 | 85 | def get_ipc_series(self): 86 | return self.ipc 87 | 88 | def get_end_statistics(self): 89 | # Total cycle count: 90 | total_cycle_count = Simulation.cycle 91 | 92 | # Total energy consumption: 93 | total_energy = sum([n.energy for n in self.graph.nodes]) 94 | 95 | # Average utilization percentage: 96 | utilizations = [n.utilization/total_cycle_count for n in self.graph.nodes if n.utilization > 0] 97 | avg_utilization = (sum(utilizations)/len(self.graph.nodes))*100 if len(self.graph.nodes) > 0 else 0 98 | 99 | # Simulator run-time: 100 | runtime = self.end_time - self.start_time 101 | 102 | return (total_cycle_count, total_energy, avg_utilization, runtime) -------------------------------------------------------------------------------- /coolname/coolname.py: -------------------------------------------------------------------------------- 1 | from coolname.gui import GUI 2 | from coolname.control import Simulation 3 | from coolname.logger import Logger 4 | from coolname.memory import DefaultMemorySimulator 5 | 6 | def main(): 7 | my_mem = DefaultMemorySimulator() 8 | my_gui = GUI() 9 | my_logger = Logger(my_gui) 10 | my_sim = Simulation(mem=my_mem, logger=my_logger) 11 | 12 | my_gui.simulation = my_sim 13 | my_gui.build() 14 | my_gui.start() -------------------------------------------------------------------------------- /coolname/fonts/JetBrainsMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffreyspaan/coolname/367db6afcab933d9dd494a49dbe51c75007fbd9f/coolname/fonts/JetBrainsMono-Regular.ttf -------------------------------------------------------------------------------- /coolname/fsm.py: -------------------------------------------------------------------------------- 1 | from enum import Enum, IntEnum 2 | 3 | class FSM(Enum): 4 | def next(self): 5 | states = list(self.__class__) 6 | return states[(states.index(self) + 1) % len(states)] 7 | 8 | 9 | class InputFSM(FSM): 10 | NONE = 1 11 | SOME = 2 12 | ALL = 3 13 | 14 | 15 | class OutputFSM(FSM): 16 | FREE = 1 17 | BUSY = 2 18 | 19 | 20 | class DataFSM(FSM): 21 | NONE = 1 22 | INITIATED = 2 23 | COMPLETED = 3 24 | TRANSMITTED = 4 -------------------------------------------------------------------------------- /coolname/gui.py: -------------------------------------------------------------------------------- 1 | from dearpygui.core import * 2 | from dearpygui.simple import * 3 | import os 4 | import json 5 | 6 | from .config import * 7 | from .operator_ import * 8 | from .control import * 9 | from .nodes import * 10 | 11 | class GUI: 12 | def __init__(self): 13 | self.simulation = None 14 | self.animation_ctr = 1 15 | 16 | self.mem_table_rows = 0 17 | self.mem_table_data = [] 18 | 19 | def build(self): 20 | set_main_window_size(1650, 915) 21 | set_main_window_title(' simulator') 22 | add_additional_font("coolname/fonts/JetBrainsMono-Regular.ttf", 15) 23 | set_exit_callback(self.stop) 24 | 25 | set_theme('Dark 2') 26 | set_theme_item(mvGuiCol_Text, 235, 235, 235, 230) 27 | set_theme_item(mvGuiCol_Tab, 0, 121, 0, 255) 28 | set_theme_item(mvGuiCol_TabHovered, 0, 175, 0, 255) 29 | set_theme_item(mvGuiCol_TabActive, 0, 175, 0, 255) 30 | set_theme_item(mvGuiCol_ButtonActive, 45, 105, 200, 173) 31 | set_theme_item(mvGuiCol_WindowBg, 23, 23, 38, 240) 32 | 33 | 34 | self.create_config_window() 35 | self.create_memory_window() 36 | self.create_graph_window() 37 | self.create_editor_window() 38 | self.create_control_window() 39 | self.create_logger_window() 40 | self.create_performance_window() 41 | 42 | def start(self): 43 | start_dearpygui(primary_window='graph_window') 44 | 45 | def stop(self, sender, data): 46 | if self.animation_ctr > 1: 47 | os.remove(f'IR{self.animation_ctr-1}.png') 48 | 49 | def reset(self): 50 | # Reset results and log: 51 | clear_log(logger='logger_window##logger') 52 | set_table_item('performance_window##table', 0, 1, '...') 53 | set_table_item('performance_window##table', 1, 1, '...') 54 | set_table_item('performance_window##table', 2, 1, '...') 55 | set_table_item('performance_window##table', 3, 1, '...') 56 | add_stem_series('performance_window##plot', 'IPC', [0.0], [0.0]) 57 | set_value('performance_window##ipc_data', '...') 58 | 59 | def create_config_window(self): 60 | with window('config_window', label='Config', x_pos=0, y_pos=0, width=400, height=640): 61 | add_text('Graph') 62 | add_button("config_window##load_ir_button", label='Select IR file', callback=(lambda s, d: open_file_dialog(self.cb_config_load_dot, ".dot,.DOT"))) 63 | 64 | add_same_line(spacing=20) 65 | add_text('config_window##count1', default_value='0', color=[0,255,0]) 66 | add_same_line(spacing=5) 67 | add_text('blocks') 68 | add_same_line(spacing=20) 69 | add_text('config_window##count2', default_value='0', color=[0,255,0]) 70 | add_same_line(spacing=5) 71 | add_text('nodes') 72 | add_same_line(spacing=20) 73 | add_text('config_window##count3', default_value='0', color=[0,255,0]) 74 | add_same_line(spacing=5) 75 | add_text('wires') 76 | 77 | add_spacing(count=2) 78 | add_separator() 79 | add_spacing(count=2) 80 | 81 | add_text('Parameters') 82 | 83 | with tab_bar('parameter_tabs'): 84 | with tab('parameter_tab_latency', label='Latency'): 85 | add_text('parameter_tab_latency##group1', default_value='Communication') 86 | with child('parameter_tab_latency##child1', border=True, autosize_x=True, height=90): 87 | add_input_int('parameter_l_com', width=200, min_value=0, default_value=Config.Latency.communication, callback=self.cb_parameter_latency, callback_data='communication', label='wire') 88 | add_input_int('parameter_l_meml', width=200, min_value=0, default_value=Config.Latency.mem_load, callback=self.cb_parameter_latency, callback_data='mem_load', label='Memory load') 89 | add_input_int('parameter_l_mems', width=200, min_value=0, default_value=Config.Latency.mem_store, callback=self.cb_parameter_latency, callback_data='mem_store', label='Memory store') 90 | 91 | add_spacing(count=3) 92 | add_text('parameter_tab_latency##group2', default_value='Operations') 93 | with child('parameter_tab_latency##child2', border=True, autosize_x=True, height=155): 94 | 95 | add_text('parameter_tab_latency##text3', default_value='Latency') 96 | add_same_line(xoffset=210) 97 | add_text('parameter_tab_latency##text4', default_value='Operator') 98 | 99 | add_input_int('parameter_l_plus', width=200, min_value=0, default_value=Config.Latency.computation[Operator.ADD], callback=self.cb_parameter_latency_comp, callback_data=Operator.ADD, label='+ (add)') 100 | add_input_int('parameter_l_sub', width=200, min_value=0, default_value=Config.Latency.computation[Operator.SUB], callback=self.cb_parameter_latency_comp, callback_data=Operator.SUB, label='- (subtract)') 101 | add_input_int('parameter_l_mul', width=200, min_value=0, default_value=Config.Latency.computation[Operator.MUL], callback=self.cb_parameter_latency_comp, callback_data=Operator.MUL, label='* (multiply)') 102 | add_input_int('parameter_l_div', width=200, min_value=0, default_value=Config.Latency.computation[Operator.DIV], callback=self.cb_parameter_latency_comp, callback_data=Operator.DIV, label='/ (divide)') 103 | add_input_int('parameter_l_mod', width=200, min_value=0, default_value=Config.Latency.computation[Operator.MOD], callback=self.cb_parameter_latency_comp, callback_data=Operator.MOD, label='% (modulo)') 104 | add_input_int('parameter_l_lt', width=200, min_value=0, default_value=Config.Latency.computation[Operator.LT], callback=self.cb_parameter_latency_comp, callback_data=Operator.LT, label='< (less than)') 105 | add_input_int('parameter_l_le', width=200, min_value=0, default_value=Config.Latency.computation[Operator.LE], callback=self.cb_parameter_latency_comp, callback_data=Operator.LE, label='<= (less or equal)') 106 | add_input_int('parameter_l_gt', width=200, min_value=0, default_value=Config.Latency.computation[Operator.GT], callback=self.cb_parameter_latency_comp, callback_data=Operator.GT, label='> (greater than)') 107 | add_input_int('parameter_l_ge', width=200, min_value=0, default_value=Config.Latency.computation[Operator.GE], callback=self.cb_parameter_latency_comp, callback_data=Operator.GE, label='>= (greater or equal)') 108 | add_input_int('parameter_l_eq', width=200, min_value=0, default_value=Config.Latency.computation[Operator.EQ], callback=self.cb_parameter_latency_comp, callback_data=Operator.EQ, label='== (equal to)') 109 | add_input_int('parameter_l_ne', width=200, min_value=0, default_value=Config.Latency.computation[Operator.NE], callback=self.cb_parameter_latency_comp, callback_data=Operator.NE, label='!= (not equal to)') 110 | add_input_int('parameter_l_neg', width=200, min_value=0, default_value=Config.Latency.computation[Operator.NEG], callback=self.cb_parameter_latency_comp, callback_data=Operator.NEG, label='- (negation)') 111 | add_input_int('parameter_l_not', width=200, min_value=0, default_value=Config.Latency.computation[Operator.NOT], callback=self.cb_parameter_latency_comp, callback_data=Operator.NOT, label='! (not)') 112 | 113 | add_spacing(count=3) 114 | add_text('parameter_tab_latency##group3', default_value='Nodes') 115 | with child('parameter_tab_latency##child3', border=True, autosize_x=True, height=160): 116 | 117 | add_text('parameter_tab_latency##text5', default_value='Latency') 118 | add_same_line(xoffset=210) 119 | add_text('parameter_tab_latency##text6', default_value='Node') 120 | 121 | add_input_int('parameter_l_eta', width=200, default_value=Config.Latency.eta, callback=self.cb_parameter_latency, callback_data='eta', label='ETA', min_value=0) 122 | add_input_text('parameter_l_mu', width=200, default_value=Config.Latency.mu_str, callback=self.cb_parameter_latency_f, callback_data='mu', label='Mu', tip='n: amount of inputs') 123 | add_input_text('parameter_l_mux', width=200, default_value=Config.Latency.mux_str, callback=self.cb_parameter_latency_f, callback_data='mux', label='Mux', tip='n: amount of inputs') 124 | add_input_text('parameter_l_combine', width=200, default_value=Config.Latency.combine_str, callback=self.cb_parameter_latency_f, callback_data='combine', label='Combine', tip='n: amount of inputs') 125 | add_input_text('parameter_l_xor', width=200, default_value=Config.Latency.xor_str, callback=self.cb_parameter_latency_f, callback_data='xor', label='XOR', tip='n: amount of inputs') 126 | 127 | 128 | with tab('parameter_tab_energy', label='Energy'): 129 | add_text('parameter_tab_energy##group1', default_value='Communication') 130 | with child('parameter_tab_energy##child1', border=True, autosize_x=True, height=90): 131 | add_input_int('parameter_e_com', width=200, min_value=0, default_value=Config.Energy.communication, callback=self.cb_parameter_energy, callback_data='communication', label='wire') 132 | add_input_int('parameter_e_meml', width=200, min_value=0, default_value=Config.Energy.mem_load, callback=self.cb_parameter_energy, callback_data='mem_load', label='Memory load') 133 | add_input_int('parameter_e_mems', width=200, min_value=0, default_value=Config.Energy.mem_store, callback=self.cb_parameter_energy, callback_data='mem_store', label='Memory store') 134 | 135 | add_spacing(count=3) 136 | add_text('parameter_tab_energy##group2', default_value='Operations') 137 | with child('parameter_tab_energy##child2', border=True, autosize_x=True, height=155): 138 | 139 | add_text('parameter_tab_energy##text3', default_value='Energy (pJ)') 140 | add_same_line(xoffset=210) 141 | add_text('parameter_tab_energy##text4', default_value='Operator') 142 | 143 | add_input_int('parameter_e_plus', width=200, min_value=0, default_value=Config.Energy.computation[Operator.ADD], callback=self.cb_parameter_energy_comp, callback_data=Operator.ADD, label='+ (add)') 144 | add_input_int('parameter_e_sub', width=200, min_value=0, default_value=Config.Energy.computation[Operator.SUB], callback=self.cb_parameter_energy_comp, callback_data=Operator.SUB, label='- (subtract)') 145 | add_input_int('parameter_e_mul', width=200, min_value=0, default_value=Config.Energy.computation[Operator.MUL], callback=self.cb_parameter_energy_comp, callback_data=Operator.MUL, label='* (multiply)') 146 | add_input_int('parameter_e_div', width=200, min_value=0, default_value=Config.Energy.computation[Operator.DIV], callback=self.cb_parameter_energy_comp, callback_data=Operator.DIV, label='/ (divide)') 147 | add_input_int('parameter_e_mod', width=200, min_value=0, default_value=Config.Energy.computation[Operator.MOD], callback=self.cb_parameter_energy_comp, callback_data=Operator.MOD, label='% (modulo)') 148 | add_input_int('parameter_e_lt', width=200, min_value=0, default_value=Config.Energy.computation[Operator.LT], callback=self.cb_parameter_energy_comp, callback_data=Operator.LT, label='< (less than)') 149 | add_input_int('parameter_e_le', width=200, min_value=0, default_value=Config.Energy.computation[Operator.LE], callback=self.cb_parameter_energy_comp, callback_data=Operator.LE, label='<= (less or equal)') 150 | add_input_int('parameter_e_gt', width=200, min_value=0, default_value=Config.Energy.computation[Operator.GT], callback=self.cb_parameter_energy_comp, callback_data=Operator.GT, label='> (greater than)') 151 | add_input_int('parameter_e_ge', width=200, min_value=0, default_value=Config.Energy.computation[Operator.GE], callback=self.cb_parameter_energy_comp, callback_data=Operator.GE, label='>= (greater or equal)') 152 | add_input_int('parameter_e_eq', width=200, min_value=0, default_value=Config.Energy.computation[Operator.EQ], callback=self.cb_parameter_energy_comp, callback_data=Operator.EQ, label='== (equal to)') 153 | add_input_int('parameter_e_ne', width=200, min_value=0, default_value=Config.Energy.computation[Operator.NE], callback=self.cb_parameter_energy_comp, callback_data=Operator.NE, label='!= (not equal to)') 154 | add_input_int('parameter_e_neg', width=200, min_value=0, default_value=Config.Energy.computation[Operator.NEG], callback=self.cb_parameter_energy_comp, callback_data=Operator.NEG, label='- (negation)') 155 | add_input_int('parameter_e_not', width=200, min_value=0, default_value=Config.Energy.computation[Operator.NOT], callback=self.cb_parameter_energy_comp, callback_data=Operator.NOT, label='! (not)') 156 | 157 | add_spacing(count=3) 158 | add_text('parameter_tab_energy##group3', default_value='Nodes') 159 | with child('parameter_tab_energy##child3', border=True, autosize_x=True, height=160): 160 | 161 | add_text('parameter_tab_energy##text5', default_value='Energy (pJ)') 162 | add_same_line(xoffset=210) 163 | add_text('parameter_tab_energy##text6', default_value='Node') 164 | 165 | add_input_int('parameter_e_eta', width=200, default_value=Config.Energy.communication, callback=self.cb_parameter_energy, callback_data='eta', label='ETA', min_value=0,) 166 | add_input_text('parameter_e_mu', width=200, default_value=Config.Energy.mu_str, callback=self.cb_parameter_energy_f, callback_data='mu', label='Mu', tip='n: amount of inputs') 167 | add_input_text('parameter_e_mux', width=200, default_value=Config.Energy.mux_str, callback=self.cb_parameter_energy_f, callback_data='mux', label='Mux', tip='n: amount of inputs') 168 | add_input_text('parameter_e_combine', width=200, default_value=Config.Energy.combine_str, callback=self.cb_parameter_energy_f, callback_data='combine', label='Combine', tip='n: amount of inputs') 169 | add_input_text('parameter_e_xor', width=200, default_value=Config.Energy.xor_str, callback=self.cb_parameter_energy_f, callback_data='xor', label='XOR', tip='n: amount of inputs') 170 | 171 | def create_memory_window(self): 172 | with window('memory_window', label='Memory', x_pos=0, y_pos=650, width=400, height=265): 173 | add_button('memory_window##load', label='Load JSON', callback=(lambda s,d: open_file_dialog(self.cb_memory_table_load, ".json,.*"))) 174 | 175 | add_same_line(xoffset=200) 176 | add_button('memory_window##save', callback=self.cb_memory_table_save, label='Save state') 177 | add_same_line() 178 | add_button('memory_window##revert', callback=self.cb_memory_table_revert, label='Revert state') 179 | 180 | add_spacing(count=3) 181 | 182 | with child('memory_window##table', border=False, autosize_x=True, height=165): 183 | with managed_columns('memory_window##table_head', 3): 184 | add_text('Identifier') 185 | add_text('Indices') 186 | add_text('Value') 187 | 188 | add_dummy() 189 | add_same_line(spacing=8) 190 | add_button('memory_window##add_row', small=True, callback=self.cb_memory_table_add_row, label='Add row') 191 | 192 | def memory_table_add_row(self, identifier='', indices='', value=''): 193 | configure_item('memory_window', label='Memory (not saved)') 194 | 195 | 196 | self.mem_table_data.append([identifier, indices, value]) 197 | row_str = str(self.mem_table_rows) 198 | 199 | with managed_columns(f'memory_window##table_row{row_str}', 3, parent='memory_window##table'): 200 | add_input_text(f"##memory_window##table_row{row_str}_0", callback=self.cb_memory_table_update, default_value=identifier, width=-1) 201 | add_input_text(f"##memory_window##table_row{row_str}_1", callback=self.cb_memory_table_update, default_value=indices, width=-1) 202 | add_input_text(f"##memory_window##table_row{row_str}_2", callback=self.cb_memory_table_update, default_value=value, width=-1) 203 | 204 | self.mem_table_rows += 1 205 | 206 | def cb_memory_table_update(self, sender, data): 207 | configure_item('memory_window', label='Memory (not saved)') 208 | 209 | def cb_memory_table_add_row(self, sender, data): 210 | self.memory_table_add_row() 211 | 212 | def cb_memory_table_load(self, sender, data): 213 | configure_item('memory_window', label='Memory (not saved)') 214 | dir_, file_ = data 215 | 216 | with open(f'{dir_}/{file_}') as f: 217 | # We expect a json array with each memory item an array consisting of 218 | # an identifier, indices (can be []) and a value. For example: 219 | # [a, [], 123] 220 | # [b, [1,2], true] 221 | json_mem = json.load(f) 222 | 223 | for identifier, indices, value in json_mem: 224 | self.log_mem(value, identifier, indices) 225 | 226 | self.cb_memory_table_save(None, None) 227 | 228 | 229 | def cb_memory_table_save(self, sender, data): 230 | try: 231 | for r in range(self.mem_table_rows): 232 | identifier = get_value(f"##memory_window##table_row{r}_0") 233 | indices = get_value(f"##memory_window##table_row{r}_1") 234 | value = get_value(f"##memory_window##table_row{r}_2") 235 | 236 | self.mem_table_data[r][0] = identifier 237 | self.mem_table_data[r][1] = indices 238 | self.mem_table_data[r][2] = value 239 | 240 | # print('save', identifier) 241 | self.simulation.mem.store(eval(value), identifier, eval(indices) if indices else None) 242 | 243 | # print('DUMP') 244 | # print(self.mem_table_data) 245 | # self.simulation.mem.dump() 246 | 247 | configure_item('memory_window', label='Memory (saved)') 248 | except SyntaxError: 249 | log_error('Memory could not be saved (SyntaxError)', logger='logger_window##logger') 250 | 251 | def cb_memory_table_revert(self, sender, data): 252 | configure_item('memory_window', label='Memory (not saved)') 253 | 254 | for r in range(self.mem_table_rows): 255 | set_value(f"##memory_window##table_row{r}_0", self.mem_table_data[r][0]) 256 | set_value(f"##memory_window##table_row{r}_1", self.mem_table_data[r][1]) 257 | set_value(f"##memory_window##table_row{r}_2", self.mem_table_data[r][2]) 258 | 259 | 260 | def log_mem(self, value, identifier, indices=None): 261 | for i,r in enumerate(self.mem_table_data): 262 | if r[0] == identifier: 263 | if indices: 264 | if indices == eval(r[1]): 265 | set_value(f"##memory_window##table_row{i}_2", str(value)) 266 | return 267 | else: 268 | set_value(f"##memory_window##table_row{i}_2", str(value)) 269 | return 270 | 271 | # Memory table was not updated, so a new entry must be inserted. 272 | self.memory_table_add_row(str(identifier), str(indices) if indices else '', str(value)) 273 | 274 | def create_graph_window(self): 275 | with window('graph_window', label='Intermediate Representation'): 276 | add_plot("graph_window##plot", no_legend=True, equal_aspects=True, anti_aliased=True, no_mouse_pos=True, yaxis_no_tick_labels=True, yaxis_no_tick_marks=True, xaxis_no_tick_labels=True, xaxis_no_tick_marks=True, label='Intermediate representation (green=busy, red=computing)') 277 | self.update_graph() 278 | 279 | 280 | def create_editor_window(self): 281 | pass 282 | 283 | def create_control_window(self): 284 | with window('control_window', label='Control', x_pos=1150, y_pos=0, width=500, height=145): 285 | 286 | add_text('Exit condition') 287 | 288 | add_checkbox('control_window##stop_after_check', default_value=False, callback=self.cb_control_stop_after, label='stop after') 289 | add_same_line() 290 | add_input_int('control_window##stop_after_cycles', width=100, min_value=1, default_value=100, callback=self.cb_control_stop_after_cycles, enabled=False, label='cycles') 291 | 292 | add_same_line(spacing=20) 293 | add_checkbox('control_window##animation_check', default_value=True, label='Animate graph') 294 | 295 | add_spacing(count=2) 296 | add_separator() 297 | add_spacing(count=2) 298 | 299 | add_text('Control') 300 | 301 | add_button('control_window_button##run', callback=self.cb_control_run, label='Run') 302 | add_same_line() 303 | add_button('control_window_button##step', callback=self.cb_control_step, label='Step') 304 | add_same_line() 305 | add_button('control_window_button##halt', callback=self.cb_control_halt, label='Halt') 306 | set_item_color('control_window_button##halt', mvGuiCol_Button, [150,0,0]) 307 | set_item_color('control_window_button##halt', mvGuiCol_ButtonHovered, [200,0,0]) 308 | set_item_color('control_window_button##halt', mvGuiCol_ButtonActive, [255,0,0]) 309 | add_same_line() 310 | add_button('control_window_button##reset', callback=self.cb_control_reset, label='Reset') 311 | set_item_color('control_window_button##reset', mvGuiCol_Button, [0,150,0]) 312 | set_item_color('control_window_button##reset', mvGuiCol_ButtonHovered, [0,200,0]) 313 | set_item_color('control_window_button##reset', mvGuiCol_ButtonActive, [0,255,0]) 314 | 315 | 316 | def create_logger_window(self): 317 | with window('logger_window', label='Logging', x_pos=1150, y_pos=155, width=500, height=385): 318 | with group('logger_window##group2'): 319 | add_text('Only show log type ...') 320 | add_same_line() 321 | 322 | logger_help_msg = 'and logs of higher importance' 323 | add_text('(?)'+logger_help_msg, color=[150, 150, 150], default_value='(?)') 324 | add_tooltip('(?)'+logger_help_msg, logger_help_msg + 'tip') 325 | add_text(logger_help_msg) 326 | end() 327 | 328 | add_radio_button('logger_window##log_type', horizontal=True, items=('Trace', 'Debug', 'Info', 'Warning', 'Error', 'Off'), callback=self.cb_logger_type) 329 | 330 | add_spacing(count=2) 331 | add_separator() 332 | add_spacing(count=2) 333 | 334 | add_logger('logger_window##logger', log_level=0, autosize_x=True, height=230, auto_scroll=True) 335 | clear_log(logger='logger_window##logger') 336 | 337 | def create_performance_window(self): 338 | with window('performance_window', label='Performance', x_pos=1150, y_pos=550, width=500, height=365): 339 | add_table('performance_window##table', ['Metric', 'Result'], height=105) 340 | add_row('performance_window##table', ['Total cycle count', '...']) 341 | add_row('performance_window##table', ['Total enery consumption (pJ)', '...']) 342 | add_row('performance_window##table', ['Average utilization (%)', '...']) 343 | add_row('performance_window##table', ['Simulator run-time (s)', '...']) 344 | 345 | add_plot('performance_window##plot', height=190, label='Instructions Per Cycle (IPC)', no_legend=True) 346 | 347 | add_text('Raw:') 348 | add_same_line() 349 | add_input_text('performance_window##ipc_data', width=-2, readonly=True, default_value='...', label='') 350 | 351 | # add_button('performance_window##button', label='Raw IPC data') 352 | # with popup('performance_window##button', 'IPC data##modal', modal=True, mousebutton=0, width=500): 353 | # add_input_text('performance_window##ipc_data', multiline=True, readonly=True, height=20, default_value='...') 354 | # add_button("performance_window##close_button", callback=self.cb_performance_close_modal, label='Close') 355 | 356 | def cb_config_load_dot(self, sender, data): 357 | dir_, file_ = data 358 | self.simulation.graph = IR.from_DOT(f'{dir_}/{file_}') 359 | set_value('config_window##count1', str(len(self.simulation.graph.blocks)-1)) 360 | set_value('config_window##count2', str(len(self.simulation.graph.nodes))) 361 | set_value('config_window##count3', str(len(self.simulation.graph.wires))) 362 | 363 | self.reset() 364 | self.update_graph() 365 | 366 | def cb_parameter_latency(self, sender, data): 367 | setattr(Config.Latency, data, int(get_value(sender))) 368 | 369 | def cb_parameter_latency_comp(self, sender, data): 370 | Config.Latency.computation[data] = int(get_value(sender)) 371 | 372 | def cb_parameter_latency_f(self, sender, data): 373 | try: 374 | setattr(Config.Latency, data, eval(get_value(sender))) 375 | except SyntaxError: 376 | pass 377 | 378 | 379 | def cb_parameter_energy(self, sender, data): 380 | setattr(Config.Energy, data, int(get_value(sender))) 381 | 382 | def cb_parameter_energy_comp(self, sender, data): 383 | Config.Energy.computation[data] = int(get_value(sender)) 384 | 385 | def cb_parameter_energy_f(self, sender, data): 386 | setattr(Config.Energy, data, eval(get_value(sender))) 387 | 388 | 389 | 390 | def cb_control_stop_after(self, sender, data): 391 | if not get_value(sender): 392 | self.simulation.stop_after = None 393 | 394 | configure_item('control_window##stop_after_cycles', enabled=get_value(sender)) 395 | 396 | def cb_control_stop_after_cycles(self, sender, data): 397 | self.simulation.stop_after = get_value(sender) 398 | 399 | def cb_control_run(self, sender, data): 400 | if self.simulation.graph is not None: 401 | self.simulation.run() 402 | self.show_statistics() 403 | self.show_IPC() 404 | 405 | def cb_control_step(self, sender, data): 406 | if self.simulation.graph is not None: 407 | self.simulation.step() 408 | self.show_statistics() 409 | self.show_IPC() 410 | self.update_graph() 411 | 412 | def cb_control_halt(self, sender, data): 413 | self.simulation.halt_now = True 414 | 415 | def cb_control_reset(self, sender, data): 416 | if self.simulation.graph is not None: 417 | # Reset GUI (except graph, which depends on the simulator reset) 418 | self.reset() 419 | 420 | # Reset sim: 421 | self.simulation.reset() 422 | 423 | # Reset graph explorer: 424 | self.update_graph() 425 | 426 | def cb_logger_type(self, sender, data): 427 | set_log_level(get_value(sender), logger='logger_window##logger') 428 | 429 | def log(self, cycle, level, msg): 430 | msg = f'[{cycle}] {msg}' 431 | 432 | if level == 'trace': 433 | log(msg, logger='logger_window##logger') 434 | elif level == 'debug': 435 | log_debug(msg, logger='logger_window##logger') 436 | elif level == 'info': 437 | log_info(msg, logger='logger_window##logger') 438 | elif level == 'warning': 439 | log_warning(msg, logger='logger_window##logger') 440 | elif level == 'error': 441 | log_error(msg, logger='logger_window##logger') 442 | 443 | 444 | def cb_performance_close_modal(self, sender, data): 445 | close_popup("IPC data##modal") 446 | 447 | def show_IPC(self): 448 | ipc_series = self.simulation.get_ipc_series() 449 | plot_x = [float(x) for x in range(1,len(ipc_series)+1)] 450 | plot_y = [float(y) for y in ipc_series] 451 | 452 | add_stem_series('performance_window##plot', 'IPC', plot_x, plot_y, update_bounds=True) 453 | 454 | set_value('performance_window##ipc_data', str(ipc_series)) 455 | 456 | def show_statistics(self): 457 | (total_cycle_count, total_energy, avg_utilization, runtime) = self.simulation.get_end_statistics() 458 | 459 | set_table_item('performance_window##table', 0, 1, str(total_cycle_count)) 460 | set_table_item('performance_window##table', 1, 1, str(total_energy)) 461 | set_table_item('performance_window##table', 2, 1, str(avg_utilization)) 462 | set_table_item('performance_window##table', 3, 1, str(runtime)) 463 | 464 | def update_graph(self): 465 | if get_value('control_window##animation_check'): 466 | filename = self.simulation.graph.to_stylizedPNGfile(f'IR{self.animation_ctr}.png') 467 | series_name = 'graph_window##plot_graph' + str(self.animation_ctr) 468 | 469 | if self.animation_ctr == 1: 470 | add_image_series('graph_window##plot', series_name, filename, bounds_min=[0,0], bounds_max=get_main_window_size()) 471 | else: 472 | add_image_series('graph_window##plot', series_name, filename, bounds_min=[0,0], bounds_max=get_main_window_size(), update_bounds=False) 473 | os.remove(f'IR{self.animation_ctr-1}.png') 474 | 475 | self.animation_ctr += 1 476 | 477 | -------------------------------------------------------------------------------- /coolname/logger.py: -------------------------------------------------------------------------------- 1 | class Logger: 2 | 3 | def __init__(self, gui=None): 4 | self.gui = gui 5 | 6 | def log_inputFSM_transition(self, cycle, node, specific=None): 7 | if specific: 8 | msg = f'[{node.name}] input: {node.input_state.name} -> {specific.name}' 9 | else: 10 | msg = f'[{node.name}] input: {node.input_state.name} -> {node.input_state.next().name}' 11 | 12 | self._report(cycle, 'trace', msg) 13 | 14 | def log_outputFSM_transition(self, cycle, node, specific=None): 15 | if specific: 16 | msg = f'[{node.name}] output: {node.output_state.name} -> {specific.name}' 17 | else: 18 | msg = f'[{node.name}] output: {node.output_state.name} -> {node.output_state.next().name}' 19 | 20 | self._report(cycle, 'trace', msg) 21 | 22 | def log_dataFSM_transition(self, cycle, node, specific=None): 23 | if specific: 24 | msg = f'[{node.name}] data: {node.data_state.name} -> {specific.name}' 25 | else: 26 | msg = f'[{node.name}] data: {node.data_state.name} -> {node.data_state.next().name}' 27 | 28 | self._report(cycle, 'trace', msg) 29 | 30 | def log_send(self, cycle, wire, data): 31 | msg = f'[{wire.input_.name}] sending [{data}] to [{wire.output_.name}] on wire [{wire.name}]' 32 | self._report(cycle, 'debug', msg) 33 | 34 | def log_error(self, cycle, node, error): 35 | msg = f'[{node.name}]: {error}' 36 | self._report(cycle, 'error', msg) 37 | 38 | def _report(self, cycle, level, msg): 39 | if self.gui: 40 | self.gui.log(cycle, level, msg) 41 | else: 42 | print(f'{cycle}| {msg}') 43 | 44 | def log_mem_store(self, value, identifier, indices=None): 45 | if self.gui: 46 | self.gui.log_mem(value, identifier, indices) 47 | else: 48 | print(f'Memory store: {identifier}{indices if indices else ""} = {value}') -------------------------------------------------------------------------------- /coolname/memory.py: -------------------------------------------------------------------------------- 1 | from .config import * 2 | 3 | class MemorySimulator(): 4 | def load(self, addr, indices=None): 5 | """ 6 | Must return (value, latency, error) pair. 7 | """ 8 | raise NotImplementedError 9 | 10 | def store(self, val, addr, indices=None): 11 | """ 12 | Must return (latency, error) pair. 13 | """ 14 | raise NotImplementedError 15 | 16 | def dump(self): 17 | """ 18 | Outputs all values currently in memory. 19 | """ 20 | raise NotImplementedError 21 | 22 | 23 | class DefaultMemorySimulator(MemorySimulator): 24 | def __init__(self): 25 | self.load_latency = Config.Latency.mem_load 26 | self.store_latency = Config.Latency.mem_store 27 | self.load_energy = Config.Energy.mem_load 28 | self.store_energy = Config.Energy.mem_store 29 | 30 | self.memory = dict() 31 | 32 | def load(self, addr, indices=None): 33 | mem_val = self.memory.get(addr) 34 | 35 | if mem_val is None: 36 | return None, None, None, True, 'No value is stored on this address' 37 | elif isinstance(mem_val, dict): 38 | if indices is None: 39 | return None, None, None, True, 'Attempted to get primtive from array, forgot indices?' 40 | 41 | array_val = mem_val.get(tuple(indices)) 42 | 43 | if array_val is None: 44 | return None, None, None, True, 'No value is stored on this array element address' 45 | 46 | return array_val, self.load_latency, self.load_energy, False, None 47 | else: # primitive value 48 | if indices: 49 | return None, None, None, True, 'Attempted to get array element from primitive, why indices?' 50 | 51 | return mem_val, self.load_latency, self.load_energy, False, None 52 | 53 | def store(self, val, addr, indices=None): 54 | mem_val = self.memory.get(addr) 55 | 56 | if mem_val is None: 57 | if indices: 58 | self.memory[addr] = dict() 59 | self.memory[addr][tuple(indices)] = val 60 | else: 61 | self.memory[addr] = val 62 | 63 | return self.store_latency, self.store_energy, False, None 64 | elif isinstance(mem_val, dict): 65 | if indices is None: 66 | return None, None, True, 'Attempted to store primtive as array, forgot indices?' 67 | 68 | self.memory[addr][tuple(indices)] = val 69 | return self.store_latency, self.store_energy, False, None 70 | else: 71 | if indices: 72 | return None, None, True, 'Attempted to store array element as primitive, why indices?' 73 | 74 | self.memory[addr] = val 75 | return self.store_latency, self.store_energy, False, None 76 | 77 | print('UNCHARTED WATERS: abort') 78 | exit() 79 | 80 | def dump(self): 81 | print('MEMORY DUMP:') 82 | print() 83 | 84 | for addr, val in self.memory.items(): 85 | if isinstance(val, dict): 86 | print(f'\'{addr}\'') 87 | print('type=array') 88 | for arr_indices, arr_val in val.items(): 89 | print(f'value{list(arr_indices)}={arr_val}') 90 | else: 91 | print(f'\'{addr}\'') 92 | print('type=primitive') 93 | print(f'value={val}') 94 | 95 | print() -------------------------------------------------------------------------------- /coolname/nodes.py: -------------------------------------------------------------------------------- 1 | from enum import Enum, IntEnum 2 | import re 3 | import math 4 | import pydot 5 | 6 | from .operator_ import * 7 | from .config import * 8 | from .control import * 9 | from .fsm import * 10 | 11 | class Input: 12 | value_types = IntEnum('Types', 'DATA PREDICATE TOKEN') 13 | 14 | def read(self, consume=True): 15 | raise NotImplementedError 16 | 17 | def send(self, data, latency=None): 18 | raise NotImplementedError 19 | 20 | def acknowledge(self, latency=None): 21 | raise NotImplementedError 22 | 23 | def is_ready(self): 24 | raise NotImplementedError 25 | 26 | def is_acknowledged(self): 27 | raise NotImplementedError 28 | 29 | 30 | class IntegratedConstant(Input): 31 | def __init__(self, data, value_type, name='ICONST'): 32 | self.data = data 33 | self.name = name 34 | self.value_type = value_type 35 | 36 | def read(self, consume=True): 37 | return self.data 38 | 39 | def acknowledge(self, latency=None): 40 | return 41 | 42 | def is_ready(self): 43 | return True 44 | 45 | 46 | class Wire(Input): 47 | def __init__(self, input_, output_, value_type, name='WIRE'): 48 | assert isinstance(input_, Node), 'Input node class is unknown' 49 | self.input_ = input_ 50 | 51 | assert isinstance(output_, Node), 'Output node class is unknown' 52 | self.output_ = output_ 53 | 54 | input_.add_output(self) 55 | output_.add_input(self) 56 | 57 | self.name = name 58 | 59 | assert isinstance(value_type, Input.value_types), 'Wire value type is unknown' 60 | self.value_type = value_type 61 | 62 | self.data = None 63 | self.data_ready = -1 64 | self.acknowledged = -1 65 | 66 | def reset(self): 67 | self.data = None 68 | self.data_ready = -1 69 | self.acknowledged = -1 70 | 71 | def read(self, consume=True): 72 | data = self.data 73 | 74 | if consume: 75 | self.data = None 76 | self.data_ready = -1 77 | 78 | return data 79 | 80 | def send(self, data, latency=None): 81 | if self.is_ready(): 82 | Simulation.logger.log_error(Simulation.cycle, self, 83 | f'cannot send, [{self.data}] already in wire {self.name}: [{self.input_.name}] -> [{self.output_.name}]') 84 | else: 85 | Simulation.logger.log_send(Simulation.cycle, self, data) 86 | 87 | if not latency: 88 | latency = Config.Latency.communication 89 | 90 | self.acknowledged = -1 91 | self.data = data 92 | self.data_ready = Simulation.cycle + latency 93 | 94 | def acknowledge(self, latency=None): 95 | if not latency: 96 | latency = Config.Latency.communication 97 | 98 | self.acknowledged = Simulation.cycle + latency 99 | 100 | def is_ready(self): 101 | return self.data_ready >= 0 and \ 102 | self.data_ready <= Simulation.cycle 103 | 104 | def is_acknowledged(self): 105 | return self.acknowledged >= 0 and \ 106 | self.acknowledged <= Simulation.cycle 107 | 108 | 109 | class Node: 110 | name = "UNNAMED" 111 | 112 | def __init__(self): 113 | self.inputs = [] 114 | self.outputs = [] 115 | 116 | # Default FSM states. 117 | self.input_state = InputFSM.NONE 118 | self.output_state = OutputFSM.FREE 119 | self.data_state = DataFSM.NONE 120 | 121 | self.default_data_ready = -1 122 | self.data_ready = self.default_data_ready 123 | 124 | self.energy = 0 125 | self.utilization = 0 126 | 127 | self.busy = False 128 | self.in_computation = False 129 | 130 | @staticmethod 131 | def generate_dummy_data(type_): 132 | if type_ is int: 133 | return 1 134 | if type_ is float: 135 | return 1.0 136 | if type_ is bool: 137 | return True 138 | else: 139 | Simulation.logger.log_error(Simulation.cycle, self, 140 | f'cannot generate dummy value, type [{type_}] is unknown') 141 | 142 | def add_input(self, i): 143 | self.inputs.append(i) 144 | 145 | def add_output(self, o): 146 | self.outputs.append(o) 147 | 148 | def get_data_inputs(self): 149 | return [i for i in self.inputs if i.value_type == Input.value_types.DATA] 150 | 151 | def get_predicate_inputs(self): 152 | return [i for i in self.inputs if i.value_type == Input.value_types.PREDICATE] 153 | 154 | def get_token_input(self): 155 | return [i for i in self.inputs if i.value_type == Input.value_types.TOKEN] 156 | 157 | def get_matching_inputs(self): 158 | matches = [] 159 | names = set([i.name for i in self.inputs]) 160 | 161 | for name in names: 162 | matches.append(sorted([i for i in self.inputs if i.name == name], 163 | key=lambda i: i.value_type)) 164 | 165 | return matches 166 | 167 | def step(self): 168 | self.busy = False 169 | self.in_computation = False 170 | 171 | self.process_inputs() 172 | self.process_outputs() 173 | self.process_data() 174 | 175 | def reset(self): 176 | self.input_state = InputFSM.NONE 177 | self.output_state = OutputFSM.FREE 178 | self.data_state = DataFSM.NONE 179 | 180 | self.busy = False 181 | self.in_computation = False 182 | 183 | self.data_ready = self.default_data_ready 184 | 185 | self.energy = 0 186 | self.utilization = 0 187 | 188 | ################ 189 | ## Input FSM ## 190 | ################ 191 | 192 | def process_inputs(self): 193 | if self.input_state == InputFSM.NONE: 194 | self.process_inputs_NONE() 195 | 196 | if self.input_state == InputFSM.SOME: 197 | self.process_inputs_SOME() 198 | 199 | def process_inputs_NONE(self): 200 | inputs_ready = [i.is_ready() for i in self.inputs] 201 | 202 | if sum(inputs_ready) > 0: 203 | Simulation.logger.log_inputFSM_transition(Simulation.cycle, self) 204 | self.input_state = InputFSM.SOME 205 | 206 | def process_inputs_SOME(self): 207 | inputs_ready = [i.is_ready() for i in self.inputs] 208 | 209 | if all(inputs_ready): 210 | Simulation.logger.log_inputFSM_transition(Simulation.cycle, self) 211 | self.input_state = InputFSM.ALL 212 | 213 | 214 | ################ 215 | ## Output FSM ## 216 | ################ 217 | 218 | def process_outputs(self): 219 | if self.output_state == OutputFSM.BUSY: 220 | self.process_outputs_BUSY() 221 | 222 | def process_outputs_BUSY(self): 223 | if all([o.is_acknowledged() for o in self.outputs]): 224 | Simulation.logger.log_outputFSM_transition(Simulation.cycle, self) 225 | self.output_state = OutputFSM.FREE 226 | 227 | ################ 228 | ## Data FSM ## 229 | ################ 230 | 231 | def is_busy(self): 232 | return self.busy or self.in_computation 233 | 234 | def data_is_ready(self): 235 | return self.data_ready >= 0 and \ 236 | self.data_ready <= Simulation.cycle 237 | 238 | def reset_data_ready(self): 239 | self.data_ready = self.default_data_ready 240 | 241 | def process_data(self): 242 | if self.data_state == DataFSM.NONE: 243 | self.process_data_NONE() 244 | 245 | if self.data_state == DataFSM.INITIATED: 246 | self.process_data_INITIATED() 247 | 248 | if self.data_state == DataFSM.COMPLETED: 249 | self.process_data_COMPLETED() 250 | 251 | if self.data_state == DataFSM.TRANSMITTED: 252 | self.process_data_TRANSMITTED() 253 | 254 | def process_data_NONE(self): 255 | raise NotImplementedError 256 | 257 | def process_data_INITIATED(self): 258 | self.in_computation = True 259 | 260 | if self.data_is_ready(): 261 | self.in_computation = False 262 | self.busy = True 263 | 264 | self.reset_data_ready() 265 | 266 | Simulation.logger.log_dataFSM_transition(Simulation.cycle, self) 267 | self.data_state = DataFSM.COMPLETED 268 | 269 | def process_data_COMPLETED(self): 270 | if self.output_state == OutputFSM.FREE: 271 | self.busy = True 272 | 273 | # Transmit the data on all output wires. 274 | for o in self.outputs: 275 | o.send(self.data) 276 | 277 | Simulation.logger.log_dataFSM_transition(Simulation.cycle, self) 278 | self.data_state = DataFSM.TRANSMITTED 279 | 280 | Simulation.logger.log_outputFSM_transition(Simulation.cycle, self) 281 | self.output_state = OutputFSM.BUSY 282 | 283 | def process_data_TRANSMITTED(self): 284 | self.busy = True 285 | 286 | if self.inputs: 287 | # Send acknowledgements to all inputs. 288 | for i in self.inputs: 289 | i.acknowledge() 290 | 291 | Simulation.logger.log_inputFSM_transition(Simulation.cycle, self) 292 | self.input_state = InputFSM.NONE 293 | 294 | Simulation.logger.log_dataFSM_transition(Simulation.cycle, self) 295 | self.data_state = DataFSM.NONE 296 | 297 | 298 | class Computation(Node): 299 | ctr = 1 300 | 301 | def __init__(self, operator, type_=None, name=None): 302 | super().__init__() 303 | 304 | if name is None: 305 | self.name = 'COMP' + str(Computation.ctr) 306 | Computation.ctr += 1 307 | else: 308 | self.name = name 309 | 310 | self.operator = operator 311 | self.type_ = type_ 312 | 313 | def process_data_NONE(self): 314 | if self.input_state == InputFSM.ALL: 315 | self.busy = True 316 | 317 | pred = self.get_predicate_inputs()[0].read() 318 | data_inputs = {i.name:i.read() for i in self.get_data_inputs()} 319 | 320 | if pred: 321 | self.data = self.operator.compute(data_inputs) 322 | self.data_ready = Simulation.cycle \ 323 | + Config.Latency.computation[self.operator] 324 | 325 | self.energy += Config.Energy.computation[self.operator] 326 | self.utilization += Config.Latency.computation[self.operator] 327 | else: 328 | self.data = self.generate_dummy_data(self.type_) 329 | self.data_ready = Simulation.cycle 330 | 331 | Simulation.logger.log_dataFSM_transition(Simulation.cycle, self) 332 | self.data_state = DataFSM.INITIATED 333 | 334 | 335 | class ContinualConstant(Node): 336 | ctr = 1 337 | 338 | def __init__(self, data, name=None): 339 | super().__init__() 340 | 341 | if name is None: 342 | self.name = 'CC' + str(ContinualConstant.ctr) 343 | ContinualConstant.ctr += 1 344 | else: 345 | self.name = name 346 | 347 | self.data = data 348 | 349 | def process_data_NONE(self): 350 | self.busy = True 351 | 352 | # Constants always have zero latency. 353 | self.data_ready = Simulation.cycle 354 | 355 | Simulation.logger.log_dataFSM_transition(Simulation.cycle, self) 356 | self.data_state = DataFSM.INITIATED 357 | 358 | 359 | class OnetimeConstant(Node): 360 | ctr = 1 361 | 362 | def __init__(self, data, name=None): 363 | super().__init__() 364 | 365 | if name is None: 366 | self.name = 'OTC' + str(OnetimeConstant.ctr) 367 | OnetimeConstant.ctr += 1 368 | else: 369 | self.name = name 370 | 371 | self.data = data 372 | self.has_fired = False 373 | 374 | def reset(self): 375 | super().reset() 376 | self.has_fired = False 377 | 378 | def process_data_NONE(self): 379 | if not self.has_fired: 380 | self.has_fired = True 381 | self.busy = True 382 | 383 | # Constants always have zero latency. 384 | self.data_ready = Simulation.cycle 385 | 386 | Simulation.logger.log_dataFSM_transition(Simulation.cycle, self) 387 | self.data_state = DataFSM.INITIATED 388 | 389 | 390 | class Mu(Node): 391 | ctr = 1 392 | 393 | def __init__(self, name=None): 394 | super().__init__() 395 | 396 | if name is None: 397 | self.name = 'MU' + str(Mu.ctr) 398 | Mu.ctr += 1 399 | else: 400 | self.name = name 401 | 402 | self.data = None 403 | self.data_carrying_input = None 404 | 405 | def reset(self): 406 | super().reset() 407 | self.data_carrying_input = None 408 | 409 | def check(self): 410 | inputs_ready = [i.is_ready() for i in self.inputs] 411 | assert sum(inputs_ready) <= 1, 'Mu node "{}" has multiple inputs to choose from'.format(self.name) 412 | 413 | def process_data_NONE(self): 414 | if self.input_state == InputFSM.SOME or \ 415 | (self.input_state == InputFSM.ALL and len(self.inputs) == 1): 416 | self.busy = True 417 | 418 | # Determine which input has sent something and read the data. 419 | self.data_carrying_input = None 420 | self.data = None 421 | 422 | for i in self.inputs: 423 | if i.is_ready(): 424 | self.data_carrying_input = i 425 | self.data = i.read() 426 | 427 | self.data_ready = Simulation.cycle \ 428 | + math.ceil(Config.Latency.mu(len(self.inputs))) 429 | 430 | self.energy += Config.Energy.mu(len(self.inputs)) 431 | self.utilization += math.ceil(Config.Latency.mu(len(self.inputs))) 432 | 433 | Simulation.logger.log_dataFSM_transition(Simulation.cycle, self) 434 | self.data_state = DataFSM.INITIATED 435 | 436 | elif self.input_state == InputFSM.ALL and len(self.inputs) > 1: 437 | Simulation.logger.log_error(Simulation.cycle, self, 438 | f'mu [{self.name}] has multiple input values to choose from') 439 | 440 | def process_data_TRANSMITTED(self): 441 | self.busy = True 442 | 443 | # Send acknowledgements to the input which has sent something. 444 | self.data_carrying_input.acknowledge() 445 | 446 | # Note that the input FSM advances to NONE from SOME, 447 | # skipping ALL because if more than one input is ready, 448 | # the graph is incorrect. 449 | Simulation.logger.log_inputFSM_transition(Simulation.cycle, self, specific=InputFSM.NONE) 450 | self.input_state = InputFSM.NONE 451 | 452 | Simulation.logger.log_dataFSM_transition(Simulation.cycle, self) 453 | self.data_state = DataFSM.NONE 454 | 455 | 456 | class ETA(Node): 457 | ctr = 1 458 | 459 | def __init__(self, name=None): 460 | super().__init__() 461 | 462 | if name is None: 463 | self.name = 'ETA' + str(ETA.ctr) 464 | ETA.ctr += 1 465 | else: 466 | self.name = name 467 | 468 | self.data = None 469 | 470 | def check(self): 471 | assert len(self.inputs) == 2 472 | 473 | def data_is_ready(self): 474 | return self.data_ready >= 0 and \ 475 | self.data_ready <= Simulation.cycle 476 | 477 | def process_data_NONE(self): 478 | if self.input_state == InputFSM.ALL: 479 | self.busy = True 480 | 481 | data = self.get_data_inputs()[0].read() 482 | pred = self.get_predicate_inputs()[0].read() 483 | 484 | if pred: 485 | self.data = data 486 | self.data_ready = Simulation.cycle \ 487 | + Config.Latency.eta 488 | 489 | self.energy += Config.Energy.eta 490 | self.utilization += Config.Latency.eta 491 | 492 | Simulation.logger.log_dataFSM_transition(Simulation.cycle, self) 493 | self.data_state = DataFSM.INITIATED 494 | else: 495 | # The predicate is false, so the data must be discarded 496 | # and the inputs acknowledged. 497 | for i in self.inputs: 498 | i.acknowledge() 499 | 500 | Simulation.logger.log_inputFSM_transition(Simulation.cycle, self) 501 | self.input_state = InputFSM.NONE 502 | 503 | Simulation.logger.log_dataFSM_transition(Simulation.cycle, self, specific=DataFSM.NONE) 504 | self.data_state = DataFSM.NONE 505 | 506 | 507 | class Mux(Node): 508 | ctr = 1 509 | 510 | def __init__(self, name=None): 511 | super().__init__() 512 | 513 | if name is None: 514 | self.name = 'MUX' + str(Mux.ctr) 515 | Mux.ctr += 1 516 | else: 517 | self.name = name 518 | 519 | self.data = None 520 | 521 | def process_data_NONE(self): 522 | if self.input_state != InputFSM.NONE: 523 | for i_data, i_pred in self.get_matching_inputs(): 524 | if i_data.is_ready() and i_pred.is_ready(): 525 | if i_pred.read(consume=False): 526 | self.busy = True 527 | 528 | self.data = i_data.read(consume=False) 529 | self.data_ready = Simulation.cycle \ 530 | + math.ceil(Config.Latency.mux(len(self.inputs))) 531 | 532 | self.energy += Config.Energy.mux(len(self.inputs)) 533 | self.utilization += math.ceil(Config.Latency.mux(len(self.inputs))) 534 | 535 | Simulation.logger.log_dataFSM_transition(Simulation.cycle, self) 536 | self.data_state = DataFSM.INITIATED 537 | elif self.input_state == InputFSM.ALL: 538 | pass 539 | # TODO: what to do if all predicates are False: send dummy output? send nothing? 540 | 541 | def process_data_TRANSMITTED(self): 542 | if self.input_state == InputFSM.ALL: 543 | self.busy = True 544 | 545 | # Send acknowledgements to all inputs, which is only done after 546 | # inputs are ready (but might be done x cycles after data is sent). 547 | for i in self.inputs: 548 | # Consume unneeded data. 549 | if i.is_ready(): 550 | i.read() 551 | 552 | i.acknowledge() 553 | 554 | Simulation.logger.log_inputFSM_transition(Simulation.cycle, self) 555 | self.input_state = InputFSM.NONE 556 | 557 | Simulation.logger.log_dataFSM_transition(Simulation.cycle, self) 558 | self.data_state = DataFSM.NONE 559 | 560 | 561 | class MemoryLoad(Node): 562 | ctr = 1 563 | 564 | def __init__(self, addr, type_, name=None): 565 | super().__init__() 566 | 567 | if name is None: 568 | self.name = 'MEML' + str(MemoryLoad.ctr) 569 | MemoryLoad.ctr += 1 570 | else: 571 | self.name = name 572 | 573 | self.addr = addr 574 | self.type_ = type_ 575 | self.data = None 576 | 577 | def process_data_NONE(self): 578 | if self.input_state == InputFSM.ALL: 579 | self.busy = True 580 | indices = [] 581 | 582 | if len(self.get_data_inputs()) > 0: 583 | indices_pairs = [(i.name, i.read()) for i in self.get_data_inputs()] 584 | indices = sorted(indices_pairs, key=(lambda a: int(a[0][1:-1:]))) 585 | indices = [value for _,value in indices] 586 | 587 | pred = self.get_predicate_inputs()[0].read() 588 | 589 | if pred: 590 | self.data, load_latency, load_energy, error, error_msg = Simulation.mem.load(self.addr, indices=indices) 591 | 592 | if error: 593 | mem_str = self.addr + '[' + ']['.join(map(str,indices)) + ']' if indices else self.addr 594 | Simulation.logger.log_error(Simulation.cycle, self, f'memory load {mem_str} failed: {error_msg}') 595 | 596 | self.data_ready = Simulation.cycle \ 597 | + load_latency 598 | 599 | self.energy += load_energy 600 | self.utilization += load_latency 601 | else: 602 | # The predicate is false, so no memory value is retrieved 603 | # and dummy data is used. The data is set to be ready 604 | # this cycle (to immediatly be transmitted). 605 | self.data = self.generate_dummy_data(self.type_) 606 | self.data_ready = Simulation.cycle 607 | 608 | Simulation.logger.log_dataFSM_transition(Simulation.cycle, self) 609 | self.data_state = DataFSM.INITIATED 610 | 611 | def process_data_COMPLETED(self): 612 | if self.output_state == OutputFSM.FREE: 613 | self.busy = True 614 | 615 | # Transmit the data on all output wires. 616 | for o in self.outputs: 617 | if o.value_type == Input.value_types.DATA: 618 | o.send(self.data) 619 | elif o.value_type == Input.value_types.PREDICATE: 620 | o.send(True) 621 | 622 | Simulation.logger.log_dataFSM_transition(Simulation.cycle, self) 623 | self.data_state = DataFSM.TRANSMITTED 624 | 625 | Simulation.logger.log_outputFSM_transition(Simulation.cycle, self) 626 | self.output_state = OutputFSM.BUSY 627 | 628 | 629 | class MemoryStore(Node): 630 | ctr = 1 631 | 632 | def __init__(self, addr, type_=None, name=None): 633 | super().__init__() 634 | 635 | if name is None: 636 | self.name = 'MEMS' + str(MemoryStore.ctr) 637 | MemoryStore.ctr += 1 638 | else: 639 | self.name = name 640 | 641 | self.addr = addr 642 | self.data = None 643 | 644 | def process_data_NONE(self): 645 | if self.input_state == InputFSM.ALL: 646 | self.busy = True 647 | indices_pairs = [] 648 | val = None 649 | 650 | for i in self.get_data_inputs(): 651 | indice_re = re.findall('\[.*\]', i.name) 652 | 653 | if indice_re: 654 | indices_pairs.append((indice_re[0], i.read())) 655 | else: 656 | val = i.read() 657 | 658 | indices = sorted(indices_pairs, key=(lambda a: a[0])) 659 | indices = [value for _,value in indices] 660 | 661 | pred = self.get_predicate_inputs()[0].read() 662 | 663 | if pred: 664 | Simulation.logger.log_mem_store(val, self.addr, indices) 665 | store_latency, store_energy, error, error_msg = Simulation.mem.store(val, self.addr, indices=indices) 666 | 667 | if error: 668 | mem_str = self.addr + '[' + ']['.join(map(str,indices)) + ']' if indices else self.addr 669 | Simulation.logger.log_error(Simulation.cycle, self, f'memory store {mem_str} failed: {error_msg}') 670 | 671 | self.data = True 672 | self.data_ready = Simulation.cycle \ 673 | + store_latency 674 | 675 | self.energy += store_energy 676 | self.utilization += store_latency 677 | else: 678 | self.data = False 679 | self.data_ready = Simulation.cycle 680 | 681 | Simulation.logger.log_dataFSM_transition(Simulation.cycle, self) 682 | self.data_state = DataFSM.INITIATED 683 | 684 | 685 | class Combine(Node): 686 | ctr = 1 687 | 688 | def __init__(self, name=None): 689 | super().__init__() 690 | 691 | if name is None: 692 | self.name = 'COMBINE' + str(Combine.ctr) 693 | Combine.ctr += 1 694 | else: 695 | self.name = name 696 | 697 | self.data = None 698 | 699 | def process_data_NONE(self): 700 | if self.input_state != InputFSM.NONE: 701 | self.busy = True 702 | 703 | ready_input_values = [i.read(consume=False) for i in self.inputs if i.is_ready()] 704 | 705 | if False in ready_input_values: 706 | # If some or all inputs are ready and one or more is False, 707 | # the combine will send a False signal. 708 | self.data = False 709 | elif len(ready_input_values) == len(self.inputs): 710 | # No input has sent a False signal and all inputs are ready, 711 | # so the combine will send a True signal. 712 | self.data = True 713 | else: 714 | # If all inputs are True but not all inputs have arrived, a 715 | # False input might still arrive in the future, thus, we do not 716 | # send a value yet. 717 | return 718 | 719 | self.data_ready = Simulation.cycle \ 720 | + math.ceil(Config.Latency.combine(len(self.inputs))) 721 | 722 | self.energy += Config.Energy.combine(len(self.inputs)) 723 | self.utilization += math.ceil(Config.Latency.combine(len(self.inputs))) 724 | 725 | Simulation.logger.log_dataFSM_transition(Simulation.cycle, self) 726 | self.data_state = DataFSM.INITIATED 727 | 728 | def process_data_TRANSMITTED(self): 729 | if self.input_state == InputFSM.ALL: 730 | self.busy = True 731 | 732 | # Send acknowledgements to all inputs, which is only done after 733 | # inputs are ready (but might be done x cycles after data is sent). 734 | for i in self.inputs: 735 | # Consume unneeded data. 736 | if i.is_ready(): 737 | i.read() 738 | 739 | i.acknowledge() 740 | 741 | Simulation.logger.log_inputFSM_transition(Simulation.cycle, self) 742 | self.input_state = InputFSM.NONE 743 | 744 | Simulation.logger.log_dataFSM_transition(Simulation.cycle, self) 745 | self.data_state = DataFSM.NONE 746 | 747 | 748 | class XOR(Node): 749 | ctr = 1 750 | 751 | def __init__(self, name=None): 752 | super().__init__() 753 | 754 | if name is None: 755 | self.name = 'XOR' + str(XOR.ctr) 756 | XOR.ctr += 1 757 | else: 758 | self.name = name 759 | 760 | self.data = None 761 | 762 | def process_data_NONE(self): 763 | if self.input_state != InputFSM.NONE: 764 | self.busy = True 765 | 766 | ready_input_values = [i.read(consume=False) for i in self.inputs if i.is_ready()] 767 | 768 | if True in ready_input_values: 769 | # If some or all inputs are ready and one or more is True, the xor 770 | # will send a True signal. 771 | self.data = True 772 | elif len(ready_input_values) == len(self.inputs): 773 | # No input has sent a True signal and all inputs are ready, 774 | # so the xor will send a False signal. 775 | self.data = False 776 | else: 777 | # If all inputs are False but not all inputs have arrived, a 778 | # False input might still arrive in the future, thus, we do not 779 | # send a value yet. 780 | return 781 | 782 | self.data_ready = Simulation.cycle \ 783 | + math.ceil(Config.Latency.xor(len(self.inputs))) 784 | 785 | self.energy += Config.Energy.xor(len(self.inputs)) 786 | self.utilization += math.ceil(Config.Latency.xor(len(self.inputs))) 787 | 788 | Simulation.logger.log_dataFSM_transition(Simulation.cycle, self) 789 | self.data_state = DataFSM.INITIATED 790 | 791 | def process_data_TRANSMITTED(self): 792 | if self.input_state == InputFSM.ALL: 793 | self.busy = True 794 | 795 | # Send acknowledgements to all inputs, which is only done after 796 | # inputs are ready (but might be done x cycles after data is sent). 797 | for i in self.inputs: 798 | # Consume unneeded data. 799 | if i.is_ready(): 800 | i.read() 801 | 802 | i.acknowledge() 803 | 804 | Simulation.logger.log_inputFSM_transition(Simulation.cycle, self) 805 | self.input_state = InputFSM.NONE 806 | 807 | Simulation.logger.log_dataFSM_transition(Simulation.cycle, self) 808 | self.data_state = DataFSM.NONE 809 | 810 | 811 | class Drain(Node): 812 | def __init__(self, name='DRAIN'): 813 | super().__init__() 814 | 815 | self.name = name 816 | 817 | def process_data(self): 818 | for i in self.inputs: 819 | if i.is_ready(): 820 | 821 | print('{} RESULT: {}'.format(self.name, i.read())) 822 | i.acknowledge() 823 | 824 | 825 | class IR: 826 | node_mapping = { 827 | # DOT shape : IR Node 828 | 'box': Computation, 829 | 'doublecircle': OnetimeConstant, 830 | 'circle': ContinualConstant, 831 | 'diamond': Mu, 832 | 'parallelogram': ETA, 833 | 'invtrapezium': Mux, 834 | 'invtriangle': MemoryLoad, 835 | 'triangle': MemoryStore, 836 | 'house': Combine, 837 | 'hexagon': XOR, 838 | 'star': Drain 839 | } 840 | 841 | sign_mapping = { 842 | # IR operator: DOT label 843 | Operator.ADD: '+', 844 | Operator.SUB: '-', 845 | Operator.MUL: '*', 846 | Operator.DIV: '/', 847 | Operator.MOD: '%', 848 | Operator.LT: '\<', 849 | Operator.LE: '\<=', 850 | Operator.GT: '\>', 851 | Operator.GE: '\>=', 852 | Operator.EQ: '==', 853 | Operator.NE: '!=', 854 | Operator.NEG: '-', 855 | Operator.NOT: '!' 856 | } 857 | 858 | operator_mapping = { 859 | # DOT operator: IR operator 860 | 'ADD': Operator.ADD, 861 | 'SUB': Operator.SUB, 862 | 'MUL': Operator.MUL, 863 | 'DIV': Operator.DIV, 864 | 'MOD': Operator.MOD, 865 | 'LT': Operator.LT, 866 | 'LE': Operator.LE, 867 | 'GT': Operator.GT, 868 | 'GE': Operator.GE, 869 | 'EQ': Operator.EQ, 870 | 'NE': Operator.NE, 871 | 'NEG': Operator.NEG, 872 | 'NOT': Operator.NOT 873 | } 874 | 875 | # Removes the need for a pointless eval(). 876 | type_mapping = { 877 | # DOT type: IR type 878 | 'int': int, 879 | 'float': float, 880 | 'bool': bool 881 | } 882 | 883 | def __init__(self, blocks=None, wires=None): 884 | # The first block inside the blocks list is the global 'block'. 885 | 886 | self.blocks = blocks 887 | self.nodes = [n for b in blocks for n in b] if blocks else None 888 | self.wires = wires 889 | 890 | @classmethod 891 | def from_DOT(cls, filename): 892 | # Notes: 893 | # All edges must be 'global', in-block edges are not registered. 894 | 895 | a = pydot.graph_from_dot_file(filename) 896 | 897 | DOT_g = pydot.graph_from_dot_file(filename)[0] 898 | g = IR() 899 | 900 | all_nodes = dict() 901 | blocks = [] 902 | wires = [] 903 | 904 | def strip_quotation(s): 905 | if s: 906 | return s[1:-1] if (s[0] == '"' and s[-1] == '"') else s 907 | 908 | def create_IR_node(DOT_n): 909 | DOT_n_name = strip_quotation(DOT_n.get_name()) 910 | DOT_n_label = strip_quotation(DOT_n.get('label')) 911 | 912 | if DOT_n_name == 'node' or DOT_n_name == 'edge' or DOT_n_name == 'graph': 913 | return 914 | 915 | node_kwargs = {} 916 | 917 | if DOT_n_label and \ 918 | (cls.node_mapping[DOT_n.get('shape')] is OnetimeConstant or \ 919 | cls.node_mapping[DOT_n.get('shape')] is ContinualConstant or \ 920 | cls.node_mapping[DOT_n.get('shape')] is MemoryLoad or \ 921 | cls.node_mapping[DOT_n.get('shape')] is MemoryStore): 922 | 923 | if DOT_n_label == 'T' or DOT_n_label == 'True' or DOT_n_label == 'true': 924 | # Constant with True value. 925 | node_kwargs['data'] = True 926 | elif DOT_n_label == 'F' or DOT_n_label == 'False' or DOT_n_label == 'false': 927 | # Constant with False value. 928 | node_kwargs['data'] = False 929 | elif DOT_n_label.isidentifier(): 930 | # Memory node with address. 931 | node_kwargs['addr'] = DOT_n_label 932 | else: 933 | # Constant with int or float value. 934 | node_kwargs['data'] = eval(DOT_n_label) 935 | 936 | if DOT_n.get('operator'): 937 | node_kwargs['operator'] = cls.operator_mapping[strip_quotation(DOT_n.get('operator'))] 938 | 939 | if DOT_n.get('type'): 940 | node_kwargs['type_'] = cls.type_mapping[strip_quotation(DOT_n.get('type'))] 941 | 942 | n = cls.node_mapping[DOT_n.get('shape')](name=DOT_n_name, **node_kwargs) 943 | return n 944 | 945 | # Add global nodes. 946 | global_nodelist = [] 947 | 948 | for DOT_n in DOT_g.get_nodes(): 949 | n = create_IR_node(DOT_n) 950 | if n is not None: 951 | all_nodes[n.name] = n 952 | global_nodelist.append(n) 953 | 954 | blocks.append(global_nodelist) 955 | 956 | # Add in-block nodes. 957 | for sg in DOT_g.get_subgraphs(): 958 | sg_nodelist = [] 959 | 960 | for DOT_n in sg.get_nodes(): 961 | n = create_IR_node(DOT_n) 962 | if n is not None: 963 | all_nodes[n.name] = n 964 | sg_nodelist.append(n) 965 | 966 | blocks.append(sg_nodelist) 967 | 968 | # Add wires. 969 | for DOT_w in DOT_g.get_edges(): 970 | wire_kwargs = {} 971 | 972 | if DOT_w.get('style') and strip_quotation(DOT_w.get('style')) == 'dotted': 973 | wire_kwargs['value_type'] = Input.value_types.PREDICATE 974 | else: 975 | wire_kwargs['value_type'] = Input.value_types.DATA 976 | 977 | if DOT_w.get('label'): 978 | wire_kwargs['name'] = strip_quotation(DOT_w.get('label')) 979 | 980 | w = Wire(input_=all_nodes[DOT_w.get_source()], output_=all_nodes[DOT_w.get_destination()], **wire_kwargs) 981 | wires.append(w) 982 | 983 | g.nodes = list(all_nodes.values()) 984 | g.blocks = blocks 985 | g.wires = wires 986 | return g 987 | 988 | def to_DOT(self, theme='Dark 2'): 989 | def add_node_to_DOT(g, n): 990 | node_kwargs = {} 991 | 992 | if n.is_busy(): 993 | if theme == 'Light': 994 | node_kwargs['fillcolor'] = '#aaccf4' 995 | elif theme == 'Dark': 996 | node_kwargs['fillcolor'] = '#009600' 997 | elif theme == 'Dark 2': 998 | node_kwargs['fillcolor'] = '#009600' 999 | 1000 | if n.in_computation: 1001 | # Might override 'busy' color, but is accepted as all 1002 | # 'in computation' nodes are by definition also busy. 1003 | if theme == 'Light': 1004 | node_kwargs['fillcolor'] = '#960000' 1005 | elif theme == 'Dark': 1006 | node_kwargs['fillcolor'] = '#960000' 1007 | elif theme == 'Dark 2': 1008 | node_kwargs['fillcolor'] = '#960000' 1009 | 1010 | if hasattr(n, 'type_') and n.type_ is not None: 1011 | for DOT_type, type_ in self.type_mapping.items(): 1012 | if type_ is n.type_: 1013 | node_kwargs['type'] = DOT_type 1014 | 1015 | if isinstance(n, Computation): 1016 | g.add_node(pydot.Node(n.name, label=f'"{n.operator.sign()}"', shape='box', operator=n.operator.name, **node_kwargs)) 1017 | elif isinstance(n, OnetimeConstant): 1018 | g.add_node(pydot.Node(n.name, label=(('"T"' if n.data else '"F"') if isinstance(n.data, bool) else str(n.data)), shape='doublecircle', **node_kwargs)) 1019 | elif isinstance(n, ContinualConstant): 1020 | g.add_node(pydot.Node(n.name, label=(('"T"' if n.data else '"F"') if isinstance(n.data, bool) else str(n.data)), shape='circle', **node_kwargs)) 1021 | elif isinstance(n, Mu): 1022 | g.add_node(pydot.Node(n.name, label='"MU"', shape='diamond', **node_kwargs)) 1023 | elif isinstance(n, ETA): 1024 | g.add_node(pydot.Node(n.name, label='"ETA"', shape='parallelogram', **node_kwargs)) 1025 | elif isinstance(n, Mux): 1026 | g.add_node(pydot.Node(n.name, label='"MUX"', shape='invtrapezium', **node_kwargs)) 1027 | elif isinstance(n, MemoryLoad): 1028 | g.add_node(pydot.Node(n.name, label=f'"{n.addr}"', shape='invtriangle', **node_kwargs)) 1029 | elif isinstance(n, MemoryStore): 1030 | g.add_node(pydot.Node(n.name, label=f'"{n.addr}"', shape='triangle', **node_kwargs)) 1031 | elif isinstance(n, Combine): 1032 | g.add_node(pydot.Node(n.name, label='"COMBINE"', shape='house', **node_kwargs)) 1033 | elif isinstance(n, XOR): 1034 | g.add_node(pydot.Node(n.name, label='"XOR"', shape='hexagon', **node_kwargs)) 1035 | else: 1036 | g.add_node(pydot.Node(n.name, label=f'"{n.name}"', shape='star', **node_kwargs)) 1037 | 1038 | g = pydot.Dot('IR', graph_type='digraph') 1039 | g.set_graph_defaults(bgcolor='transparent', ratio='0.5545') 1040 | 1041 | if theme == 'Light': 1042 | g.set_node_defaults(fillcolor='#d4f3fd', style='filled', color='#aaccf4') 1043 | if theme == 'Dark': 1044 | g.set_node_defaults(fillcolor='#1d2f49', style='filled', fontcolor='white', color='#aaccf4') 1045 | g.set_edge_defaults(color='white', fontcolor='white') 1046 | if theme == 'Dark 2': 1047 | g.set_node_defaults(fillcolor='#1d2f49', style='filled', fontcolor='white', color='#aaccf4') 1048 | g.set_edge_defaults(color='white', fontcolor='white') 1049 | 1050 | 1051 | # Add global nodes. 1052 | for n in self.blocks[0]: 1053 | add_node_to_DOT(g, n) 1054 | 1055 | # Add in-block nodes. 1056 | cluster_ctr = 1 1057 | 1058 | for b in self.blocks[1:]: 1059 | cluster_ctr += 1 1060 | 1061 | sg = pydot.Subgraph(f'cluster_{str(cluster_ctr)}', color='#aaccf4', penwidth='2') 1062 | g.add_subgraph(sg) 1063 | 1064 | for n in b: 1065 | add_node_to_DOT(sg, n) 1066 | 1067 | # Add wires. 1068 | for w in self.wires: 1069 | wire_kwargs = {} 1070 | 1071 | if w.value_type == Input.value_types.PREDICATE: 1072 | wire_kwargs['style'] = 'dotted' 1073 | 1074 | if w.name != 'WIRE': 1075 | wire_kwargs['label'] = f'"{w.name}"' 1076 | 1077 | g.add_edge(pydot.Edge(w.input_.name, w.output_.name, **wire_kwargs)) 1078 | 1079 | return g 1080 | 1081 | def to_DOTfile(self, filename): 1082 | g = self.to_DOT() 1083 | g.write_raw(filename) 1084 | 1085 | def to_stylizedPNGfile(self, filename): 1086 | g = self.to_DOT() 1087 | g.write_png(filename) 1088 | 1089 | return filename -------------------------------------------------------------------------------- /coolname/operator_.py: -------------------------------------------------------------------------------- 1 | from enum import Enum, IntEnum 2 | import operator 3 | 4 | class Operator(Enum): 5 | # Binary operators: 6 | # Arithmetic operators: 7 | ADD = 1 # + 8 | SUB = 2 # - 9 | MUL = 3 # * 10 | DIV = 4 # / 11 | MOD = 5 # % 12 | 13 | # Relational operators ("and" and "or" ommited): 14 | LT = 6 # < 15 | LE = 7 # <= 16 | GT = 8 # > 17 | GE = 9 # >= 18 | EQ = 10 # == 19 | NE = 11 # != 20 | 21 | # Monary operators: 22 | # Arithmetic operators: 23 | NEG = 12 # - 24 | 25 | # Relational operators: 26 | NOT = 13 # ! 27 | 28 | def is_binop(self): 29 | return self.value >= Operator.ADD.value and \ 30 | self.value <= Operator.NE.value 31 | 32 | def is_monop(self): 33 | return self.value == Operator.NOT.value or \ 34 | self.value == Operator.NEG.value 35 | 36 | def is_arithmetic(self): 37 | return (self.value >= Operator.ADD.value and \ 38 | self.value <= Operator.MOD.value) or \ 39 | (self.value == Operator.NEG.value) 40 | 41 | def is_relational(self): 42 | return (self.value >= Operator.LT.value and \ 43 | self.value <= Operator.NE.value) or \ 44 | (self.value == Operator.NOT.value) 45 | 46 | def sign(self): 47 | if self.value == Operator.ADD.value: return '+' 48 | elif self.value == Operator.SUB.value: return '-' 49 | elif self.value == Operator.MUL.value: return '*' 50 | elif self.value == Operator.DIV.value: return '/' 51 | elif self.value == Operator.MOD.value: return '%' 52 | elif self.value == Operator.LT.value: return '\<' 53 | elif self.value == Operator.LE.value: return '\<=' 54 | elif self.value == Operator.GT.value: return '\>' 55 | elif self.value == Operator.GE.value: return '\>=' 56 | elif self.value == Operator.EQ.value: return '==' 57 | elif self.value == Operator.NE.value: return '!=' 58 | elif self.value == Operator.NEG.value: return '-' 59 | elif self.value == Operator.NOT.value: return '!' 60 | 61 | def fun(self): 62 | # TODO: differentiate between / and // 63 | if self.value == Operator.ADD.value: return operator.add 64 | elif self.value == Operator.SUB.value: return operator.sub 65 | elif self.value == Operator.MUL.value: return operator.mul 66 | elif self.value == Operator.DIV.value: return operator.truediv 67 | elif self.value == Operator.MOD.value: return operator.mod 68 | elif self.value == Operator.LT.value: return operator.lt 69 | elif self.value == Operator.LE.value: return operator.le 70 | elif self.value == Operator.GT.value: return operator.gt 71 | elif self.value == Operator.GE.value: return operator.ge 72 | elif self.value == Operator.EQ.value: return operator.eq 73 | elif self.value == Operator.NE.value: return operator.ne 74 | elif self.value == Operator.NEG.value: return operator.neg 75 | elif self.value == Operator.NOT.value: return operator.not_ 76 | 77 | def compute(self, inputs): 78 | """ 79 | Expects inputs in the form: 80 | {'LHS': 0, 'RHS':1} 81 | {''} 82 | """ 83 | 84 | if self.is_monop(): 85 | if len(inputs) == 1: 86 | return self.fun()(list(inputs.values())[0]) 87 | else: 88 | pass 89 | # TODO: log error 90 | 91 | elif self.is_binop(): 92 | if len(inputs) == 2 and 'LHS' in inputs and 'RHS' in inputs: 93 | LHS = inputs.get('LHS') 94 | RHS = inputs.get('RHS') 95 | 96 | if type(LHS) is not type(RHS): 97 | pass 98 | # TODO: log error 99 | 100 | return self.fun()(LHS, RHS) 101 | else: 102 | pass 103 | # TODO: log error 104 | -------------------------------------------------------------------------------- /coolname/sample_ir.py: -------------------------------------------------------------------------------- 1 | from nodes import * 2 | 3 | # Triangular matrix multiplication IR graphs for atomic and speculative 4 | # mode of execution. Should be similar to the DOT representation in /data. 5 | 6 | def test_trmm_atomic(): 7 | # entry 8 | e_oc1 = OnetimeConstant(True, name='E_OC1') 9 | 10 | e_oc2 = OnetimeConstant(1, name='E_OC2') 11 | e_oc3 = OnetimeConstant(0, name='E_OC3') # i 12 | e_oc4 = OnetimeConstant(0, name='E_OC4') # j 13 | 14 | e_comp1 = Computation(Operator.ADD, name='E_COMP1') # k 15 | 16 | e_w1 = Wire(e_oc2, e_comp1, Input.value_types.DATA, name='RHS') 17 | e_w2 = Wire(e_oc3, e_comp1, Input.value_types.DATA, name='LHS') 18 | 19 | # for_body 20 | fb_ml1 = MemoryLoad('n', int, name='FB_ML1') 21 | fb_comb1 = Combine(name='FB_COMB1') 22 | fb_comp1 = Computation(Operator.LT, type_=int, name='FB_COMP1') 23 | fb_comp2 = Computation(Operator.NOT, type_=bool, name='FB_COMP2') 24 | fb_eta1 = ETA(name='FB_ETA1') 25 | fb_eta2 = ETA(name='FB_ETA2') 26 | 27 | fb_w1 = Wire(fb_ml1, fb_comb1, Input.value_types.PREDICATE) 28 | fb_w2 = Wire(fb_ml1, fb_comp1, Input.value_types.DATA, name='RHS') 29 | 30 | fb_w3 = Wire(fb_comb1, fb_eta2, Input.value_types.DATA) 31 | fb_w4 = Wire(fb_comb1, fb_eta1, Input.value_types.DATA) 32 | fb_w5 = Wire(fb_comp1, fb_comp2, Input.value_types.DATA) 33 | fb_w6 = Wire(fb_comp1, fb_eta1, Input.value_types.PREDICATE) 34 | fb_w7 = Wire(fb_comp2, fb_eta2, Input.value_types.PREDICATE) 35 | 36 | # if_else_36 37 | ie36_cc1 = ContinualConstant(1, name='IE36_CC1') 38 | ie36_cc2 = ContinualConstant(1, name='IE36_CC2') 39 | ie36_cc3 = ContinualConstant(0, name='IE36_CC3') 40 | ie36_comp1 = Computation(Operator.ADD, type_=int, name='IE36_COMP1') 41 | ie36_comp2 = Computation(Operator.ADD, type_=int, name='IE36_COMP2') 42 | ie36_eta1 = ETA(name='IE36_ETA1') 43 | 44 | ie36_w1 = Wire(ie36_cc1, ie36_comp1, Input.value_types.DATA, name='RHS') 45 | ie36_w2 = Wire(ie36_comp2, ie36_comp1, Input.value_types.DATA, name='LHS') 46 | 47 | ie36_w3 = Wire(ie36_cc2, ie36_comp2, Input.value_types.DATA, name='RHS') 48 | ie36_w4 = Wire(ie36_cc3, ie36_eta1, Input.value_types.DATA) 49 | 50 | # if_then 51 | it_ml1 = MemoryLoad('m', int, name='IT_ML1') 52 | it_comb1 = Combine(name='IT_COMB1') 53 | it_comp1 = Computation(Operator.LT, type_=int, name='IT_COMP1') 54 | it_comp2 = Computation(Operator.NOT, type_=int, name='IT_COMP2') 55 | it_eta1 = ETA(name='IT_ETA1') 56 | it_eta2 = ETA(name='IT_ETA2') 57 | 58 | it_w1 = Wire(it_ml1, it_comb1, Input.value_types.PREDICATE) 59 | it_w2 = Wire(it_ml1, it_comp1, Input.value_types.DATA, name='RHS') 60 | 61 | it_w3 = Wire(it_comb1, it_eta1, Input.value_types.DATA) 62 | it_w4 = Wire(it_comb1, it_eta2, Input.value_types.DATA) 63 | 64 | it_w5 = Wire(it_comp1, it_eta1, Input.value_types.PREDICATE) 65 | it_w6 = Wire(it_comp1, it_comp2, Input.value_types.DATA) 66 | 67 | it_w7 = Wire(it_comp2, it_eta2, Input.value_types.PREDICATE) 68 | 69 | # if_then12 70 | it12_cc1 = ContinualConstant(1, name='IT12_CC1') 71 | it12_comp1 = Computation(Operator.ADD, type_=int, name='IT12_COMP1') 72 | it12_comp2 = Computation(Operator.MUL, type_=int, name='IT12_COMP2') 73 | it12_comp3 = Computation(Operator.ADD, type_=int, name='IT12_COMP3') 74 | it12_eta1 = ETA(name='IT12_ETA1') 75 | it12_eta2 = ETA(name='IT12_ETA2') 76 | it12_ml1 = MemoryLoad('A', type_=int, name='IT12_ML1') 77 | it12_ml2 = MemoryLoad('B', type_=int, name='IT12_ML2') 78 | it12_ml3 = MemoryLoad('B', type_=int, name='IT12_ML3') 79 | it12_ms1 = MemoryStore('B', type_=int, name='IT12_MS1') 80 | it12_comb1 = Combine(name='IT12_COMB1') 81 | 82 | it12_w1 = Wire(it12_cc1, it12_comp1, Input.value_types.DATA, name='RHS') 83 | 84 | it12_w2 = Wire(it12_ml1, it12_comp2, Input.value_types.DATA, name='LHS') 85 | it12_w3 = Wire(it12_ml1, it12_comb1, Input.value_types.PREDICATE) 86 | 87 | it12_w4 = Wire(it12_ml2, it12_comb1, Input.value_types.PREDICATE) 88 | it12_w5 = Wire(it12_ml2, it12_comp2, Input.value_types.DATA, name='RHS') 89 | 90 | it12_w6 = Wire(it12_comp2, it12_comp3, Input.value_types.DATA, name='RHS') 91 | 92 | it12_w7 = Wire(it12_ml3, it12_comp3, Input.value_types.DATA, name='LHS') 93 | it12_w8 = Wire(it12_ml3, it12_comb1, Input.value_types.PREDICATE) 94 | 95 | it12_w9 = Wire(it12_comp3, it12_ms1, Input.value_types.DATA) 96 | 97 | it12_w10 = Wire(it12_ms1, it12_comb1, Input.value_types.PREDICATE) 98 | 99 | # if_else 100 | ie_cc1 = ContinualConstant(1, name='IE_CC1') 101 | ie_cc2 = ContinualConstant(1, name='IE_CC2') 102 | ie_ml1 = MemoryLoad('alpha', type_=int, name='IE_ML1') 103 | ie_ml2 = MemoryLoad('B', type_=int, name='IE_ML2') 104 | ie_eta1 = ETA(name='IE_ETA1') 105 | ie_comp1 = Computation(Operator.ADD, type_=int, name='IE_COMP1') 106 | ie_comp2 = Computation(Operator.ADD, type_=int, name='IE_COMP2') 107 | ie_comp3 = Computation(Operator.MUL, type_=int, name='IE_COMP3') 108 | ie_ms1 = MemoryStore('B', type_=int, name='IE_MS1') 109 | ie_comb1 = Combine(name='IE_COMB1') 110 | 111 | ie_w1 = Wire(ie_cc1, ie_comp1, Input.value_types.DATA, name='RHS') 112 | ie_w2 = Wire(ie_cc2, ie_comp2, Input.value_types.DATA, name='RHS') 113 | 114 | ie_w3 = Wire(ie_ml1, ie_comp3, Input.value_types.DATA, name='LHS') 115 | ie_w4 = Wire(ie_ml1, ie_comb1, Input.value_types.PREDICATE) 116 | 117 | ie_w5 = Wire(ie_ml2, ie_comp3, Input.value_types.DATA, name='RHS') 118 | ie_w6 = Wire(ie_ml2, ie_comb1, Input.value_types.PREDICATE) 119 | 120 | ie_w7 = Wire(ie_comp3, ie_ms1, Input.value_types.DATA) 121 | 122 | ie_w8 = Wire(ie_ms1, ie_comb1, Input.value_types.PREDICATE) 123 | 124 | # final 125 | f_mu1 = Mu(name='F_MU1') 126 | f_mu2 = Mu(name='F_MU2') 127 | f_mu3 = Mu(name='F_MU3') 128 | f_mu4 = Mu(name='F_MU4') 129 | f_ms1 = MemoryStore('k', type_=int, name='F_MS1') 130 | f_ms2 = MemoryStore('i', type_=int, name='F_MS2') 131 | f_ms3 = MemoryStore('j', type_=int, name='F_MS3') 132 | 133 | f_w1 = Wire(f_mu1, f_ms1, Input.value_types.DATA) # k 134 | f_w2 = Wire(f_mu2, f_ms2, Input.value_types.DATA) # i 135 | f_w3 = Wire(f_mu4, f_ms3, Input.value_types.DATA) # j 136 | 137 | f_w4 = Wire(f_mu3, f_ms1, Input.value_types.PREDICATE) 138 | f_w5 = Wire(f_mu3, f_ms2, Input.value_types.PREDICATE) 139 | f_w6 = Wire(f_mu3, f_ms3, Input.value_types.PREDICATE) 140 | 141 | ################ 142 | # Global wires # 143 | ################ 144 | 145 | # g -> entry 146 | g_w1 = Wire(e_oc1, e_comp1, Input.value_types.PREDICATE) 147 | 148 | # g -> for_body 149 | g_w2 = Wire(e_oc1, fb_ml1, Input.value_types.PREDICATE) 150 | g_w3 = Wire(e_oc1, fb_comp1, Input.value_types.PREDICATE) 151 | g_w4 = Wire(e_oc1, fb_comp2, Input.value_types.PREDICATE) 152 | 153 | # entry -> for_body 154 | g_w5 = Wire(e_oc4, fb_comp1, Input.value_types.DATA, name='LHS') 155 | 156 | # entry -> if_else36 157 | g_w6 = Wire(e_oc3, ie36_comp2, Input.value_types.DATA, name='LHS') 158 | 159 | # for_body -> if_else36 160 | g_w7 = Wire(fb_eta2, ie36_comp1, Input.value_types.PREDICATE) 161 | g_w8 = Wire(fb_eta2, ie36_comp2, Input.value_types.PREDICATE) 162 | g_w9 = Wire(fb_eta2, ie36_eta1, Input.value_types.PREDICATE) 163 | 164 | # entry -> if_then 165 | g_w10 = Wire(e_comp1, it_comp1, Input.value_types.DATA, name='LHS') 166 | 167 | # for_body -> if_then 168 | g_w11 = Wire(fb_eta1, it_ml1, Input.value_types.PREDICATE) 169 | g_w12 = Wire(fb_eta1, it_comp1, Input.value_types.PREDICATE) 170 | g_w13 = Wire(fb_eta1, it_comp2, Input.value_types.PREDICATE) 171 | 172 | # entry -> if_then12 173 | g_w14 = Wire(e_oc3, it12_eta1, Input.value_types.DATA) 174 | g_w15 = Wire(e_oc3, it12_ml1, Input.value_types.DATA, name='[1]') 175 | g_w16 = Wire(e_oc3, it12_ml3, Input.value_types.DATA, name='[0]') 176 | g_w17 = Wire(e_oc3, it12_ms1, Input.value_types.DATA, name='[0]') 177 | 178 | g_w18 = Wire(e_oc4, it12_eta2, Input.value_types.DATA) 179 | g_w19 = Wire(e_oc4, it12_ml2, Input.value_types.DATA, name='[1]') 180 | g_w20 = Wire(e_oc4, it12_ml3, Input.value_types.DATA, name='[1]') 181 | g_w21 = Wire(e_oc4, it12_ms1, Input.value_types.DATA, name='[1]') 182 | 183 | g_w22 = Wire(e_comp1, it12_comp1, Input.value_types.DATA, name='LHS') 184 | g_w23 = Wire(e_comp1, it12_ml1, Input.value_types.DATA, name='[0]') 185 | g_w24 = Wire(e_comp1, it12_ml2, Input.value_types.DATA, name='[0]') 186 | 187 | # if_then -> if_then12 188 | g_w25 = Wire(it_eta1, it12_comp1, Input.value_types.PREDICATE) 189 | g_w26 = Wire(it_eta1, it12_eta1, Input.value_types.PREDICATE) 190 | g_w27 = Wire(it_eta1, it12_ml1, Input.value_types.PREDICATE) 191 | g_w28 = Wire(it_eta1, it12_eta2, Input.value_types.PREDICATE) 192 | g_w29 = Wire(it_eta1, it12_ml2, Input.value_types.PREDICATE) 193 | g_w30 = Wire(it_eta1, it12_comp2, Input.value_types.PREDICATE) 194 | g_w31 = Wire(it_eta1, it12_ml3, Input.value_types.PREDICATE) 195 | g_w32 = Wire(it_eta1, it12_comp3, Input.value_types.PREDICATE) 196 | g_w33 = Wire(it_eta1, it12_ms1, Input.value_types.PREDICATE) 197 | 198 | # entry -> if_else 199 | g_w34 = Wire(e_oc3, ie_ml2, Input.value_types.DATA, name='[0]') 200 | g_w35 = Wire(e_oc3, ie_eta1, Input.value_types.DATA) 201 | g_w36 = Wire(e_oc3, ie_comp1, Input.value_types.DATA, name='LHS') 202 | g_w37 = Wire(e_oc3, ie_ms1, Input.value_types.DATA, name='[0]') 203 | 204 | g_w38 = Wire(e_oc4, ie_ml2, Input.value_types.DATA, name='[1]') 205 | g_w39 = Wire(e_oc4, ie_comp2, Input.value_types.DATA, name='LHS') 206 | g_w40 = Wire(e_oc4, ie_ms1, Input.value_types.DATA, name='[1]') 207 | 208 | # if_then -> if_else 209 | g_w41 = Wire(it_eta2, ie_ml1, Input.value_types.PREDICATE) 210 | g_w42 = Wire(it_eta2, ie_ml2, Input.value_types.PREDICATE) 211 | g_w43 = Wire(it_eta2, ie_eta1, Input.value_types.PREDICATE) 212 | g_w44 = Wire(it_eta2, ie_comp1, Input.value_types.PREDICATE) 213 | g_w45 = Wire(it_eta2, ie_comp2, Input.value_types.PREDICATE) 214 | g_w46 = Wire(it_eta2, ie_comp3, Input.value_types.PREDICATE) 215 | g_w47 = Wire(it_eta2, ie_ms1, Input.value_types.PREDICATE) 216 | 217 | # for_body -> final 218 | g_w48 = Wire(fb_eta2, f_mu3, Input.value_types.PREDICATE) 219 | 220 | # if_else_36 -> final 221 | g_w49 = Wire(ie36_comp1, f_mu1, Input.value_types.DATA) 222 | g_w50 = Wire(ie36_comp2, f_mu2, Input.value_types.DATA) 223 | g_w51 = Wire(ie36_eta1, f_mu4, Input.value_types.DATA) 224 | 225 | # if_then12 -> final 226 | g_w52 = Wire(it12_comp1, f_mu1, Input.value_types.DATA) 227 | g_w53 = Wire(it12_eta1, f_mu2, Input.value_types.DATA) 228 | g_w54 = Wire(it12_comb1, f_mu3, Input.value_types.PREDICATE) 229 | g_w55 = Wire(it12_eta2, f_mu4, Input.value_types.DATA) 230 | 231 | # if_else -> final 232 | g_w56 = Wire(ie_comp1, f_mu1, Input.value_types.DATA) 233 | g_w57 = Wire(ie_eta1, f_mu2, Input.value_types.DATA) 234 | g_w58 = Wire(ie_comb1, f_mu3, Input.value_types.PREDICATE) 235 | g_w59 = Wire(ie_comp2, f_mu4, Input.value_types.DATA) 236 | 237 | return IR([[e_oc1], 238 | [e_oc2, e_oc3, e_oc4, e_comp1], 239 | [fb_ml1, fb_comb1, fb_comp1, fb_comp2, fb_eta1, fb_eta2], 240 | [ie36_cc1, ie36_cc2, ie36_cc3, ie36_comp1, ie36_comp2, ie36_eta1], 241 | [it_ml1, it_comb1, it_comp1, it_comp2, it_eta1, it_eta2], 242 | [it12_cc1, it12_comp1, it12_comp2, it12_comp3, it12_eta1, it12_eta2, it12_ml1, it12_ml2, it12_ml3, it12_ms1, it12_comb1], 243 | [ie_cc1, ie_cc2, ie_ml1, ie_ml2, ie_eta1, ie_comp1, ie_comp2, ie_comp3, ie_ms1, ie_comb1], 244 | [f_mu1, f_mu2, f_mu3, f_mu4, f_ms1, f_ms2, f_ms3]], 245 | [e_w1, e_w2, 246 | fb_w1, fb_w2, fb_w3, fb_w4, fb_w5, fb_w6, fb_w7, 247 | ie36_w1, ie36_w2, ie36_w3, ie36_w4, 248 | it_w1, it_w2, it_w3, it_w4, it_w5, it_w6, it_w7, 249 | it12_w1, it12_w2, it12_w3, it12_w4, it12_w5, it12_w6, it12_w7, it12_w8, it12_w9, it12_w10, 250 | ie_w1, ie_w2, ie_w3, ie_w4, ie_w5, ie_w6, ie_w7, ie_w8, 251 | f_w1, f_w2, f_w3, f_w4, f_w5, f_w6, 252 | g_w1, g_w2, g_w3, g_w4, g_w5, g_w6, g_w7, g_w8, g_w9, g_w10, g_w11, g_w12, g_w13, g_w14, g_w15, g_w16, g_w17, g_w18, g_w19, g_w20, g_w21, g_w22, g_w23, g_w24, g_w25, g_w26, g_w27, g_w28, g_w29, g_w30, g_w31, g_w32, g_w33, g_w34, g_w35, g_w36, g_w37, g_w38, g_w39, g_w40, g_w41, g_w42, g_w43, g_w44, g_w45, g_w46, g_w47, g_w48, g_w49, g_w50, g_w51, g_w52, g_w53,g_w54,g_w55,g_w56,g_w57,g_w58,g_w59]) 253 | 254 | def test_trmm_speculated(): 255 | # entry 256 | e_oc1 = OnetimeConstant(True, name='E_OC1') 257 | e_oc2 = OnetimeConstant(1, name='E_OC2') 258 | e_oc3 = OnetimeConstant(0, name='E_OC3') # i 259 | e_oc4 = OnetimeConstant(0, name='E_OC4') # j 260 | e_comp1 = Computation(Operator.ADD, name='E_COMP1') # k 261 | 262 | e_w1 = Wire(e_oc2, e_comp1, Input.value_types.DATA, name='RHS') 263 | e_w2 = Wire(e_oc3, e_comp1, Input.value_types.DATA, name='LHS') 264 | 265 | # for_body 266 | fb_cc1 = ContinualConstant(True, name='FB_CC1') 267 | fb_ml1 = MemoryLoad('n', int, name='FB_ML1') 268 | fb_comb1 = Combine(name='FB_COMB1') 269 | fb_comb2 = Combine(name='FB_COMB2') 270 | fb_comb3 = Combine(name='FB_COMB3') 271 | fb_comp1 = Computation(Operator.LT, type_=int, name='FB_COMP1') 272 | fb_comp2 = Computation(Operator.NOT, type_=bool, name='FB_COMP2') 273 | 274 | fb_w1 = Wire(fb_ml1, fb_comb1, Input.value_types.PREDICATE) 275 | fb_w2 = Wire(fb_ml1, fb_comp1, Input.value_types.DATA, name='RHS') 276 | 277 | fb_w3 = Wire(fb_comb1, fb_comb3, Input.value_types.DATA) 278 | fb_w4 = Wire(fb_comb1, fb_comb2, Input.value_types.DATA) 279 | fb_w5 = Wire(fb_comp1, fb_comp2, Input.value_types.DATA) 280 | fb_w6 = Wire(fb_comp1, fb_comb2, Input.value_types.DATA) 281 | fb_w7 = Wire(fb_comp2, fb_comb3, Input.value_types.DATA) 282 | 283 | fb_w8 = Wire(fb_cc1, fb_comp1, Input.value_types.PREDICATE) 284 | fb_w9 = Wire(fb_cc1, fb_comp2, Input.value_types.PREDICATE) 285 | 286 | # if_else_36 287 | ie36_cc1 = ContinualConstant(1, name='IE36_CC1') 288 | ie36_cc2 = ContinualConstant(1, name='IE36_CC2') 289 | ie36_cc3 = ContinualConstant(0, name='IE36_CC3') 290 | ie36_cc4 = ContinualConstant(True, name='IE36_CC4') 291 | ie36_comp1 = Computation(Operator.ADD, type_=int, name='IE36_COMP1') 292 | ie36_comp2 = Computation(Operator.ADD, type_=int, name='IE36_COMP2') 293 | 294 | ie36_w1 = Wire(ie36_cc1, ie36_comp1, Input.value_types.DATA, name='RHS') 295 | ie36_w2 = Wire(ie36_comp1, ie36_comp2, Input.value_types.DATA, name='LHS') 296 | ie36_w3 = Wire(ie36_cc2, ie36_comp2, Input.value_types.DATA, name='RHS') 297 | 298 | ie36_w4 = Wire(ie36_cc4, ie36_comp1, Input.value_types.PREDICATE) 299 | ie36_w5 = Wire(ie36_cc4, ie36_comp2, Input.value_types.PREDICATE) 300 | 301 | # if_then 302 | it_cc1 = ContinualConstant(True, name='IT_CC1') 303 | it_ml1 = MemoryLoad('m', int, name='IT_ML1') 304 | it_comb1 = Combine(name='IT_COMB1') 305 | it_comb2 = Combine(name='IT_COMB2') 306 | it_comb3 = Combine(name='IT_COMB3') 307 | it_comp1 = Computation(Operator.LT, type_=int, name='IT_COMP1') 308 | it_comp2 = Computation(Operator.NOT, type_=int, name='IT_COMP2') 309 | 310 | it_w1 = Wire(it_ml1, it_comb1, Input.value_types.PREDICATE) 311 | it_w2 = Wire(it_ml1, it_comp1, Input.value_types.DATA, name='RHS') 312 | 313 | it_w3 = Wire(it_comb1, it_comb2, Input.value_types.DATA) 314 | it_w4 = Wire(it_comb1, it_comb3, Input.value_types.DATA) 315 | 316 | it_w5 = Wire(it_comp1, it_comb2, Input.value_types.DATA) 317 | it_w6 = Wire(it_comp1, it_comp2, Input.value_types.DATA) 318 | 319 | it_w7 = Wire(it_comp2, it_comb3, Input.value_types.DATA) 320 | 321 | it_w8 = Wire(it_cc1, it_comp1, Input.value_types.PREDICATE) 322 | it_w9 = Wire(it_cc1, it_comp2, Input.value_types.PREDICATE) 323 | 324 | # if_then12 325 | it12_cc1 = ContinualConstant(1, name='IT12_CC1') 326 | it12_cc2 = ContinualConstant(True, name='IT12_CC2') 327 | it12_comp1 = Computation(Operator.ADD, type_=int, name='IT12_COMP1') 328 | it12_comp2 = Computation(Operator.MUL, type_=int, name='IT12_COMP2') 329 | it12_comp3 = Computation(Operator.ADD, type_=int, name='IT12_COMP3') 330 | it12_ml1 = MemoryLoad('A', type_=int, name='IT12_ML1') 331 | it12_ml2 = MemoryLoad('B', type_=int, name='IT12_ML2') 332 | it12_ml3 = MemoryLoad('B', type_=int, name='IT12_ML3') 333 | it12_ms1 = MemoryStore('B', type_=int, name='IT12_MS1') 334 | it12_comb1 = Combine(name='IT12_COMB1') 335 | 336 | it12_w1 = Wire(it12_cc1, it12_comp1, Input.value_types.DATA, name='RHS') 337 | 338 | it12_w2 = Wire(it12_ml1, it12_comp2, Input.value_types.DATA, name='LHS') 339 | it12_w3 = Wire(it12_ml1, it12_comb1, Input.value_types.PREDICATE) 340 | 341 | it12_w4 = Wire(it12_ml2, it12_comb1, Input.value_types.PREDICATE) 342 | it12_w5 = Wire(it12_ml2, it12_comp2, Input.value_types.DATA, name='RHS') 343 | 344 | it12_w6 = Wire(it12_comp2, it12_comp3, Input.value_types.DATA, name='RHS') 345 | 346 | it12_w7 = Wire(it12_ml3, it12_comp3, Input.value_types.DATA, name='LHS') 347 | it12_w8 = Wire(it12_ml3, it12_comb1, Input.value_types.PREDICATE) 348 | 349 | it12_w9 = Wire(it12_comp3, it12_ms1, Input.value_types.DATA) 350 | 351 | it12_w10 = Wire(it12_ms1, it12_comb1, Input.value_types.PREDICATE) 352 | 353 | it12_w11 = Wire(it12_cc2, it12_comp1, Input.value_types.PREDICATE) 354 | it12_w12 = Wire(it12_cc2, it12_comp2, Input.value_types.PREDICATE) 355 | it12_w13 = Wire(it12_cc2, it12_comp3, Input.value_types.PREDICATE) 356 | 357 | # if_else 358 | ie_cc1 = ContinualConstant(1, name='IE_CC1') 359 | ie_cc2 = ContinualConstant(1, name='IE_CC2') 360 | ie_cc3 = ContinualConstant(True, name='IE_CC3') 361 | ie_ml1 = MemoryLoad('alpha', type_=int, name='IE_ML1') 362 | ie_ml2 = MemoryLoad('B', type_=int, name='IE_ML2') 363 | ie_comp1 = Computation(Operator.ADD, type_=int, name='IE_COMP1') 364 | ie_comp2 = Computation(Operator.ADD, type_=int, name='IE_COMP2') 365 | ie_comp3 = Computation(Operator.MUL, type_=int, name='IE_COMP3') 366 | ie_ms1 = MemoryStore('B', type_=int, name='IE_MS1') 367 | ie_comb1 = Combine(name='IE_COMB1') 368 | 369 | ie_w1 = Wire(ie_cc1, ie_comp1, Input.value_types.DATA, name='RHS') 370 | ie_w2 = Wire(ie_cc2, ie_comp2, Input.value_types.DATA, name='RHS') 371 | 372 | ie_w3 = Wire(ie_ml1, ie_comp3, Input.value_types.DATA, name='LHS') 373 | ie_w4 = Wire(ie_ml1, ie_comb1, Input.value_types.PREDICATE) 374 | 375 | ie_w5 = Wire(ie_ml2, ie_comp3, Input.value_types.DATA, name='RHS') 376 | ie_w6 = Wire(ie_ml2, ie_comb1, Input.value_types.PREDICATE) 377 | 378 | ie_w7 = Wire(ie_comp3, ie_ms1, Input.value_types.DATA) 379 | 380 | ie_w8 = Wire(ie_ms1, ie_comb1, Input.value_types.PREDICATE) 381 | 382 | ie_w9 = Wire(ie_cc3, ie_comp1, Input.value_types.PREDICATE) 383 | ie_w10 = Wire(ie_cc3, ie_comp2, Input.value_types.PREDICATE) 384 | ie_w11 = Wire(ie_cc3, ie_comp3, Input.value_types.PREDICATE) 385 | 386 | # final 387 | f_mux1 = Mux(name='F_MUX1') 388 | f_mux2 = Mux(name='F_MUX2') 389 | f_mux3 = Mux(name='F_MUX3') 390 | f_xor1 = XOR(name='F_XOR1') 391 | f_ms1 = MemoryStore('k', type_=int, name='F_MS1') 392 | f_ms2 = MemoryStore('i', type_=int, name='F_MS2') 393 | f_ms3 = MemoryStore('j', type_=int, name='F_MS3') 394 | 395 | f_w1 = Wire(f_mux1, f_ms3, Input.value_types.DATA) # j 396 | f_w2 = Wire(f_mux2, f_ms2, Input.value_types.DATA) # i 397 | f_w3 = Wire(f_mux3, f_ms1, Input.value_types.DATA) # k 398 | 399 | f_w4 = Wire(f_xor1, f_ms1, Input.value_types.PREDICATE) 400 | f_w5 = Wire(f_xor1, f_ms2, Input.value_types.PREDICATE) 401 | f_w6 = Wire(f_xor1, f_ms3, Input.value_types.PREDICATE) 402 | 403 | ################ 404 | # Global wires # 405 | ################ 406 | 407 | # e_oc3 i 408 | # e_oc4 j 409 | # e_comp1 k 410 | 411 | # f_mux2 i 412 | # f_mux1 j 413 | # f_mux3 k 414 | 415 | # g -> entry 416 | g_w1 = Wire(e_oc1, e_comp1, Input.value_types.PREDICATE) 417 | 418 | # g -> for_body 419 | g_w2 = Wire(e_oc1, fb_ml1, Input.value_types.PREDICATE) 420 | g_w3 = Wire(e_oc1, fb_comb1, Input.value_types.PREDICATE) 421 | 422 | # entry -> for_body 423 | g_w4 = Wire(e_oc4, fb_comp1, Input.value_types.DATA, name='LHS') 424 | 425 | # entry -> if_else36 426 | g_w5 = Wire(e_oc3, ie36_comp1, Input.value_types.DATA, name='LHS') 427 | 428 | # entry -> if_then 429 | g_w6 = Wire(e_comp1, it_comp1, Input.value_types.DATA, name='LHS') 430 | 431 | # for_body -> if_then 432 | g_w7 = Wire(fb_comb2, it_ml1, Input.value_types.PREDICATE) 433 | g_w8 = Wire(fb_comb2, it_comb1, Input.value_types.PREDICATE) 434 | 435 | # entry -> if_then12 436 | g_w9 = Wire(e_oc3, it12_ml1, Input.value_types.DATA, name='[1]') 437 | g_w10 = Wire(e_oc3, it12_ml3, Input.value_types.DATA, name='[0]') 438 | g_w11 = Wire(e_oc3, it12_ms1, Input.value_types.DATA, name='[0]') 439 | 440 | g_w12 = Wire(e_oc4, it12_ml2, Input.value_types.DATA, name='[1]') 441 | g_w13 = Wire(e_oc4, it12_ml3, Input.value_types.DATA, name='[1]') 442 | g_w14 = Wire(e_oc4, it12_ms1, Input.value_types.DATA, name='[1]') 443 | 444 | g_w15 = Wire(e_comp1, it12_ml1, Input.value_types.DATA, name='[0]') 445 | g_w16 = Wire(e_comp1, it12_ml2, Input.value_types.DATA, name='[0]') 446 | g_w17 = Wire(e_comp1, it12_comp1, Input.value_types.DATA, name='LHS') 447 | 448 | # if_then -> if_then12 449 | g_w18 = Wire(it_comb2, it12_ml1, Input.value_types.PREDICATE) 450 | g_w19 = Wire(it_comb2, it12_ml2, Input.value_types.PREDICATE) 451 | g_w20 = Wire(it_comb2, it12_ml3, Input.value_types.PREDICATE) 452 | g_w21 = Wire(it_comb2, it12_ms1, Input.value_types.PREDICATE) 453 | g_w22 = Wire(it_comb2, it12_comb1, Input.value_types.PREDICATE) 454 | 455 | # entry -> if_else 456 | g_w23 = Wire(e_oc3, ie_ml2, Input.value_types.DATA, name='[0]') 457 | g_w24 = Wire(e_oc3, ie_comp1, Input.value_types.DATA, name='LHS') 458 | g_w25 = Wire(e_oc3, ie_ms1, Input.value_types.DATA, name='[0]') 459 | 460 | g_w26 = Wire(e_oc4, ie_ml2, Input.value_types.DATA, name='[1]') 461 | g_w27 = Wire(e_oc4, ie_comp2, Input.value_types.DATA, name='LHS') 462 | g_w28 = Wire(e_oc4, ie_ms1, Input.value_types.DATA, name='[1]') 463 | 464 | # if_then -> if_else 465 | g_w29 = Wire(it_comb3, ie_ml1, Input.value_types.PREDICATE) 466 | g_w30 = Wire(it_comb3, ie_ml2, Input.value_types.PREDICATE) 467 | g_w31 = Wire(it_comb3, ie_ms1, Input.value_types.PREDICATE) 468 | g_w32 = Wire(it_comb3, ie_comb1, Input.value_types.PREDICATE) 469 | 470 | # for_body -> final 471 | g_w33 = Wire(fb_comb3, f_xor1, Input.value_types.PREDICATE) 472 | g_w34 = Wire(fb_comb3, f_mux2, Input.value_types.PREDICATE, name='i1') 473 | g_w35 = Wire(fb_comb3, f_mux1, Input.value_types.PREDICATE, name='j1') 474 | g_w36 = Wire(fb_comb3, f_mux3, Input.value_types.PREDICATE, name='k1') 475 | 476 | # if_else_36 -> final 477 | g_w37 = Wire(ie36_comp1, f_mux2, Input.value_types.DATA, name='i1') 478 | g_w38 = Wire(ie36_cc3, f_mux1, Input.value_types.DATA, name='j1') 479 | g_w39 = Wire(ie36_comp2, f_mux3, Input.value_types.DATA, name='k1') 480 | 481 | # if_then12 -> final 482 | g_w40 = Wire(e_oc3, f_mux2, Input.value_types.DATA, name='i2') 483 | g_w41 = Wire(e_oc4, f_mux1, Input.value_types.DATA, name='j2') 484 | g_w42 = Wire(it12_comp1, f_mux3, Input.value_types.DATA, name='k2') 485 | 486 | g_w43 = Wire(it12_comb1, f_xor1, Input.value_types.PREDICATE) 487 | g_w44 = Wire(it12_comb1, f_mux2, Input.value_types.PREDICATE, name='i2') 488 | g_w45 = Wire(it12_comb1, f_mux1, Input.value_types.PREDICATE, name='j2') 489 | g_w46 = Wire(it12_comb1, f_mux3, Input.value_types.PREDICATE, name='k2') 490 | 491 | # if_else -> final 492 | g_w47 = Wire(e_oc3, f_mux2, Input.value_types.DATA, name='i3') 493 | g_w48 = Wire(ie_comp2, f_mux1, Input.value_types.DATA, name='j3') 494 | g_w49 = Wire(ie_comp1, f_mux3, Input.value_types.DATA, name='k3') 495 | 496 | g_w50 = Wire(ie_comb1, f_xor1, Input.value_types.PREDICATE) 497 | g_w51 = Wire(ie_comb1, f_mux2, Input.value_types.PREDICATE, name='i3') 498 | g_w52 = Wire(ie_comb1, f_mux1, Input.value_types.PREDICATE, name='j3') 499 | g_w53 = Wire(ie_comb1, f_mux3, Input.value_types.PREDICATE, name='k3') 500 | 501 | return IR([[e_oc1], 502 | [e_oc2, e_oc3, e_oc4, e_comp1], 503 | [fb_cc1, fb_ml1, fb_comb1, fb_comb2, fb_comb3, fb_comp1, fb_comp2], 504 | [ie36_cc1, ie36_cc2, ie36_cc3, ie36_cc4, ie36_comp1, ie36_comp2], 505 | [it_cc1, it_ml1, it_comb1, it_comb2, it_comb3, it_comp1, it_comp2], 506 | [it12_cc1, it12_cc2, it12_comp1, it12_comp2, it12_comp3, it12_ml1, it12_ml2, it12_ml3, it12_ms1, it12_comb1], 507 | [ie_cc1, ie_cc2, ie_cc3, ie_ml1, ie_ml2, ie_comp1, ie_comp2, ie_comp3, ie_ms1, ie_comb1], 508 | [f_mux1, f_mux2, f_mux3, f_xor1, f_ms1, f_ms2, f_ms3]], 509 | [e_w1, e_w2, 510 | fb_w1, fb_w2, fb_w3, fb_w4, fb_w5, fb_w6, fb_w7, fb_w8, fb_w9, 511 | ie36_w1, ie36_w2, ie36_w3, ie36_w4, ie36_w5, 512 | it_w1, it_w2, it_w3, it_w4, it_w5, it_w6, it_w7, it_w8, it_w9, 513 | it12_w1, it12_w2, it12_w3, it12_w4, it12_w5, it12_w6, it12_w7, it12_w8, it12_w9, it12_w10, it12_w11, it12_w12, it12_w13, 514 | ie_w1, ie_w2, ie_w3, ie_w4, ie_w5, ie_w6, ie_w7, ie_w8, ie_w9, ie_w10, ie_w11, 515 | f_w1, f_w2, f_w3, f_w4, f_w5, f_w6, 516 | g_w1, g_w2, g_w3, g_w4, g_w5, g_w6, g_w7, g_w8, g_w9, g_w10, g_w11, g_w12, g_w13, g_w14, g_w15, g_w16, g_w17, g_w18, g_w19, g_w20, g_w21, g_w22, g_w23, g_w24, g_w25, g_w26, g_w27, g_w28, g_w29, g_w30, g_w31, g_w32, g_w33, g_w34, g_w35, g_w36, g_w37, g_w38, g_w39, g_w40, g_w41, g_w42, g_w43, g_w44, g_w45, g_w46, g_w47, g_w48, g_w49, g_w50, g_w51, g_w52, g_w53]) -------------------------------------------------------------------------------- /data/divergence_atomic.dot: -------------------------------------------------------------------------------- 1 | digraph IR { 2 | subgraph cluster_1 { 3 | B1_OT1 [label=1, shape=doublecircle]; 4 | B1_OT2 [label="T", shape=doublecircle]; 5 | 6 | B1_CC1 [label=2, shape=circle]; 7 | 8 | B1_ML1 [label="B", shape=invtriangle, type=int]; 9 | 10 | B1_COMB1 [label="COMBINE", shape=house]; 11 | 12 | B1_COMP1 [label="==", operator=EQ, shape=box, type=int]; 13 | B1_COMP2 [label="!", operator=NOT, shape=box, type=bool]; 14 | 15 | B1_ETA1 [label="ETA", shape=parallelogram]; 16 | B1_ETA2 [label="ETA", shape=parallelogram]; 17 | } 18 | 19 | subgraph cluster_2 { 20 | B2_CC1 [label=3, shape=circle]; 21 | B2_COMP1 [label="+", operator=ADD, shape=box, type=int]; 22 | B2_MS1 [label="B", shape=triangle]; 23 | } 24 | 25 | subgraph cluster_3 { 26 | B3_CC1 [label=3, shape=circle]; 27 | B3_COMP1 [label="*", operator=MUL, shape=box, type=int]; 28 | B3_MS1 [label="B", shape=triangle]; 29 | } 30 | 31 | # B1 wires 32 | B1_CC1 -> B1_COMP1 [label="RHS"]; 33 | B1_ML1 -> B1_COMP1 [label="LHS"]; 34 | 35 | B1_COMP1 -> B1_COMP2; 36 | B1_COMP1 -> B1_ETA1 [style=dotted]; 37 | 38 | B1_ML1 -> B1_COMB1 [style=dotted]; 39 | 40 | B1_COMB1 -> B1_ETA1; 41 | B1_COMB1 -> B1_ETA2; 42 | 43 | B1_COMP2 -> B1_ETA2 [style=dotted]; 44 | 45 | B1_OT2 -> B1_COMP1 [style=dotted]; 46 | B1_OT2 -> B1_COMP2 [style=dotted]; 47 | B1_OT2 -> B1_ML1 [style=dotted]; 48 | 49 | B1_OT1 -> B2_COMP1 [label="LHS"]; 50 | B1_OT1 -> B3_COMP1 [label="LHS"]; 51 | 52 | // B2 wires 53 | B2_CC1 -> B2_COMP1 [label="RHS"]; 54 | B2_COMP1 -> B2_MS1; 55 | 56 | // B3 wires 57 | B3_CC1 -> B3_COMP1 [label="RHS"]; 58 | B3_COMP1 -> B3_MS1; 59 | 60 | // Global wires 61 | B1_ETA1 -> B2_MS1 [style=dotted]; 62 | B1_ETA1 -> B2_COMP1 [style=dotted]; 63 | 64 | B1_ETA2 -> B3_MS1 [style=dotted]; 65 | B1_ETA2 -> B3_COMP1 [style=dotted]; 66 | } 67 | -------------------------------------------------------------------------------- /data/divergence_speculative.dot: -------------------------------------------------------------------------------- 1 | digraph IR { 2 | subgraph cluster_1 { 3 | B1_OT1 [label=1, shape=doublecircle]; 4 | B1_OT2 [label="T", shape=doublecircle]; 5 | 6 | B1_CC1 [label=2, shape=circle]; 7 | 8 | B1_ML1 [label="B", shape=invtriangle, type=int]; 9 | 10 | B1_COMB1 [label="COMBINE", shape=house]; 11 | 12 | B1_COMP1 [label="==", operator=EQ, shape=box, type=int]; 13 | B1_COMP2 [label="!", operator=NOT, shape=box, type=bool]; 14 | 15 | B1_COMB2 [label="COMBINE", shape=house]; 16 | B1_COMB3 [label="COMBINE", shape=house]; 17 | } 18 | 19 | subgraph cluster_2 { 20 | B2_CC1 [label=3, shape=circle]; 21 | B2_CC2 [label="T", shape=circle]; 22 | 23 | B2_COMP1 [label="+", operator=ADD, shape=box, type=int]; 24 | B2_MS1 [label="B", shape=triangle]; 25 | } 26 | 27 | subgraph cluster_3 { 28 | B3_CC1 [label=3, shape=circle]; 29 | B3_CC2 [label="T", shape=circle]; 30 | 31 | B3_COMP1 [label="*", operator=MUL, shape=box, type=int]; 32 | B3_MS1 [label="B", shape=triangle]; 33 | } 34 | 35 | # B1 wires 36 | B1_CC1 -> B1_COMP1 [label="RHS"]; 37 | B1_ML1 -> B1_COMP1 [label="LHS"]; 38 | 39 | B1_COMP1 -> B1_COMP2; 40 | B1_COMP1 -> B1_COMB2 [style=dotted]; 41 | 42 | B1_ML1 -> B1_COMB1 [style=dotted]; 43 | 44 | B1_COMB1 -> B1_COMB2; 45 | B1_COMB1 -> B1_COMB3; 46 | 47 | B1_COMP2 -> B1_COMB3 [style=dotted]; 48 | 49 | B1_OT2 -> B1_COMP1 [style=dotted]; 50 | B1_OT2 -> B1_COMP2 [style=dotted]; 51 | B1_OT2 -> B1_ML1 [style=dotted]; 52 | B1_OT2 -> B1_COMB1 [style=dotted]; 53 | 54 | B1_OT1 -> B2_COMP1 [label="LHS"]; 55 | B1_OT1 -> B3_COMP1 [label="LHS"]; 56 | 57 | // B2 wires 58 | B2_CC2 -> B2_COMP1 [style=dotted]; 59 | B2_CC1 -> B2_COMP1 [label="RHS"]; 60 | B2_COMP1 -> B2_MS1; 61 | 62 | // B3 wires 63 | B3_CC2 -> B3_COMP1 [style=dotted]; 64 | B3_CC1 -> B3_COMP1 [label="RHS"]; 65 | B3_COMP1 -> B3_MS1; 66 | 67 | // Global wires 68 | B1_COMB2 -> B2_MS1 [style=dotted]; 69 | B1_COMB3 -> B3_MS1 [style=dotted]; 70 | } 71 | -------------------------------------------------------------------------------- /data/prefix_sum_parallel.dot: -------------------------------------------------------------------------------- 1 | digraph IR { 2 | graph [bgcolor=transparent, ratio="0.5545"]; 3 | node [color="#aaccf4", fillcolor="#1d2f49", fontcolor=white, style=filled]; 4 | edge [color=white, fontcolor=white]; 5 | PRED [label="T", shape=doublecircle]; 6 | subgraph cluster_2 { 7 | color="#aaccf4"; 8 | penwidth=2; 9 | R0_0 [label=7, shape=doublecircle]; 10 | R0_1 [label=0, shape=doublecircle]; 11 | R0_2 [label=2, shape=doublecircle]; 12 | R0_3 [label=9, shape=doublecircle]; 13 | R0_4 [label=5, shape=doublecircle]; 14 | R0_5 [label=1, shape=doublecircle]; 15 | R0_6 [label=8, shape=doublecircle]; 16 | R0_7 [label=6, shape=doublecircle]; 17 | } 18 | 19 | subgraph cluster_3 { 20 | color="#aaccf4"; 21 | penwidth=2; 22 | R1_1 [label="+", operator=ADD, shape=box, type=int]; 23 | R1_2 [label="+", operator=ADD, shape=box, type=int]; 24 | R1_3 [label="+", operator=ADD, shape=box, type=int]; 25 | R1_4 [label="+", operator=ADD, shape=box, type=int]; 26 | R1_5 [label="+", operator=ADD, shape=box, type=int]; 27 | R1_6 [label="+", operator=ADD, shape=box, type=int]; 28 | R1_7 [label="+", operator=ADD, shape=box, type=int]; 29 | } 30 | 31 | subgraph cluster_4 { 32 | color="#aaccf4"; 33 | penwidth=2; 34 | R2_2 [label="+", operator=ADD, shape=box, type=int]; 35 | R2_3 [label="+", operator=ADD, shape=box, type=int]; 36 | R2_4 [label="+", operator=ADD, shape=box, type=int]; 37 | R2_5 [label="+", operator=ADD, shape=box, type=int]; 38 | R2_6 [label="+", operator=ADD, shape=box, type=int]; 39 | R2_7 [label="+", operator=ADD, shape=box, type=int]; 40 | } 41 | 42 | subgraph cluster_5 { 43 | color="#aaccf4"; 44 | penwidth=2; 45 | R3_4 [label="+", operator=ADD, shape=box, type=int]; 46 | R3_5 [label="+", operator=ADD, shape=box, type=int]; 47 | R3_6 [label="+", operator=ADD, shape=box, type=int]; 48 | R3_7 [label="+", operator=ADD, shape=box, type=int]; 49 | } 50 | 51 | subgraph cluster_6 { 52 | color="#aaccf4"; 53 | penwidth=2; 54 | R4_0 [label="R4_0", shape=star]; 55 | R4_1 [label="R4_1", shape=star]; 56 | R4_2 [label="R4_2", shape=star]; 57 | R4_3 [label="R4_3", shape=star]; 58 | R4_4 [label="R4_4", shape=star]; 59 | R4_5 [label="R4_5", shape=star]; 60 | R4_6 [label="R4_6", shape=star]; 61 | R4_7 [label="R4_7", shape=star]; 62 | } 63 | 64 | R0_0 -> R1_1 [label="LHS"]; 65 | R0_1 -> R1_1 [label="RHS"]; 66 | R0_1 -> R1_2 [label="LHS"]; 67 | R0_2 -> R1_2 [label="RHS"]; 68 | R0_2 -> R1_3 [label="LHS"]; 69 | R0_3 -> R1_3 [label="RHS"]; 70 | R0_3 -> R1_4 [label="LHS"]; 71 | R0_4 -> R1_4 [label="RHS"]; 72 | R0_4 -> R1_5 [label="LHS"]; 73 | R0_5 -> R1_5 [label="RHS"]; 74 | R0_5 -> R1_6 [label="LHS"]; 75 | R0_6 -> R1_6 [label="RHS"]; 76 | R0_6 -> R1_7 [label="LHS"]; 77 | R0_7 -> R1_7 [label="RHS"]; 78 | R0_0 -> R2_2 [label="LHS"]; 79 | R1_2 -> R2_2 [label="RHS"]; 80 | R1_1 -> R2_3 [label="LHS"]; 81 | R1_3 -> R2_3 [label="RHS"]; 82 | R1_2 -> R2_4 [label="LHS"]; 83 | R1_4 -> R2_4 [label="RHS"]; 84 | R1_3 -> R2_5 [label="LHS"]; 85 | R1_5 -> R2_5 [label="RHS"]; 86 | R1_4 -> R2_6 [label="LHS"]; 87 | R1_6 -> R2_6 [label="RHS"]; 88 | R1_5 -> R2_7 [label="LHS"]; 89 | R1_7 -> R2_7 [label="RHS"]; 90 | R0_0 -> R3_4 [label="LHS"]; 91 | R2_4 -> R3_4 [label="RHS"]; 92 | R1_1 -> R3_5 [label="LHS"]; 93 | R2_5 -> R3_5 [label="RHS"]; 94 | R2_2 -> R3_6 [label="LHS"]; 95 | R2_6 -> R3_6 [label="RHS"]; 96 | R2_3 -> R3_7 [label="LHS"]; 97 | R2_7 -> R3_7 [label="RHS"]; 98 | R0_0 -> R4_0; 99 | R1_1 -> R4_1; 100 | R2_2 -> R4_2; 101 | R2_3 -> R4_3; 102 | R3_4 -> R4_4; 103 | R3_5 -> R4_5; 104 | R3_6 -> R4_6; 105 | R3_7 -> R4_7; 106 | PRED -> R1_1 [style=dotted]; 107 | PRED -> R1_2 [style=dotted]; 108 | PRED -> R1_3 [style=dotted]; 109 | PRED -> R1_4 [style=dotted]; 110 | PRED -> R1_5 [style=dotted]; 111 | PRED -> R1_6 [style=dotted]; 112 | PRED -> R1_7 [style=dotted]; 113 | PRED -> R2_2 [style=dotted]; 114 | PRED -> R2_3 [style=dotted]; 115 | PRED -> R2_4 [style=dotted]; 116 | PRED -> R2_5 [style=dotted]; 117 | PRED -> R2_6 [style=dotted]; 118 | PRED -> R2_7 [style=dotted]; 119 | PRED -> R3_4 [style=dotted]; 120 | PRED -> R3_5 [style=dotted]; 121 | PRED -> R3_6 [style=dotted]; 122 | PRED -> R3_7 [style=dotted]; 123 | } 124 | -------------------------------------------------------------------------------- /data/prefix_sum_work_effective.dot: -------------------------------------------------------------------------------- 1 | digraph IR { 2 | graph [bgcolor=transparent, ratio="0.5545"]; 3 | node [color="#aaccf4", fillcolor="#1d2f49", fontcolor=white, style=filled]; 4 | edge [color=white, fontcolor=white]; 5 | PRED [label="T", shape=doublecircle]; 6 | subgraph cluster_2 { 7 | color="#aaccf4"; 8 | penwidth=2; 9 | R0_0 [label=7, shape=doublecircle]; 10 | R0_1 [label=0, shape=doublecircle]; 11 | R0_2 [label=2, shape=doublecircle]; 12 | R0_3 [label=9, shape=doublecircle]; 13 | R0_4 [label=5, shape=doublecircle]; 14 | R0_5 [label=1, shape=doublecircle]; 15 | R0_6 [label=8, shape=doublecircle]; 16 | R0_7 [label=6, shape=doublecircle]; 17 | } 18 | 19 | subgraph cluster_3 { 20 | color="#aaccf4"; 21 | penwidth=2; 22 | R1_1 [label="+", operator=ADD, shape=box, type=int]; 23 | R1_3 [label="+", operator=ADD, shape=box, type=int]; 24 | R1_5 [label="+", operator=ADD, shape=box, type=int]; 25 | R1_7 [label="+", operator=ADD, shape=box, type=int]; 26 | } 27 | 28 | subgraph cluster_4 { 29 | color="#aaccf4"; 30 | penwidth=2; 31 | R2_3 [label="+", operator=ADD, shape=box, type=int]; 32 | R2_7 [label="+", operator=ADD, shape=box, type=int]; 33 | } 34 | 35 | subgraph cluster_5 { 36 | color="#aaccf4"; 37 | penwidth=2; 38 | R3_7 [label="+", operator=ADD, shape=box, type=int]; 39 | } 40 | 41 | subgraph cluster_6 { 42 | color="#aaccf4"; 43 | penwidth=2; 44 | R4_5 [label="+", operator=ADD, shape=box, type=int]; 45 | } 46 | 47 | subgraph cluster_7 { 48 | color="#aaccf4"; 49 | penwidth=2; 50 | R5_2 [label="+", operator=ADD, shape=box, type=int]; 51 | R5_4 [label="+", operator=ADD, shape=box, type=int]; 52 | R5_6 [label="+", operator=ADD, shape=box, type=int]; 53 | } 54 | 55 | subgraph cluster_8 { 56 | color="#aaccf4"; 57 | penwidth=2; 58 | R6_0 [label="R6_0", shape=star]; 59 | R6_1 [label="R6_1", shape=star]; 60 | R6_2 [label="R6_2", shape=star]; 61 | R6_3 [label="R6_3", shape=star]; 62 | R6_4 [label="R6_4", shape=star]; 63 | R6_5 [label="R6_5", shape=star]; 64 | R6_6 [label="R6_6", shape=star]; 65 | R6_7 [label="R6_7", shape=star]; 66 | } 67 | 68 | R0_0 -> R1_1 [label="LHS"]; 69 | R0_1 -> R1_1 [label="RHS"]; 70 | R0_2 -> R1_3 [label="LHS"]; 71 | R0_3 -> R1_3 [label="RHS"]; 72 | R0_4 -> R1_5 [label="LHS"]; 73 | R0_5 -> R1_5 [label="RHS"]; 74 | R0_6 -> R1_7 [label="LHS"]; 75 | R0_7 -> R1_7 [label="RHS"]; 76 | R1_1 -> R2_3 [label="LHS"]; 77 | R1_3 -> R2_3 [label="RHS"]; 78 | R1_5 -> R2_7 [label="LHS"]; 79 | R1_7 -> R2_7 [label="RHS"]; 80 | R2_3 -> R3_7 [label="LHS"]; 81 | R2_7 -> R3_7 [label="RHS"]; 82 | R2_3 -> R4_5 [label="LHS"]; 83 | R1_5 -> R4_5 [label="RHS"]; 84 | R1_1 -> R5_2 [label="LHS"]; 85 | R0_2 -> R5_2 [label="RHS"]; 86 | R2_3 -> R5_4 [label="LHS"]; 87 | R0_4 -> R5_4 [label="RHS"]; 88 | R4_5 -> R5_6 [label="LHS"]; 89 | R0_6 -> R5_6 [label="RHS"]; 90 | R0_0 -> R6_0; 91 | R1_1 -> R6_1; 92 | R5_2 -> R6_2; 93 | R2_3 -> R6_3; 94 | R5_4 -> R6_4; 95 | R4_5 -> R6_5; 96 | R5_6 -> R6_6; 97 | R3_7 -> R6_7; 98 | PRED -> R1_1 [style=dotted]; 99 | PRED -> R1_3 [style=dotted]; 100 | PRED -> R1_5 [style=dotted]; 101 | PRED -> R1_7 [style=dotted]; 102 | PRED -> R2_3 [style=dotted]; 103 | PRED -> R2_7 [style=dotted]; 104 | PRED -> R3_7 [style=dotted]; 105 | PRED -> R4_5 [style=dotted]; 106 | PRED -> R5_2 [style=dotted]; 107 | PRED -> R5_4 [style=dotted]; 108 | PRED -> R5_6 [style=dotted]; 109 | } 110 | -------------------------------------------------------------------------------- /data/trmm_MEM.json: -------------------------------------------------------------------------------- 1 | [ 2 | ["n", [], 2], 3 | ["m", [], 2], 4 | ["alpha", [], 2], 5 | ["A", [0,0], 1], 6 | ["A", [0,1], 2], 7 | ["A", [1,0], 3], 8 | ["A", [1,1], 4], 9 | ["B", [0,0], 5], 10 | ["B", [0,1], 6], 11 | ["B", [1,0], 7], 12 | ["B", [1,1], 8] 13 | ] 14 | -------------------------------------------------------------------------------- /data/trmm_atomic_IR.dot: -------------------------------------------------------------------------------- 1 | digraph IR { 2 | graph [bgcolor=transparent, ratio="0.5545"]; 3 | node [color="#aaccf4", fillcolor="#1d2f49", fontcolor=white, style=filled]; 4 | edge [color=white, fontcolor=white]; 5 | E_OC1 [label="T", shape=doublecircle]; 6 | subgraph cluster_2 { 7 | color="#aaccf4"; 8 | penwidth=2; 9 | E_OC2 [label=1, shape=doublecircle]; 10 | E_OC3 [label=0, shape=doublecircle]; 11 | E_OC4 [label=0, shape=doublecircle]; 12 | E_COMP1 [label="+", operator=ADD, shape=box]; 13 | } 14 | 15 | subgraph cluster_3 { 16 | color="#aaccf4"; 17 | penwidth=2; 18 | FB_ML1 [label="n", shape=invtriangle, type=int]; 19 | FB_COMB1 [label="COMBINE", shape=house]; 20 | FB_COMP1 [label="\<", operator=LT, shape=box, type=int]; 21 | FB_COMP2 [label="!", operator=NOT, shape=box, type=bool]; 22 | FB_ETA1 [label="ETA", shape=parallelogram]; 23 | FB_ETA2 [label="ETA", shape=parallelogram]; 24 | } 25 | 26 | subgraph cluster_4 { 27 | color="#aaccf4"; 28 | penwidth=2; 29 | IE36_CC1 [label=1, shape=circle]; 30 | IE36_CC2 [label=1, shape=circle]; 31 | IE36_CC3 [label=0, shape=circle]; 32 | IE36_COMP1 [label="+", operator=ADD, shape=box, type=int]; 33 | IE36_COMP2 [label="+", operator=ADD, shape=box, type=int]; 34 | IE36_ETA1 [label="ETA", shape=parallelogram]; 35 | } 36 | 37 | subgraph cluster_5 { 38 | color="#aaccf4"; 39 | penwidth=2; 40 | IT_ML1 [label="m", shape=invtriangle, type=int]; 41 | IT_COMB1 [label="COMBINE", shape=house]; 42 | IT_COMP1 [label="\<", operator=LT, shape=box, type=int]; 43 | IT_COMP2 [label="!", operator=NOT, shape=box, type=int]; 44 | IT_ETA1 [label="ETA", shape=parallelogram]; 45 | IT_ETA2 [label="ETA", shape=parallelogram]; 46 | } 47 | 48 | subgraph cluster_6 { 49 | color="#aaccf4"; 50 | penwidth=2; 51 | IT12_CC1 [label=1, shape=circle]; 52 | IT12_COMP1 [label="+", operator=ADD, shape=box, type=int]; 53 | IT12_COMP2 [label="*", operator=MUL, shape=box, type=int]; 54 | IT12_COMP3 [label="+", operator=ADD, shape=box, type=int]; 55 | IT12_ETA1 [label="ETA", shape=parallelogram]; 56 | IT12_ETA2 [label="ETA", shape=parallelogram]; 57 | IT12_ML1 [label="A", shape=invtriangle, type=int]; 58 | IT12_ML2 [label="B", shape=invtriangle, type=int]; 59 | IT12_ML3 [label="B", shape=invtriangle, type=int]; 60 | IT12_MS1 [label="B", shape=triangle]; 61 | IT12_COMB1 [label="COMBINE", shape=house]; 62 | } 63 | 64 | subgraph cluster_7 { 65 | color="#aaccf4"; 66 | penwidth=2; 67 | IE_CC1 [label=1, shape=circle]; 68 | IE_CC2 [label=1, shape=circle]; 69 | IE_ML1 [label="alpha", shape=invtriangle, type=int]; 70 | IE_ML2 [label="B", shape=invtriangle, type=int]; 71 | IE_ETA1 [label="ETA", shape=parallelogram]; 72 | IE_COMP1 [label="+", operator=ADD, shape=box, type=int]; 73 | IE_COMP2 [label="+", operator=ADD, shape=box, type=int]; 74 | IE_COMP3 [label="*", operator=MUL, shape=box, type=int]; 75 | IE_MS1 [label="B", shape=triangle]; 76 | IE_COMB1 [label="COMBINE", shape=house]; 77 | } 78 | 79 | subgraph cluster_8 { 80 | color="#aaccf4"; 81 | penwidth=2; 82 | F_MU1 [label="MU", shape=diamond]; 83 | F_MU2 [label="MU", shape=diamond]; 84 | F_MU3 [label="MU", shape=diamond]; 85 | F_MU4 [label="MU", shape=diamond]; 86 | F_MS1 [label="k", shape=triangle]; 87 | F_MS2 [label="i", shape=triangle]; 88 | F_MS3 [label="j", shape=triangle]; 89 | } 90 | 91 | E_OC2 -> E_COMP1 [label="RHS"]; 92 | E_OC3 -> E_COMP1 [label="LHS"]; 93 | FB_ML1 -> FB_COMB1 [style=dotted]; 94 | FB_ML1 -> FB_COMP1 [label="RHS"]; 95 | FB_COMB1 -> FB_ETA2; 96 | FB_COMB1 -> FB_ETA1; 97 | FB_COMP1 -> FB_COMP2; 98 | FB_COMP1 -> FB_ETA1 [style=dotted]; 99 | FB_COMP2 -> FB_ETA2 [style=dotted]; 100 | IE36_CC1 -> IE36_COMP1 [label="RHS"]; 101 | IE36_COMP2 -> IE36_COMP1 [label="LHS"]; 102 | IE36_CC2 -> IE36_COMP2 [label="RHS"]; 103 | IE36_CC3 -> IE36_ETA1; 104 | IT_ML1 -> IT_COMB1 [style=dotted]; 105 | IT_ML1 -> IT_COMP1 [label="RHS"]; 106 | IT_COMB1 -> IT_ETA1; 107 | IT_COMB1 -> IT_ETA2; 108 | IT_COMP1 -> IT_ETA1 [style=dotted]; 109 | IT_COMP1 -> IT_COMP2; 110 | IT_COMP2 -> IT_ETA2 [style=dotted]; 111 | IT12_CC1 -> IT12_COMP1 [label="RHS"]; 112 | IT12_ML1 -> IT12_COMP2 [label="LHS"]; 113 | IT12_ML1 -> IT12_COMB1 [style=dotted]; 114 | IT12_ML2 -> IT12_COMB1 [style=dotted]; 115 | IT12_ML2 -> IT12_COMP2 [label="RHS"]; 116 | IT12_COMP2 -> IT12_COMP3 [label="RHS"]; 117 | IT12_ML3 -> IT12_COMP3 [label="LHS"]; 118 | IT12_ML3 -> IT12_COMB1 [style=dotted]; 119 | IT12_COMP3 -> IT12_MS1; 120 | IT12_MS1 -> IT12_COMB1 [style=dotted]; 121 | IE_CC1 -> IE_COMP1 [label="RHS"]; 122 | IE_CC2 -> IE_COMP2 [label="RHS"]; 123 | IE_ML1 -> IE_COMP3 [label="LHS"]; 124 | IE_ML1 -> IE_COMB1 [style=dotted]; 125 | IE_ML2 -> IE_COMP3 [label="RHS"]; 126 | IE_ML2 -> IE_COMB1 [style=dotted]; 127 | IE_COMP3 -> IE_MS1; 128 | IE_MS1 -> IE_COMB1 [style=dotted]; 129 | F_MU1 -> F_MS1; 130 | F_MU2 -> F_MS2; 131 | F_MU4 -> F_MS3; 132 | F_MU3 -> F_MS1 [style=dotted]; 133 | F_MU3 -> F_MS2 [style=dotted]; 134 | F_MU3 -> F_MS3 [style=dotted]; 135 | E_OC1 -> E_COMP1 [style=dotted]; 136 | E_OC1 -> FB_ML1 [style=dotted]; 137 | E_OC1 -> FB_COMP1 [style=dotted]; 138 | E_OC1 -> FB_COMP2 [style=dotted]; 139 | E_OC4 -> FB_COMP1 [label="LHS"]; 140 | E_OC3 -> IE36_COMP2 [label="LHS"]; 141 | FB_ETA2 -> IE36_COMP1 [style=dotted]; 142 | FB_ETA2 -> IE36_COMP2 [style=dotted]; 143 | FB_ETA2 -> IE36_ETA1 [style=dotted]; 144 | E_COMP1 -> IT_COMP1 [label="LHS"]; 145 | FB_ETA1 -> IT_ML1 [style=dotted]; 146 | FB_ETA1 -> IT_COMP1 [style=dotted]; 147 | FB_ETA1 -> IT_COMP2 [style=dotted]; 148 | E_OC3 -> IT12_ETA1; 149 | E_OC3 -> IT12_ML1 [label="[1]"]; 150 | E_OC3 -> IT12_ML3 [label="[0]"]; 151 | E_OC3 -> IT12_MS1 [label="[0]"]; 152 | E_OC4 -> IT12_ETA2; 153 | E_OC4 -> IT12_ML2 [label="[1]"]; 154 | E_OC4 -> IT12_ML3 [label="[1]"]; 155 | E_OC4 -> IT12_MS1 [label="[1]"]; 156 | E_COMP1 -> IT12_COMP1 [label="LHS"]; 157 | E_COMP1 -> IT12_ML1 [label="[0]"]; 158 | E_COMP1 -> IT12_ML2 [label="[0]"]; 159 | IT_ETA1 -> IT12_COMP1 [style=dotted]; 160 | IT_ETA1 -> IT12_ETA1 [style=dotted]; 161 | IT_ETA1 -> IT12_ML1 [style=dotted]; 162 | IT_ETA1 -> IT12_ETA2 [style=dotted]; 163 | IT_ETA1 -> IT12_ML2 [style=dotted]; 164 | IT_ETA1 -> IT12_COMP2 [style=dotted]; 165 | IT_ETA1 -> IT12_ML3 [style=dotted]; 166 | IT_ETA1 -> IT12_COMP3 [style=dotted]; 167 | IT_ETA1 -> IT12_MS1 [style=dotted]; 168 | E_OC3 -> IE_ML2 [label="[0]"]; 169 | E_OC3 -> IE_ETA1; 170 | E_OC3 -> IE_COMP1 [label="LHS"]; 171 | E_OC3 -> IE_MS1 [label="[0]"]; 172 | E_OC4 -> IE_ML2 [label="[1]"]; 173 | E_OC4 -> IE_COMP2 [label="LHS"]; 174 | E_OC4 -> IE_MS1 [label="[1]"]; 175 | IT_ETA2 -> IE_ML1 [style=dotted]; 176 | IT_ETA2 -> IE_ML2 [style=dotted]; 177 | IT_ETA2 -> IE_ETA1 [style=dotted]; 178 | IT_ETA2 -> IE_COMP1 [style=dotted]; 179 | IT_ETA2 -> IE_COMP2 [style=dotted]; 180 | IT_ETA2 -> IE_COMP3 [style=dotted]; 181 | IT_ETA2 -> IE_MS1 [style=dotted]; 182 | FB_ETA2 -> F_MU3 [style=dotted]; 183 | IE36_COMP1 -> F_MU1; 184 | IE36_COMP2 -> F_MU2; 185 | IE36_ETA1 -> F_MU4; 186 | IT12_COMP1 -> F_MU1; 187 | IT12_ETA1 -> F_MU2; 188 | IT12_COMB1 -> F_MU3 [style=dotted]; 189 | IT12_ETA2 -> F_MU4; 190 | IE_COMP1 -> F_MU1; 191 | IE_ETA1 -> F_MU2; 192 | IE_COMB1 -> F_MU3 [style=dotted]; 193 | IE_COMP2 -> F_MU4; 194 | } 195 | -------------------------------------------------------------------------------- /data/trmm_speculative_IR.dot: -------------------------------------------------------------------------------- 1 | digraph IR { 2 | graph [bgcolor=transparent, ratio="0.5545"]; 3 | node [color="#aaccf4", fillcolor="#1d2f49", fontcolor=white, style=filled]; 4 | edge [color=white, fontcolor=white]; 5 | E_OC1 [label="T", shape=doublecircle]; 6 | subgraph cluster_2 { 7 | color="#aaccf4"; 8 | penwidth=2; 9 | E_OC2 [label=1, shape=doublecircle]; 10 | E_OC3 [label=0, shape=doublecircle]; 11 | E_OC4 [label=0, shape=doublecircle]; 12 | E_COMP1 [label="+", operator=ADD, shape=box]; 13 | } 14 | 15 | subgraph cluster_3 { 16 | color="#aaccf4"; 17 | penwidth=2; 18 | FB_CC1 [label="T", shape=circle]; 19 | FB_ML1 [label="n", shape=invtriangle, type=int]; 20 | FB_COMB1 [label="COMBINE", shape=house]; 21 | FB_COMB2 [label="COMBINE", shape=house]; 22 | FB_COMB3 [label="COMBINE", shape=house]; 23 | FB_COMP1 [label="\<", operator=LT, shape=box, type=int]; 24 | FB_COMP2 [label="!", operator=NOT, shape=box, type=bool]; 25 | } 26 | 27 | subgraph cluster_4 { 28 | color="#aaccf4"; 29 | penwidth=2; 30 | IE36_CC1 [label=1, shape=circle]; 31 | IE36_CC2 [label=1, shape=circle]; 32 | IE36_CC3 [label=0, shape=circle]; 33 | IE36_CC4 [label="T", shape=circle]; 34 | IE36_COMP1 [label="+", operator=ADD, shape=box, type=int]; 35 | IE36_COMP2 [label="+", operator=ADD, shape=box, type=int]; 36 | } 37 | 38 | subgraph cluster_5 { 39 | color="#aaccf4"; 40 | penwidth=2; 41 | IT_CC1 [label="T", shape=circle]; 42 | IT_ML1 [label="m", shape=invtriangle, type=int]; 43 | IT_COMB1 [label="COMBINE", shape=house]; 44 | IT_COMB2 [label="COMBINE", shape=house]; 45 | IT_COMB3 [label="COMBINE", shape=house]; 46 | IT_COMP1 [label="\<", operator=LT, shape=box, type=int]; 47 | IT_COMP2 [label="!", operator=NOT, shape=box, type=int]; 48 | } 49 | 50 | subgraph cluster_6 { 51 | color="#aaccf4"; 52 | penwidth=2; 53 | IT12_CC1 [label=1, shape=circle]; 54 | IT12_CC2 [label="T", shape=circle]; 55 | IT12_COMP1 [label="+", operator=ADD, shape=box, type=int]; 56 | IT12_COMP2 [label="*", operator=MUL, shape=box, type=int]; 57 | IT12_COMP3 [label="+", operator=ADD, shape=box, type=int]; 58 | IT12_ML1 [label="A", shape=invtriangle, type=int]; 59 | IT12_ML2 [label="B", shape=invtriangle, type=int]; 60 | IT12_ML3 [label="B", shape=invtriangle, type=int]; 61 | IT12_MS1 [label="B", shape=triangle]; 62 | IT12_COMB1 [label="COMBINE", shape=house]; 63 | } 64 | 65 | subgraph cluster_7 { 66 | color="#aaccf4"; 67 | penwidth=2; 68 | IE_CC1 [label=1, shape=circle]; 69 | IE_CC2 [label=1, shape=circle]; 70 | IE_CC3 [label="T", shape=circle]; 71 | IE_ML1 [label="alpha", shape=invtriangle, type=int]; 72 | IE_ML2 [label="B", shape=invtriangle, type=int]; 73 | IE_COMP1 [label="+", operator=ADD, shape=box, type=int]; 74 | IE_COMP2 [label="+", operator=ADD, shape=box, type=int]; 75 | IE_COMP3 [label="*", operator=MUL, shape=box, type=int]; 76 | IE_MS1 [label="B", shape=triangle]; 77 | IE_COMB1 [label="COMBINE", shape=house]; 78 | } 79 | 80 | subgraph cluster_8 { 81 | color="#aaccf4"; 82 | penwidth=2; 83 | F_MUX1 [label="MUX", shape=invtrapezium]; 84 | F_MUX2 [label="MUX", shape=invtrapezium]; 85 | F_MUX3 [label="MUX", shape=invtrapezium]; 86 | F_XOR1 [label="XOR", shape=hexagon]; 87 | F_MS1 [label="k", shape=triangle]; 88 | F_MS2 [label="i", shape=triangle]; 89 | F_MS3 [label="j", shape=triangle]; 90 | } 91 | 92 | E_OC2 -> E_COMP1 [label="RHS"]; 93 | E_OC3 -> E_COMP1 [label="LHS"]; 94 | FB_ML1 -> FB_COMB1 [style=dotted]; 95 | FB_ML1 -> FB_COMP1 [label="RHS"]; 96 | FB_COMB1 -> FB_COMB3; 97 | FB_COMB1 -> FB_COMB2; 98 | FB_COMP1 -> FB_COMP2; 99 | FB_COMP1 -> FB_COMB2; 100 | FB_COMP2 -> FB_COMB3; 101 | FB_CC1 -> FB_COMP1 [style=dotted]; 102 | FB_CC1 -> FB_COMP2 [style=dotted]; 103 | IE36_CC1 -> IE36_COMP1 [label="RHS"]; 104 | IE36_COMP1 -> IE36_COMP2 [label="LHS"]; 105 | IE36_CC2 -> IE36_COMP2 [label="RHS"]; 106 | IE36_CC4 -> IE36_COMP1 [style=dotted]; 107 | IE36_CC4 -> IE36_COMP2 [style=dotted]; 108 | IT_ML1 -> IT_COMB1 [style=dotted]; 109 | IT_ML1 -> IT_COMP1 [label="RHS"]; 110 | IT_COMB1 -> IT_COMB2; 111 | IT_COMB1 -> IT_COMB3; 112 | IT_COMP1 -> IT_COMB2; 113 | IT_COMP1 -> IT_COMP2; 114 | IT_COMP2 -> IT_COMB3; 115 | IT_CC1 -> IT_COMP1 [style=dotted]; 116 | IT_CC1 -> IT_COMP2 [style=dotted]; 117 | IT12_CC1 -> IT12_COMP1 [label="RHS"]; 118 | IT12_ML1 -> IT12_COMP2 [label="LHS"]; 119 | IT12_ML1 -> IT12_COMB1 [style=dotted]; 120 | IT12_ML2 -> IT12_COMB1 [style=dotted]; 121 | IT12_ML2 -> IT12_COMP2 [label="RHS"]; 122 | IT12_COMP2 -> IT12_COMP3 [label="RHS"]; 123 | IT12_ML3 -> IT12_COMP3 [label="LHS"]; 124 | IT12_ML3 -> IT12_COMB1 [style=dotted]; 125 | IT12_COMP3 -> IT12_MS1; 126 | IT12_MS1 -> IT12_COMB1 [style=dotted]; 127 | IT12_CC2 -> IT12_COMP1 [style=dotted]; 128 | IT12_CC2 -> IT12_COMP2 [style=dotted]; 129 | IT12_CC2 -> IT12_COMP3 [style=dotted]; 130 | IE_CC1 -> IE_COMP1 [label="RHS"]; 131 | IE_CC2 -> IE_COMP2 [label="RHS"]; 132 | IE_ML1 -> IE_COMP3 [label="LHS"]; 133 | IE_ML1 -> IE_COMB1 [style=dotted]; 134 | IE_ML2 -> IE_COMP3 [label="RHS"]; 135 | IE_ML2 -> IE_COMB1 [style=dotted]; 136 | IE_COMP3 -> IE_MS1; 137 | IE_MS1 -> IE_COMB1 [style=dotted]; 138 | IE_CC3 -> IE_COMP1 [style=dotted]; 139 | IE_CC3 -> IE_COMP2 [style=dotted]; 140 | IE_CC3 -> IE_COMP3 [style=dotted]; 141 | F_MUX1 -> F_MS3; 142 | F_MUX2 -> F_MS2; 143 | F_MUX3 -> F_MS1; 144 | F_XOR1 -> F_MS1 [style=dotted]; 145 | F_XOR1 -> F_MS2 [style=dotted]; 146 | F_XOR1 -> F_MS3 [style=dotted]; 147 | E_OC1 -> E_COMP1 [style=dotted]; 148 | E_OC1 -> FB_ML1 [style=dotted]; 149 | E_OC1 -> FB_COMB1 [style=dotted]; 150 | E_OC4 -> FB_COMP1 [label="LHS"]; 151 | E_OC3 -> IE36_COMP1 [label="LHS"]; 152 | E_COMP1 -> IT_COMP1 [label="LHS"]; 153 | FB_COMB2 -> IT_ML1 [style=dotted]; 154 | FB_COMB2 -> IT_COMB1 [style=dotted]; 155 | E_OC3 -> IT12_ML1 [label="[1]"]; 156 | E_OC3 -> IT12_ML3 [label="[0]"]; 157 | E_OC3 -> IT12_MS1 [label="[0]"]; 158 | E_OC4 -> IT12_ML2 [label="[1]"]; 159 | E_OC4 -> IT12_ML3 [label="[1]"]; 160 | E_OC4 -> IT12_MS1 [label="[1]"]; 161 | E_COMP1 -> IT12_ML1 [label="[0]"]; 162 | E_COMP1 -> IT12_ML2 [label="[0]"]; 163 | E_COMP1 -> IT12_COMP1 [label="LHS"]; 164 | IT_COMB2 -> IT12_ML1 [style=dotted]; 165 | IT_COMB2 -> IT12_ML2 [style=dotted]; 166 | IT_COMB2 -> IT12_ML3 [style=dotted]; 167 | IT_COMB2 -> IT12_MS1 [style=dotted]; 168 | IT_COMB2 -> IT12_COMB1 [style=dotted]; 169 | E_OC3 -> IE_ML2 [label="[0]"]; 170 | E_OC3 -> IE_COMP1 [label="LHS"]; 171 | E_OC3 -> IE_MS1 [label="[0]"]; 172 | E_OC4 -> IE_ML2 [label="[1]"]; 173 | E_OC4 -> IE_COMP2 [label="LHS"]; 174 | E_OC4 -> IE_MS1 [label="[1]"]; 175 | IT_COMB3 -> IE_ML1 [style=dotted]; 176 | IT_COMB3 -> IE_ML2 [style=dotted]; 177 | IT_COMB3 -> IE_MS1 [style=dotted]; 178 | IT_COMB3 -> IE_COMB1 [style=dotted]; 179 | FB_COMB3 -> F_XOR1 [style=dotted]; 180 | FB_COMB3 -> F_MUX2 [label="i1", style=dotted]; 181 | FB_COMB3 -> F_MUX1 [label="j1", style=dotted]; 182 | FB_COMB3 -> F_MUX3 [label="k1", style=dotted]; 183 | IE36_COMP1 -> F_MUX2 [label="i1"]; 184 | IE36_CC3 -> F_MUX1 [label="j1"]; 185 | IE36_COMP2 -> F_MUX3 [label="k1"]; 186 | E_OC3 -> F_MUX2 [label="i2"]; 187 | E_OC4 -> F_MUX1 [label="j2"]; 188 | IT12_COMP1 -> F_MUX3 [label="k2"]; 189 | IT12_COMB1 -> F_XOR1 [style=dotted]; 190 | IT12_COMB1 -> F_MUX2 [label="i2", style=dotted]; 191 | IT12_COMB1 -> F_MUX1 [label="j2", style=dotted]; 192 | IT12_COMB1 -> F_MUX3 [label="k2", style=dotted]; 193 | E_OC3 -> F_MUX2 [label="i3"]; 194 | IE_COMP2 -> F_MUX1 [label="j3"]; 195 | IE_COMP1 -> F_MUX3 [label="k3"]; 196 | IE_COMB1 -> F_XOR1 [style=dotted]; 197 | IE_COMB1 -> F_MUX2 [label="i3", style=dotted]; 198 | IE_COMB1 -> F_MUX1 [label="j3", style=dotted]; 199 | IE_COMB1 -> F_MUX3 [label="k3", style=dotted]; 200 | } 201 | -------------------------------------------------------------------------------- /header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffreyspaan/coolname/367db6afcab933d9dd494a49dbe51c75007fbd9f/header.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | dearpygui==0.6.415 2 | pydot==1.4.2 3 | -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from coolname.coolname import main 4 | 5 | if __name__ == '__main__': 6 | main() --------------------------------------------------------------------------------