public List <Instruction> CodeGen() { var b = new List <Instruction>(); //int args or null in r8 if (args.ints.Count > 0) { for (int i = 0; i < args.ints.Count; i++) { b.AddRange(new SAssign { source = new ArithSExpr(args.ints[i], ArithSpec.Add, IntSExpr.Zero), target = FieldSRef.VarField(RegVRef.rScratchInts, "signal-" + (i + 1)), }.CodeGen()); } } else { b.AddRange(new VAssign { source = RegVRef.rNull, target = RegVRef.rScratchInts, }.CodeGen()); } //table arg or null in r7 b.AddRange(new VAssign { source = args.vars.Count > 0? args.vars[1] : RegVRef.rNull, target = RegVRef.rVarArgs, }.CodeGen()); //TODO: table args 2-n //jump to function, with return in r8.0 b.Add(new Jump { target = new AddrSExpr(name), callsite = FieldSRef.CallSite, frame = PointerIndex.ProgConst, }); // return values are in r7/r8 for use by following code //capture returned values //if (sreturn != null) b.AddRange(new SAssign { source = FieldSRef.SReturn, target = sreturn, }.CodeGen()); //if (vreturn != null) b.AddRange(new VAssign { source = RegVRef.rVarArgs, target = (VRef)vreturn ?? RegVRef.rNull, }.CodeGen()); return(b); }
public List <Instruction> BuildFunction() { var b = new List <Instruction>(); // save call site (in r8.signal-0) b.Add(new Push(RegVRef.rScratchInts)); if (localints.Count > 0) { // save parent localints b.Add(new Push(RegVRef.rLocalInts("parent"))); } // push regs as needed foreach (var sym in locals.Where(s => s.type == SymbolType.Register)) { if (sym.fixedAddr.HasValue) { b.Add(new Push(new RegVRef(sym.fixedAddr.Value))); } } // wind stack down for locals if needed if (framesize > 0) { b.Add(new Instruction { opcode = Opcode.Add, op1 = FieldSRef.Imm1(), imm1 = new IntSExpr(-framesize), acc = true, dest = FieldSRef.Pointer(PointerIndex.CallStack) }); } // copy params if named //int args or null in r8 var intparas = locals.Where(sym => sym.type == SymbolType.Parameter && sym.datatype == "int").ToList(); if (intparas.Count() > 0) { for (int i = 0; i < intparas.Count(); i++) { b.Add(new Instruction { opcode = Opcode.Add, op1 = FieldSRef.IntArg(name, intparas[i].name), dest = FieldSRef.LocalInt(name, intparas[i].name), acc = i != 0, }); } } FieldSRef.ResetScratchInts(); b.AddRange(RegVRef.rScratchInts.PutFromReg(RegVRef.rNull)); // body b.AddRange(body.CodeGen()); // convert rjmp __return => rjmp <integer> to here. for (int i = 0; i < b.Count; i++) { var inst = b[i]; if ((inst.imm1 as AddrSExpr)?.symbol == "__return") { inst.imm1 = new IntSExpr(b.Count - i); } if ((inst.imm2 as AddrSExpr)?.symbol == "__return") { inst.imm2 = new IntSExpr(b.Count - i); } b[i] = inst; } // wind stack back up for locals if needed if (framesize > 0) { b.Add(new Instruction { opcode = Opcode.Add, op1 = FieldSRef.Imm1(), imm1 = new IntSExpr(framesize), acc = true, dest = FieldSRef.Pointer(PointerIndex.CallStack) }); } // restore registers foreach (var sym in locals.Where(s => s.type == SymbolType.Register).Reverse()) { if (sym.fixedAddr.HasValue) { b.Add(new Pop(new RegVRef(sym.fixedAddr.Value))); } } if (localints.Count > 0) { // restore parent localints b.Add(new Pop(RegVRef.rLocalInts("parent"))); } // get return site b.Add(new Exchange(RegVRef.rScratchTab)); b.Add(new Instruction { opcode = Opcode.Sub, op1 = FieldSRef.VarField(RegVRef.rScratchTab, "signal-0"), op2 = FieldSRef.CallSite, dest = FieldSRef.CallSite, acc = true }); b.Add(new Pop(RegVRef.rScratchTab)); // jump to return site b.Add(new Jump { target = FieldSRef.CallSite }); return(b); }