Skip to content
Snippets Groups Projects
Verified Commit 4f2d9c4f authored by Recolic Keghart's avatar Recolic Keghart
Browse files

workaround for CALL instruction, waiting for help

parent 46b574a6
No related branches found
No related tags found
No related merge requests found
Pipeline #213 failed with stages
in 12 minutes and 28 seconds
package chocopy.pa3; package chocopy.pa3;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import chocopy.common.analysis.SymbolTable; import chocopy.common.analysis.SymbolTable;
import chocopy.common.analysis.AbstractNodeAnalyzer; import chocopy.common.analysis.AbstractNodeAnalyzer;
import chocopy.common.analysis.types.ValueType;
import chocopy.common.astnodes.*; import chocopy.common.astnodes.*;
import chocopy.common.codegen.*; import chocopy.common.codegen.*;
...@@ -51,8 +55,11 @@ public class CodeGenImpl extends CodeGenBase { ...@@ -51,8 +55,11 @@ public class CodeGenImpl extends CodeGenBase {
backend.emitADDI(FP, SP, 2 * backend.getWordSize(), "Change FP to apply new frame."); backend.emitADDI(FP, SP, 2 * backend.getWordSize(), "Change FP to apply new frame.");
// jal will set RA register properly. // 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.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(FP, "restore parent FP.");
emitPop(RA, "restore parent return address."); emitPop(RA, "restore parent return address.");
} }
...@@ -62,6 +69,59 @@ public class CodeGenImpl extends CodeGenBase { ...@@ -62,6 +69,59 @@ public class CodeGenImpl extends CodeGenBase {
emitNoop(comment); emitNoop(comment);
backend.emitJR(RA, "Return to caller."); 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. */ /** A code generator emitting instructions to BACKEND. */
...@@ -174,6 +234,8 @@ public class CodeGenImpl extends CodeGenBase { ...@@ -174,6 +234,8 @@ public class CodeGenImpl extends CodeGenBase {
* level. */ * level. */
private FuncInfo funcInfo; private FuncInfo funcInfo;
private registerManager regMgr = new registerManager();
/** An analyzer for the function described by FUNCINFO0, which is null /** An analyzer for the function described by FUNCINFO0, which is null
* for the top level. */ * for the top level. */
StmtAnalyzer(FuncInfo funcInfo0) { StmtAnalyzer(FuncInfo funcInfo0) {
...@@ -210,19 +272,22 @@ public class CodeGenImpl extends CodeGenBase { ...@@ -210,19 +272,22 @@ public class CodeGenImpl extends CodeGenBase {
if(called instanceof FuncInfo) { if(called instanceof FuncInfo) {
FuncInfo func = (FuncInfo) called; FuncInfo func = (FuncInfo) called;
// TODO: Push the FUCKING arg0 (outter function frame ptr) // TODO: Push the FUCKING arg0 (outter function frame ptr)
List<RiscVBackend.Register> args_reg = new ArrayList<>();
for(Expr expr : node.args) { for(Expr expr : node.args) {
// TODO: sub-expr may use stack.
RiscVBackend.Register result = expr.dispatch(this); RiscVBackend.Register result = expr.dispatch(this);
if(result == null) { if(result == null) {
throw new RuntimeException("NotImplemented: Expression " + expr.getClass().getName() + " returns null register."); 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); betterBackend.emitCall(func.getCodeLabel(), null);
for(Expr expr : node.args) { for(Object reg : args_reg)
betterBackend.emitPop(null, "Pop function arguments."); betterBackend.emitPop(null, "Pop function arguments.");
}
return A0; // Function return value is always in A0. return A0; // Function return value is always in A0.
} }
...@@ -234,8 +299,10 @@ public class CodeGenImpl extends CodeGenBase { ...@@ -234,8 +299,10 @@ public class CodeGenImpl extends CodeGenBase {
@Override @Override
public RiscVBackend.Register analyze(IntegerLiteral node) { public RiscVBackend.Register analyze(IntegerLiteral node) {
backend.emitLI(T0, node.value, "Set constant int to reg."); // emitConstant(node, ValueType.INT_TYPE, "Set constant int literal.");
return T0; RiscVBackend.Register tmpReg = regMgr.borrowOne();
betterBackend.emitPushIntVal(tmpReg, node.value, "Push int literal");
return tmpReg;
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment