Mercurial > lcfOS
view python/registerallocator.py @ 277:046017431c6a
Started register allocator
author | Windel Bouwman |
---|---|
date | Thu, 26 Sep 2013 21:14:25 +0200 |
parents | 6f2423df0675 |
children | 9fca39eebe50 |
line wrap: on
line source
from flowgraph import FlowGraph from interferencegraph import InterferenceGraph class RegisterAllocator: """ Target independent register allocator. Algorithm is iterated .. (ITR) by Appel and George The process consists of the following steps: - build interference graph from the instruction list - (optional) coalesc registers to remove redundant moves - (optional) spill registers - select registers """ def __init__(self): pass def useUnused(self, inslist): # Use unused temporaries at the end of the list defTemps = [] useTemps = [] for i in inslist: for d in iter(i.dst): defTemps.append(d) for s in iter(i.src): useTemps.append(s) defTemps = set(defTemps) useTemps = set(useTemps) unUsed = defTemps - useTemps assert not unUsed def build(self, f): """ 1. Construct interference graph from instruction list """ self.useUnused(f.instructions) f.cfg = FlowGraph(f.instructions) f.ig = InterferenceGraph(f.cfg) self.pre_colored = set(n for n in f.ig.nodes if n.varname in f.tempMap.keys()) print('pre-colored:', self.pre_colored) self.moves = [i for i in f.instructions if i.ismove] print('move instructions:', self.moves) self.nodestack = [] def getMoveRelated(self, f): mr = set() for i in self.moves: mr.add(f.ig.getNode(i.src[0])) mr.add(f.ig.getNode(i.dst[0])) return mr def simplify(self, f): """ 2. Remove nodes from the graph """ # Chaitin's algorithm: # remove all non move related nodes that have less than K neighbours: # Also do not remove pre-colored nodes. # move_related = self.getMoveRelated(f) #print('move related', move_related) # o_nodes = f.ig.nodes - (self.pre_colored | move_related) o_nodes = f.ig.nodes - self.pre_colored #print('o_nodes', o_nodes) while o_nodes: less_k = [n for n in o_nodes if n.Degree < self.K] if not less_k: raise NotImplementedError('Spilling not implemented') n = less_k[0] self.nodestack.append(n) f.ig.delNode(n) o_nodes.remove(n) def coalesc(self, f): # for mov in ins: # if mov.src is not connected to mov.dst # and the node being coalesced has less than K nodes # of significant degree, then the node can be coalesced. # This is briggs algorithm. for m in self.moves: src = f.ig.getNode(m.src[0]) dst = f.ig.getNode(m.dst[0]) assert not f.ig.hasEdge(src, dst) neighbours = src.Adj | dst.Adj # neighbours with significant degree: sd_nb = set(n for n in neighbours if n.Degree >= self.K) print('neighbours with significant degree', sd_nb) if len(sd_nb) < self.K: print('Coalesc:', m) if dst in self.pre_colored: if src in self.pre_colored: break v2 = src for i in f.instructions: rf = lambda x: x i.src = rf(i.src) i.dst = rf(i.dst) f.instructions.remove(m) def select(self, f): """ Add nodes of less than K degree back to the graph to color it. """ regMap = dict(f.tempMap) # start with pre-colored # Add nodes back to the graph: while self.nodestack: n = self.nodestack.pop(-1) f.ig.addNode(n) takenregs = set(regMap[m.varname] for m in n.Adj) possibleregs = set(self.regs) - takenregs regMap[n.varname] = list(possibleregs)[0] # We have a register mapping! print(regMap) # Use allocated registers: lookup = lambda t: regMap[t] for i in f.instructions: i.src = tuple(map(lookup, i.src)) i.dst = tuple(map(lookup, i.dst)) def allocFrame(self, f): """ Do register allocation for a single stack frame. """ self.regs = set(f.regs) self.K = len(self.regs) self.build(f) self.simplify(f) # TODO: implement spilling #self.coalesc(f) # Optional! self.select(f)