diff --git a/src/main/java/chocopy/pa3/CodeGenImpl.java b/src/main/java/chocopy/pa3/CodeGenImpl.java index 47a31c8..0006f80 100644 --- a/src/main/java/chocopy/pa3/CodeGenImpl.java +++ b/src/main/java/chocopy/pa3/CodeGenImpl.java @@ -2,12 +2,44 @@ package chocopy.pa3; import chocopy.common.analysis.AbstractNodeAnalyzer; import chocopy.common.analysis.SymbolTable; +import chocopy.common.astnodes.AssignStmt; +import chocopy.common.astnodes.BinaryExpr; +import chocopy.common.astnodes.BooleanLiteral; +import chocopy.common.astnodes.CallExpr; +import chocopy.common.astnodes.ClassDef; +import chocopy.common.astnodes.ClassType; +import chocopy.common.astnodes.CompilerError; +import chocopy.common.astnodes.Errors; +import chocopy.common.astnodes.Expr; +import chocopy.common.astnodes.ExprStmt; +import chocopy.common.astnodes.ForStmt; +import chocopy.common.astnodes.FuncDef; +import chocopy.common.astnodes.GlobalDecl; +import chocopy.common.astnodes.Identifier; +import chocopy.common.astnodes.IfExpr; +import chocopy.common.astnodes.IfStmt; +import chocopy.common.astnodes.IndexExpr; +import chocopy.common.astnodes.IntegerLiteral; +import chocopy.common.astnodes.ListExpr; +import chocopy.common.astnodes.ListType; +import chocopy.common.astnodes.MemberExpr; +import chocopy.common.astnodes.MethodCallExpr; +import chocopy.common.astnodes.NonLocalDecl; +import chocopy.common.astnodes.NoneLiteral; +import chocopy.common.astnodes.Program; import chocopy.common.astnodes.ReturnStmt; import chocopy.common.astnodes.Stmt; +import chocopy.common.astnodes.StringLiteral; +import chocopy.common.astnodes.TypedVar; +import chocopy.common.astnodes.UnaryExpr; +import chocopy.common.astnodes.VarDef; +import chocopy.common.astnodes.WhileStmt; import chocopy.common.codegen.*; import java.util.List; +import com.fasterxml.jackson.core.JsonProcessingException; + import static chocopy.common.codegen.RiscVBackend.Register.*; /** @@ -70,16 +102,43 @@ public class CodeGenImpl extends CodeGenBase { */ protected void emitUserDefinedFunction(FuncInfo funcInfo) { backend.emitGlobalLabel(funcInfo.getCodeLabel()); + + + + // --- Prologue --- + // space for return address = 4 + // space for control link = 4 + // space for static link = 4 + // space for params = num of params * 4 + // space for locals = num of locals * 4 + int requiredStackSpace = 4 + 4 + 4 + funcInfo.getParams().size() * 4 + funcInfo.getLocals().size() * 4; + backend.emitADDI(SP, SP, -requiredStackSpace, "Reserve space for stack frame."); + backend.emitSW(RA, SP, requiredStackSpace-4, "return address"); + backend.emitSW(FP, SP, requiredStackSpace-8, "control link"); + // if we want to add static link + //backend.emitSW(FP, SP, requiredStackSpace-12, "static link"); + backend.emitADDI(FP, SP, requiredStackSpace, "New fp is at old SP."); + + + + // --- Function Body --- + // statements load all the variables that caller put on stack + // statements use fp to load the variables + // example: 0(fp) is the last variable (z) while 8(fp) is the first variable (x) + // for function with 3 params f(x, y, z) StmtAnalyzer stmtAnalyzer = new StmtAnalyzer(funcInfo); - for (Stmt stmt : funcInfo.getStatements()) { stmt.dispatch(stmtAnalyzer); } + backend.emitJ(stmtAnalyzer.epilogue, "Jump to function epilogue"); - backend.emitMV(A0, ZERO, "Returning None implicitly"); + + + // --- Epilogue --- backend.emitLocalLabel(stmtAnalyzer.epilogue, "Epilogue"); - - // FIXME: {... reset fp etc. ...} + backend.emitLW(RA, FP, -4, "Get return address"); + backend.emitLW(FP, FP, -8, "Use control link to restore caller's fp"); + backend.emitADDI(SP, SP, requiredStackSpace, "Restore stack pointer"); backend.emitJR(RA, "Return to caller"); } @@ -136,19 +195,287 @@ public class CodeGenImpl extends CodeGenBase { epilogue = generateLocalLabel(); } - // FIXME: Example of statement. + + @Override public Void analyze(ReturnStmt stmt) { - // FIXME: Here, we emit an instruction that does nothing. Clearly, - // this is wrong, and you'll have to fix it. - // This is here just to demonstrate how to emit a - // RISC-V instruction. - backend.emitMV(ZERO, ZERO, "No-op"); + System.out.println("*** ReturnStmt"); + backend.emitLW(T6, FP, 0, "Inside ReturnStmt"); +// Expr expr = stmt.value; +// // All expressions should save their end result in A0 +// expr.dispatch(this); + backend.emitLW(A0, FP, 0, "Load var: " + "last"); + return null; + } + + + @Override + public Void analyze(CallExpr node) { + System.out.println("*** CallExpr"); + backend.emitLW(T6, FP, 0, "Inside CallExpr: " + node.function.name); + + // function + Identifier functionId = node.function; + + List args = node.args; + int spaceRequiredForArgs = (args.size() + 1)*4; + //backend.emitSW(A0, SP, -4, "Put static link"); + for (int i = 0; i < args.size(); i++) { + int argNum = i + 1; + int slotNum = argNum + 1; // We have extra slot for static link + Expr expr = args.get(i); + expr.dispatch(this); + // All expressions should save their end result in A0 + // So, once expr is evaluated add value inside A0 onto stack as an argument + backend.emitSW(A0, SP, -4*slotNum, "Push argument " + argNum + " from left"); + } + + backend.emitADDI(SP, SP, -spaceRequiredForArgs, "Set SP to last argument."); + backend.emitJAL(new Label("$"+functionId.name), "Invoke function: " + functionId.name); + backend.emitADDI(SP, SP, spaceRequiredForArgs, "Set SP to stack frame top."); + return null; + } + + + + @Override + public Void analyze(MethodCallExpr node) { + System.out.println("*** MethodCallExpr"); + backend.emitLW(T6, FP, 0, "Inside MethodCallExpr"); + // function + return defaultAction(node); + } + + + + @Override + public Void analyze(FuncDef node) { + System.out.println("*** FuncDef"); + backend.emitLW(T6, FP, 0, "Inside FuncDef"); + // function + return defaultAction(node); + } + + + + @Override + public Void analyze(GlobalDecl node) { + System.out.println("*** GlobalDecl"); + backend.emitLW(T6, FP, 0, "Inside GlobalDecl"); + // function + return defaultAction(node); + } + + + + @Override + public Void analyze(NonLocalDecl node) { + System.out.println("*** NonLocalDecl"); + backend.emitLW(T6, FP, 0, "Inside NonLocalDecl"); + // function + return defaultAction(node); + } + + + + + + + + + + // methods below are only for testing, remove or comment them when merging + @Override + public Void analyze(AssignStmt node) { + System.out.println("+++ Inside AssignStmt"); + backend.emitLW(T6, FP, 0, "Inside AssignStmt"); + return defaultAction(node); + } + + @Override + public Void analyze(BinaryExpr node) { + System.out.println("+++ Inside BinaryExpr"); + backend.emitLW(T6, FP, 0, "Inside BinaryExpr"); + return defaultAction(node); + } + + @Override + public Void analyze(BooleanLiteral node) { + System.out.println("+++ Inside BooleanLiteral"); + backend.emitLW(T6, FP, 0, "Inside BooleanLiteral"); + return defaultAction(node); + } + + @Override + public Void analyze(ClassDef node) { + System.out.println("+++ Inside ClassDef"); + backend.emitLW(T6, FP, 0, "Inside ClassDef"); + return defaultAction(node); + } + + @Override + public Void analyze(ClassType node) { + System.out.println("+++ Inside ClassType"); + backend.emitLW(T6, FP, 0, "Inside ClassType"); + return defaultAction(node); + } + + @Override + public Void analyze(CompilerError node) { + System.out.println("+++ Inside CompilerError"); + backend.emitLW(T6, FP, 0, "Inside CompilerError"); + return defaultAction(node); + } + + @Override + public Void analyze(Errors node) { + System.out.println("+++ Inside Errors"); + backend.emitLW(T6, FP, 0, "Inside Errors"); + return defaultAction(node); + } + + @Override + public Void analyze(ExprStmt node) { + System.out.println("+++ Inside ExprStmt"); + backend.emitLW(T6, FP, 0, "Inside ExprStmt: " + node.expr.kind); + node.expr.dispatch(this); + return defaultAction(node); + } + + @Override + public Void analyze(ForStmt node) { + System.out.println("+++ Inside ForStmt"); + backend.emitLW(T6, FP, 0, "Inside ForStmt"); + return defaultAction(node); + } + + + + @Override + public Void analyze(Identifier node) { + System.out.println("+++ Inside Identifier"); +// List params = funcInfo.getParams(); +// int i = 0; +// for (i = 0; i < params.size(); i++) { +// if (params.get(i).equals(node.name)) break; +// } +// backend.emitLW(A0, SP, ((i+1)-params.size())*4, "Load param " + (i+1) + " from left"); + backend.emitLW(T6, FP, 0, "Inside Identifier: " + node.name); return null; } - // FIXME: More, of course. + @Override + public Void analyze(IfExpr node) { + System.out.println("+++ Inside IfExpr"); + backend.emitLW(T6, FP, 0, "Inside IfExpr"); + return defaultAction(node); + } + + @Override + public Void analyze(IfStmt node) { + System.out.println("+++ Inside IfStmt"); + backend.emitLW(T6, FP, 0, "Inside IfStmt"); + return defaultAction(node); + } + + @Override + public Void analyze(IndexExpr node) { + System.out.println("+++ Inside IndexExpr"); + backend.emitLW(T6, FP, 0, "Inside IndexExpr"); + return defaultAction(node); + } + + @Override + public Void analyze(IntegerLiteral node) { + System.out.println("+++ Inside IntegerLiteral"); + backend.emitLA(A0, new Label("$int$prototype"), "Load prototype"); + backend.emitJAL(new Label("ra, alloc"), ""); + backend.emitLI(T0, node.value, "Load integer " + node.value); + backend.emitSW(T0, A0, "@.__int__", null); + backend.emitLW(T6, FP, 0, "Inside IntegerLiteral"); + return defaultAction(node); + } + + @Override + public Void analyze(ListExpr node) { + System.out.println("+++ Inside ListExpr"); + backend.emitLW(T6, FP, 0, "Inside ListExpr"); + return defaultAction(node); + } + + @Override + public Void analyze(ListType node) { + System.out.println("+++ Inside ListType"); + backend.emitLW(T6, FP, 0, "Inside ListType"); + return defaultAction(node); + } + + @Override + public Void analyze(MemberExpr node) { + System.out.println("+++ Inside MemberExpr"); + backend.emitLW(T6, FP, 0, "Inside MemberExpr"); + return defaultAction(node); + } + + + @Override + public Void analyze(NoneLiteral node) { + System.out.println("+++ Inside NoneLiteral"); + backend.emitLW(T6, FP, 0, "Inside NoneLiteral"); + return defaultAction(node); + } + + @Override + public Void analyze(Program node) { + System.out.println("+++ Inside Program"); + backend.emitLW(T6, FP, 0, "Inside Program"); + return defaultAction(node); + } + + + @Override + public Void analyze(StringLiteral node) { + System.out.println("+++ Inside StringLiteral"); + backend.emitLW(T6, FP, 0, "Inside StringLiteral"); + return defaultAction(node); + } + + @Override + public Void analyze(TypedVar node) { + System.out.println("+++ Inside TypedVar"); + backend.emitLW(T6, FP, 0, "Inside TypedVar"); + return defaultAction(node); + } + + @Override + public Void analyze(UnaryExpr node) { + System.out.println("+++ Inside UnaryExpr"); + backend.emitLW(T6, FP, 0, "Inside UnaryExpr"); + return defaultAction(node); + } + + @Override + public Void analyze(VarDef node) { + System.out.println("+++ Inside VarDef"); + backend.emitLW(T6, FP, 0, "Inside VarDef"); + return defaultAction(node); + } + + @Override + public Void analyze(WhileStmt node) { + System.out.println("+++ Inside WhileStmt"); + backend.emitLW(T6, FP, 0, "Inside WhileStmt"); + return defaultAction(node); + } + + + + + + + // extras end here + } /**