Mercurial > lcfOS
changeset 275:6f2423df0675
Fixed serve arm-as
author | Windel Bouwman |
---|---|
date | Sat, 14 Sep 2013 17:29:10 +0200 |
parents | ea93e0a7a31e |
children | 56d37ed4b4d2 |
files | python/c3/analyse.py python/c3/codegenerator.py python/canon.py python/codegenarm.py python/cortexm3.py python/instructionselector.py python/ir/__init__.py python/ir/module.py python/irmach.py python/registerallocator.py python/serve_arm_as.py python/target.py python/tcodegen.py python/testasm.py util/serve_arm_as.py |
diffstat | 15 files changed, 598 insertions(+), 191 deletions(-) [+] |
line wrap: on
line diff
--- a/python/c3/analyse.py Wed Sep 04 17:35:06 2013 +0200 +++ b/python/c3/analyse.py Sat Sep 14 17:29:10 2013 +0200 @@ -124,6 +124,10 @@ ft = sym.typ ft.returntype = self.resolveType(ft.returntype, sym.scope) ft.parametertypes = [self.resolveType(pt, sym.scope) for pt in ft.parametertypes] + # Mark local variables: + for d in sym.declarations: + if isinstance(d, Variable): + d.isLocal = True elif type(sym) is DefinedType: sym.typ = self.resolveType(sym.typ, sym.scope)
--- a/python/c3/codegenerator.py Wed Sep 04 17:35:06 2013 +0200 +++ b/python/c3/codegenerator.py Sat Sep 14 17:29:10 2013 +0200 @@ -35,7 +35,6 @@ f = self.newFunction(s.name) self.funcMap[s] = f for v in pkg.innerScope.Variables: - #print(v) self.varMap[v] = self.newTemp() for s in pkg.innerScope.Functions: self.genFunction(s) @@ -54,15 +53,14 @@ for sym in fn.innerScope: # TODO: handle parameters different if sym.isParameter: - print('param', sym) v = ir.Parameter(sym.name) f.addParameter(v) elif sym.isLocal: - print('local', sym) - v = self.newTemp() + v = ir.LocalVariable(sym.name) + f.addLocal(v) else: - v = self.newTemp() - #raise NotImplementedError('{}'.format(sym)) + #v = self.newTemp() + raise NotImplementedError('{}'.format(sym)) # TODO: make this ssa here?? self.varMap[sym] = v @@ -84,7 +82,7 @@ lval = self.genExprCode(code.lval) self.emit(ir.Move(lval, rval)) elif type(code) is astnodes.ExpressionStatement: - self.genExprCode(code.ex) + self.emit(ir.Exp(self.genExprCode(code.ex))) elif type(code) is astnodes.IfStatement: bbtrue = self.newBlock() bbfalse = self.newBlock()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/canon.py Sat Sep 14 17:29:10 2013 +0200 @@ -0,0 +1,128 @@ + +import ir +from itertools import chain + +def make(function, frame): + """ + Create canonicalized version of the IR-code. This means: + - Calls out of expressions. + - Other things? + """ + # Change the tree. This modifies the IR-tree! + # Move all parameters into registers + parmoves = [] + for p in function.arguments: + pt = newTemp() + frame.parMap[p] = pt + parmoves.append(ir.Move(pt, frame.argLoc(p.num))) + function.entry.instructions = parmoves + function.entry.instructions + + for block in function.Blocks: + for stmt in block.instructions: + rewriteStmt(stmt, frame) + linearize(block) + +# Visit all nodes with some function: +# TODO: rewrite into visitor. + +# Rewrite rewrites call instructions into Eseq instructions. + +def rewriteStmt(stmt, frame): + if isinstance(stmt, ir.Jump): + pass + elif isinstance(stmt, ir.CJump): + stmt.a = rewriteExp(stmt.a, frame) + stmt.b = rewriteExp(stmt.b, frame) + elif isinstance(stmt, ir.Move): + stmt.src = rewriteExp(stmt.src, frame) + stmt.dst = rewriteExp(stmt.dst, frame) + elif isinstance(stmt, ir.Terminator): + pass + elif isinstance(stmt, ir.Exp): + stmt.e = rewriteExp(stmt.e, frame) + else: + raise NotImplementedError('STMT NI: {}'.format(stmt)) + +newTemp = ir.NamedClassGenerator('canon_reg', ir.Temp).gen + +def rewriteExp(exp, frame): + if isinstance(exp, ir.Binop): + exp.a = rewriteExp(exp.a, frame) + exp.b = rewriteExp(exp.b, frame) + return exp + elif isinstance(exp, ir.Const): + return exp + elif isinstance(exp, ir.Temp): + return exp + elif isinstance(exp, ir.Parameter): + return frame.parMap[exp] + elif isinstance(exp, ir.LocalVariable): + offset = frame.allocVar(exp) + return ir.Mem(ir.Binop(frame.fp, '+', ir.Const(offset))) + elif isinstance(exp, ir.Mem): + exp.e = rewriteExp(exp.e, frame) + return exp + elif isinstance(exp, ir.Call): + exp.arguments = [rewriteExp(p, frame) for p in exp.arguments] + # Rewrite call into eseq: + t = newTemp() + return ir.Eseq(ir.Move(t, exp), t) + else: + raise NotImplementedError('NI: {}'.format(exp)) + +# The flatten functions pull out seq instructions to the sequence list. + +def flattenExp(exp): + if isinstance(exp, ir.Binop): + exp.a, sa = flattenExp(exp.a) + exp.b, sb = flattenExp(exp.b) + return exp, sa + sb + elif isinstance(exp, ir.Temp): + return exp, [] + elif isinstance(exp, ir.Const): + return exp, [] + elif isinstance(exp, ir.Mem): + exp.e, s = flattenExp(exp.e) + return exp, s + elif isinstance(exp, ir.Eseq): + s = flattenStmt(exp.stmt) + exp.e, se = flattenExp(exp.e) + return exp.e, s + se + elif isinstance(exp, ir.Call): + sp = [] + p = [] + for p_, sp_ in (flattenExp(p) for p in exp.arguments): + p.append(p_) + sp.extend(sp_) + exp.arguments = p + return exp, sp + else: + raise NotImplementedError('NI: {}'.format(exp)) + +def flattenStmt(stmt): + if isinstance(stmt, ir.Jump): + return [stmt] + elif isinstance(stmt, ir.CJump): + stmt.a, sa = flattenExp(stmt.a) + stmt.b, sb = flattenExp(stmt.b) + return sa + sb + [stmt] + elif isinstance(stmt, ir.Move): + stmt.dst, sd = flattenExp(stmt.dst) + stmt.src, ss = flattenExp(stmt.src) + return sd + ss + [stmt] + elif isinstance(stmt, ir.Terminator): + return [stmt] + elif isinstance(stmt, ir.Exp): + stmt.e, se = flattenExp(stmt.e) + return se + [stmt] + else: + raise NotImplementedError('STMT NI: {}'.format(stmt)) + + +def linearize(block): + """ + Move seq instructions to top and flatten these in an instruction list + """ + i = list(flattenStmt(s) for s in block.instructions) + block.instructions = list(chain.from_iterable(i)) +
--- a/python/codegenarm.py Wed Sep 04 17:35:06 2013 +0200 +++ b/python/codegenarm.py Sat Sep 14 17:29:10 2013 +0200 @@ -7,109 +7,179 @@ import registerallocator from instructionselector import InstructionSelector import irmach - +from irmach import makeIns +import canon +import asm class ArmFrame(irmach.Frame): """ Arm specific frame for functions. """ - pass + def __init__(self, name): + # We use r7 as frame pointer. + super().__init__(name) + self.regs = ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6'] + self.rv = ir.Temp('special_RV') + self.p1 = ir.Temp('special_P1') + self.p2 = ir.Temp('special_P2') + self.p3 = ir.Temp('special_P3') + self.p4 = ir.Temp('special_P4') + self.fp = ir.Temp('special_FP') + # Pre-colored registers: + self.tempMap = {} + self.tempMap[self.rv] = 'r0' + self.tempMap[self.p1] = 'r1' + self.tempMap[self.p2] = 'r2' + self.tempMap[self.p3] = 'r3' + self.tempMap[self.p4] = 'r4' + self.tempMap[self.fp] = 'r7' + self.locVars = {} + self.parMap = {} + + def argLoc(self, pos): + """ + Gets the function parameter location in IR-code format. + """ + if pos == 0: + return self.p1 + elif pos == 1: + return self.p2 + elif pos == 2: + return self.p3 + elif pos == 3: + return self.p4 + else: + raise NotImplementedError('No more than 4 parameters implemented') + + def allocVar(self, lvar): + if lvar not in self.locVars: + self.locVars[lvar] = self.stacksize + self.stacksize = self.stacksize + 4 + return self.locVars[lvar] + + def EntryExitGlue3(self): + """ + Add code for the prologue and the epilogue. Add a label, the + return instruction and the stack pointer adjustment for the frame. + """ + self.instructions.insert(0, makeIns('{}:'.format(self.name))) + self.instructions.insert(1, makeIns('push {lr, r7}')) + self.instructions.insert(2, makeIns('mov r7, sp')) + self.instructions.insert(3, makeIns('add sp, sp, {}'.format(self.stacksize))) + self.instructions.append(makeIns('sub sp, sp, {}'.format(self.stacksize))) + self.instructions.append(makeIns('pop {pc,r7}')) class ArmInstructionSelector(InstructionSelector): """ Instruction selector for the arm architecture """ - def newFrame(self, name): - return ArmFrame(name) - def munchExpr(self, e): if isinstance(e, ir.Alloc): return 0 + elif isinstance(e, ir.Binop) and e.operation == '+' and isinstance(e.b, ir.Const) and e.b.value < 8: + a = self.munchExpr(e.a) + d = self.newTmp() + self.emit('add %d0, %s0, {}'.format(e.b.value), dst=[d], src=[a]) + return d elif isinstance(e, ir.Binop) and e.operation == '+': - a = self.munchExpr(e.value1) - b = self.munchExpr(e.value2) + a = self.munchExpr(e.a) + b = self.munchExpr(e.b) d = self.newTmp() self.emit('add %d0, %s0, %s1', dst=[d], src=[a, b]) return d + elif isinstance(e, ir.Binop) and e.operation == '-' and isinstance(e.b, ir.Const) and e.b.value < 8: + a = self.munchExpr(e.a) + d = self.newTmp() + self.emit('sub %d0, %s0, {}'.format(e.b.value), dst=[d], src=[a]) + return d elif isinstance(e, ir.Binop) and e.operation == '-': - a = self.munchExpr(e.value1) - b = self.munchExpr(e.value2) + a = self.munchExpr(e.a) + b = self.munchExpr(e.b) d = self.newTmp() self.emit('sub %d0, %s0, %s1', dst=[d], src=[a, b]) return d elif isinstance(e, ir.Binop) and e.operation == '|': - a = self.munchExpr(e.value1) - b = self.munchExpr(e.value2) + a = self.munchExpr(e.a) + b = self.munchExpr(e.b) d = self.newTmp() self.emit('or %d0, %s0, %s1', dst=[d], src=[a, b]) return d elif isinstance(e, ir.Binop) and e.operation == '<<': - a = self.munchExpr(e.value1) - b = self.munchExpr(e.value2) + a = self.munchExpr(e.a) + b = self.munchExpr(e.b) d = self.newTmp() self.emit('lsl %d0, %s0, %s1', dst=[d], src=[a, b]) return d elif isinstance(e, ir.Binop) and e.operation == '*': - a = self.munchExpr(e.value1) - b = self.munchExpr(e.value2) + a = self.munchExpr(e.a) + b = self.munchExpr(e.b) d = self.newTmp() self.emit('mul %d0, %s0, %s1', dst=[d], src=[a, b]) return d - elif isinstance(e, ir.Const): + elif isinstance(e, ir.Const) and e.value < 256: d = self.newTmp() - if e.value < 256: - self.emit('ldr %d0, {}'.format(e.value), dst=[d]) - else: - self.emit('ldrpcrel TODO', dst=[d]) + self.emit('mov %d0, {}'.format(e.value), dst=[d]) + return d + elif isinstance(e, ir.Mem) and isinstance(e.e, ir.Binop) and \ + e.e.operation == '+' and isinstance(e.e.b, ir.Const): + base = self.munchExpr(e.e.a) + d = self.newTmp() + self.emit('ldr %d0, [%s0 + {}]'.format(e.e.b.value), src=[base], dst=[d]) return d elif isinstance(e, ir.Mem): # Load from memory - loc = self.munchExpr(e.e) + base = self.munchExpr(e.e) d = self.newTmp() - self.emit('ldr %d0, [%s0]', src=[loc], dst=[d]) + self.emit('ldr %d0, [%s0]', src=[base], dst=[d]) return d elif isinstance(e, ir.Temp): - return self.getTempReg(e) - elif isinstance(e, ir.Parameter): - offset = 1337 # TODO: determine offset in frame?? - d = self.newTmp() - self.emit('ldr %d0, [sp + {}]'.format(offset), dst=[d]) - return d + return e elif isinstance(e, ir.Call): - args = [self.munchExpr(a) for a in e.arguments] - frame_size = 222 # TODO: determine frame size? - self.emit('add sp, sp, {}'.format(frame_size)) - # TODO: save frame - for a in args: - self.emit('push %s0', src=[a]) - self.emit('bl {}'.format(e.f.name)) - self.emit('sub sp, sp, 22') + # Move arguments into proper locations: + reguses = [] + for i, a in enumerate(e.arguments): + loc = self.frame.argLoc(i) + m = ir.Move(loc, a) + self.munchStm(m) + if isinstance(loc, ir.Temp): + reguses.append(loc) + self.emit('bl {}'.format(e.f.name), src=reguses, dst=[self.frame.rv]) + d = self.newTmp() + self.move(d, self.frame.rv) + return d else: raise NotImplementedError('Expr --> {}'.format(e)) def munchStm(self, s): - if isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem): + if isinstance(s, ir.Terminator): + pass + elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem) and isinstance(s.dst.e, ir.Binop) and s.dst.e.operation == '+' and isinstance(s.dst.e.a, ir.Temp) and isinstance(s.dst.e.b, ir.Const): + val = self.munchExpr(s.src) + self.emit('str %s1, [%s0 + {}]'.format(s.dst.e.b.value), src=[s.dst.e.a, val]) + elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem): memloc = self.munchExpr(s.dst.e) val = self.munchExpr(s.src) - self.emit('str [%s0], %s1', src=[memloc, val]) + self.emit('str %s1, [%s0]', src=[memloc, val]) elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Temp): val = self.munchExpr(s.src) - dreg = self.getTempReg(s.dst) + dreg = s.dst self.emit('mov %d0, %s0', dst=[dreg], src=[val]) + elif isinstance(s, ir.Exp): + # Generate expression code and discard the result. + x = self.munchExpr(s.e) + self.emit('mov r0, r0', src=[x]) elif isinstance(s, ir.Jump): tgt = self.targets[s.target] - self.emit('jmp %l0', jumps=[tgt]) + self.emit('b {}'.format(s.target.name), jumps=[tgt]) elif isinstance(s, ir.CJump): a = self.munchExpr(s.a) b = self.munchExpr(s.b) self.emit('cmp %s0, %s1', src=[a, b]) ntgt = self.targets[s.lab_no] ytgt = self.targets[s.lab_yes] - jmp_ins = self.makeIns('jmp %l0', jumps=[ntgt]) + jmp_ins = makeIns('jmp {}'.format(s.lab_no.name), jumps=[ntgt]) # Explicitely add fallthrough: self.emit('jeq %l0', jumps=[ytgt, jmp_ins]) self.emit2(jmp_ins) - elif isinstance(s, ir.Terminator): - pass else: raise NotImplementedError('Stmt --> {}'.format(s)) @@ -136,7 +206,7 @@ defTemps = set(defTemps) useTemps = set(useTemps) unUsed = defTemps - useTemps - print('Unused:', unUsed) + assert not unUsed for uu in unUsed: inslist.append(irmach.AbstractInstruction('use %s0', src=[uu])) #print(useTemps) @@ -152,26 +222,49 @@ ig = registerallocator.InterferenceGraph(cfg) f.ig = ig - regs = ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7'] ra = registerallocator.RegisterAllocator() - regMap = ra.registerAllocate(ig, regs) - #print(regMap) + regMap = ra.registerAllocate(ig, f.regs, f.tempMap) # Use allocated registers: for i in ilist: i.src = tuple(regMap[t] for t in i.src) i.dst = tuple(regMap[t] for t in i.dst) - #print(i) + + def generateFunc(self, irfunc): + # Create a frame for this function: + frame = ArmFrame(irfunc.name) + # Canonicalize the intermediate language: + canon.make(irfunc, frame) + # print('after canonicalize:') + # irfunc.dump() + self.ins_sel.munchFunction(irfunc, frame) + # print('Selected instructions:') + #for i in frame.instructions: + # print(i) + + # Do register allocation: + self.allocFrame(frame) + # TODO: Peep-hole here? + + # Add label and return and stack adjustment: + frame.EntryExitGlue3() + return frame def generate(self, ircode): # Munch program into a bunch of frames. One frame per function. # Each frame has a flat list of abstract instructions. - frames = self.ins_sel.munchProgram(ircode) - self.frames = frames - for f in frames: - self.allocFrame(f) + # Generate code for all functions: + self.frames = [self.generateFunc(func) for func in ircode.Functions] - # TODO: Peep-hole here - # TODO: Materialize assembly - return frames + # Materialize assembly + # Reparse the register allocated instructions into a stream of + # real instructions. + # TODO: this is ugly via string representations. This could be + # another interface? + assembler = asm.Assembler(target=arm.armtarget, stream=self.outs) + self.outs.selectSection('code') + for frame in self.frames: + for i in frame.instructions: + assembler.assemble_line(str(i)) + return self.frames
--- a/python/cortexm3.py Wed Sep 04 17:35:06 2013 +0200 +++ b/python/cortexm3.py Sat Sep 14 17:29:10 2013 +0200 @@ -1,11 +1,12 @@ import struct import types -from target import Register, Instruction, Target, Imm8, Label, Imm3, LabelRef, Imm32 +from target import Register, Instruction, Target, Imm8, Label, Imm3, LabelRef, Imm32, Imm7 from asmnodes import ASymbol, ANumber, AUnop, ABinop from ppci import CompilerError import ir # TODO: encode this in DSL (domain specific language) +# TBD: is this required? def u16(h): return struct.pack('<H', h) @@ -55,6 +56,30 @@ if r.num < 8: return cls(r.num) +class Reg16Op: + def __init__(self, num): + assert num < 16 + self.num = num + + @classmethod + def Create(cls, vop): + if type(vop) is ASymbol: + name = vop.name + regs = {} + for r in armtarget.registers: + regs[r.name] = r + if name in regs: + r = regs[name] + if r.num < 16: + return cls(r.num) + +class RegSpOp: + @classmethod + def Create(cls, vop): + if type(vop) is ASymbol: + if vop.name.lower() == 'sp': + return cls() + def getRegNum(n): for r in armtarget.registers: if r.num == n: @@ -244,6 +269,7 @@ h = (self.opcode << 11) | (imm5 << 6) | (Rn << 3) | Rt return u16(h) + def __repr__(self): return '{} {}, {}'.format(self.mnemonic, self.rt, self.memloc) @@ -346,6 +372,8 @@ # Arithmatics: + + @armtarget.instruction class addregregimm3_ins(ArmInstruction): """ add Rd, Rn, imm3 """ @@ -391,6 +419,25 @@ mnemonic = 'SUB' opcode = 0b0001101 + +@armtarget.instruction +class movregreg_ext_ins(ArmInstruction): + operands = (Reg16Op, Reg16Op) + mnemonic = 'MOV' + def __init__(self, rd, rm): + self.rd = rd + self.rm = rm + def encode(self): + Rd = self.rd.num & 0x7 + D = (self.rd.num >> 3) & 0x1 + Rm = self.rm.num + opcode = 0b01000110 + return u16((opcode << 8) | (D << 7) |(Rm << 3) | Rd) + def __repr__(self): + return '{} {}, {}'.format(self.mnemonic, self.rd, self.rm) + + + class regreg_base(ArmInstruction): """ ??? Rdn, Rm """ operands = (Reg8Op, Reg8Op) @@ -575,5 +622,32 @@ def encode(self): return u16(0xbf10) +# misc: + +# add/sub SP: +@armtarget.instruction +class addspsp_ins(ArmInstruction): + operands = (RegSpOp, RegSpOp, Imm7) + mnemonic = 'add' + def __init__(self, _sp, _sp2, imm7): + self.imm7 = imm7.imm + assert self.imm7 % 4 == 0 + self.imm7 >>= 2 + + def encode(self): + return u16((0b101100000 << 7) |self.imm7) + +@armtarget.instruction +class subspsp_ins(ArmInstruction): + operands = (RegSpOp, RegSpOp, Imm7) + mnemonic = 'sub' + def __init__(self, _sp, _sp2, imm7): + self.imm7 = imm7.imm + assert self.imm7 % 4 == 0 + self.imm7 >>= 2 + + def encode(self): + return u16((0b101100001 << 7) |self.imm7) + armtarget.check()
--- a/python/instructionselector.py Wed Sep 04 17:35:06 2013 +0200 +++ b/python/instructionselector.py Sat Sep 14 17:29:10 2013 +0200 @@ -1,11 +1,12 @@ import ir import irmach +from irmach import makeIns def genTemps(): n = 900 while True: - yield 't{}'.format(n) + yield ir.Temp('t{}'.format(n)) n = n + 1 class InstructionSelector: @@ -13,51 +14,42 @@ Base instruction selector. This class must be overridden by backends. """ + def __init__(self): + self.temps = genTemps() + def newTmp(self): return self.temps.__next__() - def getTempReg(self, tmp): - if tmp not in self.tempMap: - self.tempMap[tmp] = self.newTmp() - return self.tempMap[tmp] - - def munchProgram(self, p): + def munchFunction(self, f, frame): # Entry point for instruction selection - self.temps = genTemps() - assert isinstance(p, ir.Module) - self.frames = [] + assert isinstance(f, ir.Function) self.targets = {} - self.tempMap = {} # Mapping from temporaries to infinite register - for f in p.Functions: - # Enter a frame per function: - self.frame = self.newFrame(f.name) - self.frames.append(self.frame) - # First define labels: - for bb in f.Blocks: - itgt = self.makeIns('{}:'.format(bb.name)) - self.targets[bb] = itgt - for bb in f.Blocks: - self.emit2(self.targets[bb]) - for i in bb.Instructions: - self.munchStm(i) - #bb.machIns = self.result - return self.frames + # Enter a frame per function: + self.frame = frame + # First define labels: + for bb in f.Blocks: + itgt = makeIns('{}:'.format(bb.name)) + self.targets[bb] = itgt + # Generate code for all blocks: + for bb in f.Blocks: + self.emit2(self.targets[bb]) + for i in bb.Instructions: + self.munchStm(i) + self.munchStm(ir.Move(self.frame.rv, f.return_value)) + self.emit('mov %s0, %s0', src=[self.frame.rv]) - def makeIns(self, *args, **kwargs): - return irmach.AbstractInstruction(*args, **kwargs) + def move(self, dst, src): + self.emit('mov %d0, %s0', src=[src], dst=[dst]) def emit(self, *args, **kwargs): """ Abstract instruction emitter """ - i = self.makeIns(*args, **kwargs) + i = makeIns(*args, **kwargs) return self.emit2(i) def emit2(self, i): self.frame.instructions.append(i) return i - def newFrame(self, name): - raise NotImplementedError() - def munchStm(self, s): """ Implement this in the target specific back-end """ raise NotImplementedError()
--- a/python/ir/__init__.py Wed Sep 04 17:35:06 2013 +0200 +++ b/python/ir/__init__.py Sat Sep 14 17:29:10 2013 +0200 @@ -1,3 +1,3 @@ from .module import * -from .builder import Builder +from .builder import Builder, NamedClassGenerator
--- a/python/ir/module.py Wed Sep 04 17:35:06 2013 +0200 +++ b/python/ir/module.py Sat Sep 14 17:29:10 2013 +0200 @@ -20,9 +20,9 @@ class Module: """ Main container of variables and functions. """ def __init__(self, name): - self.name = name - self.funcs = [] - self.variables = [] + self.name = name + self.funcs = [] + self.variables = [] def __repr__(self): return 'IR-module [{0}]'.format(self.name) @@ -53,17 +53,12 @@ getFunction = findFunction - def dump(self): + def dump(self, indent=' '): print(self) - indent = ' ' for v in self.Variables: print(indent, v) for fn in self.Functions: - print(fn) - for bb in fn.Blocks: - print(indent+str(bb)) - for ins in bb.Instructions: - print(indent * 2 + str(ins)) + fn.dump(indent=indent+' ') # Analysis functions: def check(self): @@ -81,7 +76,9 @@ self.entry = Block('{}_entry'.format(name)) self.epiloog = Block('{}_epilog'.format(name)) self.epiloog.addInstruction(Terminator()) + self.return_value = Temp('{}_retval'.format(name)) self.arguments = [] + self.localvars = [] def __repr__(self): args = ','.join(str(a) for a in self.arguments) @@ -128,17 +125,21 @@ for b in self.Blocks: b.check() - def addParameter(self, pname): - self.arguments.append(pname) + def addParameter(self, p): + assert type(p) is Parameter + p.num = len(self.arguments) + self.arguments.append(p) - def call(self, *args): - varmap = {} - bb = self.Entry - ip = 0 - while True: - i = bb.Instructions[ip] - ip += 1 - return + def addLocal(self, l): + assert type(l) is LocalVariable + self.localvars.append(l) + + def dump(self, indent=''): + print(indent+str(self)) + for bb in self.Blocks: + print(indent+' '+str(bb)) + for ins in bb.Instructions: + print(indent +' '*2 + str(ins)) class Block: @@ -220,7 +221,7 @@ self.value = value def __repr__(self): - return 'Constant {}'.format(self.value) + return 'Const {}'.format(self.value) # Function calling: @@ -231,7 +232,7 @@ self.arguments = arguments def __repr__(self): - args = ','.join([str(arg) for arg in self.arguments]) + args = ', '.join([str(arg) for arg in self.arguments]) return '{}({})'.format(self.f.name, args) @@ -240,12 +241,12 @@ ops = ['+', '-', '*', '/', '|', '&', '<<', '>>'] def __init__(self, value1, operation, value2): assert operation in Binop.ops - self.value1 = value1 - self.value2 = value2 + self.a = value1 + self.b = value2 self.operation = operation def __repr__(self): - a, b = self.value1, self.value2 + a, b = self.a, self.b return '({} {} {})'.format(a, self.operation, b) @@ -254,6 +255,16 @@ return Binop(a, '+', b) +class Eseq(Expression): + """ Sequence of instructions where the last is an expression """ + def __init__(self, stmt, e): + self.stmt = stmt + self.e = e + + def __repr__(self): + return '({}, {})'.format(self.stmt, self.e) + + class Alloc(Expression): """ Allocates space on the stack """ def __init__(self): @@ -272,11 +283,8 @@ class LocalVariable(Variable): - pass - - -class GlobalVariable(Variable): - pass + def __repr__(self): + return 'Local {}'.format(self.name) class Parameter(Variable): @@ -290,7 +298,7 @@ self.name = name def __repr__(self): - return 'T_{}_'.format(self.name) + return 'TMP_{}'.format(self.name) class Mem(Expression): @@ -319,8 +327,12 @@ def __init__(self, e): self.e = e + def __repr__(self): + return '{}'.format(self.e) + class Label(Statement): + # TODO: is this duplicate with block? def __init__(self, name): self.name = name self.statements = [] @@ -351,8 +363,9 @@ class CJump(LastStatement): + conditions = ['==', '<', '>', '>=', '<=', '!='] def __init__(self, a, cond, b, lab_yes, lab_no): - assert cond in ['==', '<', '>', '>=', '<=', '!='] + assert cond in CJump.conditions self.a = a self.cond = cond self.b = b
--- a/python/irmach.py Wed Sep 04 17:35:06 2013 +0200 +++ b/python/irmach.py Sat Sep 14 17:29:10 2013 +0200 @@ -16,10 +16,13 @@ def __init__(self, name): self.name = name self.instructions = [] + self.stacksize = 0 def __repr__(self): - return 'Frame' + return 'Frame {}'.format(self.name) +def makeIns(*args, **kwargs): + return AbstractInstruction(*args, **kwargs) class AbstractInstruction: """ @@ -36,6 +39,24 @@ s = str(self.src) if self.src else '' d = str(self.dst) if self.dst else '' l = str(self.jumps) if self.jumps else '' - return self.assem + s + d + l + #return self.assem + s + d + l + return self.render() + + def render(self): + """ + Substitutes source, dst and labels in the string + """ + x = self.assem + for i, s in enumerate(self.src): + p = '%s{}'.format(i) + x = x.replace(p, str(s)) + for i, d in enumerate(self.dst): + p = '%d{}'.format(i) + x = x.replace(p, str(d)) + for i, j in enumerate(self.jumps): + p = '%l{}'.format(i) + x = x.replace(p, str(j)) + + return x
--- a/python/registerallocator.py Wed Sep 04 17:35:06 2013 +0200 +++ b/python/registerallocator.py Sat Sep 14 17:29:10 2013 +0200 @@ -12,7 +12,9 @@ class InterferenceGraph(graph.Graph): def __init__(self, flowgraph): - """ Create a new interference graph from a flowgraph """ + """ + Create a new interference graph from a flowgraph + """ super().__init__() # Mapping from node to live set self.liveMap = {} @@ -60,12 +62,14 @@ class RegisterAllocator: """ Target independent register allocator """ - def registerAllocate(self, ig, regs): - """ Color the given interference graph with the provided registers """ - regMap = {} + def registerAllocate(self, ig, regs, precolored): + """ + Color the given interference graph with the provided registers + """ + regMap = dict(precolored) regs = set(regs) K = len(regs) - allvars = list(ig.nodes) + allvars = list(n for n in ig.nodes if n.varname not in regMap) # Chaitin's algorithm: # remove all nodes that have less than K neighbours: @@ -85,9 +89,9 @@ possibleregs = set(regs) - set(regMap[n.varname] for n in adj) regMap[n.varname] = list(possibleregs)[0] # We have a register mapping! - #print(self.regMap) + # print(regMap) + # TODO: implement spilling + # TODO: implement coalescing return regMap - # TODO: implement spilling - # TODO: implement coalescing
--- a/python/serve_arm_as.py Wed Sep 04 17:35:06 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ - -import subprocess -import tornado.web - - -def mangle(inp): - p_as = subprocess.Popen(['arm-elf-as', '-mthumb'], stdin=subprocess.PIPE) - p_as.communicate(input=inp.encode('ascii')) - - p_objdump = subprocess.Popen(['arm-elf-objdump', '-d'], stdout=subprocess.PIPE) - output = p_objdump.communicate()[0].decode('ascii') - print(output) - - p_objdump = subprocess.Popen(['arm-elf-objdump', '-s'], stdout=subprocess.PIPE) - output = p_objdump.communicate()[0].decode('ascii') - print(output) - -class MainHandler(tornado.web.RequestHandler): - def get(self): - self.write('Hello') - -if __name__ == '__main__': - inp = """add r1, r2, r3 - """ - inp2 = """blt henkie - bgt henkie - henkie: - """ - mangle(inp2) - -
--- a/python/target.py Wed Sep 04 17:35:06 2013 +0200 +++ b/python/target.py Sat Sep 14 17:29:10 2013 +0200 @@ -22,6 +22,16 @@ if type(vop) is ANumber and vop.number < 256: return cls(vop.number) +class Imm7: + def __init__(self, imm): + assert imm < 128 + self.imm = imm + + @classmethod + def Create(cls, vop): + if type(vop) is ANumber and vop.number < 128: + return cls(vop.number) + class Imm3: def __init__(self, imm): assert imm < 8
--- a/python/tcodegen.py Wed Sep 04 17:35:06 2013 +0200 +++ b/python/tcodegen.py Sat Sep 14 17:29:10 2013 +0200 @@ -40,10 +40,11 @@ a = b + a; cee = a; cee = cee * 2 + cee; - if (cee + a > b and b - a+b== 3*6-b) + insanemath(2, 3); + if (cee + a > b and b - a+b== 3*6-insanemath(b, 2)) { var int x = a; - x = b - a + insanemath(3, 4) - insanemath(33,2); + x = b - a + insanemath(3, 4) - insanemath(33, insanemath(2, 0)); a = x * (x + a); } else @@ -55,6 +56,50 @@ } """ +testsrc = """ +package test3; + +function int ab(int a, int b) +{ + var int c; + c = 0; + c = c + a + b; + return c; +} + +function void tesssst() +{ + var int a, b; + a = 2; + b = 3; + ab(ab(a, b) + ab(9,b), 0); +} +""" +def dump_cfg(cga, cfg_file): + print('digraph G {', file=cfg_file) + #print('edge [constraint=none]', file=cfg_file) + print('rankdir=TB', file=cfg_file) + for f in cga.frames: + print('subgraph cluster_{} {{'.format(f.name), file=cfg_file) + print('label={};'.format(f.name), file=cfg_file) + print('color=lightgrey;', file=cfg_file) + print('style=filled;', file=cfg_file) + f.cfg.to_dot(cfg_file) + print('}', file=cfg_file) + print('}', file=cfg_file) + +def dump_ig(cga, ig_file): + print('digraph G {', file=ig_file) + print('edge [arrowhead=none]', file=ig_file) + for f in cga.frames: + print('subgraph cluster_{} {{'.format(f.name), file=ig_file) + print('label={};'.format(f.name), file=ig_file) + print('color=lightgrey;', file=ig_file) + print('style=filled;', file=ig_file) + f.ig.to_dot(ig_file) + print('}', file=ig_file) + print('}', file=ig_file) + if __name__ == '__main__': diag = ppci.DiagnosticsManager() builder = c3.Builder(diag) @@ -70,32 +115,15 @@ ir2 = cga.generate(irc) with open('cfg.gv', 'w') as cfg_file: - print('digraph G {', file=cfg_file) - #print('edge [constraint=none]', file=cfg_file) - print('rankdir=TB', file=cfg_file) - for f in cga.frames: - print('subgraph cluster_{} {{'.format(f.name), file=cfg_file) - print('label={};'.format(f.name), file=cfg_file) - print('color=lightgrey;', file=cfg_file) - print('style=filled;', file=cfg_file) - f.cfg.to_dot(cfg_file) - print('}', file=cfg_file) - print('}', file=cfg_file) + dump_cfg(cga, cfg_file) with open('ig.gv', 'w') as ig_file: - print('digraph G {', file=ig_file) - print('edge [arrowhead=none]', file=ig_file) - for f in cga.frames: - print('subgraph cluster_{} {{'.format(f.name), file=ig_file) - print('label={};'.format(f.name), file=ig_file) - print('color=lightgrey;', file=ig_file) - print('style=filled;', file=ig_file) - f.ig.to_dot(ig_file) - print('}', file=ig_file) - print('}', file=ig_file) + dump_ig(cga, ig_file) for f in ir2: print(f) for i in f.instructions: print(' {}'.format(i)) + outs.dump() +
--- a/python/testasm.py Wed Sep 04 17:35:06 2013 +0200 +++ b/python/testasm.py Sat Sep 14 17:29:10 2013 +0200 @@ -265,6 +265,13 @@ self.feed('lsl r3, r5') self.check('ab40') + def testModSp(self): + self.feed('add sp,sp,8') + self.feed('add sp,sp,16') + self.feed('sub sp,sp,32') + self.feed('sub sp,sp,4') + self.check('02b004b0 88b081b0') + def testSequence1(self): self.feed('mov r5, 3') self.feed('add r4, r5, 0')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/util/serve_arm_as.py Sat Sep 14 17:29:10 2013 +0200 @@ -0,0 +1,66 @@ + +""" + Tornado webserver interface to arm-elf-as. +""" + +import subprocess +import tornado.web +import tornado.ioloop +import io + +def mangle(inp, outstream): + print('assembling...', file=outstream) + p_as = subprocess.Popen(['arm-elf-as', '-mthumb'], stdin=subprocess.PIPE) + p_as.communicate(input=inp.encode('ascii')) + + p_objdump = subprocess.Popen(['arm-elf-objdump', '-d'], stdout=subprocess.PIPE) + output = p_objdump.communicate()[0].decode('ascii') + print(output, file=outstream) + + p_objdump = subprocess.Popen(['arm-elf-objdump', '-s'], stdout=subprocess.PIPE) + output = p_objdump.communicate()[0].decode('ascii') + print(output, file=outstream) + print('Done!', file=outstream) + +page = """ +<html> +<head> +</head> +<body> +<h1> + +</h1> +<form action="" method="post"> +<textarea name="source" rows="25" cols="80"> +%src% +</textarea> +<br> +<input type="submit" value="Assemble!"> +</form> +<div> +%result% +</div> +</body> +</html> +""" + +class MainHandler(tornado.web.RequestHandler): + def get(self): + src="sub sp,sp,#8" + self.write(page.replace('%result%', '').replace('%src%', src)) + def post(self): + #print(self.request.body) + src = self.get_argument('source') + out = io.StringIO() + mangle(src, out) + txt = out.getvalue() + txt = txt.replace('\n', '<br>') + self.write(page.replace('%result%', txt).replace('%src%', src)) + + +application = tornado.web.Application([(r"/", MainHandler)]) + +if __name__ == '__main__': + application.listen(8888) + tornado.ioloop.IOLoop.instance().start() +