diff --git a/src/main/java/chocopy/pa3/CodeGenImpl.java b/src/main/java/chocopy/pa3/CodeGenImpl.java index e7c8cee1d45128a4958b7e7512c53bec421c4585..f0443026ed9cb3f645ea737d1c46454d87e50eb0 100644 --- a/src/main/java/chocopy/pa3/CodeGenImpl.java +++ b/src/main/java/chocopy/pa3/CodeGenImpl.java @@ -1,9 +1,13 @@ package chocopy.pa3; +import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import chocopy.common.analysis.SymbolTable; import chocopy.common.analysis.AbstractNodeAnalyzer; +import chocopy.common.analysis.types.ValueType; import chocopy.common.astnodes.*; import chocopy.common.codegen.*; @@ -51,8 +55,11 @@ public class CodeGenImpl extends CodeGenBase { backend.emitADDI(FP, SP, 2 * backend.getWordSize(), "Change FP to apply new frame."); // jal will set RA register properly. + // FIXME: Testing fucking silly $print + backend.emitADDI(SP, SP, 3 * backend.getWordSize(), "FUCKING SILLY BUILTIN CODE"); backend.emitJAL(calledLabel, "Call it!"); + backend.emitADDI(SP, FP, -2 * backend.getWordSize(), "Revert all local variables on this dying frame."); emitPop(FP, "restore parent FP."); emitPop(RA, "restore parent return address."); } @@ -62,6 +69,59 @@ public class CodeGenImpl extends CodeGenBase { emitNoop(comment); backend.emitJR(RA, "Return to caller."); } + public void emitPushIntVal(RiscVBackend.Register tmpReg, Integer val, String comment) { + emitNoop(comment); + backend.emitLI(tmpReg, val, "INT VAL"); + emitPush(tmpReg, null); + backend.emitLI(tmpReg, 0, "OBJECT HEAD - DISPATCH TBL = NULL"); + emitPush(tmpReg, null); + backend.emitLI(tmpReg, 4, "OBJECT HEAD - SIZE = 3+1"); + emitPush(tmpReg, null); + backend.emitLI(tmpReg, 1, "OBJECT HEAD - TYPE = INT"); + emitPush(tmpReg, null); + backend.emitADDI(tmpReg, SP, backend.getWordSize(), "Return INT address."); + } + } + + // Every function needs a register manager. + // Every variable should borrow a register, and maybe it's ok to never return it. + // because our toy compiler will only be tested on naive program. + // manager won't swap register to stack smartly (with graph coloring technic), + // because it doesn't worth my effort(nobody pay for that). + private class registerManager { + private Map<RiscVBackend.Register, Boolean> usageMap; // true if the reg is in use. + registerManager() { + usageMap = new LinkedHashMap<>(); + usageMap.put(T0, false); + usageMap.put(T1, false); + usageMap.put(T2, false); + usageMap.put(T3, false); + usageMap.put(T4, false); + usageMap.put(T5, false); + usageMap.put(T6, false); + usageMap.put(A0, false); + usageMap.put(A1, false); + usageMap.put(A2, false); + usageMap.put(A3, false); + usageMap.put(A4, false); + usageMap.put(A5, false); + usageMap.put(A6, false); + usageMap.put(A7, false); + } + + public RiscVBackend.Register borrowOne() { + for(RiscVBackend.Register reg : usageMap.keySet()) { + if(usageMap.put(reg, true) == false) { + return reg; + } + } + throw new RuntimeException("Too many variable, not enough register."); + } + + public void returnOne(RiscVBackend.Register reg) { + boolean old = usageMap.put(reg, false); + assert old == true; + } } /** A code generator emitting instructions to BACKEND. */ @@ -174,6 +234,8 @@ public class CodeGenImpl extends CodeGenBase { * level. */ private FuncInfo funcInfo; + private registerManager regMgr = new registerManager(); + /** An analyzer for the function described by FUNCINFO0, which is null * for the top level. */ StmtAnalyzer(FuncInfo funcInfo0) { @@ -210,19 +272,22 @@ public class CodeGenImpl extends CodeGenBase { if(called instanceof FuncInfo) { FuncInfo func = (FuncInfo) called; // TODO: Push the FUCKING arg0 (outter function frame ptr) + List<RiscVBackend.Register> args_reg = new ArrayList<>(); for(Expr expr : node.args) { + // TODO: sub-expr may use stack. RiscVBackend.Register result = expr.dispatch(this); if(result == null) { throw new RuntimeException("NotImplemented: Expression " + expr.getClass().getName() + " returns null register."); } - betterBackend.emitPush(result, "Push function arguments."); + args_reg.add(result); } + for(RiscVBackend.Register reg : args_reg) + betterBackend.emitPush(reg, "Push function arguments."); betterBackend.emitCall(func.getCodeLabel(), null); - for(Expr expr : node.args) { + for(Object reg : args_reg) betterBackend.emitPop(null, "Pop function arguments."); - } return A0; // Function return value is always in A0. } @@ -234,8 +299,10 @@ public class CodeGenImpl extends CodeGenBase { @Override public RiscVBackend.Register analyze(IntegerLiteral node) { - backend.emitLI(T0, node.value, "Set constant int to reg."); - return T0; + // emitConstant(node, ValueType.INT_TYPE, "Set constant int literal."); + RiscVBackend.Register tmpReg = regMgr.borrowOne(); + betterBackend.emitPushIntVal(tmpReg, node.value, "Push int literal"); + return tmpReg; } }