1 |
2 |
jondawson |
__author__ = "Jon Dawson"
|
2 |
|
|
__copyright__ = "Copyright (C) 2012, Jonathan P Dawson"
|
3 |
|
|
__version__ = "0.1"
|
4 |
|
|
|
5 |
|
|
def cleanup_functions(instructions):
|
6 |
|
|
|
7 |
|
|
"""Remove functions that are not called"""
|
8 |
|
|
|
9 |
|
|
|
10 |
|
|
#This is an iterative processr. Once a function is removed,
|
11 |
|
|
#there may be more unused functions
|
12 |
|
|
while 1:
|
13 |
|
|
|
14 |
|
|
#find function calls
|
15 |
|
|
live_functions = {}
|
16 |
|
|
for instruction in instructions:
|
17 |
|
|
if instruction["op"] == "jmp_and_link":
|
18 |
|
|
if instruction["label"].startswith("function"):
|
19 |
|
|
live_functions[instruction["label"]] = None
|
20 |
|
|
|
21 |
|
|
#remove instructions without function calls
|
22 |
|
|
kept_instructions = []
|
23 |
|
|
generate_on = True
|
24 |
|
|
for instruction in instructions:
|
25 |
|
|
if instruction["op"] == "label":
|
26 |
|
|
if instruction["label"].startswith("function"):
|
27 |
|
|
if instruction["label"] in live_functions:
|
28 |
|
|
generate_on = True
|
29 |
|
|
else:
|
30 |
|
|
generate_on = False
|
31 |
|
|
if generate_on:
|
32 |
|
|
kept_instructions.append(instruction)
|
33 |
|
|
|
34 |
|
|
if len(instructions) == len(kept_instructions):
|
35 |
|
|
return kept_instructions
|
36 |
|
|
instructions = kept_instructions
|
37 |
|
|
|
38 |
|
|
def reallocate_registers(instructions, registers):
|
39 |
|
|
|
40 |
|
|
register_map = {}
|
41 |
|
|
new_registers = {}
|
42 |
|
|
n = 0
|
43 |
|
|
for register, definition in registers.iteritems():
|
44 |
|
|
register_map[register] = n
|
45 |
|
|
new_registers[n] = definition
|
46 |
|
|
n+=1
|
47 |
|
|
|
48 |
|
|
for instruction in instructions:
|
49 |
|
|
if "dest" in instruction:
|
50 |
|
|
instruction["dest"] = register_map[instruction["dest"]]
|
51 |
|
|
if "src" in instruction:
|
52 |
|
|
instruction["src"] = register_map[instruction["src"]]
|
53 |
|
|
if "srcb" in instruction:
|
54 |
|
|
instruction["srcb"] = register_map[instruction["srcb"]]
|
55 |
|
|
|
56 |
|
|
return instructions, new_registers
|
57 |
|
|
|
58 |
|
|
def cleanup_registers(instructions, registers):
|
59 |
|
|
|
60 |
|
|
#find all the registers that are read from.
|
61 |
|
|
used_registers = {}
|
62 |
|
|
for instruction in instructions:
|
63 |
|
|
if "src" in instruction:
|
64 |
|
|
used_registers[instruction["src"]] = None
|
65 |
|
|
if "srcb" in instruction:
|
66 |
|
|
used_registers[instruction["srcb"]] = None
|
67 |
|
|
|
68 |
|
|
#remove them from the list of allocated registers
|
69 |
|
|
kept_registers = {}
|
70 |
|
|
for register, description in registers.iteritems():
|
71 |
|
|
if register in used_registers:
|
72 |
|
|
kept_registers[register] = description
|
73 |
|
|
|
74 |
|
|
#remove all instructions that read from unused registers
|
75 |
|
|
kept_instructions = []
|
76 |
|
|
for instruction in instructions:
|
77 |
|
|
if "dest" in instruction:
|
78 |
|
|
if instruction["dest"] in kept_registers:
|
79 |
|
|
kept_instructions.append(instruction)
|
80 |
|
|
else:
|
81 |
|
|
kept_instructions.append(instruction)
|
82 |
|
|
|
83 |
|
|
return reallocate_registers(kept_instructions, kept_registers)
|
84 |
|
|
|
85 |
|
|
def parallelise(instructions):
|
86 |
|
|
|
87 |
|
|
def modifies_register(instruction):
|
88 |
|
|
|
89 |
|
|
"""Return the register modified by this instruction if any"""
|
90 |
|
|
|
91 |
|
|
if "dest" in instruction:
|
92 |
|
|
return instruction["dest"]
|
93 |
|
|
return None
|
94 |
|
|
|
95 |
|
|
def uses_registers(instruction):
|
96 |
|
|
|
97 |
|
|
"""Return the registers used by this instruction if any"""
|
98 |
|
|
|
99 |
|
|
registers = []
|
100 |
|
|
for field in ["src", "srcb"]:
|
101 |
|
|
if field in instruction:
|
102 |
|
|
registers.append(instruction[field])
|
103 |
|
|
return registers
|
104 |
|
|
|
105 |
|
|
def memory_clash(a, b):
|
106 |
|
|
|
107 |
|
|
"""do instructions result in a memory clash"""
|
108 |
|
|
|
109 |
|
|
if a["op"] in ["memory_write", "memory_write_literal"]:
|
110 |
|
|
return b["op"] in ["memory_write", "memory_write_literal", "memory_read", "memory_read_wait", "memory_read_request"]
|
111 |
|
|
|
112 |
|
|
if b["op"] in ["memory_write", "memory_write_literal"]:
|
113 |
|
|
return a["op"] in ["memory_write", "memory_write_literal", "memory_read", "memory_read_wait", "memory_read_request"]
|
114 |
|
|
|
115 |
|
|
if a["op"] in ["memory_read", "memory_read_wait", "memory_read_request", "memory_write", "memory_write_literal"]:
|
116 |
|
|
return b["op"] == a["op"]
|
117 |
|
|
|
118 |
|
|
if b["op"] in ["memory_read", "memory_read_wait", "memory_read_request", "memory_write", "memory_write_literal"]:
|
119 |
|
|
return b["op"] == a["op"]
|
120 |
|
|
|
121 |
|
|
def is_part_of_read(a, b):
|
122 |
|
|
|
123 |
|
|
"""requests, waits and reads with the same sequence number must not be concurrent"""
|
124 |
|
|
|
125 |
|
|
read_instructions = ["memory_read_request", "memory_read_wait", "memory_read"]
|
126 |
|
|
if (a["op"] in read_instructions) and (b["op"] in read_instructions):
|
127 |
|
|
return a["sequence"] == b["sequence"]
|
128 |
|
|
return False
|
129 |
|
|
|
130 |
|
|
def is_solitary(instruction):
|
131 |
|
|
|
132 |
|
|
"""Return True if an instruction cannot be executed in parallel with other instructions"""
|
133 |
|
|
|
134 |
|
|
return instruction["op"] in ["read", "write", "ready", "label", "/", "%"]
|
135 |
|
|
|
136 |
|
|
def is_jump(instruction):
|
137 |
|
|
|
138 |
|
|
"""Return True if an instruction contains a branch or jump"""
|
139 |
|
|
|
140 |
|
|
return instruction["op"] in ["goto", "jmp_if_true", "jmp_if_false", "jmp_and_link",
|
141 |
|
|
"jmp_to_reg"]
|
142 |
|
|
|
143 |
|
|
def is_dependent(instruction, frame, preceding):
|
144 |
|
|
|
145 |
|
|
"""determine whether an instruction is dependent on the outcome of:
|
146 |
|
|
- an instruction within the current frame
|
147 |
|
|
- preceding instructions not within the frame """
|
148 |
|
|
|
149 |
|
|
for i in frame + preceding:
|
150 |
|
|
if modifies_register(i) is not None:
|
151 |
|
|
if modifies_register(i) in uses_registers(instruction):
|
152 |
|
|
return True
|
153 |
|
|
if modifies_register(i) == modifies_register(instruction):
|
154 |
|
|
return True
|
155 |
|
|
if memory_clash(i, instruction):
|
156 |
|
|
return True
|
157 |
|
|
if is_part_of_read(i, instruction):
|
158 |
|
|
return True
|
159 |
|
|
if is_jump(i):
|
160 |
|
|
return True
|
161 |
|
|
for i in preceding:
|
162 |
|
|
if modifies_register(instruction) is not None:
|
163 |
|
|
if modifies_register(instruction) in uses_registers(i):
|
164 |
|
|
return True
|
165 |
|
|
if memory_clash(i, instruction):
|
166 |
|
|
return True
|
167 |
|
|
if is_part_of_read(i, instruction):
|
168 |
|
|
return True
|
169 |
|
|
if is_jump(instruction) and preceding:
|
170 |
|
|
return True
|
171 |
|
|
return False
|
172 |
|
|
|
173 |
|
|
def add_instructions(frame, instructions):
|
174 |
|
|
|
175 |
|
|
"""Add more instructions to the current frame if dependencies allow."""
|
176 |
|
|
|
177 |
|
|
instructions_added = True
|
178 |
|
|
while instructions_added:
|
179 |
|
|
instructions_added = False
|
180 |
|
|
for index, instruction in enumerate(instructions):
|
181 |
|
|
if is_solitary(instruction):
|
182 |
|
|
return
|
183 |
|
|
for i in frame:
|
184 |
|
|
if is_jump(i):
|
185 |
|
|
return
|
186 |
|
|
if is_solitary(i):
|
187 |
|
|
return
|
188 |
|
|
if not is_dependent(instruction, frame, instructions[:index]):
|
189 |
|
|
frame.append(instructions.pop(index))
|
190 |
|
|
instructions_added = True
|
191 |
|
|
break
|
192 |
|
|
|
193 |
|
|
frames = []
|
194 |
|
|
while instructions:
|
195 |
|
|
frame = [instructions.pop(0)]
|
196 |
|
|
add_instructions(frame, instructions)
|
197 |
|
|
frames.append(frame)
|
198 |
|
|
|
199 |
|
|
return frames
|