diff --git a/src/main/java/chocopy/pa3/CodeGenImpl.java b/src/main/java/chocopy/pa3/CodeGenImpl.java index 81e3338..fee32c7 100644 --- a/src/main/java/chocopy/pa3/CodeGenImpl.java +++ b/src/main/java/chocopy/pa3/CodeGenImpl.java @@ -1,18 +1,43 @@ package chocopy.pa3; -import static chocopy.common.codegen.RiscVBackend.Register.A0; -import static chocopy.common.codegen.RiscVBackend.Register.A1; -import static chocopy.common.codegen.RiscVBackend.Register.FP; -import static chocopy.common.codegen.RiscVBackend.Register.RA; -import static chocopy.common.codegen.RiscVBackend.Register.SP; -import static chocopy.common.codegen.RiscVBackend.Register.ZERO; - import java.util.HashMap; import java.util.List; import java.util.Map; 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.astnodes.*; import chocopy.common.analysis.types.*; import chocopy.common.codegen.*; @@ -21,8 +46,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; + +import com.fasterxml.jackson.core.JsonProcessingException; +import static chocopy.common.codegen.RiscVBackend.Register.*; import chocopy.common.codegen.RiscVBackend.Register; + /** * This is where the main implementation of PA3 will live. * @@ -44,6 +73,68 @@ public class CodeGenImpl extends CodeGenBase public CodeGenImpl(RiscVBackend backend) { super(backend); + + } + + /** + * Generates assembly code for PROGRAM. + * + *

This is the main driver that calls internal methods for emitting DATA section (globals, + * constants, prototypes, etc) as well as the the CODE section (predefined functions, built-in + * routines, and user-defined functions). + */ + @Override + public void generate(Program program) { + System.out.println("Inside generate"); + analyzeProgram(program); + + backend.startData(); + + for (ClassInfo classInfo : this.classes) { + emitPrototype(classInfo); + } + + for (ClassInfo classInfo : this.classes) { + emitDispatchTable(classInfo); + } + + for (GlobalVarInfo global : this.globalVars) { + backend.emitGlobalLabel(global.getLabel()); + emitConstant( + global.getInitialValue(), + global.getVarType(), + String.format("Initial value of global var: %s", global.getVarName())); + } + + backend.startCode(); + + Label mainLabel = new Label("main"); + backend.emitGlobalLabel(mainLabel); + backend.emitLUI(A0, HEAP_SIZE_BYTES >> 12, "Initialize heap size (in multiples of 4KB)"); + backend.emitADD(S11, S11, A0, "Save heap size"); + backend.emitJAL(heapInitLabel, "Call heap.init routine"); + backend.emitMV(GP, A0, "Initialize heap pointer"); + backend.emitMV(S10, GP, "Set beginning of heap"); + backend.emitADD(S11, S10, S11, "Set end of heap (= start of heap + heap size)"); + backend.emitMV(RA, ZERO, "No normal return from main program."); + backend.emitMV(FP, ZERO, "No preceding frame."); + + emitTopLevel(program.statements); + + for (FuncInfo funcInfo : this.functions) { + funcInfo.emitBody(); + } + + emitStdFunc("alloc"); + emitStdFunc("alloc2"); + emitStdFunc("abort"); + emitStdFunc("heap.init"); + emitStdFunc("makeint"); + + emitCustomCode(); + + backend.startData(); + emitConstants(); } /** Operation on None. */ @@ -56,6 +147,11 @@ public class CodeGenImpl extends CodeGenBase /** Not implemented. */ private final Label errorNI = new Label("error.NI"); + + /** Label for built-in routine: makeint. */ + protected final Label makeIntLabel = new Label("makeint"); + + /** * Emits the top level of the program. * @@ -97,17 +193,54 @@ public class CodeGenImpl extends CodeGenBase protected void emitUserDefinedFunction(FuncInfo funcInfo) { backend.emitGlobalLabel(funcInfo.getCodeLabel()); + + + + // --- Prologue --- + // space for return address = 1 + // space for control link = 1 + // space for static link = 1 + // space for params = num of params + // space for locals = num of locals + int requiredStackSpace = (1 + 1 + 1 + funcInfo.getLocals().size() + funcInfo.getParams().size())*wordSize; + + 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."); + + StmtAnalyzer stmtAnalyzer = new StmtAnalyzer(funcInfo); - - for (Stmt stmt : funcInfo.getStatements()) - { + int emptySlotNum = 4; + for (StackVarInfo var : funcInfo.getLocals()) { + // store at requiredStackSpace-emptySlotNum*wordSize(SP), then emptySlotNum++ + Literal varLitral = var.getInitialValue(); + varLitral.dispatch(stmtAnalyzer); + // All Literals should save locations for the values in A0 + backend.emitSW(A0, SP, requiredStackSpace-emptySlotNum*wordSize, "Push local variable " + var.getVarName() + " onto stack"); + emptySlotNum++; + } + + // --- 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) + for (Stmt stmt : funcInfo.getStatements()) { + //System.out.println(stmt.toString()); 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"); } @@ -182,8 +315,14 @@ public class CodeGenImpl extends CodeGenBase sp_off+=i+1; max_sp = max_sp >= sp_off?max_sp:sp_off; } - + + + + + // *********** functions start *********** + public Register analyze(CallExpr node) { + backend.emitLW(T6, FP, 0, "Inside CallExpr: " + node.function.name); SymbolInfo Ty = globalSymbols.get(node.function.name); if(Ty instanceof ClassInfo){ //object create @@ -214,44 +353,150 @@ public class CodeGenImpl extends CodeGenBase backend.emitADDI(SP, FP, "-"+size_label, "Set SP to stack frame top."); -- sp_off; backend.emitLW(A0, FP, -sp_off*wordSize, String.format("Pop stack slot %d", sp_off)); - } else { - //func call + } else { + // 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, -wordSize*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 A0; } + + + + + @Override + public Register analyze(FuncDef node) { + backend.emitLW(T6, FP, 0, "Inside FuncDef: " + node.name); + // function + return null; + } + + + + @Override + public Register analyze(GlobalDecl node) { + backend.emitLW(T6, FP, 0, "Inside GlobalDecl: "); + // function + return null; + } + + + + @Override + public Register analyze(NonLocalDecl node) { + backend.emitLW(T6, FP, 0, "Inside NonLocalDecl: "); + // function + return null; + } + + + + public Register analyze(MethodCallExpr node) { + backend.emitLW(T6, FP, 0, "Inside MethodCallExpr: " + node.method.member.name); + Register obj = node.method.object.dispatch(this); + int n_args = node.args.size(); + + Label label = generateLocalLabel(); + backend.emitBNEZ(obj, label, "Ensure not None"); + backend.emitJ(errorNone, "Go to error handler"); + backend.emitLocalLabel(label, "Not None"); + incSp(n_args+1); + backend.emitSW(obj, FP, (n_args - sp_off) *wordSize, String.format("Push argument %d from last.", n_args)); + + for (int i = 0; i < n_args; ++i) + backend.emitSW(node.args.get(i).dispatch(this), FP, (n_args - i - 1 - sp_off) * wordSize, + String.format("Push argument %d from last.", n_args - i - 1)); + + backend.emitLW(A0, FP, (n_args- sp_off) * wordSize, String.format("Peek stack slot %d", sp_off - (n_args + 1))); + ClassInfo objectClass = (ClassInfo)sym.get(((Identifier)node.method.object).name); + + backend.emitLW(A1, A0, getDispatchTableOffset(), "Load address of object's dispatch table"); + backend.emitLW(A1, A1, getMethodOffset(objectClass, node.method.member.name), + String.format("Load address of method: %s.%s", objectClass.getClassName(), node.method.member.name)); + backend.emitADDI(SP, FP, -sp_off * wordSize, "Set SP to last argument."); + backend.emitJALR(A1, String.format("Invoke method: %s.%s", objectClass.getClassName(), node.method.member.name)); + backend.emitInsn(String.format("addi sp, fp, -%s", size_label), "Set SP to stack frame top."); + sp_off -= n_args+1; + + return A0; + } + + + @Override + public Register analyze(ReturnStmt stmt) { + backend.emitLW(T6, FP, 0, "Inside ReturnStmt: "); + Expr expr = stmt.value; + if (expr == null) { + backend.emitMV(A0, ZERO, "Return None"); + return A0; + } + + // All expressions should save their end result in A0 + expr.dispatch(this); + return A0; + } + + + // *********** functions end *********** @Override public Register analyze(NoneLiteral node) { + backend.emitLW(T6, FP, 0, "Inside NoneLiteral: "); backend.emitMV(Register.A0, Register.ZERO, "Load none"); return Register.A0; } + @Override public Register analyze(StringLiteral node) { + backend.emitLW(T6, FP, 0, "Inside StringLiteral: "); Label l = constants.getStrConstant(node.value); backend.emitLA(Register.A0, l, "Load string literal"); return Register.A0; } - @Override - public Register analyze(IntegerLiteral node) - { - backend.emitLI(Register.A0, node.value, "Load integer literal "+node.value); - return Register.A0; - } + + +// FIXME: This is not correct. We need to use $int$prototype to create an integer literal, so commenting it +// @Override +// public Register analyze(IntegerLiteral node) +// { +// backend.emitLI(Register.A0, node.value, "Load integer literal "+node.value); +// return Register.A0; +// } + @Override public Register analyze(BooleanLiteral node) { + backend.emitLW(T6, FP, 0, "Inside BooleanLiteral: "); if(node.value==true) backend.emitLI(Register.A0, 1, "Load boolean literal: true "); else backend.emitLI(Register.A0, 0, "Load boolean literal: false "); return Register.A0; } + @Override public Register analyze(AssignStmt node) { + backend.emitLW(T6, FP, 0, "Inside AssignStmt: "); Type t = node.value.getInferredType(); if(t.isSpecialType() || t.isListType()) { @@ -284,9 +529,11 @@ public class CodeGenImpl extends CodeGenBase @Override public Register analyze(ExprStmt node) { + backend.emitLW(T6, FP, 0, "Inside ExprStmt: "); node.expr.dispatch(this); return null; } + @Override public Register analyze(IfExpr node) { @@ -299,6 +546,7 @@ public class CodeGenImpl extends CodeGenBase backend.emitLocalLabel(ln, "End of if expression"); return null; } + @Override public Register analyze(IfStmt node) { @@ -313,10 +561,13 @@ public class CodeGenImpl extends CodeGenBase backend.emitLocalLabel(ln, "End of if statement"); return null; } + @Override public Register analyze(BinaryExpr node) { String operator = node.operator; + backend.emitLW(T6, FP, 0, "Inside BinaryExpr: "); + if(node.left.getInferredType().equals(Type.INT_TYPE) && node.right.getInferredType().equals(Type.INT_TYPE)) { node.left.dispatch(this); @@ -392,6 +643,7 @@ public class CodeGenImpl extends CodeGenBase } return null; } + @Override public Register analyze(UnaryExpr node) { @@ -414,6 +666,7 @@ public class CodeGenImpl extends CodeGenBase @Override public Register analyze(Identifier node) { + backend.emitLW(T6, FP, 0, "Inside Identifier: "); if (sym.getParent() == null) { GlobalVarInfo gvi=(GlobalVarInfo) sym.get(node.name); @@ -421,12 +674,14 @@ public class CodeGenImpl extends CodeGenBase } else { - StackVarInfo svi = (StackVarInfo) sym.get(node.name); - int loc = offsetMap.get(svi); - backend.emitLW(Register.A0, Register.FP, -loc*4, "Load local variable: "+svi.getVarName()); +// FIXME: This breaks, so had to comment it +// VarInfo svi = (VarInfo) sym.get(node.name); +// int loc = offsetMap.get(svi); +// backend.emitLW(Register.A0, Register.FP, -loc*4, "Load local variable: "+svi.getVarName()); } return null; } + @Override public Register analyze(VarDef node) { @@ -449,8 +704,10 @@ public class CodeGenImpl extends CodeGenBase stmt.dispatch(this); backend.emitJ(startLoop, "Jump to beginning of loop"); backend.emitLocalLabel(endLoop, "End of while loop"); + return null; } + @Override public Register analyze(ListExpr node) { int l = node.elements.size(); @@ -470,9 +727,26 @@ public class CodeGenImpl extends CodeGenBase return Register.A0; } + + + @Override + public Register analyze(IntegerLiteral node) { + backend.emitLW(T6, FP, 0, "Inside IntegerLiteral: " + node.value); + backend.emitLI(A0, node.value, "Load integer literal " + node.value); + backend.emitJAL(makeIntLabel, "Box integer"); +// 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); + + return A0; + } + + @Override public Register analyze(ForStmt node) { - System.out.println(node); + //System.out.println(node); /* node. Label startLoop = generateLocalLabel(); @@ -487,15 +761,13 @@ public class CodeGenImpl extends CodeGenBase } - @Override public Register analyze(IndexExpr node) { - System.out.println(node); + //System.out.println(node); return defaultAction(node); } - public Register analyze(MemberExpr node) { ClassInfo objectClass = (ClassInfo) globalSymbols.get(node.object.getInferredType().className()); @@ -509,44 +781,6 @@ public class CodeGenImpl extends CodeGenBase String.format("Get attribute: %s.%s", objectClass.getClassName(), node.member.name)); return A0; } - - public Register analyze(MethodCallExpr node) - { - Register obj = node.method.object.dispatch(this); - int n_args = node.args.size(); - - Label label = generateLocalLabel(); - backend.emitBNEZ(obj, label, "Ensure not None"); - backend.emitJ(errorNone, "Go to error handler"); - backend.emitLocalLabel(label, "Not None"); - incSp(n_args+1); - backend.emitSW(obj, FP, (n_args - sp_off) *wordSize, String.format("Push argument %d from last.", n_args)); - - for (int i = 0; i < n_args; ++i) - backend.emitSW(node.args.get(i).dispatch(this), FP, (n_args - i - 1 - sp_off) * wordSize, - String.format("Push argument %d from last.", n_args - i - 1)); - - backend.emitLW(A0, FP, (n_args- sp_off) * wordSize, String.format("Peek stack slot %d", sp_off - (n_args + 1))); - ClassInfo objectClass = (ClassInfo)sym.get(((Identifier)node.method.object).name); - - backend.emitLW(A1, A0, getDispatchTableOffset(), "Load address of object's dispatch table"); - backend.emitLW(A1, A1, getMethodOffset(objectClass, node.method.member.name), - String.format("Load address of method: %s.%s", objectClass.getClassName(), node.method.member.name)); - backend.emitADDI(SP, FP, -sp_off * wordSize, "Set SP to last argument."); - backend.emitJALR(A1, String.format("Invoke method: %s.%s", objectClass.getClassName(), node.method.member.name)); - backend.emitInsn(String.format("addi sp, fp, -%s", size_label), "Set SP to stack frame top."); - sp_off -= n_args+1; - - return A0; - } - - - - public Register analyze(ReturnStmt node) - { - return null; - } - } /**