diff --git a/run.sh b/run.sh
index f1b231f6ac71a60726de66e7d05c7cdc12dc6574..61a640d6437c511e95c450be64a75590ebb1b26f 100755
--- a/run.sh
+++ b/run.sh
@@ -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
diff --git a/src/main/java/chocopy/pa3/CodeGenImpl.java b/src/main/java/chocopy/pa3/CodeGenImpl.java
index 08cb23f6a73eef7d1ec60f379c2a368c1970c03a..43acc8fe92ba7d6387496eae4255af03fc90b016 100644
--- a/src/main/java/chocopy/pa3/CodeGenImpl.java
+++ b/src/main/java/chocopy/pa3/CodeGenImpl.java
@@ -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;
         }