Mercurial > lcfOS
view python/ppci/transform.py @ 361:614a7f6d4d4d
Fixed test
author | Windel Bouwman |
---|---|
date | Fri, 14 Mar 2014 16:18:54 +0100 |
parents | c2ddc8a36f5e |
children | c49459768aaa |
line wrap: on
line source
""" Transformation to optimize IR-code """ import logging from . import ir # Standard passes: class FunctionPass: def __init__(self): self.logger = logging.getLogger(str(self.__class__.__name__)) def run(self, ir_module): """ Main entry point for the pass """ self.logger.debug('Running pass {}'.format(self.__class__.__name__)) self.prepare() if isinstance(ir_module, ir.Module): for f in ir_module.Functions: self.onFunction(f) elif isinstance(ir_module, ir.Function): self.onFunction(ir_module) else: raise Exception() def onFunction(self, f): """ Override this virtual method """ raise NotImplementedError() def prepare(self): pass class BasicBlockPass(FunctionPass): def onFunction(self, f): for bb in f.Blocks: self.onBasicBlock(bb) def onBasicBlock(self, bb): """ Override this virtual method """ raise NotImplementedError() class InstructionPass(BasicBlockPass): def onBasicBlock(self, bb): for ins in iter(bb.Instructions): self.onInstruction(ins) def onInstruction(self, ins): """ Override this virtual method """ raise NotImplementedError() class BasePass(BasicBlockPass): def onBasicBlock(self, bb): pass # Usefull transforms: class ConstantFolder(BasePass): def __init__(self): super().__init__() self.ops = {} self.ops['+'] = lambda x, y: x + y self.ops['-'] = lambda x, y: x - y self.ops['*'] = lambda x, y: x * y self.ops['<<'] = lambda x, y: x << y def postExpr(self, expr): if type(i) is BinaryOperator and i.operation in self.ops.keys() and type(i.a) is Const and type(i.b) is Const: vr = self.ops[i.operation](i.a.value, i.b.value) return Const(vr) else: return expr class DeadCodeDeleter(BasicBlockPass): def onBasicBlock(self, bb): def instructionUsed(ins): if not type(ins) in [ImmLoad, BinaryOperator]: return True if len(ins.defs) == 0: # In case this instruction does not define any # variables, assume it is usefull. return True return any(d.Used for d in ins.defs) change = True while change: change = False for i in bb.Instructions: if instructionUsed(i): continue bb.removeInstruction(i) change = True class CommonSubexpressionElimination(BasicBlockPass): def onBasicBlock(self, bb): constMap = {} to_remove = [] for i in bb.Instructions: if isinstance(i, ImmLoad): if i.value in constMap: t_new = constMap[i.value] t_old = i.target logging.debug('Replacing {} with {}'.format(t_old, t_new)) t_old.replaceby(t_new) to_remove.append(i) else: constMap[i.value] = i.target elif isinstance(i, BinaryOperator): k = (i.value1, i.operation, i.value2) if k in constMap: t_old = i.result t_new = constMap[k] logging.debug('Replacing {} with {}'.format(t_old, t_new)) t_old.replaceby(t_new) to_remove.append(i) else: constMap[k] = i.result for i in to_remove: self.logger.debug('removing {}'.format(i)) bb.removeInstruction(i) child_nodes = {} child_nodes[ir.Binop] = ['a', 'b'] child_nodes[ir.Const] = [] child_nodes[ir.Temp] = [] child_nodes[ir.Exp] = ['e'] child_nodes[ir.Mem] = ['e'] child_nodes[ir.Addr] = ['e'] child_nodes[ir.LocalVariable] = [] child_nodes[ir.Parameter] = [] child_nodes[ir.Jump] = [] child_nodes[ir.Terminator] = [] child_nodes[ir.Call] = ['arguments'] child_nodes[ir.CJump] = ['a', 'b'] child_nodes[ir.Move] = ['src', 'dst'] def apply_function(x, f): """ Recursively apply function """ # Handle list: if type(x) is list: for i in range(len(x)): x[i] = apply_function(x[i], f) return x # Normal node: for child in child_nodes[type(x)]: v = getattr(x, child) v = apply_function(v, f) assert not (v is None) setattr(x, child, v) # Apply function! return f(x) class ExpressionFixer(InstructionPass): def onInstruction(self, i): apply_function(i, self.grok) class RemoveAddZero(ExpressionFixer): def grok(self, v): if type(v) is ir.Binop: if v.operation == '+': if type(v.b) is ir.Const and v.b.value == 0: self.logger.debug('Folding {} to {}'.format(v, v.a)) return v.a elif v.operation == '*': if type(v.b) is ir.Const and v.b.value == 1: self.logger.debug('Multiple 1 {} to {}'.format(v, v.a)) return v.a return v class CleanPass(FunctionPass): def onFunction(self, f): self.remove_empty_blocks(f) self.remove_one_preds(f) def remove_empty_blocks(self, f): """ Remove empty basic blocks from function. """ # If a block only contains a branch, it can be removed: empty = lambda b: type(b.FirstInstruction) is ir.Jump empty_blocks = list(filter(empty, f.Blocks)) for b in empty_blocks: # Update predecessors preds = b.Predecessors if b not in preds + [f.entry]: # Do not remove if preceeded by itself tgt = b.LastInstruction.target for pred in preds: pred.LastInstruction.changeTarget(b, tgt) self.logger.debug('Removing empty block: {}'.format(b)) f.removeBlock(b) def remove_one_preds(self, f): """ Remove basic blocks with only one predecessor """ change = True while change: change = False for block in f.Blocks: preds = block.Predecessors if len(preds) == 1 and block not in preds and type(preds[0].LastInstruction) is ir.Jump and block is not f.epiloog: self.glue_blocks(preds[0], block, f) change = True def glue_blocks(self, block1, block2, f): """ Glue two blocks together into the first block """ self.logger.debug('Merging {} and {}'.format(block1.name, block2.name)) # Remove the last jump: block1.removeInstruction(block1.LastInstruction) # Copy all instructions to block1: for instruction in block2.Instructions: block1.addInstruction(instruction) # This does not work somehow: #block2.parent.removeBlock(block2)