diff --git a/.gitignore b/.gitignore index 21cc758..fa645bd 100644 --- a/.gitignore +++ b/.gitignore @@ -147,3 +147,9 @@ tramp Session.vim .netrwhist *~ + + + + +### Exclude ### +!src/main/asm/chocopy/common diff --git a/.vscode/launch.json b/.vscode/launch.json index 861fe91..53608f3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -12,7 +12,8 @@ "request": "launch", "classPaths": ["chocopy-ref.jar:target/assignment.jar"], "mainClass": "chocopy.ChocoPy", - "args": [ "--pass=rrs", "--test","--dir", "src/test/data/pa3/sample/list_set_element_oob_1.py"], + //"args": [ "--pass=rrs", "--test","--dir", "src/test/data/pa3/sample/list_set_element_oob_1.py"], + "args": [ "--pass=rrs", "--test","--dir", "test.py"], "sourcePaths": [] } ] diff --git a/conslist b/conslist new file mode 100644 index 0000000..f4b83a2 --- /dev/null +++ b/conslist @@ -0,0 +1,27 @@ + + addi sp, sp, -8 + sw ra, 4(sp) + sw fp, 0(sp) + addi fp, sp, 8 + lw a1, 0(fp) + la a0, $.list$prototype + beqz a1, conslist_done + addi a1, a1, @listHeaderWords + jal alloc2 + lw t0, 0(fp) + sw t0, @.__len__(a0) + slli t1, t0, 2 + add t1, t1, fp + addi t2, a0, @.__elts__ +conslist_1: + lw t3, 0(t1) + sw t3, 0(t2) + addi t1, t1, -4 + addi t2, t2, 4 + addi t0, t0, -1 + bnez t0, conslist_1 +conslist_done: + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 8 + jr ra \ No newline at end of file diff --git a/src/main/asm/chocopy/common/concat.s b/src/main/asm/chocopy/common/concat.s new file mode 100644 index 0000000..f5bb346 --- /dev/null +++ b/src/main/asm/chocopy/common/concat.s @@ -0,0 +1,63 @@ + + addi sp, sp, -32 + sw ra, 28(sp) + sw fp, 24(sp) + addi fp, sp, 32 + sw s1, -12(fp) + sw s2, -16(fp) + sw s3, -20(fp) + sw s4, -24(fp) + sw s5, -28(fp) + lw t0, 4(fp) + lw t1, 0(fp) + beqz t0, concat_none + beqz t1, concat_none + lw t0, @.__len__(t0) + lw t1, @.__len__(t1) + add s5, t0, t1 + addi a1, s5, @listHeaderWords + la a0, $.list$prototype + jal alloc2 + sw s5, @.__len__(a0) + mv s5, a0 + addi s3, s5, @.__elts__ + lw s1, 4(fp) + lw s2, @.__len__(s1) + addi s1, s1, @.__elts__ + lw s4, 12(fp) +concat_1: + beqz s2, concat_2 + lw a0, 0(s1) + jalr ra, s4, 0 + sw a0, 0(s3) + addi s2, s2, -1 + addi s1, s1, 4 + addi s3, s3, 4 + j concat_1 +concat_2: + lw s1, 0(fp) + lw s2, @.__len__(s1) + addi s1, s1, @.__elts__ + lw s4, 8(fp) +concat_3: + beqz s2, concat_4 + lw a0, 0(s1) + jalr ra, s4, 0 + sw a0, 0(s3) + addi s2, s2, -1 + addi s1, s1, 4 + addi s3, s3, 4 + j concat_3 +concat_4: + mv a0, s5 + lw s1, -12(fp) + lw s2, -16(fp) + lw s3, -20(fp) + lw s4, -24(fp) + lw s5, -28(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 32 + jr ra +concat_none: + j error.None \ No newline at end of file diff --git a/src/main/asm/chocopy/common/conslist.s b/src/main/asm/chocopy/common/conslist.s new file mode 100644 index 0000000..f4b83a2 --- /dev/null +++ b/src/main/asm/chocopy/common/conslist.s @@ -0,0 +1,27 @@ + + addi sp, sp, -8 + sw ra, 4(sp) + sw fp, 0(sp) + addi fp, sp, 8 + lw a1, 0(fp) + la a0, $.list$prototype + beqz a1, conslist_done + addi a1, a1, @listHeaderWords + jal alloc2 + lw t0, 0(fp) + sw t0, @.__len__(a0) + slli t1, t0, 2 + add t1, t1, fp + addi t2, a0, @.__elts__ +conslist_1: + lw t3, 0(t1) + sw t3, 0(t2) + addi t1, t1, -4 + addi t2, t2, 4 + addi t0, t0, -1 + bnez t0, conslist_1 +conslist_done: + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 8 + jr ra \ No newline at end of file diff --git a/src/main/asm/chocopy/common/makebool.s b/src/main/asm/chocopy/common/makebool.s new file mode 100644 index 0000000..898b587 --- /dev/null +++ b/src/main/asm/chocopy/common/makebool.s @@ -0,0 +1,5 @@ + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra \ No newline at end of file diff --git a/src/main/asm/chocopy/common/makeint.s b/src/main/asm/chocopy/common/makeint.s new file mode 100644 index 0000000..7fd541d --- /dev/null +++ b/src/main/asm/chocopy/common/makeint.s @@ -0,0 +1,11 @@ + + addi sp, sp, -8 + sw ra, 4(sp) + sw a0, 0(sp) + la a0, $int$prototype + jal ra, alloc + lw t0, 0(sp) + sw t0, @.__int__(a0) + lw ra, 4(sp) + addi sp, sp, 8 + jr ra \ No newline at end of file diff --git a/src/main/asm/chocopy/common/strcat.s b/src/main/asm/chocopy/common/strcat.s new file mode 100644 index 0000000..c131574 --- /dev/null +++ b/src/main/asm/chocopy/common/strcat.s @@ -0,0 +1,57 @@ + + addi sp, sp, -12 + sw ra, 8(sp) + sw fp, 4(sp) + addi fp, sp, 12 + lw t0, 4(fp) + lw t1, 0(fp) + lw t0, @.__len__(t0) + beqz t0, strcat_4 + lw t1, @.__len__(t1) + beqz t1, strcat_5 + add t1, t0, t1 + sw t1, -12(fp) + addi t1, t1, 4 + srli t1, t1, 2 + addi a1, t1, @listHeaderWords + la a0, $str$prototype + jal alloc2 + lw t0, -12(fp) + sw t0, @.__len__(a0) + addi t2, a0, 16 + lw t0, 4(fp) + lw t1, @.__len__(t0) + addi t0, t0, @.__str__ +strcat_1: + beqz t1, strcat_2 + lbu t3, 0(t0) + sb t3, 0(t2) + addi t1, t1, -1 + addi t0, t0, 1 + addi t2, t2, 1 + j strcat_1 +strcat_2: + lw t0, 0(fp) + lw t1, 12(t0) + addi t0, t0, 16 +strcat_3: + beqz t1, strcat_6 + lbu t3, 0(t0) + sb t3, 0(t2) + addi t1, t1, -1 + addi t0, t0, 1 + addi t2, t2, 1 + j strcat_3 +strcat_4: + lw a0, 0(fp) + j strcat_7 +strcat_5: + lw a0, 4(fp) + j strcat_7 +strcat_6: + sb zero, 0(t2) +strcat_7: + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 12 + jr ra \ No newline at end of file diff --git a/src/main/asm/chocopy/common/streql.s b/src/main/asm/chocopy/common/streql.s new file mode 100644 index 0000000..3dc5130 --- /dev/null +++ b/src/main/asm/chocopy/common/streql.s @@ -0,0 +1,27 @@ + + addi sp, sp, -8 + sw ra, 4(sp) + sw fp, 0(sp) + addi fp, sp, 8 + lw a1, 4(fp) + lw a2, 0(fp) + lw t0, @.__len__(a1) + lw t1, @.__len__(a2) + bne t0, t1, streql_no +streql_1: + lbu t2, @.__str__(a1) + lbu t3, @.__str__(a2) + bne t2, t3, streql_no + addi a1, a1, 1 + addi a2, a2, 1 + addi t0, t0, -1 + bgtz t0, streql_1 + li a0, 1 + j streql_end +streql_no: + xor a0, a0, a0 +streql_end: + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 8 + jr ra \ No newline at end of file diff --git a/src/main/asm/chocopy/common/strneql.s b/src/main/asm/chocopy/common/strneql.s new file mode 100644 index 0000000..76e316e --- /dev/null +++ b/src/main/asm/chocopy/common/strneql.s @@ -0,0 +1,27 @@ + + addi sp, sp, -8 + sw ra, 4(sp) + sw fp, 0(sp) + addi fp, sp, 8 + lw a1, 4(fp) + lw a2, 0(fp) + lw t0, @.__len__(a1) + lw t1, @.__len__(a2) + bne t0, t1, strneql_yes +strneql_1: + lbu t2, @.__str__(a1) + lbu t3, @.__str__(a2) + bne t2, t3, strneql_yes + addi a1, a1, 1 + addi a2, a2, 1 + addi t0, t0, -1 + bgtz t0, strneql_1 + xor a0, a0, a0 + j strneql_end +strneql_yes: + li a0, 1 +strneql_end: + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 8 + jr ra \ No newline at end of file diff --git a/src/main/java/chocopy/pa3/CodeGenImpl.java b/src/main/java/chocopy/pa3/CodeGenImpl.java index 3225532..6e11970 100644 --- a/src/main/java/chocopy/pa3/CodeGenImpl.java +++ b/src/main/java/chocopy/pa3/CodeGenImpl.java @@ -1,5 +1,6 @@ package chocopy.pa3; +import java.net.Socket; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -30,74 +31,17 @@ import chocopy.common.codegen.RiscVBackend.Register; */ public class CodeGenImpl extends CodeGenBase { + /** Label for built-in routines. */ + protected final Label makeintLabel = new Label("makeint"); + protected final Label strneqlLablel = new Label("strneql"); + protected final Label streqlLablel = new Label("streql"); + protected final Label makeboolLablel = new Label("makebool"); + protected final Label strcatLablel = new Label("strcat"); + protected final Label concatLablel = new Label("concat"); + protected final Label conslistLablel = new Label("conslist"); - /** A code generator emitting instructions to BACKEND. */ - 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. */ private final Label errorNone = new Label("error.None"); @@ -106,12 +50,15 @@ public class CodeGenImpl extends CodeGenBase /** Index out of bounds. */ private final Label errorOob = new Label("error.OOB"); - /** Not implemented. */ + /** Let's try to implement everything first.*/ private final Label errorNI = new Label("error.NI"); - - /** Label for built-in routine: makeint. */ - protected final Label makeIntLabel = new Label("makeint"); + /** A code generator emitting instructions to BACKEND. */ + public CodeGenImpl(RiscVBackend backend) + { + super(backend); + + } /** @@ -339,36 +286,6 @@ public class CodeGenImpl extends CodeGenBase 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); @@ -411,6 +328,7 @@ public class CodeGenImpl extends CodeGenBase // All expressions should save their end result in A0 expr.dispatch(this); + return A0; } @@ -435,15 +353,6 @@ public class CodeGenImpl extends CodeGenBase 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) { @@ -454,21 +363,32 @@ public class CodeGenImpl extends CodeGenBase 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: "); + backend.emitLW(T6, FP, 0, "Inside AssignStmt: "); Type t = node.value.getInferredType(); - if(t.isSpecialType() || t.isListType()) + // if(t.isSpecialType() || t.isListType()) { - node.value.dispatch(this); + Register reg = node.value.dispatch(this); + if (reg == null) + reg = A0; if (sym.getParent() == null) { for(Expr target: node.targets) { - GlobalVarInfo gvi=(GlobalVarInfo)sym.get(((Identifier)target).name); - backend.emitSW(Register.A0, gvi.getLabel(), Register.T0, "Assign global: "+gvi.getVarName()+"(using tmp register)"); + if(target instanceof Identifier) + { + GlobalVarInfo gvi=(GlobalVarInfo)sym.get(((Identifier)target).name); + backend.emitSW(reg, gvi.getLabel(), Register.T0, "Assign global: "+gvi.getVarName()+"(using tmp register)"); + } + else + { + Register ret = target.dispatch(this); + backend.emitSW(T1, ret, 0, "Set list element"); + } } } else @@ -477,13 +397,9 @@ public class CodeGenImpl extends CodeGenBase { StackVarInfo svi = (StackVarInfo) sym.get(((Identifier)target).name); int loc = offsetMap.get(svi); - backend.emitSW(Register.A0, Register.FP, -loc*4, "Load local variable: "+svi.getVarName()); + backend.emitSW(reg, Register.FP, -loc*4, "Load local variable: "+svi.getVarName()); } } - } - else - {//TODO: Object Assignment - } return Register.A0; } @@ -506,7 +422,7 @@ public class CodeGenImpl extends CodeGenBase backend.emitLocalLabel(elseBlock, "Else part of if expression"); node.elseExpr.dispatch(this); backend.emitLocalLabel(ln, "End of if expression"); - return null; + return A0; } @Override @@ -601,9 +517,9 @@ public class CodeGenImpl extends CodeGenBase } else if(node.left.getInferredType().equals(Type.STR_TYPE) && node.right.getInferredType().equals(Type.STR_TYPE)) { - + } - return null; + return A0; } @Override @@ -695,7 +611,7 @@ public class CodeGenImpl extends CodeGenBase 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"); + 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"), ""); @@ -723,12 +639,34 @@ public class CodeGenImpl extends CodeGenBase } - @Override - public Register analyze(IndexExpr node) - { - //System.out.println(node); - return defaultAction(node); - } + @Override + public Register analyze(IndexExpr node) + { + incSp(1); + Register listObj = node.list.dispatch(this); + backend.emitSW(listObj, FP, -sp_off * wordSize, String.format("Push on stack slot %d", sp_off)); + Register index = node.index.dispatch(this); + Register vacantReg = (index != A0) ? A0 : A1; + + if (node.list.getInferredType().isListType()) { + backend.emitLW(vacantReg, FP, -sp_off * wordSize, String.format("Pop stack slot %d", sp_off)); + + this.d(vacantReg); + return this.a(vacantReg, index, A0, false); + }else{ + this.a(0, vacantReg); + Register a = a(index); + Label ch = generateLocalLabel(); + backend.emitLW(a, vacantReg, getAttrOffset(strClass, "__len__"), "Load attribute: __len__"); + backend.emitBLTU(index, a, ch, "Ensure 0 <= idx < len"); + backend.emitJ(f, "Go to error handler"); + backend.emitLocalLabel(ch, "Index within bounds"); + this.c(index); + Register a2 = this.a(false); + this.a(1); + return a2; + } + } public Register analyze(MemberExpr node) { @@ -764,10 +702,19 @@ public class CodeGenImpl extends CodeGenBase * to out-of-bounds error and abort"); */ protected void emitCustomCode() { + + emitStdFunc("concat"); + emitStdFunc("conslist"); + emitStdFunc("strcat"); + emitStdFunc("streql"); + emitStdFunc("strneql"); + emitStdFunc("makeint"); + emitStdFunc("makebool"); + emitErrorFunc(errorNone, "Operation on None"); emitErrorFunc(errorDiv, "Division by zero"); emitErrorFunc(errorOob, "Index out of bounds"); - emitErrorFunc(errorNI, "Not Implemented"); + // emitErrorFunc(errorNI, "Not Implemented."); } /** Emit an error routine labeled ERRLABEL that aborts with message MSG. */