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

MILESTONE: good function call!!!

parent 5a943384
No related branches found
No related tags found
No related merge requests found
Pipeline #288 passed with warnings with stages
in 10 minutes and 18 seconds
......@@ -8,6 +8,8 @@ classPath="chocopy-ref.jar:target/assignment.jar"
if [[ "$task" = codegen ]]; then
java -cp "$classPath" chocopy.ChocoPy --pass=rrs --out "$output" "$input"
elif [[ "$task" = codegen-ref ]]; then
java -cp "$classPath" chocopy.ChocoPy --pass=rrr --out "$output" "$input"
elif [[ "$task" = ass ]]; then
java -cp "$classPath" chocopy.ChocoPy --pass=..s --run --dir src/test/data/pa3/sample/ --test | tee /tmp/cs164_ass.log
# Should pass all positive test, else return error_code=2
......
......@@ -26,6 +26,47 @@ import static chocopy.common.codegen.RiscVBackend.Register.*;
* importance is knowing what all the SymbolInfo classes contain.
*/
/* Recolic func manage logic:
IMPORTANT!!! NEVER DELETE THESE COMMENTS
emitPush(arg1)
emitPush(arg2)
emitCall("someFunc")
emitPop(null)
emitPop(null)
$someFunc:
-------- emitFunctionBegin ------
emitPush(RA) // save My RA
emitPush(FP) // save parent FP // that's a good fucking design
emitMv(FP, SP+2*WORD) // load My FP
emitJ($someFunc$saveReg)
$someFunc$saveRegContinue:
-------- emitFunctionBegin ------
some code...
using S1...
using S2...
calling others...
...
MV A0, returnValue // IMPORTANT!
-------- emitFunctionEnd ------
emitMv(SP, FP-4*WORD) // 2 WORD for FP and RA, and 2 WORD for register S1 and S2.
emitPop(S2)
emitPop(S1)
emitPop(FP) // restore parent's FP
emitPop(RA) // restore My RA
emitJR(RA) // return!
$someFunc$saveReg:
emitPush(S1)
emitPush(S2)
emitJ($someFunc$saveRegContinue)
-------- emitFunctionEnd ------
*/
public class CodeGenImpl extends CodeGenBase {
private class BetterRsicVBackend {
......@@ -47,30 +88,37 @@ public class CodeGenImpl extends CodeGenBase {
backend.emitLW(reg, SP, 0, comment);
backend.emitADDI(SP, SP, backend.getWordSize(), comment);
}
public void emitSavedFPCall(Label calledLabel, String comment) {
public void emitCall(Label calledLabel, String comment) {
// Arguments should be already pushed to stack.
backend.emitJAL(calledLabel, comment);
}
public void emitFunctionBegin(String funcName, String comment) {
emitNoop(comment);
emitPush(RA, "backup return address of parent.");
emitPush(RA, "backup my return address.");
emitPush(FP, "backup parent fp.");
backend.emitADDI(FP, SP, 2 * backend.getWordSize(), "Change FP to apply new frame.");
// jal will set RA register properly.
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.");
backend.emitJ(new Label("$" + funcName + "$saveReg"), "Jump to save callee-saved registers");
backend.emitLocalLabel(new Label("$" + funcName + "$saveRegContinue"), "Begin real function codes:");
}
public void emitCall(Label calledLabel, String comment) {
// Arguments should be already pushed to stack.
emitNoop(comment);
backend.emitJAL(calledLabel, "Call it!");
}
public void emitRet(String comment) {
// All local variable should already be poped.
public void emitFunctionEnd(String funcName, registerManager regMgr, String comment) {
// Return value should be in A0
List<RiscVBackend.Register> savedRegs = regMgr.registerToSaveAndRestoreInFunc;
emitNoop(comment);
backend.emitJR(RA, "Return to caller.");
backend.emitADDI(SP, FP, -(2+savedRegs.size()) * backend.getWordSize(), "Revert all local variables on this dying frame.");
for (int i = savedRegs.size(); i --> 0; ) {
emitPop(savedRegs.get(i), "restore callee-saved reg.");
}
emitPop(FP, "restore parent FP.");
emitPop(RA, "restore my return address.");
backend.emitJR(RA, "Real return!");
backend.emitLocalLabel(new Label("$" + funcName + "$saveReg"), "Save callee-saved registers before use.");
for(int i = 0; i < savedRegs.size(); ++i) {
emitPush(savedRegs.get(i), "save callee-saved reg.");
}
backend.emitJ(new Label("$" + funcName + "$saveRegContinue"), "go back to execute real function code.");
}
public void emitPushIntVal(RiscVBackend.Register tmpReg, Integer val, String comment) {
emitNoop(comment);
......@@ -163,29 +211,58 @@ public class CodeGenImpl extends CodeGenBase {
// --- pop S0 ; pop S1 ---
// --- restore FP, return ---
private class registerManager {
private Map<RiscVBackend.Register, Boolean> usageMap; // true if the reg is in use.
private Map<RiscVBackend.Register, Boolean> callerSavedUsageMap; // true if the reg is in use.
private Map<RiscVBackend.Register, Boolean> calleeSavedUsageMap; // true if the reg is in use.
public List<RiscVBackend.Register> registerToSaveAndRestoreInFunc;
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(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);
// usageMap.put(A0, false); // used as return. not managed
callerSavedUsageMap = new LinkedHashMap<>();
calleeSavedUsageMap = new LinkedHashMap<>();
callerSavedUsageMap.put(T0, false);
callerSavedUsageMap.put(T1, false);
callerSavedUsageMap.put(T2, false);
callerSavedUsageMap.put(T3, false);
callerSavedUsageMap.put(T4, false);
callerSavedUsageMap.put(T5, false);
callerSavedUsageMap.put(T6, false);
callerSavedUsageMap.put(A1, false);
callerSavedUsageMap.put(A2, false);
callerSavedUsageMap.put(A3, false);
callerSavedUsageMap.put(A4, false);
callerSavedUsageMap.put(A5, false);
callerSavedUsageMap.put(A6, false);
callerSavedUsageMap.put(A7, false);
// callerSavedUsageMap.put(A0, false); // used as return. not managed
calleeSavedUsageMap.put(S1, false);
calleeSavedUsageMap.put(S2, false);
calleeSavedUsageMap.put(S3, false);
calleeSavedUsageMap.put(S4, false);
calleeSavedUsageMap.put(S5, false);
calleeSavedUsageMap.put(S6, false);
calleeSavedUsageMap.put(S7, false);
calleeSavedUsageMap.put(S8, false);
calleeSavedUsageMap.put(S9, false);
registerToSaveAndRestoreInFunc = new ArrayList<>();
}
// For converience: we call caller-saved register as `temp register`,
// call callee-saved register as `persist register` or `saved register`, because they should be saved before the function.
public RiscVBackend.Register borrowOneTmp() {
for(RiscVBackend.Register reg : callerSavedUsageMap.keySet()) {
if(callerSavedUsageMap.put(reg, true) == false) {
return reg;
}
}
throw new RuntimeException("Too many variable, not enough register.");
}
public RiscVBackend.Register borrowOne() {
for(RiscVBackend.Register reg : usageMap.keySet()) {
if(usageMap.put(reg, true) == false) {
public RiscVBackend.Register borrowOnePersist() {
for(RiscVBackend.Register reg : calleeSavedUsageMap.keySet()) {
if(calleeSavedUsageMap.put(reg, true) == false) {
if(!registerToSaveAndRestoreInFunc.contains(reg))
registerToSaveAndRestoreInFunc.add(reg);
return reg;
}
}
......@@ -193,9 +270,24 @@ public class CodeGenImpl extends CodeGenBase {
}
public void returnOne(RiscVBackend.Register reg) {
boolean old = usageMap.put(reg, false);
assert old == true;
if(calleeSavedUsageMap.containsKey(reg))
assert calleeSavedUsageMap.put(reg, false);
else
assert callerSavedUsageMap.put(reg, false);
}
/*
public void generateCodeToBackupReg() {
for(RiscVBackend.Register reg : registerToSaveAndRestoreInFunc) {
betterBackend.emitPush(reg, "Backup used callee saved register in this func.");
}
}
public void generateCodeToRestoreReg() {
for(RiscVBackend.Register reg : registerToSaveAndRestoreInFunc) {
betterBackend.emitPop(reg, "Restore backuped callee saved registers.");
}
}
*/
}
/** A code generator emitting instructions to BACKEND. */
......@@ -254,11 +346,14 @@ public class CodeGenImpl extends CodeGenBase {
backend.emitGlobalLabel(funcInfo.getCodeLabel());
StmtAnalyzer stmtAnalyzer = new StmtAnalyzer(funcInfo);
betterBackend.emitFunctionBegin(funcInfo.getFuncName(), "BEGIN FUNCTION");
for (Stmt stmt : funcInfo.getStatements()) {
stmt.dispatch(stmtAnalyzer);
}
backend.emitMV(A0, ZERO, "Returning None implicitly");
betterBackend.emitFunctionEnd(funcInfo.getFuncName(), stmtAnalyzer.regMgr, "BEGIN FUNCTION");
backend.emitLocalLabel(stmtAnalyzer.epilogue, "Epilogue");
// FIXME: {... reset fp etc. ...}
......@@ -345,15 +440,9 @@ public class CodeGenImpl extends CodeGenBase {
SymbolInfo called = sym.get(node.function.name);
if(called instanceof FuncInfo) {
FuncInfo func = (FuncInfo) called;
if(func.getFuncName() != "print") {
throw new RuntimeException("Not implemented: emitCall doesn't allow calling user-defined function, because RA will be messed up.");
// TODO: analyze the reference compiler, to see why $print use 0(SP) as arg0, and how to call it with RA saved.
// https://piazza.com/class/jr5kaiy0u71499?cid=234
}
// TODO: Push the FUCKING arg0 (outter function frame ptr)
List<RiscVBackend.Register> args_reg = new ArrayList<>();
for(Expr expr : node.args) {
// TODO: See register allocator TODOS.
RiscVBackend.Register result = expr.dispatch(this);
if(result == null) {
throw new RuntimeException("NotImplemented: Expression " + expr.getClass().getName() + " returns null register.");
......@@ -380,14 +469,20 @@ public class CodeGenImpl extends CodeGenBase {
@Override
public RiscVBackend.Register analyze(BinaryExpr node) {
RiscVBackend.Register leftRes = node.left.dispatch(this);
RiscVBackend.Register rightRes = node.right.dispatch(this);
if(leftRes == null || rightRes == null)
RiscVBackend.Register leftReturnReg = node.left.dispatch(this);
if(leftReturnReg == null) return null;
RiscVBackend.Register leftRes = regMgr.borrowOnePersist();
backend.emitMV(leftRes, leftReturnReg, "Move left operand result to a callee saved register");
regMgr.returnOne(leftReturnReg);
// because right operand may overwrite temp registers.
RiscVBackend.Register rightReturnReg = node.right.dispatch(this);
RiscVBackend.Register rightRes = rightReturnReg;
if(rightReturnReg == null)
return null;
switch(node.operator) {
case "+":
if(node.left.getInferredType().equals(SymbolType.INT_TYPE)) {
RiscVBackend.Register savedLeftAddr = regMgr.borrowOne();
RiscVBackend.Register savedLeftAddr = regMgr.borrowOneTmp();
backend.emitMV(savedLeftAddr, leftRes, "Backup reg leftRes");
backend.emitLW(leftRes, leftRes, 3 * backend.getWordSize(), "Operator+ Fetch left int result");
backend.emitLW(rightRes, rightRes, 3 * backend.getWordSize(), "Operator+ Fetch right int result");
......@@ -407,7 +502,7 @@ public class CodeGenImpl extends CodeGenBase {
}
case "-":
if(node.left.getInferredType().equals(SymbolType.INT_TYPE)) {
RiscVBackend.Register savedLeftAddr = regMgr.borrowOne();
RiscVBackend.Register savedLeftAddr = regMgr.borrowOneTmp();
backend.emitMV(savedLeftAddr, leftRes, "Backup reg leftRes");
backend.emitLW(leftRes, leftRes, 3 * backend.getWordSize(), "Operator- Fetch left int result");
backend.emitLW(rightRes, rightRes, 3 * backend.getWordSize(), "Operator- Fetch right int result");
......@@ -419,7 +514,7 @@ public class CodeGenImpl extends CodeGenBase {
}
case "*":
if(node.left.getInferredType().equals(SymbolType.INT_TYPE)) {
RiscVBackend.Register savedLeftAddr = regMgr.borrowOne();
RiscVBackend.Register savedLeftAddr = regMgr.borrowOneTmp();
backend.emitMV(savedLeftAddr, leftRes, "Backup reg leftRes");
backend.emitLW(leftRes, leftRes, 3 * backend.getWordSize(), "Operator* Fetch left int result");
backend.emitLW(rightRes, rightRes, 3 * backend.getWordSize(), "Operator* Fetch right int result");
......@@ -438,7 +533,7 @@ public class CodeGenImpl extends CodeGenBase {
SymbolInfo id = sym.get(node.name);
if(id instanceof GlobalVarInfo) {
GlobalVarInfo globalVarInfo = (GlobalVarInfo) id;
RiscVBackend.Register tmpReg = regMgr.borrowOne();
RiscVBackend.Register tmpReg = regMgr.borrowOneTmp();
backend.emitLA(tmpReg, globalVarInfo.getLabel(), "Load address of the global var.");
return tmpReg;
}
......@@ -449,21 +544,21 @@ public class CodeGenImpl extends CodeGenBase {
@Override
public RiscVBackend.Register analyze(IntegerLiteral node) {
// emitConstant(node, ValueType.INT_TYPE, "Set constant int literal.");
RiscVBackend.Register tmpReg = regMgr.borrowOne();
RiscVBackend.Register tmpReg = regMgr.borrowOneTmp();
betterBackend.emitPushIntVal(tmpReg, node.value, "Push int literal");
return tmpReg;
}
@Override
public RiscVBackend.Register analyze(BooleanLiteral node) {
RiscVBackend.Register tmpReg = regMgr.borrowOne();
RiscVBackend.Register tmpReg = regMgr.borrowOneTmp();
betterBackend.emitPushBoolVal(tmpReg, node.value, "Push bool literal");
return tmpReg;
}
@Override
public RiscVBackend.Register analyze(StringLiteral node) {
RiscVBackend.Register tmpReg = regMgr.borrowOne();
RiscVBackend.Register tmpReg = regMgr.borrowOneTmp();
betterBackend.emitPushStrVal(tmpReg, node.value, "push string 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