Skip to content

Commit 5210a78

Browse files
committed
Improve optimizers and fix print double-quoting
1 parent 9837843 commit 5210a78

File tree

2 files changed

+156
-50
lines changed

2 files changed

+156
-50
lines changed

compiler/ir.py

Lines changed: 152 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,12 @@ def __init__(self, downstream=None):
149149
self.downstream = downstream
150150

151151
def emit(self, insn):
152+
#print(self.__class__.__name__, "emits", insn)
152153
if self.downstream:
153154
self.downstream.handle_insn(insn)
154155

155156
def handle_insn(self, insn):
157+
#print(self.__class__.__name__, "receives", insn)
156158
self.insn_func_map[type(insn)](insn)
157159

158160
def handle_fn_begin(self, insn):
@@ -257,82 +259,170 @@ def node_debug(node):
257259

258260
class OptimizerLoop(IRVisitor):
259261

260-
def handle_insn(self, insn):
261-
#print("DOWNSTREAM", node_debug(insn))
262-
super().handle_insn(insn)
262+
def __init__(self, upstream, downstream):
263+
super().__init__(downstream)
264+
self.upstream = upstream
265+
self.buffer = []
266+
267+
def emit(self, insn):
268+
self.buffer.append(insn)
269+
270+
def handle_fn_end(self, insn):
271+
self.emit(insn)
272+
if self._success:
273+
for insn in self.buffer:
274+
self.upstream.handle_insn(insn)
275+
else:
276+
for insn in self.buffer:
277+
super().emit(insn)
278+
self.buffer = []
279+
280+
def new_fn(self):
281+
self.buffer = []
282+
self._success = False
283+
284+
def report_success(self):
285+
self._success = True
263286

264287
class Optimizer(IRVisitor):
265288

266289
def __init__(self, downstream):
267-
optimizer = OptimizerLoop(downstream)
268-
optimizer = ConstantElimination(optimizer)
269-
optimizer = JumpElimination(optimizer)
290+
loop = OptimizerLoop(self, downstream)
291+
optimizer = loop
292+
optimizer = ConstantElimination(loop, optimizer)
293+
optimizer = JumpElimination(loop, optimizer)
294+
optimizer = DeadCodeElimination(loop, optimizer)
270295
super().__init__(optimizer)
296+
self.loop = loop
297+
298+
def handle_entity_local(self, insn):
299+
# This appears before functions begin, pass straight through
300+
self.loop.downstream.handle_insn(insn)
301+
302+
def handle_fn_begin(self, insn):
303+
self.loop.new_fn()
304+
self.emit(insn)
271305

272306
def handle_insn(self, insn):
273307
#print("UPSTREAM", node_debug(insn))
274308
super().handle_insn(insn)
275309

276-
class JumpElimination(IRVisitor):
310+
class OptimizerVisitor(IRVisitor):
277311

278-
def __init__(self, downstream):
312+
def __init__(self, loop, downstream):
279313
super().__init__(downstream)
280-
self.buffer = []
281-
self.aliases = {}
282-
self.previous = None
314+
self.loop = loop
315+
self.init()
316+
317+
def init(self):
318+
pass
319+
320+
def success(self):
321+
# print("SUCCESS from", self.__class__.__name__)
322+
self.loop.report_success()
323+
324+
class DeadCodeElimination(OptimizerVisitor):
325+
326+
def init(self):
327+
self.dead = False
283328

284329
def emit(self, insn):
285-
self.buffer.append(insn)
286-
self.previous = insn
330+
if not self.dead:
331+
super().emit(insn)
332+
333+
def handle_entity_local(self, insn):
334+
self.dead = False
335+
self.emit(insn)
287336

288337
def handle_fn_begin(self, insn):
338+
self.dead = False
289339
self.emit(insn)
290340

291341
def handle_fn_end(self, insn):
342+
self.dead = False
292343
self.emit(insn)
293-
for i in self.buffer:
294-
if isinstance(i, (IR.Jump, IR.JumpIf, IR.JumpIfNot)):
295-
aliases = self.aliases[i.dest]
296-
if aliases:
297-
i = i._replace(dest=aliases[0])
298-
super().emit(i)
344+
345+
def handle_jump(self, insn):
346+
self.emit(insn)
347+
self.dead = True
348+
349+
def handle_label(self, insn):
350+
self.dead = False
351+
self.emit(insn)
352+
353+
class JumpElimination(OptimizerVisitor):
354+
355+
def init(self):
299356
self.buffer = []
300357
self.aliases = {}
301358
self.previous = None
359+
self.label_used = {}
360+
self.aliases_of = {}
302361

303-
def handle_label(self, label):
304-
if not label in self.aliases:
305-
self.aliases[label] = []
306-
if isinstance(self.previous, IR.Label):
307-
self.aliases[label].append(self.previous)
308-
emit = False
309-
else:
310-
emit = True
311-
for i in range(1, 3):
312-
if len(self.buffer) < i:
313-
continue
314-
prev = self.buffer[-i]
315-
if isinstance(prev, (IR.Jump, IR.JumpIf, IR.JumpIfNot)):
316-
if prev.dest == label or \
317-
prev.dest in self.aliases[label]:
318-
self.buffer.pop(-i)
319-
break
320-
if emit:
321-
self.emit(label)
362+
def emit(self, insn):
363+
self.buffer.append(insn)
364+
self.previous = insn
365+
366+
def is_jump(self, insn):
367+
return isinstance(insn, (IR.Jump, IR.JumpIf, IR.JumpIfNot))
322368

323369
def handle_jump(self, insn):
370+
self.uses_label(insn.dest)
324371
self.emit(insn)
325372

326373
def handle_jump_if(self, insn):
374+
self.uses_label(insn.dest)
327375
self.emit(insn)
328376

329377
def handle_jump_if_not(self, insn):
378+
self.uses_label(insn.dest)
330379
self.emit(insn)
331380

332-
class ConstantElimination(IRVisitor):
381+
def uses_label(self, label):
382+
self.label_used[label] = True
333383

334-
def __init__(self, downstream):
335-
super().__init__(downstream)
384+
def handle_fn_begin(self, insn):
385+
self.init()
386+
self.emit(insn)
387+
388+
def label_is_used(self, label):
389+
if label in self.label_used:
390+
return True
391+
if label not in self.aliases_of:
392+
return False
393+
# Label is used if any of its aliases are used
394+
return any(filter(self.label_is_used, self.aliases_of[label]))
395+
396+
def handle_fn_end(self, insn):
397+
self.emit(insn)
398+
for insn in self.buffer:
399+
if self.is_jump(insn):
400+
old_label = insn.dest
401+
if old_label in self.aliases:
402+
self.success()
403+
insn = insn._replace(dest=self.aliases[old_label])
404+
elif isinstance(insn, IR.Label):
405+
if not self.label_is_used(insn):
406+
# Label not used, remove
407+
self.success()
408+
continue
409+
super().emit(insn)
410+
411+
def handle_label(self, label):
412+
if isinstance(self.previous, IR.Label):
413+
# If the previous was a label, then we are simply an alias of it
414+
self.aliases[label] = self.previous
415+
self.aliases_of.setdefault(self.previous, []).append(label)
416+
return
417+
if isinstance(self.previous, IR.Jump):
418+
# If the previous was a jump to this label, eliminate the jump
419+
if self.previous.dest == label:
420+
self.buffer.pop()
421+
self.emit(label)
422+
423+
class ConstantElimination(OptimizerVisitor):
424+
425+
def init(self):
336426
self.slot_value_map = {}
337427

338428
def literal(self, ref):
@@ -359,11 +449,27 @@ def handle_jump(self, insn):
359449

360450
def handle_jump_if(self, insn):
361451
self.slot_value_map = {}
362-
self.emit(insn)
452+
cond = self.literal(insn.cond)
453+
if cond is not None:
454+
self.success()
455+
if cond != 0:
456+
self.emit(IR.Jump(insn.dest))
457+
else:
458+
pass # just don't jump
459+
else:
460+
self.emit(insn)
363461

364462
def handle_jump_if_not(self, insn):
365463
self.slot_value_map = {}
366-
self.emit(insn)
464+
cond = self.literal(insn.cond)
465+
if cond is not None:
466+
self.success()
467+
if cond != 0:
468+
pass # just don't jump
469+
else:
470+
self.emit(IR.Jump(insn.dest))
471+
else:
472+
self.emit(insn)
367473

368474
def handle_call(self, insn):
369475
self.slot_value_map = {}
@@ -401,10 +507,13 @@ def handle_operation(self, insn):
401507
val = func(left, right)
402508
if type(val) == bool: # for boolean evaluations
403509
val = 1 if val else 0
510+
self.success()
404511
self.handle_insn(IR.Move(self.int(val), insn.dest))
405512
elif i_mode & 2 and left == ident:
513+
self.success()
406514
self.handle_insn(IR.Move(insn.right, insn.dest))
407515
elif i_mode & 1 and right == ident:
516+
self.success()
408517
self.handle_insn(IR.Move(insn.left, insn.dest))
409518
else:
410519
if insn.dest in self.slot_value_map:

compiler/lib/stdio.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,11 @@ def printf(visitor, expr):
1010
visitor.emit(IR.Print(tuple(map(visitor.eliminate_offset, args))))
1111
return IR.ReturnRegister
1212

13-
def quote(string):
14-
return '"%s"' % string.replace('"', '\\"')
15-
1613
def string_format(visitor, template, args):
1714
ret = []
1815
if template == '':
1916
assert not args
20-
return ['""']
17+
return ['']
2118
section = template
2219
ind = section.find('%')
2320
while ind != -1 and args:
@@ -30,15 +27,15 @@ def string_format(visitor, template, args):
3027
else:
3128
assert False
3229
if isinstance(arg, IR.LiteralString):
33-
arg = quote(arg.val)
30+
arg = arg.val
3431
before = section[:ind]
3532
if before:
36-
ret.append(quote(before))
33+
ret.append(before)
3734
ret.append(arg)
3835
section = section[ind+2:]
3936
ind = section.find('%')
4037
if ind == -1 and section:
41-
ret.append(quote(section))
38+
ret.append(section)
4239
assert ind == -1 and not args
4340
return ret
4441

0 commit comments

Comments
 (0)