From 9786fbbc69d6f33b646b2a84e152306eaf5aec9f Mon Sep 17 00:00:00 2001 From: bill Date: Fri, 30 Apr 2021 16:45:30 +0800 Subject: [PATCH] Classes/Objects/Methods --- .vscode/launch.json | 19 + .vscode/settings.json | 3 + src/main/java/chocopy/pa3/CodeGenImpl.java | 166 +- .../data/pa3/benchmarks/exp.py.ast.typed.s | 795 +++++++++ .../data/pa3/benchmarks/prime.py.ast.typed.s | 789 +++++++++ .../data/pa3/benchmarks/sieve.py.ast.typed.s | 1492 +++++++++++++++++ .../data/pa3/benchmarks/stdlib.py.ast.typed.s | 1198 +++++++++++++ .../data/pa3/benchmarks/tree.py.ast.typed.s | 1267 ++++++++++++++ src/test/data/pa3/sample/call.py.ast.typed.s | 794 +++++++++ .../pa3/sample/call_with_args.py.ast.typed.s | 806 +++++++++ .../pa3/sample/error_div_zero.py.ast.typed.s | 673 ++++++++ .../sample/error_invalid_print.py.ast.typed.s | 654 ++++++++ .../pa3/sample/error_mod_zero.py.ast.typed.s | 670 ++++++++ .../data/pa3/sample/expr_if.py.ast.typed.s | 674 ++++++++ .../data/pa3/sample/id_global.py.ast.typed.s | 659 ++++++++ .../data/pa3/sample/id_local.py.ast.typed.s | 676 ++++++++ src/test/data/pa3/sample/input.py.ast.typed.s | 687 ++++++++ .../pa3/sample/len_invalid_1.py.ast.typed.s | 663 ++++++++ .../pa3/sample/len_invalid_2.py.ast.typed.s | 664 ++++++++ .../pa3/sample/list_concat.py.ast.typed.s | 751 +++++++++ .../pa3/sample/list_concat_2.py.ast.typed.s | 748 +++++++++ .../sample/list_concat_none.py.ast.typed.s | 677 ++++++++ .../sample/list_get_element.py.ast.typed.s | 728 ++++++++ .../list_get_element_complex.py.ast.typed.s | 738 ++++++++ .../list_get_element_none.py.ast.typed.s | 674 ++++++++ .../list_get_element_oob_1.py.ast.typed.s | 687 ++++++++ .../list_get_element_oob_2.py.ast.typed.s | 686 ++++++++ .../list_get_element_oob_3.py.ast.typed.s | 680 ++++++++ .../data/pa3/sample/list_len.py.ast.typed.s | 675 ++++++++ .../pa3/sample/list_len_empty.py.ast.typed.s | 669 ++++++++ .../sample/list_set_element.py.ast.typed.s | 785 +++++++++ .../list_set_element_none.py.ast.typed.s | 672 ++++++++ .../list_set_element_oob_1.py.ast.typed.s | 748 +++++++++ .../list_set_element_oob_2.py.ast.typed.s | 747 +++++++++ .../list_set_element_oob_3.py.ast.typed.s | 678 ++++++++ .../pa3/sample/literal_bool.py.ast.typed.s | 661 ++++++++ .../pa3/sample/literal_int.py.ast.typed.s | 661 ++++++++ .../pa3/sample/literal_str.py.ast.typed.s | 663 ++++++++ .../data/pa3/sample/nested.py.ast.typed.s | 728 ++++++++ .../data/pa3/sample/nested2.py.ast.typed.s | 753 +++++++++ .../pa3/sample/object_attr_get.py.ast.typed.s | 755 +++++++++ .../object_attr_get_none.py.ast.typed.s | 752 +++++++++ .../pa3/sample/object_attr_set.py.ast.typed.s | 773 +++++++++ .../object_attr_set_eval_order.py.ast.typed.s | 902 ++++++++++ .../object_attr_set_none.py.ast.typed.s | 770 +++++++++ .../pa3/sample/object_init.py.ast.typed.s | 713 ++++++++ .../pa3/sample/object_method.py.ast.typed.s | 786 +++++++++ .../object_method_complex_call.py.ast.typed.s | 824 +++++++++ .../object_method_nested.py.ast.typed.s | 806 +++++++++ .../sample/object_method_none.py.ast.typed.s | 788 +++++++++ .../object_method_override.py.ast.typed.s | 803 +++++++++ .../data/pa3/sample/op_add.py.ast.typed.s | 659 ++++++++ .../pa3/sample/op_cmp_bool.py.ast.typed.s | 745 ++++++++ .../data/pa3/sample/op_cmp_int.py.ast.typed.s | 785 +++++++++ .../data/pa3/sample/op_div_mod.py.ast.typed.s | 702 ++++++++ src/test/data/pa3/sample/op_is.py.ast.typed.s | 778 +++++++++ .../data/pa3/sample/op_logical.py.ast.typed.s | 765 +++++++++ .../data/pa3/sample/op_mul.py.ast.typed.s | 663 ++++++++ .../data/pa3/sample/op_negate.py.ast.typed.s | 660 ++++++++ .../data/pa3/sample/op_sub.py.ast.typed.s | 659 ++++++++ src/test/data/pa3/sample/pass.py.ast.typed.s | 649 +++++++ .../sample/predef_constructors.py.ast.typed.s | 695 ++++++++ .../pa3/sample/stmt_for_list.py.ast.typed.s | 697 ++++++++ .../sample/stmt_for_list_empty.py.ast.typed.s | 747 +++++++++ .../sample/stmt_for_list_eval.py.ast.typed.s | 703 ++++++++ .../stmt_for_list_modify.py.ast.typed.s | 716 ++++++++ .../stmt_for_list_nested.py.ast.typed.s | 727 ++++++++ ...mt_for_list_nested_same_var.py.ast.typed.s | 723 ++++++++ .../sample/stmt_for_list_none.py.ast.typed.s | 685 ++++++++ .../stmt_for_list_nonlocal.py.ast.typed.s | 791 +++++++++ .../stmt_for_list_return.py.ast.typed.s | 719 ++++++++ .../pa3/sample/stmt_for_str.py.ast.typed.s | 726 ++++++++ .../sample/stmt_for_str_empty.py.ast.typed.s | 767 +++++++++ .../sample/stmt_for_str_eval.py.ast.typed.s | 737 ++++++++ .../sample/stmt_for_str_nested.py.ast.typed.s | 767 +++++++++ .../stmt_for_str_same_var.py.ast.typed.s | 713 ++++++++ .../data/pa3/sample/stmt_if.py.ast.typed.s | 683 ++++++++ .../sample/stmt_return_early.py.ast.typed.s | 680 ++++++++ .../data/pa3/sample/stmt_while.py.ast.typed.s | 673 ++++++++ .../data/pa3/sample/str_cat.py.ast.typed.s | 835 +++++++++ .../data/pa3/sample/str_cat_2.py.ast.typed.s | 795 +++++++++ .../data/pa3/sample/str_cmp.py.ast.typed.s | 806 +++++++++ .../pa3/sample/str_get_element.py.ast.typed.s | 779 +++++++++ .../str_get_element_oob_1.py.ast.typed.s | 746 +++++++++ .../str_get_element_oob_2.py.ast.typed.s | 745 ++++++++ .../str_get_element_oob_3.py.ast.typed.s | 736 ++++++++ .../data/pa3/sample/str_len.py.ast.typed.s | 668 ++++++++ .../data/pa3/sample/var_assign.py.ast.typed.s | 677 ++++++++ web/WebCompiler.py.ast | 0 89 files changed, 63620 insertions(+), 11 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 src/test/data/pa3/benchmarks/exp.py.ast.typed.s create mode 100644 src/test/data/pa3/benchmarks/prime.py.ast.typed.s create mode 100644 src/test/data/pa3/benchmarks/sieve.py.ast.typed.s create mode 100644 src/test/data/pa3/benchmarks/stdlib.py.ast.typed.s create mode 100644 src/test/data/pa3/benchmarks/tree.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/call.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/call_with_args.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/error_div_zero.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/error_invalid_print.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/error_mod_zero.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/expr_if.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/id_global.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/id_local.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/input.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/len_invalid_1.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/len_invalid_2.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/list_concat.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/list_concat_2.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/list_concat_none.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/list_get_element.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/list_get_element_complex.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/list_get_element_none.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/list_get_element_oob_1.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/list_get_element_oob_2.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/list_get_element_oob_3.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/list_len.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/list_len_empty.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/list_set_element.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/list_set_element_none.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/list_set_element_oob_1.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/list_set_element_oob_2.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/list_set_element_oob_3.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/literal_bool.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/literal_int.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/literal_str.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/nested.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/nested2.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/object_attr_get.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/object_attr_get_none.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/object_attr_set.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/object_attr_set_eval_order.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/object_attr_set_none.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/object_init.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/object_method.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/object_method_complex_call.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/object_method_nested.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/object_method_none.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/object_method_override.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/op_add.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/op_cmp_bool.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/op_cmp_int.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/op_div_mod.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/op_is.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/op_logical.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/op_mul.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/op_negate.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/op_sub.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/pass.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/predef_constructors.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/stmt_for_list.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/stmt_for_list_empty.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/stmt_for_list_eval.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/stmt_for_list_modify.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/stmt_for_list_nested.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/stmt_for_list_nested_same_var.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/stmt_for_list_none.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/stmt_for_list_nonlocal.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/stmt_for_list_return.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/stmt_for_str.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/stmt_for_str_empty.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/stmt_for_str_eval.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/stmt_for_str_nested.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/stmt_for_str_same_var.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/stmt_if.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/stmt_return_early.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/stmt_while.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/str_cat.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/str_cat_2.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/str_cmp.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/str_get_element.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/str_get_element_oob_1.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/str_get_element_oob_2.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/str_get_element_oob_3.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/str_len.py.ast.typed.s create mode 100644 src/test/data/pa3/sample/var_assign.py.ast.typed.s create mode 100644 web/WebCompiler.py.ast diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..861fe91 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,19 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + + { + "type": "java", + "name": "Launch Current File", + "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"], + "sourcePaths": [] + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..c5f3f6b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.configuration.updateBuildConfiguration": "interactive" +} \ 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 47a31c8..ac0a67b 100644 --- a/src/main/java/chocopy/pa3/CodeGenImpl.java +++ b/src/main/java/chocopy/pa3/CodeGenImpl.java @@ -2,12 +2,14 @@ package chocopy.pa3; import chocopy.common.analysis.AbstractNodeAnalyzer; import chocopy.common.analysis.SymbolTable; -import chocopy.common.astnodes.ReturnStmt; -import chocopy.common.astnodes.Stmt; +import chocopy.common.analysis.types.FuncType; +import chocopy.common.analysis.types.Type; +import chocopy.common.astnodes.*; import chocopy.common.codegen.*; import java.util.List; +import chocopy.common.codegen.RiscVBackend.Register; import static chocopy.common.codegen.RiscVBackend.Register.*; /** @@ -84,7 +86,7 @@ public class CodeGenImpl extends CodeGenBase { } /** An analyzer that encapsulates code generation for statements. */ - private class StmtAnalyzer extends AbstractNodeAnalyzer { + private class StmtAnalyzer extends AbstractNodeAnalyzer { /* * The symbol table has all the info you need to determine * what a given identifier 'x' in the current scope is. You can @@ -124,29 +126,171 @@ public class CodeGenImpl extends CodeGenBase { /** The descriptor for the current function, or null at the top level. */ private final FuncInfo funcInfo; + private final String size_label; + private int sp_off, max_sp; /** An analyzer for the function described by FUNCINFO0, which is null for the top level. */ StmtAnalyzer(FuncInfo funcInfo0) { funcInfo = funcInfo0; if (funcInfo == null) { sym = globalSymbols; + sp_off = max_sp = 2; + size_label = "@..main.size"; } else { sym = funcInfo.getSymbolTable(); + sp_off = max_sp = funcInfo0.getLocals().size() + 2; + size_label = "@"+funcInfo0.getFuncName()+".size"; } 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"); + public Register analyze(AssignStmt node) { return null; } + + public Register analyze(BinaryExpr node) { + return null; + } + + public Register analyze(BooleanLiteral node) { + return null; + } + + public Register analyze(CallExpr node) { + SymbolInfo Ty = globalSymbols.get(node.function.name); + if(Ty instanceof ClassInfo){ + //object create + ClassInfo cls = (ClassInfo) Ty; + /** + la a0, $DoublingVector$prototype # Load pointer to prototype of: DoublingVector + jal alloc # Allocate new object in A0 + sw a0, -12(fp) # Push on stack slot 3 + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 0(a1) # Load address of method: DoublingVector.__init__ + jalr a1 # Invoke method: DoublingVector.__init__ + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, -12(fp) # Pop stack slot 3 + */ + backend.emitLA(A0, cls.getPrototypeLabel(), + String.format("Load pointer to prototype of: %s", cls.getClassName())); + backend.emitJAL(objectAllocLabel, "Allocate new object in A0"); + backend.emitSW(A0, FP, -sp_off*wordSize, String.format("Push on stack slot %d", sp_off)); + if(sp_off>max_sp) + max_sp = sp_off; + sp_off++; + backend.emitSW(A0, FP, -sp_off*wordSize, "Push argument 0 from last."); + backend.emitADDI(SP, FP, sp_off, "Set SP to last argument."); + backend.emitLW(A1, A0, getDispatchTableOffset(), "Load address of object's dispatch table"); + backend.emitLW(A1, A1, getMethodOffset(cls, "__init__"), String.format("Load address of method: %s.__init__", cls.getClassName())); + backend.emitJALR(A1, String.format("Invoke method: %s.__init", cls.getClassName())); + 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 + } + + return null; + } + + public Register analyze(ExprStmt node) { + return null; + } + + public Register analyze(ForStmt node) { + return null; + } + + public Register analyze(Identifier node) { + return null; + } + + public Register analyze(IfExpr node) { + return null; + } + + public Register analyze(IfStmt node) { + return null; + } + + public Register analyze(IndexExpr node) { + return null; + } + + public Register analyze(IntegerLiteral node) { + return null; + } + + public Register analyze(ListExpr node) { + return null; + } + + public Register analyze(MemberExpr node) { + ClassInfo objectClass = (ClassInfo) globalSymbols.get(node.object.getInferredType().className()); + Label label = generateLocalLabel(); + Register obj = node.object.dispatch(this); + + backend.emitBNEZ(obj, label, "Ensure not None"); + backend.emitJ(errorNone, "Go to error handler"); + backend.emitLocalLabel(label, "Not None"); + backend.emitLW(A0, obj, getAttrOffset(objectClass, node.member.name), + 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"); + if(sp_off>max_sp) + max_sp = sp_off; + sp_off += (n_args+1)*wordSize; + 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)*wordSize; + + return A0; + } + + public Register analyze(NoneLiteral node) { + return null; + } + + public Register analyze(ReturnStmt node) { + return null; + } + + public Register analyze(StringLiteral node) { + return null; + } + + public Register analyze(UnaryExpr node) { + return null; + } + + public Register analyze(WhileStmt node) { + return null; + } + // FIXME: More, of course. } diff --git a/src/test/data/pa3/benchmarks/exp.py.ast.typed.s b/src/test/data/pa3/benchmarks/exp.py.ast.typed.s new file mode 100644 index 0000000..98d8973 --- /dev/null +++ b/src/test/data/pa3/benchmarks/exp.py.ast.typed.s @@ -0,0 +1,795 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $n +$n: + .word 42 # Initial value of global var: n + +.globl $i +$i: + .word 0 # Initial value of global var: i + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + j label_2 # Jump to loop test +label_1: # Top of while loop + li a0, 2 # Load integer literal 2 + sw a0, -28(fp) # Push argument 1 from last. + lw a0, $i # Load global: i + sw a0, -36(fp) # Push on stack slot 9 + li a0, 31 # Load integer literal 31 + lw t0, -36(fp) # Pop stack slot 9 + bnez a0, label_3 # Ensure non-zero divisor + j error.Div # Go to error handler +label_3: # Divisor is non-zero + rem t2, t0, a0 # Operator rem + beqz t2, label_4 # If no remainder, no adjustment + xor t3, t2, a0 # Check for differing signs. + bgez t3, label_4 # Don't adjust if signs equal. + add a0, t2, a0 # Adjust + j label_5 +label_4: # Store result + mv a0, t2 +label_5: # End of % + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $exp # Invoke function: exp + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $i # Load global: i + sw a0, -12(fp) # Push on stack slot 3 + li a0, 1 # Load integer literal 1 + lw t0, -12(fp) # Pop stack slot 3 + add a0, t0, a0 # Operator + + sw a0, $i, t0 # Assign global: i (using tmp register) +label_2: # Test loop condition + lw a0, $i # Load global: i + sw a0, -12(fp) # Push on stack slot 3 + lw a0, $n # Load global: n + lw t0, -12(fp) # Pop stack slot 3 + bge a0, t0, label_1 # Branch on <= + .equiv @..main.size, 48 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $exp.f.geta +$exp.f.geta: + addi sp, sp, -@exp.f.geta.size # Reserve space for stack frame. + sw ra, @exp.f.geta.size-4(sp) # return address + sw fp, @exp.f.geta.size-8(sp) # control link + addi fp, sp, @exp.f.geta.size # New fp is at old SP. + lw t0, 0(fp) # Load static link from exp.f.geta to exp.f + lw t0, 4(t0) # Load static link from exp.f to exp + lw a0, -12(t0) # Load var: exp.a + j label_7 # Go to return + mv a0, zero # Load None + j label_7 # Jump to function epilogue +label_7: # Epilogue + .equiv @exp.f.geta.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @exp.f.geta.size # Restore stack pointer + jr ra # Return to caller + +.globl $exp.f +$exp.f: + addi sp, sp, -@exp.f.size # Reserve space for stack frame. + sw ra, @exp.f.size-4(sp) # return address + sw fp, @exp.f.size-8(sp) # control link + addi fp, sp, @exp.f.size # New fp is at old SP. + lw a0, 0(fp) # Load var: exp.f.i + sw a0, -12(fp) # Push on stack slot 3 + li a0, 0 # Load integer literal 0 + lw t0, -12(fp) # Pop stack slot 3 + blt a0, t0, label_11 # Branch on not <= + mv t0, fp # Get static link to exp.f + sw t0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $exp.f.geta # Invoke function: exp.f.geta + addi sp, fp, -@exp.f.size # Set SP to stack frame top. + j label_9 # Go to return + j label_10 # Then body complete; jump to end-if +label_11: # Else body + lw t0, 4(fp) # Load static link from exp.f to exp + lw a0, -12(t0) # Load var: exp.a + sw a0, -12(fp) # Push on stack slot 3 + lw t0, 4(fp) # Load static link from exp.f to exp + lw a0, 4(t0) # Load var: exp.x + lw t0, -12(fp) # Pop stack slot 3 + mul a0, t0, a0 # Operator * + lw t0, 4(fp) # Load static link from exp.f to exp + sw a0, -12(t0) # Assign var: exp.a + mv t0, fp # Get static link to exp.f + lw t0, 4(t0) # Get static link to exp + sw t0, -12(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: exp.f.i + sw a0, -20(fp) # Push on stack slot 5 + li a0, 1 # Load integer literal 1 + lw t0, -20(fp) # Pop stack slot 5 + sub a0, t0, a0 # Operator - + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $exp.f # Invoke function: exp.f + addi sp, fp, -@exp.f.size # Set SP to stack frame top. + j label_9 # Go to return +label_10: # End of if-else statement + mv a0, zero # Load None + j label_9 # Jump to function epilogue +label_9: # Epilogue + .equiv @exp.f.size, 32 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @exp.f.size # Restore stack pointer + jr ra # Return to caller + +.globl $exp +$exp: + addi sp, sp, -@exp.size # Reserve space for stack frame. + sw ra, @exp.size-4(sp) # return address + sw fp, @exp.size-8(sp) # control link + addi fp, sp, @exp.size # New fp is at old SP. + li a0, 0 # Load integer literal 0 + sw a0, -12(fp) # local variable a + li a0, 1 # Load integer literal 1 + sw a0, -12(fp) # Assign var: exp.a + mv t0, fp # Get static link to exp + sw t0, -28(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: exp.y + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $exp.f # Invoke function: exp.f + addi sp, fp, -@exp.size # Set SP to stack frame top. + j label_13 # Go to return + mv a0, zero # Load None + j label_13 # Jump to function epilogue +label_13: # Epilogue + .equiv @exp.size, 32 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @exp.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/benchmarks/prime.py.ast.typed.s b/src/test/data/pa3/benchmarks/prime.py.ast.typed.s new file mode 100644 index 0000000..95e6a74 --- /dev/null +++ b/src/test/data/pa3/benchmarks/prime.py.ast.typed.s @@ -0,0 +1,789 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $n +$n: + .word 15 # Initial value of global var: n + +.globl $i +$i: + .word 1 # Initial value of global var: i + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + j label_2 # Jump to loop test +label_1: # Top of while loop + lw a0, $i # Load global: i + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $get_prime # Invoke function: get_prime + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $i # Load global: i + sw a0, -12(fp) # Push on stack slot 3 + li a0, 1 # Load integer literal 1 + lw t0, -12(fp) # Pop stack slot 3 + add a0, t0, a0 # Operator + + sw a0, $i, t0 # Assign global: i (using tmp register) +label_2: # Test loop condition + lw a0, $i # Load global: i + sw a0, -12(fp) # Push on stack slot 3 + lw a0, $n # Load global: n + lw t0, -12(fp) # Pop stack slot 3 + bge a0, t0, label_1 # Branch on <= + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $get_prime +$get_prime: + addi sp, sp, -@get_prime.size # Reserve space for stack frame. + sw ra, @get_prime.size-4(sp) # return address + sw fp, @get_prime.size-8(sp) # control link + addi fp, sp, @get_prime.size # New fp is at old SP. + li a0, 2 # Load integer literal 2 + sw a0, -12(fp) # local variable candidate + li a0, 0 # Load integer literal 0 + sw a0, -16(fp) # local variable found + j label_6 # Jump to loop test +label_5: # Top of while loop + lw a0, -12(fp) # Load var: get_prime.candidate + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $is_prime # Invoke function: is_prime + addi sp, fp, -@get_prime.size # Set SP to stack frame top. + beqz a0, label_7 # Branch on false. + lw a0, -16(fp) # Load var: get_prime.found + sw a0, -20(fp) # Push on stack slot 5 + li a0, 1 # Load integer literal 1 + lw t0, -20(fp) # Pop stack slot 5 + add a0, t0, a0 # Operator + + sw a0, -16(fp) # Assign var: get_prime.found + lw a0, -16(fp) # Load var: get_prime.found + sw a0, -20(fp) # Push on stack slot 5 + lw a0, 0(fp) # Load var: get_prime.n + lw t0, -20(fp) # Pop stack slot 5 + bne t0, a0, label_8 # Branch on not == + lw a0, -12(fp) # Load var: get_prime.candidate + j label_4 # Go to return +label_8: # End of if-else statement +label_7: # End of if-else statement + lw a0, -12(fp) # Load var: get_prime.candidate + sw a0, -20(fp) # Push on stack slot 5 + li a0, 1 # Load integer literal 1 + lw t0, -20(fp) # Pop stack slot 5 + add a0, t0, a0 # Operator + + sw a0, -12(fp) # Assign var: get_prime.candidate +label_6: # Test loop condition + j label_5 # Branch on true. + li a0, 0 # Load integer literal 0 + j label_4 # Go to return + mv a0, zero # Load None + j label_4 # Jump to function epilogue +label_4: # Epilogue + .equiv @get_prime.size, 32 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @get_prime.size # Restore stack pointer + jr ra # Return to caller + +.globl $is_prime +$is_prime: + addi sp, sp, -@is_prime.size # Reserve space for stack frame. + sw ra, @is_prime.size-4(sp) # return address + sw fp, @is_prime.size-8(sp) # control link + addi fp, sp, @is_prime.size # New fp is at old SP. + li a0, 2 # Load integer literal 2 + sw a0, -12(fp) # local variable div + j label_12 # Jump to loop test +label_11: # Top of while loop + lw a0, 0(fp) # Load var: is_prime.x + sw a0, -16(fp) # Push on stack slot 4 + lw a0, -12(fp) # Load var: is_prime.div + lw t0, -16(fp) # Pop stack slot 4 + bnez a0, label_14 # Ensure non-zero divisor + j error.Div # Go to error handler +label_14: # Divisor is non-zero + rem t2, t0, a0 # Operator rem + beqz t2, label_15 # If no remainder, no adjustment + xor t3, t2, a0 # Check for differing signs. + bgez t3, label_15 # Don't adjust if signs equal. + add a0, t2, a0 # Adjust + j label_16 +label_15: # Store result + mv a0, t2 +label_16: # End of % + sw a0, -16(fp) # Push on stack slot 4 + li a0, 0 # Load integer literal 0 + lw t0, -16(fp) # Pop stack slot 4 + bne t0, a0, label_13 # Branch on not == + li a0, 0 # Load boolean literal: false + j label_10 # Go to return +label_13: # End of if-else statement + lw a0, -12(fp) # Load var: is_prime.div + sw a0, -16(fp) # Push on stack slot 4 + li a0, 1 # Load integer literal 1 + lw t0, -16(fp) # Pop stack slot 4 + add a0, t0, a0 # Operator + + sw a0, -12(fp) # Assign var: is_prime.div +label_12: # Test loop condition + lw a0, -12(fp) # Load var: is_prime.div + sw a0, -16(fp) # Push on stack slot 4 + lw a0, 0(fp) # Load var: is_prime.x + lw t0, -16(fp) # Pop stack slot 4 + blt t0, a0, label_11 # Branch on < + li a0, 1 # Load boolean literal: true + j label_10 # Go to return + mv a0, zero # Load None + j label_10 # Jump to function epilogue +label_10: # Epilogue + .equiv @is_prime.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @is_prime.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/benchmarks/sieve.py.ast.typed.s b/src/test/data/pa3/benchmarks/sieve.py.ast.typed.s new file mode 100644 index 0000000..2805e7b --- /dev/null +++ b/src/test/data/pa3/benchmarks/sieve.py.ast.typed.s @@ -0,0 +1,1492 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $Vector$prototype +$Vector$prototype: + .word 4 # Type tag for class: Vector + .word 5 # Object size + .word $Vector$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: items + .word 0 # Initial value of attribute: size + .align 2 + +.globl $DoublingVector$prototype +$DoublingVector$prototype: + .word 5 # Type tag for class: DoublingVector + .word 6 # Object size + .word $DoublingVector$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: items + .word 0 # Initial value of attribute: size + .word 1000 # Initial value of attribute: doubling_limit + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $Vector$dispatchTable +$Vector$dispatchTable: + .word $Vector.__init__ # Implementation for method: Vector.__init__ + .word $Vector.capacity # Implementation for method: Vector.capacity + .word $Vector.increase_capacity # Implementation for method: Vector.increase_capacity + .word $Vector.append # Implementation for method: Vector.append + .word $Vector.append_all # Implementation for method: Vector.append_all + .word $Vector.remove_at # Implementation for method: Vector.remove_at + .word $Vector.get # Implementation for method: Vector.get + .word $Vector.length # Implementation for method: Vector.length + +.globl $DoublingVector$dispatchTable +$DoublingVector$dispatchTable: + .word $Vector.__init__ # Implementation for method: DoublingVector.__init__ + .word $Vector.capacity # Implementation for method: DoublingVector.capacity + .word $DoublingVector.increase_capacity # Implementation for method: DoublingVector.increase_capacity + .word $Vector.append # Implementation for method: DoublingVector.append + .word $Vector.append_all # Implementation for method: DoublingVector.append_all + .word $Vector.remove_at # Implementation for method: DoublingVector.remove_at + .word $Vector.get # Implementation for method: DoublingVector.get + .word $Vector.length # Implementation for method: DoublingVector.length + +.globl $n +$n: + .word 50 # Initial value of global var: n + +.globl $v +$v: + .word 0 # Initial value of global var: v + +.globl $i +$i: + .word 0 # Initial value of global var: i + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 2 # Load integer literal 2 + sw a0, -12(fp) # Push argument 1 from last. + lw a0, $n # Load global: n + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $vrange # Invoke function: vrange + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $v, t0 # Assign global: v (using tmp register) + lw a0, $v # Load global: v + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $sieve # Invoke function: sieve + addi sp, fp, -@..main.size # Set SP to stack frame top. + j label_2 # Jump to loop test +label_1: # Top of while loop + lw a0, $v # Load global: v + bnez a0, label_3 # Ensure not None + j error.None # Go to error handler +label_3: # Not None + sw a0, -28(fp) # Push argument 1 from last. + lw a0, $i # Load global: i + sw a0, -32(fp) # Push argument 0 from last. + lw a0, -28(fp) # Peek stack slot 6 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 24(a1) # Load address of method: Vector.get + addi sp, fp, -32 # Set SP to last argument. + jalr a1 # Invoke method: Vector.get + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $i # Load global: i + sw a0, -12(fp) # Push on stack slot 3 + li a0, 1 # Load integer literal 1 + lw t0, -12(fp) # Pop stack slot 3 + add a0, t0, a0 # Operator + + sw a0, $i, t0 # Assign global: i (using tmp register) +label_2: # Test loop condition + lw a0, $i # Load global: i + sw a0, -12(fp) # Push on stack slot 3 + lw a0, $v # Load global: v + bnez a0, label_4 # Ensure not None + j error.None # Go to error handler +label_4: # Not None + sw a0, -16(fp) # Push argument 0 from last. + lw a0, -16(fp) # Peek stack slot 3 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 28(a1) # Load address of method: Vector.length + addi sp, fp, -16 # Set SP to last argument. + jalr a1 # Invoke method: Vector.length + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw t0, -12(fp) # Pop stack slot 3 + blt t0, a0, label_1 # Branch on < + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $Vector.__init__ +$Vector.__init__: + addi sp, sp, -@Vector.__init__.size # Reserve space for stack frame. + sw ra, @Vector.__init__.size-4(sp) # return address + sw fp, @Vector.__init__.size-8(sp) # control link + addi fp, sp, @Vector.__init__.size # New fp is at old SP. + li a0, 0 # Load integer literal 0 + sw a0, -12(fp) # Push argument 1 from last. + li a0, 1 # Pass list length + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@Vector.__init__.size # Set SP to stack frame top. + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 0(fp) # Load var: Vector.__init__.self + mv a1, a0 # Move object + lw a0, -12(fp) # Pop stack slot 3 + bnez a1, label_7 # Ensure not None + j error.None # Go to error handler +label_7: # Not None + sw a0, 12(a1) # Set attribute: Vector.items + mv a0, zero # Load None + j label_6 # Jump to function epilogue +label_6: # Epilogue + .equiv @Vector.__init__.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @Vector.__init__.size # Restore stack pointer + jr ra # Return to caller + +.globl $Vector.capacity +$Vector.capacity: + addi sp, sp, -@Vector.capacity.size # Reserve space for stack frame. + sw ra, @Vector.capacity.size-4(sp) # return address + sw fp, @Vector.capacity.size-8(sp) # control link + addi fp, sp, @Vector.capacity.size # New fp is at old SP. + lw a0, 0(fp) # Load var: Vector.capacity.self + bnez a0, label_10 # Ensure not None + j error.None # Go to error handler +label_10: # Not None + lw a0, 12(a0) # Get attribute: Vector.items + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $len # Invoke function: len + addi sp, fp, -@Vector.capacity.size # Set SP to stack frame top. + j label_9 # Go to return + mv a0, zero # Load None + j label_9 # Jump to function epilogue +label_9: # Epilogue + .equiv @Vector.capacity.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @Vector.capacity.size # Restore stack pointer + jr ra # Return to caller + +.globl $Vector.increase_capacity +$Vector.increase_capacity: + addi sp, sp, -@Vector.increase_capacity.size # Reserve space for stack frame. + sw ra, @Vector.increase_capacity.size-4(sp) # return address + sw fp, @Vector.increase_capacity.size-8(sp) # control link + addi fp, sp, @Vector.increase_capacity.size # New fp is at old SP. + la t0, noconv # Identity conversion + sw t0, -20(fp) # Push argument 3 from last. + la t0, noconv # Identity conversion + sw t0, -24(fp) # Push argument 2 from last. + lw a0, 0(fp) # Load var: Vector.increase_capacity.self + bnez a0, label_13 # Ensure not None + j error.None # Go to error handler +label_13: # Not None + lw a0, 12(a0) # Get attribute: Vector.items + sw a0, -28(fp) # Push argument 1 from last. + li a0, 0 # Load integer literal 0 + sw a0, -44(fp) # Push argument 1 from last. + li a0, 1 # Pass list length + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@Vector.increase_capacity.size # Set SP to stack frame top. + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal concat # Call runtime concatenation routine. + addi sp, fp, -@Vector.increase_capacity.size # Set SP to stack frame top. + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 0(fp) # Load var: Vector.increase_capacity.self + mv a1, a0 # Move object + lw a0, -12(fp) # Pop stack slot 3 + bnez a1, label_14 # Ensure not None + j error.None # Go to error handler +label_14: # Not None + sw a0, 12(a1) # Set attribute: Vector.items + lw a0, 0(fp) # Load var: Vector.increase_capacity.self + bnez a0, label_15 # Ensure not None + j error.None # Go to error handler +label_15: # Not None + sw a0, -16(fp) # Push argument 0 from last. + lw a0, -16(fp) # Peek stack slot 3 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 4(a1) # Load address of method: Vector.capacity + addi sp, fp, -16 # Set SP to last argument. + jalr a1 # Invoke method: Vector.capacity + addi sp, fp, -@Vector.increase_capacity.size # Set SP to stack frame top. + j label_12 # Go to return + mv a0, zero # Load None + j label_12 # Jump to function epilogue +label_12: # Epilogue + .equiv @Vector.increase_capacity.size, 48 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @Vector.increase_capacity.size # Restore stack pointer + jr ra # Return to caller + +.globl $Vector.append +$Vector.append: + addi sp, sp, -@Vector.append.size # Reserve space for stack frame. + sw ra, @Vector.append.size-4(sp) # return address + sw fp, @Vector.append.size-8(sp) # control link + addi fp, sp, @Vector.append.size # New fp is at old SP. + lw a0, 4(fp) # Load var: Vector.append.self + bnez a0, label_19 # Ensure not None + j error.None # Go to error handler +label_19: # Not None + lw a0, 16(a0) # Get attribute: Vector.size + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 4(fp) # Load var: Vector.append.self + bnez a0, label_20 # Ensure not None + j error.None # Go to error handler +label_20: # Not None + sw a0, -16(fp) # Push argument 0 from last. + lw a0, -16(fp) # Peek stack slot 3 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 4(a1) # Load address of method: Vector.capacity + addi sp, fp, -16 # Set SP to last argument. + jalr a1 # Invoke method: Vector.capacity + addi sp, fp, -@Vector.append.size # Set SP to stack frame top. + lw t0, -12(fp) # Pop stack slot 3 + bne t0, a0, label_18 # Branch on not == + lw a0, 4(fp) # Load var: Vector.append.self + bnez a0, label_21 # Ensure not None + j error.None # Go to error handler +label_21: # Not None + sw a0, -16(fp) # Push argument 0 from last. + lw a0, -16(fp) # Peek stack slot 3 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 8(a1) # Load address of method: Vector.increase_capacity + addi sp, fp, -16 # Set SP to last argument. + jalr a1 # Invoke method: Vector.increase_capacity + addi sp, fp, -@Vector.append.size # Set SP to stack frame top. +label_18: # End of if-else statement + lw a0, 0(fp) # Load var: Vector.append.item + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 4(fp) # Load var: Vector.append.self + bnez a0, label_22 # Ensure not None + j error.None # Go to error handler +label_22: # Not None + lw a0, 12(a0) # Get attribute: Vector.items + sw a0, -16(fp) # Push on stack slot 4 + lw a0, 4(fp) # Load var: Vector.append.self + bnez a0, label_23 # Ensure not None + j error.None # Go to error handler +label_23: # Not None + lw a0, 16(a0) # Get attribute: Vector.size + lw t0, -16(fp) # Pop stack slot 4 + lw t1, -12(fp) # Pop stack slot 3 + bnez t0, label_24 # Ensure not None + j error.None # Go to error handler +label_24: # Not None + lw t2, 12(t0) # Load attribute: __len__ + bltu a0, t2, label_25 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_25: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul a0, a0, t2 # Compute list element offset in bytes + add a0, t0, a0 # Pointer to list element + sw t1, 0(a0) # Set list element + lw a0, 4(fp) # Load var: Vector.append.self + bnez a0, label_26 # Ensure not None + j error.None # Go to error handler +label_26: # Not None + lw a0, 16(a0) # Get attribute: Vector.size + sw a0, -12(fp) # Push on stack slot 3 + li a0, 1 # Load integer literal 1 + lw t0, -12(fp) # Pop stack slot 3 + add a0, t0, a0 # Operator + + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 4(fp) # Load var: Vector.append.self + mv a1, a0 # Move object + lw a0, -12(fp) # Pop stack slot 3 + bnez a1, label_27 # Ensure not None + j error.None # Go to error handler +label_27: # Not None + sw a0, 16(a1) # Set attribute: Vector.size + mv a0, zero # Load None + j label_17 # Jump to function epilogue +label_17: # Epilogue + .equiv @Vector.append.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @Vector.append.size # Restore stack pointer + jr ra # Return to caller + +.globl $Vector.append_all +$Vector.append_all: + addi sp, sp, -@Vector.append_all.size # Reserve space for stack frame. + sw ra, @Vector.append_all.size-4(sp) # return address + sw fp, @Vector.append_all.size-8(sp) # control link + addi fp, sp, @Vector.append_all.size # New fp is at old SP. + li a0, 0 # Load integer literal 0 + sw a0, -12(fp) # local variable item + lw a0, 0(fp) # Load var: Vector.append_all.new_items + bnez a0, label_30 # Ensure not None + j error.None # Go to error handler +label_30: # Not None + sw a0, -16(fp) # Push on stack slot 4 + mv t1, zero # Initialize for-loop index + sw t1, -20(fp) # Push on stack slot 5 +label_31: # for-loop header + lw t1, -20(fp) # Pop stack slot 5 + lw t0, -16(fp) # Peek stack slot 3 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_32 # Exit loop if idx >= len(iter) + addi t1, t1, 1 # Increment idx + sw t1, -20(fp) # Push on stack slot 5 + addi t1, t1, 3 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul t1, t1, t2 # Compute list element offset in bytes + add t1, t0, t1 # Pointer to list element + lw t0, 0(t1) # Get list element + sw t0, -12(fp) # Assign var: Vector.append_all.item + lw a0, 4(fp) # Load var: Vector.append_all.self + bnez a0, label_33 # Ensure not None + j error.None # Go to error handler +label_33: # Not None + sw a0, -28(fp) # Push argument 1 from last. + lw a0, -12(fp) # Load var: Vector.append_all.item + sw a0, -32(fp) # Push argument 0 from last. + lw a0, -28(fp) # Peek stack slot 6 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 12(a1) # Load address of method: Vector.append + addi sp, fp, -32 # Set SP to last argument. + jalr a1 # Invoke method: Vector.append + addi sp, fp, -@Vector.append_all.size # Set SP to stack frame top. + j label_31 # Loop back to header +label_32: # for-loop footer + mv a0, zero # Load None + j label_29 # Jump to function epilogue +label_29: # Epilogue + .equiv @Vector.append_all.size, 32 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @Vector.append_all.size # Restore stack pointer + jr ra # Return to caller + +.globl $Vector.remove_at +$Vector.remove_at: + addi sp, sp, -@Vector.remove_at.size # Reserve space for stack frame. + sw ra, @Vector.remove_at.size-4(sp) # return address + sw fp, @Vector.remove_at.size-8(sp) # control link + addi fp, sp, @Vector.remove_at.size # New fp is at old SP. + lw a0, 0(fp) # Load var: Vector.remove_at.idx + sw a0, -12(fp) # Push on stack slot 3 + li a0, 0 # Load integer literal 0 + lw t0, -12(fp) # Pop stack slot 3 + bge t0, a0, label_36 # Branch on not < + mv a0, zero # Returning None implicitly + j label_35 # Go to return +label_36: # End of if-else statement + j label_38 # Jump to loop test +label_37: # Top of while loop + lw a0, 4(fp) # Load var: Vector.remove_at.self + bnez a0, label_39 # Ensure not None + j error.None # Go to error handler +label_39: # Not None + lw a0, 12(a0) # Get attribute: Vector.items + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 0(fp) # Load var: Vector.remove_at.idx + sw a0, -16(fp) # Push on stack slot 4 + li a0, 1 # Load integer literal 1 + lw t0, -16(fp) # Pop stack slot 4 + add a0, t0, a0 # Operator + + lw a1, -12(fp) # Pop stack slot 3 + bnez a1, label_40 # Ensure not None + j error.None # Go to error handler +label_40: # Not None + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_41 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_41: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t0, 4 # Word size in bytes + mul a0, a0, t0 # Compute list element offset in bytes + add a0, a1, a0 # Pointer to list element + lw a0, 0(a0) # Get list element + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 4(fp) # Load var: Vector.remove_at.self + bnez a0, label_42 # Ensure not None + j error.None # Go to error handler +label_42: # Not None + lw a0, 12(a0) # Get attribute: Vector.items + sw a0, -16(fp) # Push on stack slot 4 + lw a0, 0(fp) # Load var: Vector.remove_at.idx + lw t0, -16(fp) # Pop stack slot 4 + lw t1, -12(fp) # Pop stack slot 3 + bnez t0, label_43 # Ensure not None + j error.None # Go to error handler +label_43: # Not None + lw t2, 12(t0) # Load attribute: __len__ + bltu a0, t2, label_44 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_44: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul a0, a0, t2 # Compute list element offset in bytes + add a0, t0, a0 # Pointer to list element + sw t1, 0(a0) # Set list element + lw a0, 0(fp) # Load var: Vector.remove_at.idx + sw a0, -12(fp) # Push on stack slot 3 + li a0, 1 # Load integer literal 1 + lw t0, -12(fp) # Pop stack slot 3 + add a0, t0, a0 # Operator + + sw a0, 0(fp) # Assign var: Vector.remove_at.idx +label_38: # Test loop condition + lw a0, 0(fp) # Load var: Vector.remove_at.idx + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 4(fp) # Load var: Vector.remove_at.self + bnez a0, label_45 # Ensure not None + j error.None # Go to error handler +label_45: # Not None + lw a0, 16(a0) # Get attribute: Vector.size + sw a0, -16(fp) # Push on stack slot 4 + li a0, 1 # Load integer literal 1 + lw t0, -16(fp) # Pop stack slot 4 + sub a0, t0, a0 # Operator - + lw t0, -12(fp) # Pop stack slot 3 + blt t0, a0, label_37 # Branch on < + lw a0, 4(fp) # Load var: Vector.remove_at.self + bnez a0, label_46 # Ensure not None + j error.None # Go to error handler +label_46: # Not None + lw a0, 16(a0) # Get attribute: Vector.size + sw a0, -12(fp) # Push on stack slot 3 + li a0, 1 # Load integer literal 1 + lw t0, -12(fp) # Pop stack slot 3 + sub a0, t0, a0 # Operator - + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 4(fp) # Load var: Vector.remove_at.self + mv a1, a0 # Move object + lw a0, -12(fp) # Pop stack slot 3 + bnez a1, label_47 # Ensure not None + j error.None # Go to error handler +label_47: # Not None + sw a0, 16(a1) # Set attribute: Vector.size + mv a0, zero # Load None + j label_35 # Jump to function epilogue +label_35: # Epilogue + .equiv @Vector.remove_at.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @Vector.remove_at.size # Restore stack pointer + jr ra # Return to caller + +.globl $Vector.get +$Vector.get: + addi sp, sp, -@Vector.get.size # Reserve space for stack frame. + sw ra, @Vector.get.size-4(sp) # return address + sw fp, @Vector.get.size-8(sp) # control link + addi fp, sp, @Vector.get.size # New fp is at old SP. + lw a0, 4(fp) # Load var: Vector.get.self + bnez a0, label_50 # Ensure not None + j error.None # Go to error handler +label_50: # Not None + lw a0, 12(a0) # Get attribute: Vector.items + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 0(fp) # Load var: Vector.get.idx + lw a1, -12(fp) # Pop stack slot 3 + bnez a1, label_51 # Ensure not None + j error.None # Go to error handler +label_51: # Not None + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_52 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_52: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t0, 4 # Word size in bytes + mul a0, a0, t0 # Compute list element offset in bytes + add a0, a1, a0 # Pointer to list element + lw a0, 0(a0) # Get list element + j label_49 # Go to return + mv a0, zero # Load None + j label_49 # Jump to function epilogue +label_49: # Epilogue + .equiv @Vector.get.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @Vector.get.size # Restore stack pointer + jr ra # Return to caller + +.globl $Vector.length +$Vector.length: + addi sp, sp, -@Vector.length.size # Reserve space for stack frame. + sw ra, @Vector.length.size-4(sp) # return address + sw fp, @Vector.length.size-8(sp) # control link + addi fp, sp, @Vector.length.size # New fp is at old SP. + lw a0, 0(fp) # Load var: Vector.length.self + bnez a0, label_55 # Ensure not None + j error.None # Go to error handler +label_55: # Not None + lw a0, 16(a0) # Get attribute: Vector.size + j label_54 # Go to return + mv a0, zero # Load None + j label_54 # Jump to function epilogue +label_54: # Epilogue + .equiv @Vector.length.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @Vector.length.size # Restore stack pointer + jr ra # Return to caller + +.globl $DoublingVector.increase_capacity +$DoublingVector.increase_capacity: + addi sp, sp, -@DoublingVector.increase_capacity.size # Reserve space for stack frame. + sw ra, @DoublingVector.increase_capacity.size-4(sp) # return address + sw fp, @DoublingVector.increase_capacity.size-8(sp) # control link + addi fp, sp, @DoublingVector.increase_capacity.size # New fp is at old SP. + lw a0, 0(fp) # Load var: DoublingVector.increase_capacity.self + bnez a0, label_60 # Ensure not None + j error.None # Go to error handler +label_60: # Not None + sw a0, -16(fp) # Push argument 0 from last. + lw a0, -16(fp) # Peek stack slot 3 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 4(a1) # Load address of method: DoublingVector.capacity + addi sp, fp, -16 # Set SP to last argument. + jalr a1 # Invoke method: DoublingVector.capacity + addi sp, fp, -@DoublingVector.increase_capacity.size # Set SP to stack frame top. + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 0(fp) # Load var: DoublingVector.increase_capacity.self + bnez a0, label_61 # Ensure not None + j error.None # Go to error handler +label_61: # Not None + lw a0, 20(a0) # Get attribute: DoublingVector.doubling_limit + sw a0, -16(fp) # Push on stack slot 4 + li a0, 2 # Load integer literal 2 + lw t0, -16(fp) # Pop stack slot 4 + bnez a0, label_62 # Ensure non-zero divisor + j error.Div # Go to error handler +label_62: # Divisor is non-zero + xor t2, t0, a0 # Check for same sign + bltz t2, label_64 # If !=, need to adjust left operand + div a0, t0, a0 # Operator // + j label_63 +label_64: # Operands have differing signs + slt t2, zero, a0 # tmp = 1 if right > 0 else 0 + add t2, t2, t2 # tmp *= 2 + addi t2, t2, -1 # tmp = 1 if right>=0 else -1 + add t2, t0, t2 # Adjust left operand + div t2, t2, a0 # Adjusted division, toward 0 + addi a0, t2, -1 # Complete division when signs != +label_63: # End of // + lw t0, -12(fp) # Pop stack slot 3 + blt a0, t0, label_59 # Branch on not <= + la t0, noconv # Identity conversion + sw t0, -20(fp) # Push argument 3 from last. + la t0, noconv # Identity conversion + sw t0, -24(fp) # Push argument 2 from last. + lw a0, 0(fp) # Load var: DoublingVector.increase_capacity.self + bnez a0, label_65 # Ensure not None + j error.None # Go to error handler +label_65: # Not None + lw a0, 12(a0) # Get attribute: DoublingVector.items + sw a0, -28(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: DoublingVector.increase_capacity.self + bnez a0, label_66 # Ensure not None + j error.None # Go to error handler +label_66: # Not None + lw a0, 12(a0) # Get attribute: DoublingVector.items + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal concat # Call runtime concatenation routine. + addi sp, fp, -@DoublingVector.increase_capacity.size # Set SP to stack frame top. + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 0(fp) # Load var: DoublingVector.increase_capacity.self + mv a1, a0 # Move object + lw a0, -12(fp) # Pop stack slot 3 + bnez a1, label_67 # Ensure not None + j error.None # Go to error handler +label_67: # Not None + sw a0, 12(a1) # Set attribute: DoublingVector.items + j label_58 # Then body complete; jump to end-if +label_59: # Else body + la t0, noconv # Identity conversion + sw t0, -20(fp) # Push argument 3 from last. + la t0, noconv # Identity conversion + sw t0, -24(fp) # Push argument 2 from last. + lw a0, 0(fp) # Load var: DoublingVector.increase_capacity.self + bnez a0, label_68 # Ensure not None + j error.None # Go to error handler +label_68: # Not None + lw a0, 12(a0) # Get attribute: DoublingVector.items + sw a0, -28(fp) # Push argument 1 from last. + li a0, 0 # Load integer literal 0 + sw a0, -44(fp) # Push argument 1 from last. + li a0, 1 # Pass list length + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@DoublingVector.increase_capacity.size # Set SP to stack frame top. + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal concat # Call runtime concatenation routine. + addi sp, fp, -@DoublingVector.increase_capacity.size # Set SP to stack frame top. + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 0(fp) # Load var: DoublingVector.increase_capacity.self + mv a1, a0 # Move object + lw a0, -12(fp) # Pop stack slot 3 + bnez a1, label_69 # Ensure not None + j error.None # Go to error handler +label_69: # Not None + sw a0, 12(a1) # Set attribute: DoublingVector.items +label_58: # End of if-else statement + lw a0, 0(fp) # Load var: DoublingVector.increase_capacity.self + bnez a0, label_70 # Ensure not None + j error.None # Go to error handler +label_70: # Not None + sw a0, -16(fp) # Push argument 0 from last. + lw a0, -16(fp) # Peek stack slot 3 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 4(a1) # Load address of method: DoublingVector.capacity + addi sp, fp, -16 # Set SP to last argument. + jalr a1 # Invoke method: DoublingVector.capacity + addi sp, fp, -@DoublingVector.increase_capacity.size # Set SP to stack frame top. + j label_57 # Go to return + mv a0, zero # Load None + j label_57 # Jump to function epilogue +label_57: # Epilogue + .equiv @DoublingVector.increase_capacity.size, 48 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @DoublingVector.increase_capacity.size # Restore stack pointer + jr ra # Return to caller + +.globl $vrange +$vrange: + addi sp, sp, -@vrange.size # Reserve space for stack frame. + sw ra, @vrange.size-4(sp) # return address + sw fp, @vrange.size-8(sp) # control link + addi fp, sp, @vrange.size # New fp is at old SP. + mv a0, zero # Load None + sw a0, -12(fp) # local variable v + la a0, $DoublingVector$prototype # Load pointer to prototype of: DoublingVector + jal alloc # Allocate new object in A0 + sw a0, -16(fp) # Push on stack slot 4 + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 0(a1) # Load address of method: DoublingVector.__init__ + jalr a1 # Invoke method: DoublingVector.__init__ + addi sp, fp, -@vrange.size # Set SP to stack frame top. + lw a0, -16(fp) # Pop stack slot 4 + sw a0, -12(fp) # Assign var: vrange.v + j label_74 # Jump to loop test +label_73: # Top of while loop + lw a0, -12(fp) # Load var: vrange.v + bnez a0, label_75 # Ensure not None + j error.None # Go to error handler +label_75: # Not None + sw a0, -28(fp) # Push argument 1 from last. + lw a0, 4(fp) # Load var: vrange.i + sw a0, -32(fp) # Push argument 0 from last. + lw a0, -28(fp) # Peek stack slot 6 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 12(a1) # Load address of method: Vector.append + addi sp, fp, -32 # Set SP to last argument. + jalr a1 # Invoke method: Vector.append + addi sp, fp, -@vrange.size # Set SP to stack frame top. + lw a0, 4(fp) # Load var: vrange.i + sw a0, -16(fp) # Push on stack slot 4 + li a0, 1 # Load integer literal 1 + lw t0, -16(fp) # Pop stack slot 4 + add a0, t0, a0 # Operator + + sw a0, 4(fp) # Assign var: vrange.i +label_74: # Test loop condition + lw a0, 4(fp) # Load var: vrange.i + sw a0, -16(fp) # Push on stack slot 4 + lw a0, 0(fp) # Load var: vrange.j + lw t0, -16(fp) # Pop stack slot 4 + blt t0, a0, label_73 # Branch on < + lw a0, -12(fp) # Load var: vrange.v + j label_72 # Go to return + mv a0, zero # Load None + j label_72 # Jump to function epilogue +label_72: # Epilogue + .equiv @vrange.size, 32 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @vrange.size # Restore stack pointer + jr ra # Return to caller + +.globl $sieve +$sieve: + addi sp, sp, -@sieve.size # Reserve space for stack frame. + sw ra, @sieve.size-4(sp) # return address + sw fp, @sieve.size-8(sp) # control link + addi fp, sp, @sieve.size # New fp is at old SP. + li a0, 0 # Load integer literal 0 + sw a0, -12(fp) # local variable i + li a0, 0 # Load integer literal 0 + sw a0, -16(fp) # local variable j + li a0, 0 # Load integer literal 0 + sw a0, -20(fp) # local variable k + j label_79 # Jump to loop test +label_78: # Top of while loop + lw a0, 0(fp) # Load var: sieve.v + bnez a0, label_80 # Ensure not None + j error.None # Go to error handler +label_80: # Not None + sw a0, -28(fp) # Push argument 1 from last. + lw a0, -12(fp) # Load var: sieve.i + sw a0, -32(fp) # Push argument 0 from last. + lw a0, -28(fp) # Peek stack slot 6 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 24(a1) # Load address of method: Vector.get + addi sp, fp, -32 # Set SP to last argument. + jalr a1 # Invoke method: Vector.get + addi sp, fp, -@sieve.size # Set SP to stack frame top. + sw a0, -20(fp) # Assign var: sieve.k + lw a0, -12(fp) # Load var: sieve.i + sw a0, -24(fp) # Push on stack slot 6 + li a0, 1 # Load integer literal 1 + lw t0, -24(fp) # Pop stack slot 6 + add a0, t0, a0 # Operator + + sw a0, -16(fp) # Assign var: sieve.j + j label_82 # Jump to loop test +label_81: # Top of while loop + lw a0, 0(fp) # Load var: sieve.v + bnez a0, label_85 # Ensure not None + j error.None # Go to error handler +label_85: # Not None + sw a0, -28(fp) # Push argument 1 from last. + lw a0, -16(fp) # Load var: sieve.j + sw a0, -32(fp) # Push argument 0 from last. + lw a0, -28(fp) # Peek stack slot 6 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 24(a1) # Load address of method: Vector.get + addi sp, fp, -32 # Set SP to last argument. + jalr a1 # Invoke method: Vector.get + addi sp, fp, -@sieve.size # Set SP to stack frame top. + sw a0, -24(fp) # Push on stack slot 6 + lw a0, -20(fp) # Load var: sieve.k + lw t0, -24(fp) # Pop stack slot 6 + bnez a0, label_86 # Ensure non-zero divisor + j error.Div # Go to error handler +label_86: # Divisor is non-zero + rem t2, t0, a0 # Operator rem + beqz t2, label_87 # If no remainder, no adjustment + xor t3, t2, a0 # Check for differing signs. + bgez t3, label_87 # Don't adjust if signs equal. + add a0, t2, a0 # Adjust + j label_88 +label_87: # Store result + mv a0, t2 +label_88: # End of % + sw a0, -24(fp) # Push on stack slot 6 + li a0, 0 # Load integer literal 0 + lw t0, -24(fp) # Pop stack slot 6 + bne t0, a0, label_84 # Branch on not == + lw a0, 0(fp) # Load var: sieve.v + bnez a0, label_89 # Ensure not None + j error.None # Go to error handler +label_89: # Not None + sw a0, -28(fp) # Push argument 1 from last. + lw a0, -16(fp) # Load var: sieve.j + sw a0, -32(fp) # Push argument 0 from last. + lw a0, -28(fp) # Peek stack slot 6 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 20(a1) # Load address of method: Vector.remove_at + addi sp, fp, -32 # Set SP to last argument. + jalr a1 # Invoke method: Vector.remove_at + addi sp, fp, -@sieve.size # Set SP to stack frame top. + j label_83 # Then body complete; jump to end-if +label_84: # Else body + lw a0, -16(fp) # Load var: sieve.j + sw a0, -24(fp) # Push on stack slot 6 + li a0, 1 # Load integer literal 1 + lw t0, -24(fp) # Pop stack slot 6 + add a0, t0, a0 # Operator + + sw a0, -16(fp) # Assign var: sieve.j +label_83: # End of if-else statement +label_82: # Test loop condition + lw a0, -16(fp) # Load var: sieve.j + sw a0, -24(fp) # Push on stack slot 6 + lw a0, 0(fp) # Load var: sieve.v + bnez a0, label_90 # Ensure not None + j error.None # Go to error handler +label_90: # Not None + sw a0, -32(fp) # Push argument 0 from last. + lw a0, -32(fp) # Peek stack slot 7 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 28(a1) # Load address of method: Vector.length + addi sp, fp, -32 # Set SP to last argument. + jalr a1 # Invoke method: Vector.length + addi sp, fp, -@sieve.size # Set SP to stack frame top. + lw t0, -24(fp) # Pop stack slot 6 + blt t0, a0, label_81 # Branch on < + lw a0, -12(fp) # Load var: sieve.i + sw a0, -24(fp) # Push on stack slot 6 + li a0, 1 # Load integer literal 1 + lw t0, -24(fp) # Pop stack slot 6 + add a0, t0, a0 # Operator + + sw a0, -12(fp) # Assign var: sieve.i +label_79: # Test loop condition + lw a0, -12(fp) # Load var: sieve.i + sw a0, -24(fp) # Push on stack slot 6 + lw a0, 0(fp) # Load var: sieve.v + bnez a0, label_91 # Ensure not None + j error.None # Go to error handler +label_91: # Not None + sw a0, -32(fp) # Push argument 0 from last. + lw a0, -32(fp) # Peek stack slot 7 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 28(a1) # Load address of method: Vector.length + addi sp, fp, -32 # Set SP to last argument. + jalr a1 # Invoke method: Vector.length + addi sp, fp, -@sieve.size # Set SP to stack frame top. + lw t0, -24(fp) # Pop stack slot 6 + blt t0, a0, label_78 # Branch on < + mv a0, zero # Load None + j label_77 # Jump to function epilogue +label_77: # Epilogue + .equiv @sieve.size, 32 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @sieve.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/benchmarks/stdlib.py.ast.typed.s b/src/test/data/pa3/benchmarks/stdlib.py.ast.typed.s new file mode 100644 index 0000000..36ff54e --- /dev/null +++ b/src/test/data/pa3/benchmarks/stdlib.py.ast.typed.s @@ -0,0 +1,1198 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $c +$c: + .word 42 # Initial value of global var: c + +.globl $n +$n: + .word 10 # Initial value of global var: n + +.globl $s +$s: + .word const_2 # Initial value of global var: s + +.globl $i +$i: + .word 0 # Initial value of global var: i + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $n # Load global: n + sub a0, zero, a0 # Unary negation + sw a0, -12(fp) # Push on stack slot 3 + lw a0, $c # Load global: c + lw t0, -12(fp) # Pop stack slot 3 + mul a0, t0, a0 # Operator * + sw a0, $i, t0 # Assign global: i (using tmp register) + j label_2 # Jump to loop test +label_1: # Top of while loop + lw a0, $i # Load global: i + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $int_to_str # Invoke function: int_to_str + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $s, t0 # Assign global: s (using tmp register) + lw a0, $s # Load global: s + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $s # Load global: s + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $str_to_int # Invoke function: str_to_int + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -12(fp) # Push on stack slot 3 + lw a0, $c # Load global: c + lw t0, -12(fp) # Pop stack slot 3 + add a0, t0, a0 # Operator + + sw a0, $i, t0 # Assign global: i (using tmp register) +label_2: # Test loop condition + lw a0, $i # Load global: i + sw a0, -12(fp) # Push on stack slot 3 + lw a0, $n # Load global: n + sw a0, -16(fp) # Push on stack slot 4 + lw a0, $c # Load global: c + lw t0, -16(fp) # Pop stack slot 4 + mul a0, t0, a0 # Operator * + lw t0, -12(fp) # Pop stack slot 3 + bge a0, t0, label_1 # Branch on <= + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_3 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_4 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_5 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_3 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $int_to_str +$int_to_str: + addi sp, sp, -@int_to_str.size # Reserve space for stack frame. + sw ra, @int_to_str.size-4(sp) # return address + sw fp, @int_to_str.size-8(sp) # control link + addi fp, sp, @int_to_str.size # New fp is at old SP. + mv a0, zero # Load None + sw a0, -12(fp) # local variable digits + la a0, const_2 # Load string literal + sw a0, -16(fp) # local variable result + la a0, const_6 # Load string literal + sw a0, -24(fp) # Push argument 10 from last. + la a0, const_7 # Load string literal + sw a0, -28(fp) # Push argument 9 from last. + la a0, const_8 # Load string literal + sw a0, -32(fp) # Push argument 8 from last. + la a0, const_9 # Load string literal + sw a0, -36(fp) # Push argument 7 from last. + la a0, const_10 # Load string literal + sw a0, -40(fp) # Push argument 6 from last. + la a0, const_11 # Load string literal + sw a0, -44(fp) # Push argument 5 from last. + la a0, const_12 # Load string literal + sw a0, -48(fp) # Push argument 4 from last. + la a0, const_13 # Load string literal + sw a0, -52(fp) # Push argument 3 from last. + la a0, const_14 # Load string literal + sw a0, -56(fp) # Push argument 2 from last. + la a0, const_15 # Load string literal + sw a0, -60(fp) # Push argument 1 from last. + li a0, 10 # Pass list length + sw a0, -64(fp) # Push argument 0 from last. + addi sp, fp, -64 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@int_to_str.size # Set SP to stack frame top. + sw a0, -12(fp) # Assign var: int_to_str.digits + lw a0, 0(fp) # Load var: int_to_str.x + sw a0, -20(fp) # Push on stack slot 5 + li a0, 0 # Load integer literal 0 + lw t0, -20(fp) # Pop stack slot 5 + bge t0, a0, label_5 # Branch on not < + la a0, const_16 # Load string literal + sw a0, -16(fp) # Assign var: int_to_str.result + lw a0, 0(fp) # Load var: int_to_str.x + sub a0, zero, a0 # Unary negation + sw a0, 0(fp) # Assign var: int_to_str.x +label_5: # End of if-else statement + lw a0, 0(fp) # Load var: int_to_str.x + sw a0, -20(fp) # Push on stack slot 5 + li a0, 10 # Load integer literal 10 + lw t0, -20(fp) # Pop stack slot 5 + blt t0, a0, label_6 # Branch on not >= + lw a0, -16(fp) # Load var: int_to_str.result + sw a0, -28(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: int_to_str.x + sw a0, -52(fp) # Push on stack slot 13 + li a0, 10 # Load integer literal 10 + lw t0, -52(fp) # Pop stack slot 13 + bnez a0, label_7 # Ensure non-zero divisor + j error.Div # Go to error handler +label_7: # Divisor is non-zero + xor t2, t0, a0 # Check for same sign + bltz t2, label_9 # If !=, need to adjust left operand + div a0, t0, a0 # Operator // + j label_8 +label_9: # Operands have differing signs + slt t2, zero, a0 # tmp = 1 if right > 0 else 0 + add t2, t2, t2 # tmp *= 2 + addi t2, t2, -1 # tmp = 1 if right>=0 else -1 + add t2, t0, t2 # Adjust left operand + div t2, t2, a0 # Adjusted division, toward 0 + addi a0, t2, -1 # Complete division when signs != +label_8: # End of // + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal $int_to_str # Invoke function: int_to_str + addi sp, fp, -@int_to_str.size # Set SP to stack frame top. + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal strcat # Call string concatenation function + addi sp, fp, -@int_to_str.size # Set SP to stack frame top. + sw a0, -16(fp) # Assign var: int_to_str.result +label_6: # End of if-else statement + lw a0, -16(fp) # Load var: int_to_str.result + sw a0, -28(fp) # Push argument 1 from last. + lw a0, -12(fp) # Load var: int_to_str.digits + sw a0, -36(fp) # Push on stack slot 9 + lw a0, 0(fp) # Load var: int_to_str.x + sw a0, -40(fp) # Push on stack slot 10 + li a0, 10 # Load integer literal 10 + lw t0, -40(fp) # Pop stack slot 10 + bnez a0, label_10 # Ensure non-zero divisor + j error.Div # Go to error handler +label_10: # Divisor is non-zero + rem t2, t0, a0 # Operator rem + beqz t2, label_11 # If no remainder, no adjustment + xor t3, t2, a0 # Check for differing signs. + bgez t3, label_11 # Don't adjust if signs equal. + add a0, t2, a0 # Adjust + j label_12 +label_11: # Store result + mv a0, t2 +label_12: # End of % + lw a1, -36(fp) # Pop stack slot 9 + bnez a1, label_13 # Ensure not None + j error.None # Go to error handler +label_13: # Not None + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_14 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_14: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t0, 4 # Word size in bytes + mul a0, a0, t0 # Compute list element offset in bytes + add a0, a1, a0 # Pointer to list element + lw a0, 0(a0) # Get list element + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal strcat # Call string concatenation function + addi sp, fp, -@int_to_str.size # Set SP to stack frame top. + sw a0, -16(fp) # Assign var: int_to_str.result + lw a0, -16(fp) # Load var: int_to_str.result + j label_4 # Go to return + mv a0, zero # Load None + j label_4 # Jump to function epilogue +label_4: # Epilogue + .equiv @int_to_str.size, 64 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @int_to_str.size # Restore stack pointer + jr ra # Return to caller + +.globl $str_to_int +$str_to_int: + addi sp, sp, -@str_to_int.size # Reserve space for stack frame. + sw ra, @str_to_int.size-4(sp) # return address + sw fp, @str_to_int.size-8(sp) # control link + addi fp, sp, @str_to_int.size # New fp is at old SP. + li a0, 0 # Load integer literal 0 + sw a0, -12(fp) # local variable result + li a0, 0 # Load integer literal 0 + sw a0, -16(fp) # local variable digit + la a0, const_2 # Load string literal + sw a0, -20(fp) # local variable char + li a0, 1 # Load integer literal 1 + sw a0, -24(fp) # local variable sign + li a0, 1 # Load boolean literal: true + sw a0, -28(fp) # local variable first_char + lw a0, 0(fp) # Load var: str_to_int.x + sw a0, -32(fp) # Push on stack slot 8 + mv t1, zero # Initialize for-loop index + sw t1, -36(fp) # Push on stack slot 9 +label_17: # for-loop header + lw t1, -36(fp) # Peek stack slot 8 + lw t0, -32(fp) # Peek stack slot 7 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_18 # Exit loop if idx >= len(iter) + lw t0, -36(fp) # Pop stack slot 9 + lw a1, -32(fp) # Peek stack slot 7 + addi t1, t0, 1 # Increment index for next iteration + sw t1, -36(fp) # Push on stack slot 9 + addi t0, t0, 16 # Convert index to offset to char in bytes + add t0, a1, t0 # Get pointer to char + lbu t0, 0(t0) # Load character + li t1, 20 + mul t0, t0, t1 # Multiply by size of string object + la a0, allChars # Index into single-char table + add a0, a0, t0 + sw a0, -20(fp) # Assign var: str_to_int.char + lw a0, -20(fp) # Load var: str_to_int.char + sw a0, -44(fp) # Push argument 1 from last. + la a0, const_16 # Load string literal + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal streql # Call string == function + addi sp, fp, -@str_to_int.size # Set SP to stack frame top. + beqz a0, label_20 # Branch on false. + lw a0, -28(fp) # Load var: str_to_int.first_char + bnez a0, label_21 # Branch on true. + li a0, 0 # Load integer literal 0 + j label_16 # Go to return +label_21: # End of if-else statement + li a0, 1 # Load integer literal 1 + sub a0, zero, a0 # Unary negation + sw a0, -24(fp) # Assign var: str_to_int.sign + j label_19 # Then body complete; jump to end-if +label_20: # Else body + lw a0, -20(fp) # Load var: str_to_int.char + sw a0, -44(fp) # Push argument 1 from last. + la a0, const_6 # Load string literal + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal streql # Call string == function + addi sp, fp, -@str_to_int.size # Set SP to stack frame top. + beqz a0, label_23 # Branch on false. + li a0, 0 # Load integer literal 0 + sw a0, -16(fp) # Assign var: str_to_int.digit + j label_22 # Then body complete; jump to end-if +label_23: # Else body + lw a0, -20(fp) # Load var: str_to_int.char + sw a0, -44(fp) # Push argument 1 from last. + la a0, const_7 # Load string literal + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal streql # Call string == function + addi sp, fp, -@str_to_int.size # Set SP to stack frame top. + beqz a0, label_25 # Branch on false. + li a0, 1 # Load integer literal 1 + sw a0, -16(fp) # Assign var: str_to_int.digit + j label_24 # Then body complete; jump to end-if +label_25: # Else body + lw a0, -20(fp) # Load var: str_to_int.char + sw a0, -44(fp) # Push argument 1 from last. + la a0, const_8 # Load string literal + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal streql # Call string == function + addi sp, fp, -@str_to_int.size # Set SP to stack frame top. + beqz a0, label_27 # Branch on false. + li a0, 2 # Load integer literal 2 + sw a0, -16(fp) # Assign var: str_to_int.digit + j label_26 # Then body complete; jump to end-if +label_27: # Else body + lw a0, -20(fp) # Load var: str_to_int.char + sw a0, -44(fp) # Push argument 1 from last. + la a0, const_9 # Load string literal + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal streql # Call string == function + addi sp, fp, -@str_to_int.size # Set SP to stack frame top. + beqz a0, label_29 # Branch on false. + li a0, 3 # Load integer literal 3 + sw a0, -16(fp) # Assign var: str_to_int.digit + j label_28 # Then body complete; jump to end-if +label_29: # Else body + lw a0, -20(fp) # Load var: str_to_int.char + sw a0, -44(fp) # Push argument 1 from last. + la a0, const_9 # Load string literal + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal streql # Call string == function + addi sp, fp, -@str_to_int.size # Set SP to stack frame top. + beqz a0, label_31 # Branch on false. + li a0, 3 # Load integer literal 3 + sw a0, -16(fp) # Assign var: str_to_int.digit + j label_30 # Then body complete; jump to end-if +label_31: # Else body + lw a0, -20(fp) # Load var: str_to_int.char + sw a0, -44(fp) # Push argument 1 from last. + la a0, const_10 # Load string literal + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal streql # Call string == function + addi sp, fp, -@str_to_int.size # Set SP to stack frame top. + beqz a0, label_33 # Branch on false. + li a0, 4 # Load integer literal 4 + sw a0, -16(fp) # Assign var: str_to_int.digit + j label_32 # Then body complete; jump to end-if +label_33: # Else body + lw a0, -20(fp) # Load var: str_to_int.char + sw a0, -44(fp) # Push argument 1 from last. + la a0, const_11 # Load string literal + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal streql # Call string == function + addi sp, fp, -@str_to_int.size # Set SP to stack frame top. + beqz a0, label_35 # Branch on false. + li a0, 5 # Load integer literal 5 + sw a0, -16(fp) # Assign var: str_to_int.digit + j label_34 # Then body complete; jump to end-if +label_35: # Else body + lw a0, -20(fp) # Load var: str_to_int.char + sw a0, -44(fp) # Push argument 1 from last. + la a0, const_12 # Load string literal + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal streql # Call string == function + addi sp, fp, -@str_to_int.size # Set SP to stack frame top. + beqz a0, label_37 # Branch on false. + li a0, 6 # Load integer literal 6 + sw a0, -16(fp) # Assign var: str_to_int.digit + j label_36 # Then body complete; jump to end-if +label_37: # Else body + lw a0, -20(fp) # Load var: str_to_int.char + sw a0, -44(fp) # Push argument 1 from last. + la a0, const_13 # Load string literal + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal streql # Call string == function + addi sp, fp, -@str_to_int.size # Set SP to stack frame top. + beqz a0, label_39 # Branch on false. + li a0, 7 # Load integer literal 7 + sw a0, -16(fp) # Assign var: str_to_int.digit + j label_38 # Then body complete; jump to end-if +label_39: # Else body + lw a0, -20(fp) # Load var: str_to_int.char + sw a0, -44(fp) # Push argument 1 from last. + la a0, const_14 # Load string literal + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal streql # Call string == function + addi sp, fp, -@str_to_int.size # Set SP to stack frame top. + beqz a0, label_41 # Branch on false. + li a0, 8 # Load integer literal 8 + sw a0, -16(fp) # Assign var: str_to_int.digit + j label_40 # Then body complete; jump to end-if +label_41: # Else body + lw a0, -20(fp) # Load var: str_to_int.char + sw a0, -44(fp) # Push argument 1 from last. + la a0, const_15 # Load string literal + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal streql # Call string == function + addi sp, fp, -@str_to_int.size # Set SP to stack frame top. + beqz a0, label_43 # Branch on false. + li a0, 9 # Load integer literal 9 + sw a0, -16(fp) # Assign var: str_to_int.digit + j label_42 # Then body complete; jump to end-if +label_43: # Else body + li a0, 0 # Load integer literal 0 + j label_16 # Go to return +label_42: # End of if-else statement +label_40: # End of if-else statement +label_38: # End of if-else statement +label_36: # End of if-else statement +label_34: # End of if-else statement +label_32: # End of if-else statement +label_30: # End of if-else statement +label_28: # End of if-else statement +label_26: # End of if-else statement +label_24: # End of if-else statement +label_22: # End of if-else statement +label_19: # End of if-else statement + li a0, 0 # Load boolean literal: false + sw a0, -28(fp) # Assign var: str_to_int.first_char + lw a0, -12(fp) # Load var: str_to_int.result + sw a0, -40(fp) # Push on stack slot 10 + li a0, 10 # Load integer literal 10 + lw t0, -40(fp) # Pop stack slot 10 + mul a0, t0, a0 # Operator * + sw a0, -40(fp) # Push on stack slot 10 + lw a0, -16(fp) # Load var: str_to_int.digit + lw t0, -40(fp) # Pop stack slot 10 + add a0, t0, a0 # Operator + + sw a0, -12(fp) # Assign var: str_to_int.result + j label_17 # Loop back to header +label_18: # for-loop footer + lw a0, -12(fp) # Load var: str_to_int.result + sw a0, -32(fp) # Push on stack slot 8 + lw a0, -24(fp) # Load var: str_to_int.sign + lw t0, -32(fp) # Pop stack slot 8 + mul a0, t0, a0 # Operator * + j label_16 # Go to return + mv a0, zero # Load None + j label_16 # Jump to function epilogue +label_16: # Epilogue + .equiv @str_to_int.size, 48 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @str_to_int.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_17 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + la a0, $str$prototype + lw t0, 0(a0) + lw t1, 4(a0) + lw t2, 8(a0) + li t3, 1 + la a0, allChars + li t4, 256 + mv t5, zero +initchars_1: + sw t0, 0(a0) + sw t1, 4(a0) + sw t2, 8(a0) + sw t3, 12(a0) + sw t5, 16(a0) + addi a0, a0, 20 + addi t5, t5, 1 + bne t4, t5, initchars_1 + jr ra + .data + .align 2 + .globl allChars +allChars: + .space 5120 + .text + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_18 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_19 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_20 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __len__ + .string "" # Constant value of attribute: __str__ + .align 2 + +.globl const_17 +const_17: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 + +.globl const_16 +const_16: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "-" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "0" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "1" # Constant value of attribute: __str__ + .align 2 + +.globl const_19 +const_19: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "2" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "3" # Constant value of attribute: __str__ + .align 2 + +.globl const_10 +const_10: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "4" # Constant value of attribute: __str__ + .align 2 + +.globl const_11 +const_11: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "5" # Constant value of attribute: __str__ + .align 2 + +.globl const_12 +const_12: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "6" # Constant value of attribute: __str__ + .align 2 + +.globl const_20 +const_20: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_13 +const_13: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "7" # Constant value of attribute: __str__ + .align 2 + +.globl const_14 +const_14: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "8" # Constant value of attribute: __str__ + .align 2 + +.globl const_15 +const_15: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "9" # Constant value of attribute: __str__ + .align 2 + +.globl const_18 +const_18: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/benchmarks/tree.py.ast.typed.s b/src/test/data/pa3/benchmarks/tree.py.ast.typed.s new file mode 100644 index 0000000..c6feef8 --- /dev/null +++ b/src/test/data/pa3/benchmarks/tree.py.ast.typed.s @@ -0,0 +1,1267 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $TreeNode$prototype +$TreeNode$prototype: + .word 4 # Type tag for class: TreeNode + .word 6 # Object size + .word $TreeNode$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: value + .word 0 # Initial value of attribute: left + .word 0 # Initial value of attribute: right + .align 2 + +.globl $Tree$prototype +$Tree$prototype: + .word 5 # Type tag for class: Tree + .word 5 # Object size + .word $Tree$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: root + .word 0 # Initial value of attribute: size + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $TreeNode$dispatchTable +$TreeNode$dispatchTable: + .word $object.__init__ # Implementation for method: TreeNode.__init__ + .word $TreeNode.insert # Implementation for method: TreeNode.insert + .word $TreeNode.contains # Implementation for method: TreeNode.contains + +.globl $Tree$dispatchTable +$Tree$dispatchTable: + .word $object.__init__ # Implementation for method: Tree.__init__ + .word $Tree.insert # Implementation for method: Tree.insert + .word $Tree.contains # Implementation for method: Tree.contains + +.globl $n +$n: + .word 100 # Initial value of global var: n + +.globl $c +$c: + .word 4 # Initial value of global var: c + +.globl $t +$t: + .word 0 # Initial value of global var: t + +.globl $i +$i: + .word 0 # Initial value of global var: i + +.globl $k +$k: + .word 37813 # Initial value of global var: k + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + la a0, $Tree$prototype # Load pointer to prototype of: Tree + jal alloc # Allocate new object in A0 + sw a0, -12(fp) # Push on stack slot 3 + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 0(a1) # Load address of method: Tree.__init__ + jalr a1 # Invoke method: Tree.__init__ + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, -12(fp) # Pop stack slot 3 + sw a0, $t, t0 # Assign global: t (using tmp register) + j label_2 # Jump to loop test +label_1: # Top of while loop + lw a0, $t # Load global: t + bnez a0, label_3 # Ensure not None + j error.None # Go to error handler +label_3: # Not None + sw a0, -12(fp) # Push argument 1 from last. + lw a0, $k # Load global: k + sw a0, -16(fp) # Push argument 0 from last. + lw a0, -12(fp) # Peek stack slot 2 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 4(a1) # Load address of method: Tree.insert + addi sp, fp, -16 # Set SP to last argument. + jalr a1 # Invoke method: Tree.insert + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $k # Load global: k + sw a0, -12(fp) # Push on stack slot 3 + li a0, 37813 # Load integer literal 37813 + lw t0, -12(fp) # Pop stack slot 3 + mul a0, t0, a0 # Operator * + sw a0, -12(fp) # Push on stack slot 3 + li a0, 37831 # Load integer literal 37831 + lw t0, -12(fp) # Pop stack slot 3 + bnez a0, label_4 # Ensure non-zero divisor + j error.Div # Go to error handler +label_4: # Divisor is non-zero + rem t2, t0, a0 # Operator rem + beqz t2, label_5 # If no remainder, no adjustment + xor t3, t2, a0 # Check for differing signs. + bgez t3, label_5 # Don't adjust if signs equal. + add a0, t2, a0 # Adjust + j label_6 +label_5: # Store result + mv a0, t2 +label_6: # End of % + sw a0, $k, t0 # Assign global: k (using tmp register) + lw a0, $i # Load global: i + sw a0, -12(fp) # Push on stack slot 3 + lw a0, $c # Load global: c + lw t0, -12(fp) # Pop stack slot 3 + bnez a0, label_8 # Ensure non-zero divisor + j error.Div # Go to error handler +label_8: # Divisor is non-zero + rem t2, t0, a0 # Operator rem + beqz t2, label_9 # If no remainder, no adjustment + xor t3, t2, a0 # Check for differing signs. + bgez t3, label_9 # Don't adjust if signs equal. + add a0, t2, a0 # Adjust + j label_10 +label_9: # Store result + mv a0, t2 +label_10: # End of % + sw a0, -12(fp) # Push on stack slot 3 + li a0, 0 # Load integer literal 0 + lw t0, -12(fp) # Pop stack slot 3 + beq t0, a0, label_7 # Branch on not != + lw a0, $t # Load global: t + bnez a0, label_11 # Ensure not None + j error.None # Go to error handler +label_11: # Not None + sw a0, -12(fp) # Push argument 1 from last. + lw a0, $i # Load global: i + sw a0, -16(fp) # Push argument 0 from last. + lw a0, -12(fp) # Peek stack slot 2 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 4(a1) # Load address of method: Tree.insert + addi sp, fp, -16 # Set SP to last argument. + jalr a1 # Invoke method: Tree.insert + addi sp, fp, -@..main.size # Set SP to stack frame top. +label_7: # End of if-else statement + lw a0, $i # Load global: i + sw a0, -12(fp) # Push on stack slot 3 + li a0, 1 # Load integer literal 1 + lw t0, -12(fp) # Pop stack slot 3 + add a0, t0, a0 # Operator + + sw a0, $i, t0 # Assign global: i (using tmp register) +label_2: # Test loop condition + lw a0, $i # Load global: i + sw a0, -12(fp) # Push on stack slot 3 + lw a0, $n # Load global: n + lw t0, -12(fp) # Pop stack slot 3 + blt t0, a0, label_1 # Branch on < + lw a0, $t # Load global: t + bnez a0, label_12 # Ensure not None + j error.None # Go to error handler +label_12: # Not None + lw a0, 16(a0) # Get attribute: Tree.size + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + li a0, 4 # Load integer literal 4 + sw a0, -24(fp) # Push argument 6 from last. + li a0, 8 # Load integer literal 8 + sw a0, -28(fp) # Push argument 5 from last. + li a0, 15 # Load integer literal 15 + sw a0, -32(fp) # Push argument 4 from last. + li a0, 16 # Load integer literal 16 + sw a0, -36(fp) # Push argument 3 from last. + li a0, 23 # Load integer literal 23 + sw a0, -40(fp) # Push argument 2 from last. + li a0, 42 # Load integer literal 42 + sw a0, -44(fp) # Push argument 1 from last. + li a0, 6 # Pass list length + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + bnez a0, label_13 # Ensure not None + j error.None # Go to error handler +label_13: # Not None + sw a0, -12(fp) # Push on stack slot 3 + mv t1, zero # Initialize for-loop index + sw t1, -16(fp) # Push on stack slot 4 +label_14: # for-loop header + lw t1, -16(fp) # Pop stack slot 4 + lw t0, -12(fp) # Peek stack slot 2 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_15 # Exit loop if idx >= len(iter) + addi t1, t1, 1 # Increment idx + sw t1, -16(fp) # Push on stack slot 4 + addi t1, t1, 3 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul t1, t1, t2 # Compute list element offset in bytes + add t1, t0, t1 # Pointer to list element + lw t0, 0(t1) # Get list element + sw t0, $i, t1 # Assign global: i (using tmp register) + lw a0, $t # Load global: t + bnez a0, label_17 # Ensure not None + j error.None # Go to error handler +label_17: # Not None + sw a0, -28(fp) # Push argument 1 from last. + lw a0, $i # Load global: i + sw a0, -32(fp) # Push argument 0 from last. + lw a0, -28(fp) # Peek stack slot 6 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 8(a1) # Load address of method: Tree.contains + addi sp, fp, -32 # Set SP to last argument. + jalr a1 # Invoke method: Tree.contains + addi sp, fp, -@..main.size # Set SP to stack frame top. + beqz a0, label_16 # Branch on false. + lw a0, $i # Load global: i + jal makeint # Box integer + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. +label_16: # End of if-else statement + j label_14 # Loop back to header +label_15: # for-loop footer + .equiv @..main.size, 48 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $TreeNode.insert +$TreeNode.insert: + addi sp, sp, -@TreeNode.insert.size # Reserve space for stack frame. + sw ra, @TreeNode.insert.size-4(sp) # return address + sw fp, @TreeNode.insert.size-8(sp) # control link + addi fp, sp, @TreeNode.insert.size # New fp is at old SP. + lw a0, 0(fp) # Load var: TreeNode.insert.x + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 4(fp) # Load var: TreeNode.insert.self + bnez a0, label_22 # Ensure not None + j error.None # Go to error handler +label_22: # Not None + lw a0, 12(a0) # Get attribute: TreeNode.value + lw t0, -12(fp) # Pop stack slot 3 + bge t0, a0, label_21 # Branch on not < + lw a0, 4(fp) # Load var: TreeNode.insert.self + bnez a0, label_25 # Ensure not None + j error.None # Go to error handler +label_25: # Not None + lw a0, 16(a0) # Get attribute: TreeNode.left + sw a0, -12(fp) # Push on stack slot 3 + mv a0, zero # Load None + lw t0, -12(fp) # Pop stack slot 3 + bne t0, a0, label_24 # Branch if unequal pointers + lw a0, 0(fp) # Load var: TreeNode.insert.x + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $makeNode # Invoke function: makeNode + addi sp, fp, -@TreeNode.insert.size # Set SP to stack frame top. + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 4(fp) # Load var: TreeNode.insert.self + mv a1, a0 # Move object + lw a0, -12(fp) # Pop stack slot 3 + bnez a1, label_26 # Ensure not None + j error.None # Go to error handler +label_26: # Not None + sw a0, 16(a1) # Set attribute: TreeNode.left + li a0, 1 # Load boolean literal: true + j label_19 # Go to return + j label_23 # Then body complete; jump to end-if +label_24: # Else body + lw a0, 4(fp) # Load var: TreeNode.insert.self + bnez a0, label_27 # Ensure not None + j error.None # Go to error handler +label_27: # Not None + lw a0, 16(a0) # Get attribute: TreeNode.left + bnez a0, label_28 # Ensure not None + j error.None # Go to error handler +label_28: # Not None + sw a0, -12(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: TreeNode.insert.x + sw a0, -16(fp) # Push argument 0 from last. + lw a0, -12(fp) # Peek stack slot 2 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 4(a1) # Load address of method: TreeNode.insert + addi sp, fp, -16 # Set SP to last argument. + jalr a1 # Invoke method: TreeNode.insert + addi sp, fp, -@TreeNode.insert.size # Set SP to stack frame top. + j label_19 # Go to return +label_23: # End of if-else statement + j label_20 # Then body complete; jump to end-if +label_21: # Else body + lw a0, 0(fp) # Load var: TreeNode.insert.x + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 4(fp) # Load var: TreeNode.insert.self + bnez a0, label_30 # Ensure not None + j error.None # Go to error handler +label_30: # Not None + lw a0, 12(a0) # Get attribute: TreeNode.value + lw t0, -12(fp) # Pop stack slot 3 + bge a0, t0, label_29 # Branch on not > + lw a0, 4(fp) # Load var: TreeNode.insert.self + bnez a0, label_33 # Ensure not None + j error.None # Go to error handler +label_33: # Not None + lw a0, 20(a0) # Get attribute: TreeNode.right + sw a0, -12(fp) # Push on stack slot 3 + mv a0, zero # Load None + lw t0, -12(fp) # Pop stack slot 3 + bne t0, a0, label_32 # Branch if unequal pointers + lw a0, 0(fp) # Load var: TreeNode.insert.x + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $makeNode # Invoke function: makeNode + addi sp, fp, -@TreeNode.insert.size # Set SP to stack frame top. + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 4(fp) # Load var: TreeNode.insert.self + mv a1, a0 # Move object + lw a0, -12(fp) # Pop stack slot 3 + bnez a1, label_34 # Ensure not None + j error.None # Go to error handler +label_34: # Not None + sw a0, 20(a1) # Set attribute: TreeNode.right + li a0, 1 # Load boolean literal: true + j label_19 # Go to return + j label_31 # Then body complete; jump to end-if +label_32: # Else body + lw a0, 4(fp) # Load var: TreeNode.insert.self + bnez a0, label_35 # Ensure not None + j error.None # Go to error handler +label_35: # Not None + lw a0, 20(a0) # Get attribute: TreeNode.right + bnez a0, label_36 # Ensure not None + j error.None # Go to error handler +label_36: # Not None + sw a0, -12(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: TreeNode.insert.x + sw a0, -16(fp) # Push argument 0 from last. + lw a0, -12(fp) # Peek stack slot 2 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 4(a1) # Load address of method: TreeNode.insert + addi sp, fp, -16 # Set SP to last argument. + jalr a1 # Invoke method: TreeNode.insert + addi sp, fp, -@TreeNode.insert.size # Set SP to stack frame top. + j label_19 # Go to return +label_31: # End of if-else statement +label_29: # End of if-else statement +label_20: # End of if-else statement + li a0, 0 # Load boolean literal: false + j label_19 # Go to return + mv a0, zero # Load None + j label_19 # Jump to function epilogue +label_19: # Epilogue + .equiv @TreeNode.insert.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @TreeNode.insert.size # Restore stack pointer + jr ra # Return to caller + +.globl $TreeNode.contains +$TreeNode.contains: + addi sp, sp, -@TreeNode.contains.size # Reserve space for stack frame. + sw ra, @TreeNode.contains.size-4(sp) # return address + sw fp, @TreeNode.contains.size-8(sp) # control link + addi fp, sp, @TreeNode.contains.size # New fp is at old SP. + lw a0, 0(fp) # Load var: TreeNode.contains.x + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 4(fp) # Load var: TreeNode.contains.self + bnez a0, label_41 # Ensure not None + j error.None # Go to error handler +label_41: # Not None + lw a0, 12(a0) # Get attribute: TreeNode.value + lw t0, -12(fp) # Pop stack slot 3 + bge t0, a0, label_40 # Branch on not < + lw a0, 4(fp) # Load var: TreeNode.contains.self + bnez a0, label_44 # Ensure not None + j error.None # Go to error handler +label_44: # Not None + lw a0, 16(a0) # Get attribute: TreeNode.left + sw a0, -12(fp) # Push on stack slot 3 + mv a0, zero # Load None + lw t0, -12(fp) # Pop stack slot 3 + bne t0, a0, label_43 # Branch if unequal pointers + li a0, 0 # Load boolean literal: false + j label_38 # Go to return + j label_42 # Then body complete; jump to end-if +label_43: # Else body + lw a0, 4(fp) # Load var: TreeNode.contains.self + bnez a0, label_45 # Ensure not None + j error.None # Go to error handler +label_45: # Not None + lw a0, 16(a0) # Get attribute: TreeNode.left + bnez a0, label_46 # Ensure not None + j error.None # Go to error handler +label_46: # Not None + sw a0, -12(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: TreeNode.contains.x + sw a0, -16(fp) # Push argument 0 from last. + lw a0, -12(fp) # Peek stack slot 2 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 8(a1) # Load address of method: TreeNode.contains + addi sp, fp, -16 # Set SP to last argument. + jalr a1 # Invoke method: TreeNode.contains + addi sp, fp, -@TreeNode.contains.size # Set SP to stack frame top. + j label_38 # Go to return +label_42: # End of if-else statement + j label_39 # Then body complete; jump to end-if +label_40: # Else body + lw a0, 0(fp) # Load var: TreeNode.contains.x + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 4(fp) # Load var: TreeNode.contains.self + bnez a0, label_49 # Ensure not None + j error.None # Go to error handler +label_49: # Not None + lw a0, 12(a0) # Get attribute: TreeNode.value + lw t0, -12(fp) # Pop stack slot 3 + bge a0, t0, label_48 # Branch on not > + lw a0, 4(fp) # Load var: TreeNode.contains.self + bnez a0, label_52 # Ensure not None + j error.None # Go to error handler +label_52: # Not None + lw a0, 20(a0) # Get attribute: TreeNode.right + sw a0, -12(fp) # Push on stack slot 3 + mv a0, zero # Load None + lw t0, -12(fp) # Pop stack slot 3 + bne t0, a0, label_51 # Branch if unequal pointers + li a0, 0 # Load boolean literal: false + j label_38 # Go to return + j label_50 # Then body complete; jump to end-if +label_51: # Else body + lw a0, 4(fp) # Load var: TreeNode.contains.self + bnez a0, label_53 # Ensure not None + j error.None # Go to error handler +label_53: # Not None + lw a0, 20(a0) # Get attribute: TreeNode.right + bnez a0, label_54 # Ensure not None + j error.None # Go to error handler +label_54: # Not None + sw a0, -12(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: TreeNode.contains.x + sw a0, -16(fp) # Push argument 0 from last. + lw a0, -12(fp) # Peek stack slot 2 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 8(a1) # Load address of method: TreeNode.contains + addi sp, fp, -16 # Set SP to last argument. + jalr a1 # Invoke method: TreeNode.contains + addi sp, fp, -@TreeNode.contains.size # Set SP to stack frame top. + j label_38 # Go to return +label_50: # End of if-else statement + j label_47 # Then body complete; jump to end-if +label_48: # Else body + li a0, 1 # Load boolean literal: true + j label_38 # Go to return +label_47: # End of if-else statement +label_39: # End of if-else statement + mv a0, zero # Load None + j label_38 # Jump to function epilogue +label_38: # Epilogue + .equiv @TreeNode.contains.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @TreeNode.contains.size # Restore stack pointer + jr ra # Return to caller + +.globl $Tree.insert +$Tree.insert: + addi sp, sp, -@Tree.insert.size # Reserve space for stack frame. + sw ra, @Tree.insert.size-4(sp) # return address + sw fp, @Tree.insert.size-8(sp) # control link + addi fp, sp, @Tree.insert.size # New fp is at old SP. + lw a0, 4(fp) # Load var: Tree.insert.self + bnez a0, label_59 # Ensure not None + j error.None # Go to error handler +label_59: # Not None + lw a0, 12(a0) # Get attribute: Tree.root + sw a0, -12(fp) # Push on stack slot 3 + mv a0, zero # Load None + lw t0, -12(fp) # Pop stack slot 3 + bne t0, a0, label_58 # Branch if unequal pointers + lw a0, 0(fp) # Load var: Tree.insert.x + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $makeNode # Invoke function: makeNode + addi sp, fp, -@Tree.insert.size # Set SP to stack frame top. + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 4(fp) # Load var: Tree.insert.self + mv a1, a0 # Move object + lw a0, -12(fp) # Pop stack slot 3 + bnez a1, label_60 # Ensure not None + j error.None # Go to error handler +label_60: # Not None + sw a0, 12(a1) # Set attribute: Tree.root + li a0, 1 # Load integer literal 1 + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 4(fp) # Load var: Tree.insert.self + mv a1, a0 # Move object + lw a0, -12(fp) # Pop stack slot 3 + bnez a1, label_61 # Ensure not None + j error.None # Go to error handler +label_61: # Not None + sw a0, 16(a1) # Set attribute: Tree.size + j label_57 # Then body complete; jump to end-if +label_58: # Else body + lw a0, 4(fp) # Load var: Tree.insert.self + bnez a0, label_63 # Ensure not None + j error.None # Go to error handler +label_63: # Not None + lw a0, 12(a0) # Get attribute: Tree.root + bnez a0, label_64 # Ensure not None + j error.None # Go to error handler +label_64: # Not None + sw a0, -12(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: Tree.insert.x + sw a0, -16(fp) # Push argument 0 from last. + lw a0, -12(fp) # Peek stack slot 2 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 4(a1) # Load address of method: TreeNode.insert + addi sp, fp, -16 # Set SP to last argument. + jalr a1 # Invoke method: TreeNode.insert + addi sp, fp, -@Tree.insert.size # Set SP to stack frame top. + beqz a0, label_62 # Branch on false. + lw a0, 4(fp) # Load var: Tree.insert.self + bnez a0, label_65 # Ensure not None + j error.None # Go to error handler +label_65: # Not None + lw a0, 16(a0) # Get attribute: Tree.size + sw a0, -12(fp) # Push on stack slot 3 + li a0, 1 # Load integer literal 1 + lw t0, -12(fp) # Pop stack slot 3 + add a0, t0, a0 # Operator + + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 4(fp) # Load var: Tree.insert.self + mv a1, a0 # Move object + lw a0, -12(fp) # Pop stack slot 3 + bnez a1, label_66 # Ensure not None + j error.None # Go to error handler +label_66: # Not None + sw a0, 16(a1) # Set attribute: Tree.size +label_62: # End of if-else statement +label_57: # End of if-else statement + mv a0, zero # Load None + j label_56 # Jump to function epilogue +label_56: # Epilogue + .equiv @Tree.insert.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @Tree.insert.size # Restore stack pointer + jr ra # Return to caller + +.globl $Tree.contains +$Tree.contains: + addi sp, sp, -@Tree.contains.size # Reserve space for stack frame. + sw ra, @Tree.contains.size-4(sp) # return address + sw fp, @Tree.contains.size-8(sp) # control link + addi fp, sp, @Tree.contains.size # New fp is at old SP. + lw a0, 4(fp) # Load var: Tree.contains.self + bnez a0, label_71 # Ensure not None + j error.None # Go to error handler +label_71: # Not None + lw a0, 12(a0) # Get attribute: Tree.root + sw a0, -12(fp) # Push on stack slot 3 + mv a0, zero # Load None + lw t0, -12(fp) # Pop stack slot 3 + bne t0, a0, label_70 # Branch if unequal pointers + li a0, 0 # Load boolean literal: false + j label_68 # Go to return + j label_69 # Then body complete; jump to end-if +label_70: # Else body + lw a0, 4(fp) # Load var: Tree.contains.self + bnez a0, label_72 # Ensure not None + j error.None # Go to error handler +label_72: # Not None + lw a0, 12(a0) # Get attribute: Tree.root + bnez a0, label_73 # Ensure not None + j error.None # Go to error handler +label_73: # Not None + sw a0, -12(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: Tree.contains.x + sw a0, -16(fp) # Push argument 0 from last. + lw a0, -12(fp) # Peek stack slot 2 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 8(a1) # Load address of method: TreeNode.contains + addi sp, fp, -16 # Set SP to last argument. + jalr a1 # Invoke method: TreeNode.contains + addi sp, fp, -@Tree.contains.size # Set SP to stack frame top. + j label_68 # Go to return +label_69: # End of if-else statement + mv a0, zero # Load None + j label_68 # Jump to function epilogue +label_68: # Epilogue + .equiv @Tree.contains.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @Tree.contains.size # Restore stack pointer + jr ra # Return to caller + +.globl $makeNode +$makeNode: + addi sp, sp, -@makeNode.size # Reserve space for stack frame. + sw ra, @makeNode.size-4(sp) # return address + sw fp, @makeNode.size-8(sp) # control link + addi fp, sp, @makeNode.size # New fp is at old SP. + mv a0, zero # Load None + sw a0, -12(fp) # local variable b + la a0, $TreeNode$prototype # Load pointer to prototype of: TreeNode + jal alloc # Allocate new object in A0 + sw a0, -16(fp) # Push on stack slot 4 + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 0(a1) # Load address of method: TreeNode.__init__ + jalr a1 # Invoke method: TreeNode.__init__ + addi sp, fp, -@makeNode.size # Set SP to stack frame top. + lw a0, -16(fp) # Pop stack slot 4 + sw a0, -12(fp) # Assign var: makeNode.b + lw a0, 0(fp) # Load var: makeNode.x + sw a0, -16(fp) # Push on stack slot 4 + lw a0, -12(fp) # Load var: makeNode.b + mv a1, a0 # Move object + lw a0, -16(fp) # Pop stack slot 4 + bnez a1, label_76 # Ensure not None + j error.None # Go to error handler +label_76: # Not None + sw a0, 12(a1) # Set attribute: TreeNode.value + lw a0, -12(fp) # Load var: makeNode.b + j label_75 # Go to return + mv a0, zero # Load None + j label_75 # Jump to function epilogue +label_75: # Epilogue + .equiv @makeNode.size, 32 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @makeNode.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/call.py.ast.typed.s b/src/test/data/pa3/sample/call.py.ast.typed.s new file mode 100644 index 0000000..bd6d256 --- /dev/null +++ b/src/test/data/pa3/sample/call.py.ast.typed.s @@ -0,0 +1,794 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + addi sp, fp, -16 # Set SP to last argument. + jal $f # Invoke function: f + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $f +$f: + addi sp, sp, -@f.size # Reserve space for stack frame. + sw ra, @f.size-4(sp) # return address + sw fp, @f.size-8(sp) # control link + addi fp, sp, @f.size # New fp is at old SP. + la a0, const_5 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@f.size # Set SP to stack frame top. + addi sp, fp, -16 # Set SP to last argument. + jal $g # Invoke function: g + addi sp, fp, -@f.size # Set SP to stack frame top. + la a0, const_6 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@f.size # Set SP to stack frame top. + li a0, 42 # Load integer literal 42 + j label_2 # Go to return + mv a0, zero # Load None + j label_2 # Jump to function epilogue +label_2: # Epilogue + .equiv @f.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @f.size # Restore stack pointer + jr ra # Return to caller + +.globl $g +$g: + addi sp, sp, -@g.size # Reserve space for stack frame. + sw ra, @g.size-4(sp) # return address + sw fp, @g.size-8(sp) # control link + addi fp, sp, @g.size # New fp is at old SP. + la a0, const_7 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@g.size # Set SP to stack frame top. + addi sp, fp, -16 # Set SP to last argument. + jal $h # Invoke function: h + addi sp, fp, -@g.size # Set SP to stack frame top. + la a0, const_8 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@g.size # Set SP to stack frame top. + mv a0, zero # Load None + j label_4 # Jump to function epilogue +label_4: # Epilogue + .equiv @g.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @g.size # Restore stack pointer + jr ra # Return to caller + +.globl $h +$h: + addi sp, sp, -@h.size # Reserve space for stack frame. + sw ra, @h.size-4(sp) # return address + sw fp, @h.size-8(sp) # control link + addi fp, sp, @h.size # New fp is at old SP. + la a0, const_9 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@h.size # Set SP to stack frame top. + la a0, const_10 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@h.size # Set SP to stack frame top. + mv a0, zero # Load None + j label_6 # Jump to function epilogue +label_6: # Epilogue + .equiv @h.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @h.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_11 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_12 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_13 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_14 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "end g" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 7 # Constant value of attribute: __len__ + .string "start h" # Constant value of attribute: __str__ + .align 2 + +.globl const_10 +const_10: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "end h" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 7 # Constant value of attribute: __len__ + .string "start g" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 7 # Constant value of attribute: __len__ + .string "start f" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "end f" # Constant value of attribute: __str__ + .align 2 + +.globl const_11 +const_11: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 + +.globl const_13 +const_13: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_14 +const_14: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_12 +const_12: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/call_with_args.py.ast.typed.s b/src/test/data/pa3/sample/call_with_args.py.ast.typed.s new file mode 100644 index 0000000..fb7e78c --- /dev/null +++ b/src/test/data/pa3/sample/call_with_args.py.ast.typed.s @@ -0,0 +1,806 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 4 # Load integer literal 4 + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $f # Invoke function: f + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $f +$f: + addi sp, sp, -@f.size # Reserve space for stack frame. + sw ra, @f.size-4(sp) # return address + sw fp, @f.size-8(sp) # control link + addi fp, sp, @f.size # New fp is at old SP. + la a0, const_5 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@f.size # Set SP to stack frame top. + lw a0, 0(fp) # Load var: f.x + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@f.size # Set SP to stack frame top. + li a0, 1 # Load integer literal 1 + sw a0, -12(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: f.x + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $g # Invoke function: g + addi sp, fp, -@f.size # Set SP to stack frame top. + la a0, const_6 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@f.size # Set SP to stack frame top. + lw a0, 0(fp) # Load var: f.x + j label_2 # Go to return + mv a0, zero # Load None + j label_2 # Jump to function epilogue +label_2: # Epilogue + .equiv @f.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @f.size # Restore stack pointer + jr ra # Return to caller + +.globl $g +$g: + addi sp, sp, -@g.size # Reserve space for stack frame. + sw ra, @g.size-4(sp) # return address + sw fp, @g.size-8(sp) # control link + addi fp, sp, @g.size # New fp is at old SP. + la a0, const_7 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@g.size # Set SP to stack frame top. + lw a0, 4(fp) # Load var: g.y + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@g.size # Set SP to stack frame top. + lw a0, 0(fp) # Load var: g.z + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@g.size # Set SP to stack frame top. + la a0, const_8 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $h # Invoke function: h + addi sp, fp, -@g.size # Set SP to stack frame top. + la a0, const_9 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@g.size # Set SP to stack frame top. + mv a0, zero # Load None + j label_4 # Jump to function epilogue +label_4: # Epilogue + .equiv @g.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @g.size # Restore stack pointer + jr ra # Return to caller + +.globl $h +$h: + addi sp, sp, -@h.size # Reserve space for stack frame. + sw ra, @h.size-4(sp) # return address + sw fp, @h.size-8(sp) # control link + addi fp, sp, @h.size # New fp is at old SP. + lw a0, 0(fp) # Load var: h.msg + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@h.size # Set SP to stack frame top. + mv a0, zero # Load None + j label_6 # Jump to function epilogue +label_6: # Epilogue + .equiv @h.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @h.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_10 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_11 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_12 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_13 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "end g" # Constant value of attribute: __str__ + .align 2 + +.globl const_12 +const_12: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 7 # Constant value of attribute: __len__ + .string "start g" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 7 # Constant value of attribute: __len__ + .string "start f" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "end f" # Constant value of attribute: __str__ + .align 2 + +.globl const_10 +const_10: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_13 +const_13: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "h" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_11 +const_11: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/error_div_zero.py.ast.typed.s b/src/test/data/pa3/sample/error_div_zero.py.ast.typed.s new file mode 100644 index 0000000..d7648d5 --- /dev/null +++ b/src/test/data/pa3/sample/error_div_zero.py.ast.typed.s @@ -0,0 +1,673 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 42 # Load integer literal 42 + sw a0, -20(fp) # Push on stack slot 5 + li a0, 0 # Load integer literal 0 + lw t0, -20(fp) # Pop stack slot 5 + bnez a0, label_1 # Ensure non-zero divisor + j error.Div # Go to error handler +label_1: # Divisor is non-zero + xor t2, t0, a0 # Check for same sign + bltz t2, label_3 # If !=, need to adjust left operand + div a0, t0, a0 # Operator // + j label_2 +label_3: # Operands have differing signs + slt t2, zero, a0 # tmp = 1 if right > 0 else 0 + add t2, t2, t2 # tmp *= 2 + addi t2, t2, -1 # tmp = 1 if right>=0 else -1 + add t2, t0, t2 # Adjust left operand + div t2, t2, a0 # Adjusted division, toward 0 + addi a0, t2, -1 # Complete division when signs != +label_2: # End of // + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/error_invalid_print.py.ast.typed.s b/src/test/data/pa3/sample/error_invalid_print.py.ast.typed.s new file mode 100644 index 0000000..8bdc6b2 --- /dev/null +++ b/src/test/data/pa3/sample/error_invalid_print.py.ast.typed.s @@ -0,0 +1,654 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + mv a0, zero # Load None + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/error_mod_zero.py.ast.typed.s b/src/test/data/pa3/sample/error_mod_zero.py.ast.typed.s new file mode 100644 index 0000000..5d91f8e --- /dev/null +++ b/src/test/data/pa3/sample/error_mod_zero.py.ast.typed.s @@ -0,0 +1,670 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 42 # Load integer literal 42 + sw a0, -20(fp) # Push on stack slot 5 + li a0, 0 # Load integer literal 0 + lw t0, -20(fp) # Pop stack slot 5 + bnez a0, label_1 # Ensure non-zero divisor + j error.Div # Go to error handler +label_1: # Divisor is non-zero + rem t2, t0, a0 # Operator rem + beqz t2, label_2 # If no remainder, no adjustment + xor t3, t2, a0 # Check for differing signs. + bgez t3, label_2 # Don't adjust if signs equal. + add a0, t2, a0 # Adjust + j label_3 +label_2: # Store result + mv a0, t2 +label_3: # End of % + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/expr_if.py.ast.typed.s b/src/test/data/pa3/sample/expr_if.py.ast.typed.s new file mode 100644 index 0000000..52baf16 --- /dev/null +++ b/src/test/data/pa3/sample/expr_if.py.ast.typed.s @@ -0,0 +1,674 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 3 # Load integer literal 3 + mv a0, a0 # Set result from 'then' expression + j label_2 +label_1: # Else part + li a0, 4 # Load integer literal 4 + mv a0, a0 # Set result from 'else' expression +label_2: # End of if-else expression + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + j label_3 # Branch on false. + li a0, 3 # Load integer literal 3 + mv a0, a0 # Set result from 'then' expression + j label_4 +label_3: # Else part + li a0, 4 # Load integer literal 4 + mv a0, a0 # Set result from 'else' expression +label_4: # End of if-else expression + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/id_global.py.ast.typed.s b/src/test/data/pa3/sample/id_global.py.ast.typed.s new file mode 100644 index 0000000..ffc6393 --- /dev/null +++ b/src/test/data/pa3/sample/id_global.py.ast.typed.s @@ -0,0 +1,659 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 42 # Initial value of global var: x + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $x # Load global: x + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/id_local.py.ast.typed.s b/src/test/data/pa3/sample/id_local.py.ast.typed.s new file mode 100644 index 0000000..07fd798 --- /dev/null +++ b/src/test/data/pa3/sample/id_local.py.ast.typed.s @@ -0,0 +1,676 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + addi sp, fp, -16 # Set SP to last argument. + jal $f # Invoke function: f + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $f +$f: + addi sp, sp, -@f.size # Reserve space for stack frame. + sw ra, @f.size-4(sp) # return address + sw fp, @f.size-8(sp) # control link + addi fp, sp, @f.size # New fp is at old SP. + li a0, 1 # Load integer literal 1 + sw a0, -12(fp) # local variable x + lw a0, -12(fp) # Load var: f.x + j label_2 # Go to return + mv a0, zero # Load None + j label_2 # Jump to function epilogue +label_2: # Epilogue + .equiv @f.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @f.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/input.py.ast.typed.s b/src/test/data/pa3/sample/input.py.ast.typed.s new file mode 100644 index 0000000..e2a03c0 --- /dev/null +++ b/src/test/data/pa3/sample/input.py.ast.typed.s @@ -0,0 +1,687 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $s +$s: + .word const_2 # Initial value of global var: s + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + addi sp, fp, -16 # Set SP to last argument. + jal $input # Invoke function: input + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $s, t0 # Assign global: s (using tmp register) + j label_2 # Jump to loop test +label_1: # Top of while loop + lw a0, $s # Load global: s + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + addi sp, fp, -16 # Set SP to last argument. + jal $input # Invoke function: input + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $s, t0 # Assign global: s (using tmp register) +label_2: # Test loop condition + lw a0, $s # Load global: s + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $len # Invoke function: len + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -12(fp) # Push on stack slot 3 + li a0, 0 # Load integer literal 0 + lw t0, -12(fp) # Pop stack slot 3 + blt a0, t0, label_1 # Branch on > + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_3 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_4 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_5 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_3 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_6 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __len__ + .string "" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/len_invalid_1.py.ast.typed.s b/src/test/data/pa3/sample/len_invalid_1.py.ast.typed.s new file mode 100644 index 0000000..70b7d40 --- /dev/null +++ b/src/test/data/pa3/sample/len_invalid_1.py.ast.typed.s @@ -0,0 +1,663 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $x # Load global: x + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $len # Invoke function: len + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/len_invalid_2.py.ast.typed.s b/src/test/data/pa3/sample/len_invalid_2.py.ast.typed.s new file mode 100644 index 0000000..2e5e6a8 --- /dev/null +++ b/src/test/data/pa3/sample/len_invalid_2.py.ast.typed.s @@ -0,0 +1,664 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 1 # Initial value of global var: x + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $x # Load global: x + jal makeint # Box integer + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $len # Invoke function: len + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/list_concat.py.ast.typed.s b/src/test/data/pa3/sample/list_concat.py.ast.typed.s new file mode 100644 index 0000000..63e6373 --- /dev/null +++ b/src/test/data/pa3/sample/list_concat.py.ast.typed.s @@ -0,0 +1,751 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $z +$z: + .word 0 # Initial value of global var: z + +.globl $i +$i: + .word 0 # Initial value of global var: i + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 1 # Load integer literal 1 + sw a0, -20(fp) # Push argument 3 from last. + li a0, 2 # Load integer literal 2 + sw a0, -24(fp) # Push argument 2 from last. + li a0, 3 # Load integer literal 3 + sw a0, -28(fp) # Push argument 1 from last. + li a0, 3 # Pass list length + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -12(fp) # Push argument 1 from last. + li a0, 4 # Load integer literal 4 + sw a0, -20(fp) # Push argument 3 from last. + li a0, 5 # Load integer literal 5 + sw a0, -24(fp) # Push argument 2 from last. + li a0, 6 # Load integer literal 6 + sw a0, -28(fp) # Push argument 1 from last. + li a0, 3 # Pass list length + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $concat # Invoke function: concat + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $z, t0 # Assign global: z (using tmp register) + j label_2 # Jump to loop test +label_1: # Top of while loop + lw a0, $z # Load global: z + sw a0, -20(fp) # Push on stack slot 5 + lw a0, $i # Load global: i + lw a1, -20(fp) # Pop stack slot 5 + bnez a1, label_3 # Ensure not None + j error.None # Go to error handler +label_3: # Not None + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_4 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_4: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t0, 4 # Word size in bytes + mul a0, a0, t0 # Compute list element offset in bytes + add a0, a1, a0 # Pointer to list element + lw a0, 0(a0) # Get list element + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $i # Load global: i + sw a0, -12(fp) # Push on stack slot 3 + li a0, 1 # Load integer literal 1 + lw t0, -12(fp) # Pop stack slot 3 + add a0, t0, a0 # Operator + + sw a0, $i, t0 # Assign global: i (using tmp register) +label_2: # Test loop condition + lw a0, $i # Load global: i + sw a0, -12(fp) # Push on stack slot 3 + lw a0, $z # Load global: z + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $len # Invoke function: len + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw t0, -12(fp) # Pop stack slot 3 + blt t0, a0, label_1 # Branch on < + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $concat +$concat: + addi sp, sp, -@concat.size # Reserve space for stack frame. + sw ra, @concat.size-4(sp) # return address + sw fp, @concat.size-8(sp) # control link + addi fp, sp, @concat.size # New fp is at old SP. + la t0, noconv # Identity conversion + sw t0, -20(fp) # Push argument 3 from last. + la t0, noconv # Identity conversion + sw t0, -24(fp) # Push argument 2 from last. + lw a0, 4(fp) # Load var: concat.x + sw a0, -28(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: concat.y + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal concat # Call runtime concatenation routine. + addi sp, fp, -@concat.size # Set SP to stack frame top. + j label_6 # Go to return + mv a0, zero # Load None + j label_6 # Jump to function epilogue +label_6: # Epilogue + .equiv @concat.size, 32 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @concat.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/list_concat_2.py.ast.typed.s b/src/test/data/pa3/sample/list_concat_2.py.ast.typed.s new file mode 100644 index 0000000..b358cfe --- /dev/null +++ b/src/test/data/pa3/sample/list_concat_2.py.ast.typed.s @@ -0,0 +1,748 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $z +$z: + .word 0 # Initial value of global var: z + +.globl $i +$i: + .word 0 # Initial value of global var: i + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + la t0, noconv # Identity conversion + sw t0, -20(fp) # Push argument 3 from last. + la t0, noconv # Identity conversion + sw t0, -24(fp) # Push argument 2 from last. + la t0, noconv # Identity conversion + sw t0, -36(fp) # Push argument 3 from last. + la t0, noconv # Identity conversion + sw t0, -40(fp) # Push argument 2 from last. + li a0, 1 # Load integer literal 1 + sw a0, -52(fp) # Push argument 3 from last. + li a0, 2 # Load integer literal 2 + sw a0, -56(fp) # Push argument 2 from last. + li a0, 3 # Load integer literal 3 + sw a0, -60(fp) # Push argument 1 from last. + li a0, 3 # Pass list length + sw a0, -64(fp) # Push argument 0 from last. + addi sp, fp, -64 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -44(fp) # Push argument 1 from last. + li a0, 4 # Load integer literal 4 + sw a0, -52(fp) # Push argument 3 from last. + li a0, 5 # Load integer literal 5 + sw a0, -56(fp) # Push argument 2 from last. + li a0, 6 # Load integer literal 6 + sw a0, -60(fp) # Push argument 1 from last. + li a0, 3 # Pass list length + sw a0, -64(fp) # Push argument 0 from last. + addi sp, fp, -64 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal concat # Call runtime concatenation routine. + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -28(fp) # Push argument 1 from last. + li a0, 7 # Load integer literal 7 + sw a0, -36(fp) # Push argument 3 from last. + li a0, 8 # Load integer literal 8 + sw a0, -40(fp) # Push argument 2 from last. + li a0, 9 # Load integer literal 9 + sw a0, -44(fp) # Push argument 1 from last. + li a0, 3 # Pass list length + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal concat # Call runtime concatenation routine. + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $z, t0 # Assign global: z (using tmp register) + j label_2 # Jump to loop test +label_1: # Top of while loop + lw a0, $z # Load global: z + sw a0, -20(fp) # Push on stack slot 5 + lw a0, $i # Load global: i + lw a1, -20(fp) # Pop stack slot 5 + bnez a1, label_3 # Ensure not None + j error.None # Go to error handler +label_3: # Not None + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_4 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_4: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t0, 4 # Word size in bytes + mul a0, a0, t0 # Compute list element offset in bytes + add a0, a1, a0 # Pointer to list element + lw a0, 0(a0) # Get list element + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $i # Load global: i + sw a0, -12(fp) # Push on stack slot 3 + li a0, 1 # Load integer literal 1 + lw t0, -12(fp) # Pop stack slot 3 + add a0, t0, a0 # Operator + + sw a0, $i, t0 # Assign global: i (using tmp register) +label_2: # Test loop condition + lw a0, $i # Load global: i + sw a0, -12(fp) # Push on stack slot 3 + lw a0, $z # Load global: z + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $len # Invoke function: len + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw t0, -12(fp) # Pop stack slot 3 + blt t0, a0, label_1 # Branch on < + .equiv @..main.size, 64 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/list_concat_none.py.ast.typed.s b/src/test/data/pa3/sample/list_concat_none.py.ast.typed.s new file mode 100644 index 0000000..42391db --- /dev/null +++ b/src/test/data/pa3/sample/list_concat_none.py.ast.typed.s @@ -0,0 +1,677 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.globl $y +$y: + .word 0 # Initial value of global var: y + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + la t0, noconv # Identity conversion + sw t0, -36(fp) # Push argument 3 from last. + la t0, noconv # Identity conversion + sw t0, -40(fp) # Push argument 2 from last. + lw a0, $x # Load global: x + sw a0, -44(fp) # Push argument 1 from last. + lw a0, $y # Load global: y + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal concat # Call runtime concatenation routine. + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $len # Invoke function: len + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 48 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/list_get_element.py.ast.typed.s b/src/test/data/pa3/sample/list_get_element.py.ast.typed.s new file mode 100644 index 0000000..5e59a14 --- /dev/null +++ b/src/test/data/pa3/sample/list_get_element.py.ast.typed.s @@ -0,0 +1,728 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 1 # Load integer literal 1 + sw a0, -20(fp) # Push argument 3 from last. + li a0, 2 # Load integer literal 2 + sw a0, -24(fp) # Push argument 2 from last. + li a0, 3 # Load integer literal 3 + sw a0, -28(fp) # Push argument 1 from last. + li a0, 3 # Pass list length + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $x, t0 # Assign global: x (using tmp register) + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + li a0, 0 # Load integer literal 0 + lw a1, -20(fp) # Pop stack slot 5 + bnez a1, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_2 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_2: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t0, 4 # Word size in bytes + mul a0, a0, t0 # Compute list element offset in bytes + add a0, a1, a0 # Pointer to list element + lw a0, 0(a0) # Get list element + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + li a0, 1 # Load integer literal 1 + lw a1, -20(fp) # Pop stack slot 5 + bnez a1, label_3 # Ensure not None + j error.None # Go to error handler +label_3: # Not None + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_4 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_4: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t0, 4 # Word size in bytes + mul a0, a0, t0 # Compute list element offset in bytes + add a0, a1, a0 # Pointer to list element + lw a0, 0(a0) # Get list element + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + li a0, 2 # Load integer literal 2 + lw a1, -20(fp) # Pop stack slot 5 + bnez a1, label_5 # Ensure not None + j error.None # Go to error handler +label_5: # Not None + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_6 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_6: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t0, 4 # Word size in bytes + mul a0, a0, t0 # Compute list element offset in bytes + add a0, a1, a0 # Pointer to list element + lw a0, 0(a0) # Get list element + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/list_get_element_complex.py.ast.typed.s b/src/test/data/pa3/sample/list_get_element_complex.py.ast.typed.s new file mode 100644 index 0000000..4b94b83 --- /dev/null +++ b/src/test/data/pa3/sample/list_get_element_complex.py.ast.typed.s @@ -0,0 +1,738 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $next +$next: + .word 0 # Initial value of global var: next + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + addi sp, fp, -16 # Set SP to last argument. + jal $make_list # Invoke function: make_list + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -20(fp) # Push on stack slot 5 + addi sp, fp, -32 # Set SP to last argument. + jal $next_int # Invoke function: next_int + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -24(fp) # Push on stack slot 6 + li a0, 3 # Load integer literal 3 + lw t0, -24(fp) # Pop stack slot 6 + sub a0, t0, a0 # Operator - + lw a1, -20(fp) # Pop stack slot 5 + bnez a1, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_2 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_2: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t0, 4 # Word size in bytes + mul a0, a0, t0 # Compute list element offset in bytes + add a0, a1, a0 # Pointer to list element + lw a0, 0(a0) # Get list element + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $next_int +$next_int: + addi sp, sp, -@next_int.size # Reserve space for stack frame. + sw ra, @next_int.size-4(sp) # return address + sw fp, @next_int.size-8(sp) # control link + addi fp, sp, @next_int.size # New fp is at old SP. + lw a0, $next # Load global: next + sw a0, -12(fp) # Push on stack slot 3 + li a0, 1 # Load integer literal 1 + lw t0, -12(fp) # Pop stack slot 3 + add a0, t0, a0 # Operator + + sw a0, $next, t0 # Assign global: next (using tmp register) + lw a0, $next # Load global: next + j label_4 # Go to return + mv a0, zero # Load None + j label_4 # Jump to function epilogue +label_4: # Epilogue + .equiv @next_int.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @next_int.size # Restore stack pointer + jr ra # Return to caller + +.globl $make_list +$make_list: + addi sp, sp, -@make_list.size # Reserve space for stack frame. + sw ra, @make_list.size-4(sp) # return address + sw fp, @make_list.size-8(sp) # control link + addi fp, sp, @make_list.size # New fp is at old SP. + addi sp, fp, -32 # Set SP to last argument. + jal $next_int # Invoke function: next_int + addi sp, fp, -@make_list.size # Set SP to stack frame top. + sw a0, -20(fp) # Push argument 3 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $next_int # Invoke function: next_int + addi sp, fp, -@make_list.size # Set SP to stack frame top. + sw a0, -24(fp) # Push argument 2 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $next_int # Invoke function: next_int + addi sp, fp, -@make_list.size # Set SP to stack frame top. + sw a0, -28(fp) # Push argument 1 from last. + li a0, 3 # Pass list length + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@make_list.size # Set SP to stack frame top. + j label_6 # Go to return + mv a0, zero # Load None + j label_6 # Jump to function epilogue +label_6: # Epilogue + .equiv @make_list.size, 32 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @make_list.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/list_get_element_none.py.ast.typed.s b/src/test/data/pa3/sample/list_get_element_none.py.ast.typed.s new file mode 100644 index 0000000..9ae5241 --- /dev/null +++ b/src/test/data/pa3/sample/list_get_element_none.py.ast.typed.s @@ -0,0 +1,674 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + li a0, 0 # Load integer literal 0 + lw a1, -20(fp) # Pop stack slot 5 + bnez a1, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_2 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_2: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t0, 4 # Word size in bytes + mul a0, a0, t0 # Compute list element offset in bytes + add a0, a1, a0 # Pointer to list element + lw a0, 0(a0) # Get list element + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/list_get_element_oob_1.py.ast.typed.s b/src/test/data/pa3/sample/list_get_element_oob_1.py.ast.typed.s new file mode 100644 index 0000000..56fd249 --- /dev/null +++ b/src/test/data/pa3/sample/list_get_element_oob_1.py.ast.typed.s @@ -0,0 +1,687 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 1 # Load integer literal 1 + sw a0, -20(fp) # Push argument 3 from last. + li a0, 2 # Load integer literal 2 + sw a0, -24(fp) # Push argument 2 from last. + li a0, 3 # Load integer literal 3 + sw a0, -28(fp) # Push argument 1 from last. + li a0, 3 # Pass list length + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $x, t0 # Assign global: x (using tmp register) + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + li a0, 1 # Load integer literal 1 + sub a0, zero, a0 # Unary negation + lw a1, -20(fp) # Pop stack slot 5 + bnez a1, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_2 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_2: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t0, 4 # Word size in bytes + mul a0, a0, t0 # Compute list element offset in bytes + add a0, a1, a0 # Pointer to list element + lw a0, 0(a0) # Get list element + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/list_get_element_oob_2.py.ast.typed.s b/src/test/data/pa3/sample/list_get_element_oob_2.py.ast.typed.s new file mode 100644 index 0000000..963102d --- /dev/null +++ b/src/test/data/pa3/sample/list_get_element_oob_2.py.ast.typed.s @@ -0,0 +1,686 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 1 # Load integer literal 1 + sw a0, -20(fp) # Push argument 3 from last. + li a0, 2 # Load integer literal 2 + sw a0, -24(fp) # Push argument 2 from last. + li a0, 3 # Load integer literal 3 + sw a0, -28(fp) # Push argument 1 from last. + li a0, 3 # Pass list length + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $x, t0 # Assign global: x (using tmp register) + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + li a0, 3 # Load integer literal 3 + lw a1, -20(fp) # Pop stack slot 5 + bnez a1, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_2 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_2: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t0, 4 # Word size in bytes + mul a0, a0, t0 # Compute list element offset in bytes + add a0, a1, a0 # Pointer to list element + lw a0, 0(a0) # Get list element + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/list_get_element_oob_3.py.ast.typed.s b/src/test/data/pa3/sample/list_get_element_oob_3.py.ast.typed.s new file mode 100644 index 0000000..c22d09e --- /dev/null +++ b/src/test/data/pa3/sample/list_get_element_oob_3.py.ast.typed.s @@ -0,0 +1,680 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 0 # Pass list length + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $x, t0 # Assign global: x (using tmp register) + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + li a0, 0 # Load integer literal 0 + lw a1, -20(fp) # Pop stack slot 5 + bnez a1, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_2 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_2: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t0, 4 # Word size in bytes + mul a0, a0, t0 # Compute list element offset in bytes + add a0, a1, a0 # Pointer to list element + lw a0, 0(a0) # Get list element + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/list_len.py.ast.typed.s b/src/test/data/pa3/sample/list_len.py.ast.typed.s new file mode 100644 index 0000000..aa6145c --- /dev/null +++ b/src/test/data/pa3/sample/list_len.py.ast.typed.s @@ -0,0 +1,675 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 1 # Load integer literal 1 + sw a0, -20(fp) # Push argument 3 from last. + li a0, 2 # Load integer literal 2 + sw a0, -24(fp) # Push argument 2 from last. + li a0, 3 # Load integer literal 3 + sw a0, -28(fp) # Push argument 1 from last. + li a0, 3 # Pass list length + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $x, t0 # Assign global: x (using tmp register) + lw a0, $x # Load global: x + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $len # Invoke function: len + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/list_len_empty.py.ast.typed.s b/src/test/data/pa3/sample/list_len_empty.py.ast.typed.s new file mode 100644 index 0000000..4d693cf --- /dev/null +++ b/src/test/data/pa3/sample/list_len_empty.py.ast.typed.s @@ -0,0 +1,669 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 0 # Pass list length + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $x, t0 # Assign global: x (using tmp register) + lw a0, $x # Load global: x + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $len # Invoke function: len + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/list_set_element.py.ast.typed.s b/src/test/data/pa3/sample/list_set_element.py.ast.typed.s new file mode 100644 index 0000000..608c5d8 --- /dev/null +++ b/src/test/data/pa3/sample/list_set_element.py.ast.typed.s @@ -0,0 +1,785 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 1 # Load integer literal 1 + sw a0, -20(fp) # Push argument 3 from last. + li a0, 2 # Load integer literal 2 + sw a0, -24(fp) # Push argument 2 from last. + li a0, 3 # Load integer literal 3 + sw a0, -28(fp) # Push argument 1 from last. + li a0, 3 # Pass list length + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $x, t0 # Assign global: x (using tmp register) + li a0, 4 # Load integer literal 4 + sw a0, -12(fp) # Push on stack slot 3 + lw a0, $x # Load global: x + sw a0, -16(fp) # Push on stack slot 4 + li a0, 0 # Load integer literal 0 + lw t0, -16(fp) # Pop stack slot 4 + lw t1, -12(fp) # Pop stack slot 3 + bnez t0, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + lw t2, 12(t0) # Load attribute: __len__ + bltu a0, t2, label_2 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_2: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul a0, a0, t2 # Compute list element offset in bytes + add a0, t0, a0 # Pointer to list element + sw t1, 0(a0) # Set list element + li a0, 5 # Load integer literal 5 + sw a0, -12(fp) # Push on stack slot 3 + lw a0, $x # Load global: x + sw a0, -16(fp) # Push on stack slot 4 + li a0, 1 # Load integer literal 1 + lw t0, -16(fp) # Pop stack slot 4 + lw t1, -12(fp) # Pop stack slot 3 + bnez t0, label_3 # Ensure not None + j error.None # Go to error handler +label_3: # Not None + lw t2, 12(t0) # Load attribute: __len__ + bltu a0, t2, label_4 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_4: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul a0, a0, t2 # Compute list element offset in bytes + add a0, t0, a0 # Pointer to list element + sw t1, 0(a0) # Set list element + li a0, 6 # Load integer literal 6 + sw a0, -12(fp) # Push on stack slot 3 + lw a0, $x # Load global: x + sw a0, -16(fp) # Push on stack slot 4 + li a0, 2 # Load integer literal 2 + lw t0, -16(fp) # Pop stack slot 4 + lw t1, -12(fp) # Pop stack slot 3 + bnez t0, label_5 # Ensure not None + j error.None # Go to error handler +label_5: # Not None + lw t2, 12(t0) # Load attribute: __len__ + bltu a0, t2, label_6 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_6: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul a0, a0, t2 # Compute list element offset in bytes + add a0, t0, a0 # Pointer to list element + sw t1, 0(a0) # Set list element + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + li a0, 0 # Load integer literal 0 + lw a1, -20(fp) # Pop stack slot 5 + bnez a1, label_7 # Ensure not None + j error.None # Go to error handler +label_7: # Not None + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_8 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_8: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t0, 4 # Word size in bytes + mul a0, a0, t0 # Compute list element offset in bytes + add a0, a1, a0 # Pointer to list element + lw a0, 0(a0) # Get list element + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + li a0, 1 # Load integer literal 1 + lw a1, -20(fp) # Pop stack slot 5 + bnez a1, label_9 # Ensure not None + j error.None # Go to error handler +label_9: # Not None + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_10 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_10: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t0, 4 # Word size in bytes + mul a0, a0, t0 # Compute list element offset in bytes + add a0, a1, a0 # Pointer to list element + lw a0, 0(a0) # Get list element + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + li a0, 2 # Load integer literal 2 + lw a1, -20(fp) # Pop stack slot 5 + bnez a1, label_11 # Ensure not None + j error.None # Go to error handler +label_11: # Not None + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_12 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_12: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t0, 4 # Word size in bytes + mul a0, a0, t0 # Compute list element offset in bytes + add a0, a1, a0 # Pointer to list element + lw a0, 0(a0) # Get list element + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/list_set_element_none.py.ast.typed.s b/src/test/data/pa3/sample/list_set_element_none.py.ast.typed.s new file mode 100644 index 0000000..dc925b0 --- /dev/null +++ b/src/test/data/pa3/sample/list_set_element_none.py.ast.typed.s @@ -0,0 +1,672 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 1 # Load integer literal 1 + sw a0, -12(fp) # Push on stack slot 3 + lw a0, $x # Load global: x + sw a0, -16(fp) # Push on stack slot 4 + li a0, 0 # Load integer literal 0 + lw t0, -16(fp) # Pop stack slot 4 + lw t1, -12(fp) # Pop stack slot 3 + bnez t0, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + lw t2, 12(t0) # Load attribute: __len__ + bltu a0, t2, label_2 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_2: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul a0, a0, t2 # Compute list element offset in bytes + add a0, t0, a0 # Pointer to list element + sw t1, 0(a0) # Set list element + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/list_set_element_oob_1.py.ast.typed.s b/src/test/data/pa3/sample/list_set_element_oob_1.py.ast.typed.s new file mode 100644 index 0000000..ae9e3af --- /dev/null +++ b/src/test/data/pa3/sample/list_set_element_oob_1.py.ast.typed.s @@ -0,0 +1,748 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 1 # Load integer literal 1 + sw a0, -20(fp) # Push argument 3 from last. + li a0, 2 # Load integer literal 2 + sw a0, -24(fp) # Push argument 2 from last. + li a0, 3 # Load integer literal 3 + sw a0, -28(fp) # Push argument 1 from last. + li a0, 3 # Pass list length + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $x, t0 # Assign global: x (using tmp register) + li a0, 4 # Load integer literal 4 + sw a0, -12(fp) # Push on stack slot 3 + lw a0, $x # Load global: x + sw a0, -16(fp) # Push on stack slot 4 + li a0, 1 # Load integer literal 1 + sub a0, zero, a0 # Unary negation + lw t0, -16(fp) # Pop stack slot 4 + lw t1, -12(fp) # Pop stack slot 3 + bnez t0, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + lw t2, 12(t0) # Load attribute: __len__ + bltu a0, t2, label_2 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_2: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul a0, a0, t2 # Compute list element offset in bytes + add a0, t0, a0 # Pointer to list element + sw t1, 0(a0) # Set list element + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + li a0, 0 # Load integer literal 0 + lw a1, -20(fp) # Pop stack slot 5 + bnez a1, label_3 # Ensure not None + j error.None # Go to error handler +label_3: # Not None + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_4 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_4: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t0, 4 # Word size in bytes + mul a0, a0, t0 # Compute list element offset in bytes + add a0, a1, a0 # Pointer to list element + lw a0, 0(a0) # Get list element + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + li a0, 1 # Load integer literal 1 + lw a1, -20(fp) # Pop stack slot 5 + bnez a1, label_5 # Ensure not None + j error.None # Go to error handler +label_5: # Not None + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_6 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_6: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t0, 4 # Word size in bytes + mul a0, a0, t0 # Compute list element offset in bytes + add a0, a1, a0 # Pointer to list element + lw a0, 0(a0) # Get list element + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + li a0, 2 # Load integer literal 2 + lw a1, -20(fp) # Pop stack slot 5 + bnez a1, label_7 # Ensure not None + j error.None # Go to error handler +label_7: # Not None + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_8 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_8: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t0, 4 # Word size in bytes + mul a0, a0, t0 # Compute list element offset in bytes + add a0, a1, a0 # Pointer to list element + lw a0, 0(a0) # Get list element + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/list_set_element_oob_2.py.ast.typed.s b/src/test/data/pa3/sample/list_set_element_oob_2.py.ast.typed.s new file mode 100644 index 0000000..6745567 --- /dev/null +++ b/src/test/data/pa3/sample/list_set_element_oob_2.py.ast.typed.s @@ -0,0 +1,747 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 1 # Load integer literal 1 + sw a0, -20(fp) # Push argument 3 from last. + li a0, 2 # Load integer literal 2 + sw a0, -24(fp) # Push argument 2 from last. + li a0, 3 # Load integer literal 3 + sw a0, -28(fp) # Push argument 1 from last. + li a0, 3 # Pass list length + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $x, t0 # Assign global: x (using tmp register) + li a0, 4 # Load integer literal 4 + sw a0, -12(fp) # Push on stack slot 3 + lw a0, $x # Load global: x + sw a0, -16(fp) # Push on stack slot 4 + li a0, 4 # Load integer literal 4 + lw t0, -16(fp) # Pop stack slot 4 + lw t1, -12(fp) # Pop stack slot 3 + bnez t0, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + lw t2, 12(t0) # Load attribute: __len__ + bltu a0, t2, label_2 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_2: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul a0, a0, t2 # Compute list element offset in bytes + add a0, t0, a0 # Pointer to list element + sw t1, 0(a0) # Set list element + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + li a0, 0 # Load integer literal 0 + lw a1, -20(fp) # Pop stack slot 5 + bnez a1, label_3 # Ensure not None + j error.None # Go to error handler +label_3: # Not None + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_4 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_4: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t0, 4 # Word size in bytes + mul a0, a0, t0 # Compute list element offset in bytes + add a0, a1, a0 # Pointer to list element + lw a0, 0(a0) # Get list element + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + li a0, 1 # Load integer literal 1 + lw a1, -20(fp) # Pop stack slot 5 + bnez a1, label_5 # Ensure not None + j error.None # Go to error handler +label_5: # Not None + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_6 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_6: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t0, 4 # Word size in bytes + mul a0, a0, t0 # Compute list element offset in bytes + add a0, a1, a0 # Pointer to list element + lw a0, 0(a0) # Get list element + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + li a0, 2 # Load integer literal 2 + lw a1, -20(fp) # Pop stack slot 5 + bnez a1, label_7 # Ensure not None + j error.None # Go to error handler +label_7: # Not None + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_8 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_8: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t0, 4 # Word size in bytes + mul a0, a0, t0 # Compute list element offset in bytes + add a0, a1, a0 # Pointer to list element + lw a0, 0(a0) # Get list element + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/list_set_element_oob_3.py.ast.typed.s b/src/test/data/pa3/sample/list_set_element_oob_3.py.ast.typed.s new file mode 100644 index 0000000..b72f4ec --- /dev/null +++ b/src/test/data/pa3/sample/list_set_element_oob_3.py.ast.typed.s @@ -0,0 +1,678 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 0 # Pass list length + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $x, t0 # Assign global: x (using tmp register) + li a0, 4 # Load integer literal 4 + sw a0, -12(fp) # Push on stack slot 3 + lw a0, $x # Load global: x + sw a0, -16(fp) # Push on stack slot 4 + li a0, 0 # Load integer literal 0 + lw t0, -16(fp) # Pop stack slot 4 + lw t1, -12(fp) # Pop stack slot 3 + bnez t0, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + lw t2, 12(t0) # Load attribute: __len__ + bltu a0, t2, label_2 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_2: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul a0, a0, t2 # Compute list element offset in bytes + add a0, t0, a0 # Pointer to list element + sw t1, 0(a0) # Set list element + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/literal_bool.py.ast.typed.s b/src/test/data/pa3/sample/literal_bool.py.ast.typed.s new file mode 100644 index 0000000..4fe0129 --- /dev/null +++ b/src/test/data/pa3/sample/literal_bool.py.ast.typed.s @@ -0,0 +1,661 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 1 # Load boolean literal: true + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + li a0, 0 # Load boolean literal: false + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/literal_int.py.ast.typed.s b/src/test/data/pa3/sample/literal_int.py.ast.typed.s new file mode 100644 index 0000000..1d9ab5b --- /dev/null +++ b/src/test/data/pa3/sample/literal_int.py.ast.typed.s @@ -0,0 +1,661 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 42 # Load integer literal 42 + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + li a0, 65999 # Load integer literal 65999 + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/literal_str.py.ast.typed.s b/src/test/data/pa3/sample/literal_str.py.ast.typed.s new file mode 100644 index 0000000..c47f99c --- /dev/null +++ b/src/test/data/pa3/sample/literal_str.py.ast.typed.s @@ -0,0 +1,663 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + la a0, const_2 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_3 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_4 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_5 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_3 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_6 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 7 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 11 # Constant value of attribute: __len__ + .string "Hello World" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/nested.py.ast.typed.s b/src/test/data/pa3/sample/nested.py.ast.typed.s new file mode 100644 index 0000000..a21c539 --- /dev/null +++ b/src/test/data/pa3/sample/nested.py.ast.typed.s @@ -0,0 +1,728 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $g +$g: + .word 1 # Initial value of global var: g + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $g # Load global: g + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $foo # Invoke function: foo + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $foo.bar.baz +$foo.bar.baz: + addi sp, sp, -@foo.bar.baz.size # Reserve space for stack frame. + sw ra, @foo.bar.baz.size-4(sp) # return address + sw fp, @foo.bar.baz.size-8(sp) # control link + addi fp, sp, @foo.bar.baz.size # New fp is at old SP. + lw t0, 0(fp) # Load static link from foo.bar.baz to foo.bar + lw t0, 0(t0) # Load static link from foo.bar to foo + lw a0, -12(t0) # Load var: foo.y + j label_2 # Go to return + mv a0, zero # Load None + j label_2 # Jump to function epilogue +label_2: # Epilogue + .equiv @foo.bar.baz.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @foo.bar.baz.size # Restore stack pointer + jr ra # Return to caller + +.globl $foo.bar +$foo.bar: + addi sp, sp, -@foo.bar.size # Reserve space for stack frame. + sw ra, @foo.bar.size-4(sp) # return address + sw fp, @foo.bar.size-8(sp) # control link + addi fp, sp, @foo.bar.size # New fp is at old SP. + li a0, 3 # Load integer literal 3 + sw a0, -12(fp) # local variable z + mv t0, fp # Get static link to foo.bar + sw t0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $foo.bar.baz # Invoke function: foo.bar.baz + addi sp, fp, -@foo.bar.size # Set SP to stack frame top. + j label_4 # Go to return + mv a0, zero # Load None + j label_4 # Jump to function epilogue +label_4: # Epilogue + .equiv @foo.bar.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @foo.bar.size # Restore stack pointer + jr ra # Return to caller + +.globl $foo +$foo: + addi sp, sp, -@foo.size # Reserve space for stack frame. + sw ra, @foo.size-4(sp) # return address + sw fp, @foo.size-8(sp) # control link + addi fp, sp, @foo.size # New fp is at old SP. + li a0, 2 # Load integer literal 2 + sw a0, -12(fp) # local variable y + mv t0, fp # Get static link to foo + sw t0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $foo.bar # Invoke function: foo.bar + addi sp, fp, -@foo.size # Set SP to stack frame top. + j label_6 # Go to return + mv a0, zero # Load None + j label_6 # Jump to function epilogue +label_6: # Epilogue + .equiv @foo.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @foo.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/nested2.py.ast.typed.s b/src/test/data/pa3/sample/nested2.py.ast.typed.s new file mode 100644 index 0000000..ba0c2a0 --- /dev/null +++ b/src/test/data/pa3/sample/nested2.py.ast.typed.s @@ -0,0 +1,753 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $g +$g: + .word 1 # Initial value of global var: g + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $g # Load global: g + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $foo # Invoke function: foo + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $foo.bar.baz +$foo.bar.baz: + addi sp, sp, -@foo.bar.baz.size # Reserve space for stack frame. + sw ra, @foo.bar.baz.size-4(sp) # return address + sw fp, @foo.bar.baz.size-8(sp) # control link + addi fp, sp, @foo.bar.baz.size # New fp is at old SP. + mv t0, fp # Get static link to foo.bar.baz + lw t0, 0(t0) # Get static link to foo.bar + lw t0, 0(t0) # Get static link to foo + sw t0, -12(fp) # Push argument 1 from last. + lw t0, 0(fp) # Load static link from foo.bar.baz to foo.bar + lw t0, 0(t0) # Load static link from foo.bar to foo + lw a0, -12(t0) # Load var: foo.y + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $foo.qux # Invoke function: foo.qux + addi sp, fp, -@foo.bar.baz.size # Set SP to stack frame top. + j label_2 # Go to return + mv a0, zero # Load None + j label_2 # Jump to function epilogue +label_2: # Epilogue + .equiv @foo.bar.baz.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @foo.bar.baz.size # Restore stack pointer + jr ra # Return to caller + +.globl $foo.bar +$foo.bar: + addi sp, sp, -@foo.bar.size # Reserve space for stack frame. + sw ra, @foo.bar.size-4(sp) # return address + sw fp, @foo.bar.size-8(sp) # control link + addi fp, sp, @foo.bar.size # New fp is at old SP. + li a0, 3 # Load integer literal 3 + sw a0, -12(fp) # local variable z + mv t0, fp # Get static link to foo.bar + sw t0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $foo.bar.baz # Invoke function: foo.bar.baz + addi sp, fp, -@foo.bar.size # Set SP to stack frame top. + j label_4 # Go to return + mv a0, zero # Load None + j label_4 # Jump to function epilogue +label_4: # Epilogue + .equiv @foo.bar.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @foo.bar.size # Restore stack pointer + jr ra # Return to caller + +.globl $foo.qux +$foo.qux: + addi sp, sp, -@foo.qux.size # Reserve space for stack frame. + sw ra, @foo.qux.size-4(sp) # return address + sw fp, @foo.qux.size-8(sp) # control link + addi fp, sp, @foo.qux.size # New fp is at old SP. + lw a0, 0(fp) # Load var: foo.qux.p + j label_6 # Go to return + mv a0, zero # Load None + j label_6 # Jump to function epilogue +label_6: # Epilogue + .equiv @foo.qux.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @foo.qux.size # Restore stack pointer + jr ra # Return to caller + +.globl $foo +$foo: + addi sp, sp, -@foo.size # Reserve space for stack frame. + sw ra, @foo.size-4(sp) # return address + sw fp, @foo.size-8(sp) # control link + addi fp, sp, @foo.size # New fp is at old SP. + li a0, 2 # Load integer literal 2 + sw a0, -12(fp) # local variable y + mv t0, fp # Get static link to foo + sw t0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $foo.bar # Invoke function: foo.bar + addi sp, fp, -@foo.size # Set SP to stack frame top. + j label_8 # Go to return + mv a0, zero # Load None + j label_8 # Jump to function epilogue +label_8: # Epilogue + .equiv @foo.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @foo.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/object_attr_get.py.ast.typed.s b/src/test/data/pa3/sample/object_attr_get.py.ast.typed.s new file mode 100644 index 0000000..1b1201a --- /dev/null +++ b/src/test/data/pa3/sample/object_attr_get.py.ast.typed.s @@ -0,0 +1,755 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $A$prototype +$A$prototype: + .word 4 # Type tag for class: A + .word 4 # Object size + .word $A$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .align 2 + +.globl $B$prototype +$B$prototype: + .word 5 # Type tag for class: B + .word 5 # Object size + .word $B$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .word 1 # Initial value of attribute: b + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $A$dispatchTable +$A$dispatchTable: + .word $object.__init__ # Implementation for method: A.__init__ + +.globl $B$dispatchTable +$B$dispatchTable: + .word $B.__init__ # Implementation for method: B.__init__ + +.globl $a +$a: + .word 0 # Initial value of global var: a + +.globl $b +$b: + .word 0 # Initial value of global var: b + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + la a0, $B$prototype # Load pointer to prototype of: B + jal alloc # Allocate new object in A0 + sw a0, -12(fp) # Push on stack slot 3 + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 0(a1) # Load address of method: B.__init__ + jalr a1 # Invoke method: B.__init__ + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, -12(fp) # Pop stack slot 3 + sw a0, -12(fp) # Push on stack slot 3 + sw a0, $a, t0 # Assign global: a (using tmp register) + lw a0, -12(fp) # Pop stack slot 3 + sw a0, $b, t0 # Assign global: b (using tmp register) + lw a0, $a # Load global: a + bnez a0, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + lw a0, 12(a0) # Get attribute: A.a + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $b # Load global: b + bnez a0, label_2 # Ensure not None + j error.None # Go to error handler +label_2: # Not None + lw a0, 12(a0) # Get attribute: B.a + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $b # Load global: b + bnez a0, label_3 # Ensure not None + j error.None # Go to error handler +label_3: # Not None + lw a0, 16(a0) # Get attribute: B.b + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $B.__init__ +$B.__init__: + addi sp, sp, -@B.__init__.size # Reserve space for stack frame. + sw ra, @B.__init__.size-4(sp) # return address + sw fp, @B.__init__.size-8(sp) # control link + addi fp, sp, @B.__init__.size # New fp is at old SP. + la a0, const_5 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@B.__init__.size # Set SP to stack frame top. + mv a0, zero # Load None + j label_5 # Jump to function epilogue +label_5: # Epilogue + .equiv @B.__init__.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @B.__init__.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_6 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "B" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/object_attr_get_none.py.ast.typed.s b/src/test/data/pa3/sample/object_attr_get_none.py.ast.typed.s new file mode 100644 index 0000000..6936a0b --- /dev/null +++ b/src/test/data/pa3/sample/object_attr_get_none.py.ast.typed.s @@ -0,0 +1,752 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $A$prototype +$A$prototype: + .word 4 # Type tag for class: A + .word 4 # Object size + .word $A$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .align 2 + +.globl $B$prototype +$B$prototype: + .word 5 # Type tag for class: B + .word 5 # Object size + .word $B$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .word 1 # Initial value of attribute: b + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $A$dispatchTable +$A$dispatchTable: + .word $object.__init__ # Implementation for method: A.__init__ + +.globl $B$dispatchTable +$B$dispatchTable: + .word $B.__init__ # Implementation for method: B.__init__ + +.globl $a +$a: + .word 0 # Initial value of global var: a + +.globl $b +$b: + .word 0 # Initial value of global var: b + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + la a0, $B$prototype # Load pointer to prototype of: B + jal alloc # Allocate new object in A0 + sw a0, -12(fp) # Push on stack slot 3 + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 0(a1) # Load address of method: B.__init__ + jalr a1 # Invoke method: B.__init__ + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, -12(fp) # Pop stack slot 3 + sw a0, $a, t0 # Assign global: a (using tmp register) + lw a0, $a # Load global: a + bnez a0, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + lw a0, 12(a0) # Get attribute: A.a + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $b # Load global: b + bnez a0, label_2 # Ensure not None + j error.None # Go to error handler +label_2: # Not None + lw a0, 12(a0) # Get attribute: B.a + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $b # Load global: b + bnez a0, label_3 # Ensure not None + j error.None # Go to error handler +label_3: # Not None + lw a0, 16(a0) # Get attribute: B.b + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $B.__init__ +$B.__init__: + addi sp, sp, -@B.__init__.size # Reserve space for stack frame. + sw ra, @B.__init__.size-4(sp) # return address + sw fp, @B.__init__.size-8(sp) # control link + addi fp, sp, @B.__init__.size # New fp is at old SP. + la a0, const_5 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@B.__init__.size # Set SP to stack frame top. + mv a0, zero # Load None + j label_5 # Jump to function epilogue +label_5: # Epilogue + .equiv @B.__init__.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @B.__init__.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_6 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "B" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/object_attr_set.py.ast.typed.s b/src/test/data/pa3/sample/object_attr_set.py.ast.typed.s new file mode 100644 index 0000000..124fc5c --- /dev/null +++ b/src/test/data/pa3/sample/object_attr_set.py.ast.typed.s @@ -0,0 +1,773 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $A$prototype +$A$prototype: + .word 4 # Type tag for class: A + .word 4 # Object size + .word $A$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .align 2 + +.globl $B$prototype +$B$prototype: + .word 5 # Type tag for class: B + .word 5 # Object size + .word $B$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .word 1 # Initial value of attribute: b + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $A$dispatchTable +$A$dispatchTable: + .word $object.__init__ # Implementation for method: A.__init__ + +.globl $B$dispatchTable +$B$dispatchTable: + .word $B.__init__ # Implementation for method: B.__init__ + +.globl $a +$a: + .word 0 # Initial value of global var: a + +.globl $b +$b: + .word 0 # Initial value of global var: b + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + la a0, $B$prototype # Load pointer to prototype of: B + jal alloc # Allocate new object in A0 + sw a0, -12(fp) # Push on stack slot 3 + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 0(a1) # Load address of method: B.__init__ + jalr a1 # Invoke method: B.__init__ + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, -12(fp) # Pop stack slot 3 + sw a0, -12(fp) # Push on stack slot 3 + sw a0, $a, t0 # Assign global: a (using tmp register) + lw a0, -12(fp) # Pop stack slot 3 + sw a0, $b, t0 # Assign global: b (using tmp register) + li a0, 1 # Load integer literal 1 + sw a0, -12(fp) # Push on stack slot 3 + lw a0, $b # Load global: b + mv a1, a0 # Move object + lw a0, -12(fp) # Pop stack slot 3 + bnez a1, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + sw a0, 12(a1) # Set attribute: B.a + li a0, 0 # Load boolean literal: false + sw a0, -12(fp) # Push on stack slot 3 + lw a0, $b # Load global: b + mv a1, a0 # Move object + lw a0, -12(fp) # Pop stack slot 3 + bnez a1, label_2 # Ensure not None + j error.None # Go to error handler +label_2: # Not None + sw a0, 16(a1) # Set attribute: B.b + lw a0, $a # Load global: a + bnez a0, label_3 # Ensure not None + j error.None # Go to error handler +label_3: # Not None + lw a0, 12(a0) # Get attribute: A.a + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $b # Load global: b + bnez a0, label_4 # Ensure not None + j error.None # Go to error handler +label_4: # Not None + lw a0, 12(a0) # Get attribute: B.a + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $b # Load global: b + bnez a0, label_5 # Ensure not None + j error.None # Go to error handler +label_5: # Not None + lw a0, 16(a0) # Get attribute: B.b + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $B.__init__ +$B.__init__: + addi sp, sp, -@B.__init__.size # Reserve space for stack frame. + sw ra, @B.__init__.size-4(sp) # return address + sw fp, @B.__init__.size-8(sp) # control link + addi fp, sp, @B.__init__.size # New fp is at old SP. + la a0, const_5 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@B.__init__.size # Set SP to stack frame top. + mv a0, zero # Load None + j label_7 # Jump to function epilogue +label_7: # Epilogue + .equiv @B.__init__.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @B.__init__.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_6 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "B" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/object_attr_set_eval_order.py.ast.typed.s b/src/test/data/pa3/sample/object_attr_set_eval_order.py.ast.typed.s new file mode 100644 index 0000000..4cf3855 --- /dev/null +++ b/src/test/data/pa3/sample/object_attr_set_eval_order.py.ast.typed.s @@ -0,0 +1,902 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $A$prototype +$A$prototype: + .word 4 # Type tag for class: A + .word 4 # Object size + .word $A$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .align 2 + +.globl $B$prototype +$B$prototype: + .word 5 # Type tag for class: B + .word 5 # Object size + .word $B$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .word 1 # Initial value of attribute: b + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $A$dispatchTable +$A$dispatchTable: + .word $object.__init__ # Implementation for method: A.__init__ + +.globl $B$dispatchTable +$B$dispatchTable: + .word $B.__init__ # Implementation for method: B.__init__ + +.globl $a +$a: + .word 0 # Initial value of global var: a + +.globl $b +$b: + .word 0 # Initial value of global var: b + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + la a0, $B$prototype # Load pointer to prototype of: B + jal alloc # Allocate new object in A0 + sw a0, -12(fp) # Push on stack slot 3 + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 0(a1) # Load address of method: B.__init__ + jalr a1 # Invoke method: B.__init__ + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, -12(fp) # Pop stack slot 3 + sw a0, -12(fp) # Push on stack slot 3 + sw a0, $a, t0 # Assign global: a (using tmp register) + lw a0, -12(fp) # Pop stack slot 3 + sw a0, $b, t0 # Assign global: b (using tmp register) + addi sp, fp, -16 # Set SP to last argument. + jal $get_one # Invoke function: get_one + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -12(fp) # Push on stack slot 3 + addi sp, fp, -16 # Set SP to last argument. + jal $get_b # Invoke function: get_b + addi sp, fp, -@..main.size # Set SP to stack frame top. + mv a1, a0 # Move object + lw a0, -12(fp) # Pop stack slot 3 + bnez a1, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + sw a0, 12(a1) # Set attribute: B.a + la a0, const_2 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + addi sp, fp, -16 # Set SP to last argument. + jal $get_false # Invoke function: get_false + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -12(fp) # Push on stack slot 3 + addi sp, fp, -16 # Set SP to last argument. + jal $get_b # Invoke function: get_b + addi sp, fp, -@..main.size # Set SP to stack frame top. + mv a1, a0 # Move object + lw a0, -12(fp) # Pop stack slot 3 + bnez a1, label_2 # Ensure not None + j error.None # Go to error handler +label_2: # Not None + sw a0, 16(a1) # Set attribute: B.b + la a0, const_3 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $a # Load global: a + bnez a0, label_3 # Ensure not None + j error.None # Go to error handler +label_3: # Not None + lw a0, 12(a0) # Get attribute: A.a + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $b # Load global: b + bnez a0, label_4 # Ensure not None + j error.None # Go to error handler +label_4: # Not None + lw a0, 12(a0) # Get attribute: B.a + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $b # Load global: b + bnez a0, label_5 # Ensure not None + j error.None # Go to error handler +label_5: # Not None + lw a0, 16(a0) # Get attribute: B.b + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_4 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_5 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_6 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_4 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $B.__init__ +$B.__init__: + addi sp, sp, -@B.__init__.size # Reserve space for stack frame. + sw ra, @B.__init__.size-4(sp) # return address + sw fp, @B.__init__.size-8(sp) # control link + addi fp, sp, @B.__init__.size # New fp is at old SP. + la a0, const_7 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@B.__init__.size # Set SP to stack frame top. + mv a0, zero # Load None + j label_7 # Jump to function epilogue +label_7: # Epilogue + .equiv @B.__init__.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @B.__init__.size # Restore stack pointer + jr ra # Return to caller + +.globl $get_b +$get_b: + addi sp, sp, -@get_b.size # Reserve space for stack frame. + sw ra, @get_b.size-4(sp) # return address + sw fp, @get_b.size-8(sp) # control link + addi fp, sp, @get_b.size # New fp is at old SP. + la a0, const_8 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@get_b.size # Set SP to stack frame top. + lw a0, $b # Load global: b + j label_9 # Go to return + mv a0, zero # Load None + j label_9 # Jump to function epilogue +label_9: # Epilogue + .equiv @get_b.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @get_b.size # Restore stack pointer + jr ra # Return to caller + +.globl $get_one +$get_one: + addi sp, sp, -@get_one.size # Reserve space for stack frame. + sw ra, @get_one.size-4(sp) # return address + sw fp, @get_one.size-8(sp) # control link + addi fp, sp, @get_one.size # New fp is at old SP. + la a0, const_9 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@get_one.size # Set SP to stack frame top. + li a0, 1 # Load integer literal 1 + j label_11 # Go to return + mv a0, zero # Load None + j label_11 # Jump to function epilogue +label_11: # Epilogue + .equiv @get_one.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @get_one.size # Restore stack pointer + jr ra # Return to caller + +.globl $get_false +$get_false: + addi sp, sp, -@get_false.size # Reserve space for stack frame. + sw ra, @get_false.size-4(sp) # return address + sw fp, @get_false.size-8(sp) # control link + addi fp, sp, @get_false.size # New fp is at old SP. + la a0, const_10 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@get_false.size # Set SP to stack frame top. + li a0, 0 # Load boolean literal: false + j label_13 # Go to return + mv a0, zero # Load None + j label_13 # Jump to function epilogue +label_13: # Epilogue + .equiv @get_false.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @get_false.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_11 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_12 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_13 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_14 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "B" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 7 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 9 # Constant value of attribute: __len__ + .string "Getting 1" # Constant value of attribute: __str__ + .align 2 + +.globl const_11 +const_11: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_10 +const_10: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Getting False" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 + +.globl const_13 +const_13: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 12 # Constant value of attribute: __len__ + .string "Assigned B.b" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 12 # Constant value of attribute: __len__ + .string "Assigned B.a" # Constant value of attribute: __str__ + .align 2 + +.globl const_14 +const_14: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 7 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 9 # Constant value of attribute: __len__ + .string "Getting B" # Constant value of attribute: __str__ + .align 2 + +.globl const_12 +const_12: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/object_attr_set_none.py.ast.typed.s b/src/test/data/pa3/sample/object_attr_set_none.py.ast.typed.s new file mode 100644 index 0000000..5b17825 --- /dev/null +++ b/src/test/data/pa3/sample/object_attr_set_none.py.ast.typed.s @@ -0,0 +1,770 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $A$prototype +$A$prototype: + .word 4 # Type tag for class: A + .word 4 # Object size + .word $A$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .align 2 + +.globl $B$prototype +$B$prototype: + .word 5 # Type tag for class: B + .word 5 # Object size + .word $B$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .word 1 # Initial value of attribute: b + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $A$dispatchTable +$A$dispatchTable: + .word $object.__init__ # Implementation for method: A.__init__ + +.globl $B$dispatchTable +$B$dispatchTable: + .word $B.__init__ # Implementation for method: B.__init__ + +.globl $a +$a: + .word 0 # Initial value of global var: a + +.globl $b +$b: + .word 0 # Initial value of global var: b + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + la a0, $B$prototype # Load pointer to prototype of: B + jal alloc # Allocate new object in A0 + sw a0, -12(fp) # Push on stack slot 3 + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 0(a1) # Load address of method: B.__init__ + jalr a1 # Invoke method: B.__init__ + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, -12(fp) # Pop stack slot 3 + sw a0, $a, t0 # Assign global: a (using tmp register) + lw a0, $a # Load global: a + bnez a0, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + lw a0, 12(a0) # Get attribute: A.a + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + li a0, 1 # Load integer literal 1 + sw a0, -12(fp) # Push on stack slot 3 + lw a0, $b # Load global: b + mv a1, a0 # Move object + lw a0, -12(fp) # Pop stack slot 3 + bnez a1, label_2 # Ensure not None + j error.None # Go to error handler +label_2: # Not None + sw a0, 12(a1) # Set attribute: B.a + li a0, 0 # Load boolean literal: false + sw a0, -12(fp) # Push on stack slot 3 + lw a0, $b # Load global: b + mv a1, a0 # Move object + lw a0, -12(fp) # Pop stack slot 3 + bnez a1, label_3 # Ensure not None + j error.None # Go to error handler +label_3: # Not None + sw a0, 16(a1) # Set attribute: B.b + lw a0, $b # Load global: b + bnez a0, label_4 # Ensure not None + j error.None # Go to error handler +label_4: # Not None + lw a0, 12(a0) # Get attribute: B.a + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $b # Load global: b + bnez a0, label_5 # Ensure not None + j error.None # Go to error handler +label_5: # Not None + lw a0, 16(a0) # Get attribute: B.b + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $B.__init__ +$B.__init__: + addi sp, sp, -@B.__init__.size # Reserve space for stack frame. + sw ra, @B.__init__.size-4(sp) # return address + sw fp, @B.__init__.size-8(sp) # control link + addi fp, sp, @B.__init__.size # New fp is at old SP. + la a0, const_5 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@B.__init__.size # Set SP to stack frame top. + mv a0, zero # Load None + j label_7 # Jump to function epilogue +label_7: # Epilogue + .equiv @B.__init__.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @B.__init__.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_6 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "B" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/object_init.py.ast.typed.s b/src/test/data/pa3/sample/object_init.py.ast.typed.s new file mode 100644 index 0000000..0d286c8 --- /dev/null +++ b/src/test/data/pa3/sample/object_init.py.ast.typed.s @@ -0,0 +1,713 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $A$prototype +$A$prototype: + .word 4 # Type tag for class: A + .word 4 # Object size + .word $A$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .align 2 + +.globl $B$prototype +$B$prototype: + .word 5 # Type tag for class: B + .word 5 # Object size + .word $B$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .word 1 # Initial value of attribute: b + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $A$dispatchTable +$A$dispatchTable: + .word $object.__init__ # Implementation for method: A.__init__ + +.globl $B$dispatchTable +$B$dispatchTable: + .word $B.__init__ # Implementation for method: B.__init__ + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + la a0, $B$prototype # Load pointer to prototype of: B + jal alloc # Allocate new object in A0 + sw a0, -12(fp) # Push on stack slot 3 + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 0(a1) # Load address of method: B.__init__ + jalr a1 # Invoke method: B.__init__ + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, -12(fp) # Pop stack slot 3 + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $B.__init__ +$B.__init__: + addi sp, sp, -@B.__init__.size # Reserve space for stack frame. + sw ra, @B.__init__.size-4(sp) # return address + sw fp, @B.__init__.size-8(sp) # control link + addi fp, sp, @B.__init__.size # New fp is at old SP. + la a0, const_5 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@B.__init__.size # Set SP to stack frame top. + mv a0, zero # Load None + j label_2 # Jump to function epilogue +label_2: # Epilogue + .equiv @B.__init__.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @B.__init__.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_6 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "B" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/object_method.py.ast.typed.s b/src/test/data/pa3/sample/object_method.py.ast.typed.s new file mode 100644 index 0000000..a06aa6b --- /dev/null +++ b/src/test/data/pa3/sample/object_method.py.ast.typed.s @@ -0,0 +1,786 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $A$prototype +$A$prototype: + .word 4 # Type tag for class: A + .word 4 # Object size + .word $A$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .align 2 + +.globl $B$prototype +$B$prototype: + .word 5 # Type tag for class: B + .word 5 # Object size + .word $B$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .word 1 # Initial value of attribute: b + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $A$dispatchTable +$A$dispatchTable: + .word $object.__init__ # Implementation for method: A.__init__ + .word $A.foo # Implementation for method: A.foo + +.globl $B$dispatchTable +$B$dispatchTable: + .word $B.__init__ # Implementation for method: B.__init__ + .word $A.foo # Implementation for method: B.foo + .word $B.bar # Implementation for method: B.bar + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + la a0, $B$prototype # Load pointer to prototype of: B + jal alloc # Allocate new object in A0 + sw a0, -20(fp) # Push on stack slot 5 + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 0(a1) # Load address of method: B.__init__ + jalr a1 # Invoke method: B.__init__ + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, -20(fp) # Pop stack slot 5 + bnez a0, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + sw a0, -32(fp) # Push argument 0 from last. + lw a0, -32(fp) # Peek stack slot 7 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 8(a1) # Load address of method: B.bar + addi sp, fp, -32 # Set SP to last argument. + jalr a1 # Invoke method: B.bar + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $A.foo +$A.foo: + addi sp, sp, -@A.foo.size # Reserve space for stack frame. + sw ra, @A.foo.size-4(sp) # return address + sw fp, @A.foo.size-8(sp) # control link + addi fp, sp, @A.foo.size # New fp is at old SP. + lw a0, 4(fp) # Load var: A.foo.self + bnez a0, label_4 # Ensure not None + j error.None # Go to error handler +label_4: # Not None + lw a0, 12(a0) # Get attribute: A.a + j label_3 # Go to return + mv a0, zero # Load None + j label_3 # Jump to function epilogue +label_3: # Epilogue + .equiv @A.foo.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @A.foo.size # Restore stack pointer + jr ra # Return to caller + +.globl $B.__init__ +$B.__init__: + addi sp, sp, -@B.__init__.size # Reserve space for stack frame. + sw ra, @B.__init__.size-4(sp) # return address + sw fp, @B.__init__.size-8(sp) # control link + addi fp, sp, @B.__init__.size # New fp is at old SP. + la a0, const_5 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@B.__init__.size # Set SP to stack frame top. + mv a0, zero # Load None + j label_6 # Jump to function epilogue +label_6: # Epilogue + .equiv @B.__init__.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @B.__init__.size # Restore stack pointer + jr ra # Return to caller + +.globl $B.bar +$B.bar: + addi sp, sp, -@B.bar.size # Reserve space for stack frame. + sw ra, @B.bar.size-4(sp) # return address + sw fp, @B.bar.size-8(sp) # control link + addi fp, sp, @B.bar.size # New fp is at old SP. + lw a0, 0(fp) # Load var: B.bar.self + bnez a0, label_9 # Ensure not None + j error.None # Go to error handler +label_9: # Not None + sw a0, -12(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: B.bar.self + bnez a0, label_10 # Ensure not None + j error.None # Go to error handler +label_10: # Not None + lw a0, 16(a0) # Get attribute: B.b + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + lw a0, -12(fp) # Peek stack slot 2 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 4(a1) # Load address of method: B.foo + addi sp, fp, -16 # Set SP to last argument. + jalr a1 # Invoke method: B.foo + addi sp, fp, -@B.bar.size # Set SP to stack frame top. + j label_8 # Go to return + mv a0, zero # Load None + j label_8 # Jump to function epilogue +label_8: # Epilogue + .equiv @B.bar.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @B.bar.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_6 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "B" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/object_method_complex_call.py.ast.typed.s b/src/test/data/pa3/sample/object_method_complex_call.py.ast.typed.s new file mode 100644 index 0000000..da46cdc --- /dev/null +++ b/src/test/data/pa3/sample/object_method_complex_call.py.ast.typed.s @@ -0,0 +1,824 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $A$prototype +$A$prototype: + .word 4 # Type tag for class: A + .word 4 # Object size + .word $A$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .align 2 + +.globl $B$prototype +$B$prototype: + .word 5 # Type tag for class: B + .word 5 # Object size + .word $B$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .word 1 # Initial value of attribute: b + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $A$dispatchTable +$A$dispatchTable: + .word $object.__init__ # Implementation for method: A.__init__ + .word $A.foo # Implementation for method: A.foo + +.globl $B$dispatchTable +$B$dispatchTable: + .word $B.__init__ # Implementation for method: B.__init__ + .word $B.foo # Implementation for method: B.foo + .word $B.bar # Implementation for method: B.bar + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + la a0, $B$prototype # Load pointer to prototype of: B + jal alloc # Allocate new object in A0 + sw a0, -20(fp) # Push on stack slot 5 + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 0(a1) # Load address of method: B.__init__ + jalr a1 # Invoke method: B.__init__ + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, -20(fp) # Pop stack slot 5 + bnez a0, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + sw a0, -32(fp) # Push argument 0 from last. + lw a0, -32(fp) # Peek stack slot 7 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 8(a1) # Load address of method: B.bar + addi sp, fp, -32 # Set SP to last argument. + jalr a1 # Invoke method: B.bar + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $A.foo +$A.foo: + addi sp, sp, -@A.foo.size # Reserve space for stack frame. + sw ra, @A.foo.size-4(sp) # return address + sw fp, @A.foo.size-8(sp) # control link + addi fp, sp, @A.foo.size # New fp is at old SP. + lw a0, 4(fp) # Load var: A.foo.self + bnez a0, label_4 # Ensure not None + j error.None # Go to error handler +label_4: # Not None + lw a0, 12(a0) # Get attribute: A.a + j label_3 # Go to return + mv a0, zero # Load None + j label_3 # Jump to function epilogue +label_3: # Epilogue + .equiv @A.foo.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @A.foo.size # Restore stack pointer + jr ra # Return to caller + +.globl $B.__init__ +$B.__init__: + addi sp, sp, -@B.__init__.size # Reserve space for stack frame. + sw ra, @B.__init__.size-4(sp) # return address + sw fp, @B.__init__.size-8(sp) # control link + addi fp, sp, @B.__init__.size # New fp is at old SP. + la a0, const_5 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@B.__init__.size # Set SP to stack frame top. + mv a0, zero # Load None + j label_6 # Jump to function epilogue +label_6: # Epilogue + .equiv @B.__init__.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @B.__init__.size # Restore stack pointer + jr ra # Return to caller + +.globl $B.bar +$B.bar: + addi sp, sp, -@B.bar.size # Reserve space for stack frame. + sw ra, @B.bar.size-4(sp) # return address + sw fp, @B.bar.size-8(sp) # control link + addi fp, sp, @B.bar.size # New fp is at old SP. + lw a0, 0(fp) # Load var: B.bar.self + bnez a0, label_9 # Ensure not None + j error.None # Go to error handler +label_9: # Not None + sw a0, -12(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: B.bar.self + bnez a0, label_10 # Ensure not None + j error.None # Go to error handler +label_10: # Not None + sw a0, -28(fp) # Push argument 1 from last. + la a0, const_6 # Load string literal + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@B.bar.size # Set SP to stack frame top. + sw a0, -32(fp) # Push argument 0 from last. + lw a0, -28(fp) # Peek stack slot 6 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 4(a1) # Load address of method: B.foo + addi sp, fp, -32 # Set SP to last argument. + jalr a1 # Invoke method: B.foo + addi sp, fp, -@B.bar.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + lw a0, -12(fp) # Peek stack slot 2 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 4(a1) # Load address of method: B.foo + addi sp, fp, -16 # Set SP to last argument. + jalr a1 # Invoke method: B.foo + addi sp, fp, -@B.bar.size # Set SP to stack frame top. + j label_8 # Go to return + mv a0, zero # Load None + j label_8 # Jump to function epilogue +label_8: # Epilogue + .equiv @B.bar.size, 48 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @B.bar.size # Restore stack pointer + jr ra # Return to caller + +.globl $B.foo +$B.foo: + addi sp, sp, -@B.foo.size # Reserve space for stack frame. + sw ra, @B.foo.size-4(sp) # return address + sw fp, @B.foo.size-8(sp) # control link + addi fp, sp, @B.foo.size # New fp is at old SP. + li a0, 1 # Load integer literal 1 + j label_12 # Go to return + mv a0, zero # Load None + j label_12 # Jump to function epilogue +label_12: # Epilogue + .equiv @B.foo.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @B.foo.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_7 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_10 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "B" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_10 +const_10: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 3 # Constant value of attribute: __len__ + .string "..." # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/object_method_nested.py.ast.typed.s b/src/test/data/pa3/sample/object_method_nested.py.ast.typed.s new file mode 100644 index 0000000..9cdc60a --- /dev/null +++ b/src/test/data/pa3/sample/object_method_nested.py.ast.typed.s @@ -0,0 +1,806 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $A$prototype +$A$prototype: + .word 4 # Type tag for class: A + .word 4 # Object size + .word $A$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .align 2 + +.globl $B$prototype +$B$prototype: + .word 5 # Type tag for class: B + .word 5 # Object size + .word $B$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .word 1 # Initial value of attribute: b + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $A$dispatchTable +$A$dispatchTable: + .word $object.__init__ # Implementation for method: A.__init__ + .word $A.foo # Implementation for method: A.foo + +.globl $B$dispatchTable +$B$dispatchTable: + .word $B.__init__ # Implementation for method: B.__init__ + .word $A.foo # Implementation for method: B.foo + .word $B.bar # Implementation for method: B.bar + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + la a0, $B$prototype # Load pointer to prototype of: B + jal alloc # Allocate new object in A0 + sw a0, -20(fp) # Push on stack slot 5 + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 0(a1) # Load address of method: B.__init__ + jalr a1 # Invoke method: B.__init__ + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, -20(fp) # Pop stack slot 5 + bnez a0, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + sw a0, -32(fp) # Push argument 0 from last. + lw a0, -32(fp) # Peek stack slot 7 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 8(a1) # Load address of method: B.bar + addi sp, fp, -32 # Set SP to last argument. + jalr a1 # Invoke method: B.bar + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $A.foo +$A.foo: + addi sp, sp, -@A.foo.size # Reserve space for stack frame. + sw ra, @A.foo.size-4(sp) # return address + sw fp, @A.foo.size-8(sp) # control link + addi fp, sp, @A.foo.size # New fp is at old SP. + lw a0, 4(fp) # Load var: A.foo.self + bnez a0, label_4 # Ensure not None + j error.None # Go to error handler +label_4: # Not None + lw a0, 12(a0) # Get attribute: A.a + j label_3 # Go to return + mv a0, zero # Load None + j label_3 # Jump to function epilogue +label_3: # Epilogue + .equiv @A.foo.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @A.foo.size # Restore stack pointer + jr ra # Return to caller + +.globl $B.__init__ +$B.__init__: + addi sp, sp, -@B.__init__.size # Reserve space for stack frame. + sw ra, @B.__init__.size-4(sp) # return address + sw fp, @B.__init__.size-8(sp) # control link + addi fp, sp, @B.__init__.size # New fp is at old SP. + la a0, const_5 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@B.__init__.size # Set SP to stack frame top. + mv a0, zero # Load None + j label_6 # Jump to function epilogue +label_6: # Epilogue + .equiv @B.__init__.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @B.__init__.size # Restore stack pointer + jr ra # Return to caller + +.globl $B.bar.qux +$B.bar.qux: + addi sp, sp, -@B.bar.qux.size # Reserve space for stack frame. + sw ra, @B.bar.qux.size-4(sp) # return address + sw fp, @B.bar.qux.size-8(sp) # control link + addi fp, sp, @B.bar.qux.size # New fp is at old SP. + lw t0, 4(fp) # Load static link from B.bar.qux to B.bar + lw a0, 0(t0) # Load var: B.bar.self + bnez a0, label_9 # Ensure not None + j error.None # Go to error handler +label_9: # Not None + sw a0, -12(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: B.bar.qux.p + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + lw a0, -12(fp) # Peek stack slot 2 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 4(a1) # Load address of method: B.foo + addi sp, fp, -16 # Set SP to last argument. + jalr a1 # Invoke method: B.foo + addi sp, fp, -@B.bar.qux.size # Set SP to stack frame top. + j label_8 # Go to return + mv a0, zero # Load None + j label_8 # Jump to function epilogue +label_8: # Epilogue + .equiv @B.bar.qux.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @B.bar.qux.size # Restore stack pointer + jr ra # Return to caller + +.globl $B.bar +$B.bar: + addi sp, sp, -@B.bar.size # Reserve space for stack frame. + sw ra, @B.bar.size-4(sp) # return address + sw fp, @B.bar.size-8(sp) # control link + addi fp, sp, @B.bar.size # New fp is at old SP. + mv t0, fp # Get static link to B.bar + sw t0, -12(fp) # Push argument 1 from last. + li a0, 1 # Load boolean literal: true + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $B.bar.qux # Invoke function: B.bar.qux + addi sp, fp, -@B.bar.size # Set SP to stack frame top. + j label_11 # Go to return + mv a0, zero # Load None + j label_11 # Jump to function epilogue +label_11: # Epilogue + .equiv @B.bar.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @B.bar.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_6 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "B" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/object_method_none.py.ast.typed.s b/src/test/data/pa3/sample/object_method_none.py.ast.typed.s new file mode 100644 index 0000000..c171c09 --- /dev/null +++ b/src/test/data/pa3/sample/object_method_none.py.ast.typed.s @@ -0,0 +1,788 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $A$prototype +$A$prototype: + .word 4 # Type tag for class: A + .word 4 # Object size + .word $A$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .align 2 + +.globl $B$prototype +$B$prototype: + .word 5 # Type tag for class: B + .word 5 # Object size + .word $B$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .word 1 # Initial value of attribute: b + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $A$dispatchTable +$A$dispatchTable: + .word $object.__init__ # Implementation for method: A.__init__ + .word $A.foo # Implementation for method: A.foo + +.globl $B$dispatchTable +$B$dispatchTable: + .word $B.__init__ # Implementation for method: B.__init__ + .word $A.foo # Implementation for method: B.foo + .word $B.bar # Implementation for method: B.bar + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + la a0, $B$prototype # Load pointer to prototype of: B + jal alloc # Allocate new object in A0 + sw a0, -20(fp) # Push on stack slot 5 + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 0(a1) # Load address of method: B.__init__ + jalr a1 # Invoke method: B.__init__ + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, -20(fp) # Pop stack slot 5 + bnez a0, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + sw a0, -32(fp) # Push argument 0 from last. + lw a0, -32(fp) # Peek stack slot 7 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 8(a1) # Load address of method: B.bar + addi sp, fp, -32 # Set SP to last argument. + jalr a1 # Invoke method: B.bar + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $A.foo +$A.foo: + addi sp, sp, -@A.foo.size # Reserve space for stack frame. + sw ra, @A.foo.size-4(sp) # return address + sw fp, @A.foo.size-8(sp) # control link + addi fp, sp, @A.foo.size # New fp is at old SP. + lw a0, 4(fp) # Load var: A.foo.self + bnez a0, label_4 # Ensure not None + j error.None # Go to error handler +label_4: # Not None + lw a0, 12(a0) # Get attribute: A.a + j label_3 # Go to return + mv a0, zero # Load None + j label_3 # Jump to function epilogue +label_3: # Epilogue + .equiv @A.foo.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @A.foo.size # Restore stack pointer + jr ra # Return to caller + +.globl $B.__init__ +$B.__init__: + addi sp, sp, -@B.__init__.size # Reserve space for stack frame. + sw ra, @B.__init__.size-4(sp) # return address + sw fp, @B.__init__.size-8(sp) # control link + addi fp, sp, @B.__init__.size # New fp is at old SP. + la a0, const_5 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@B.__init__.size # Set SP to stack frame top. + mv a0, zero # Load None + j label_6 # Jump to function epilogue +label_6: # Epilogue + .equiv @B.__init__.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @B.__init__.size # Restore stack pointer + jr ra # Return to caller + +.globl $B.bar +$B.bar: + addi sp, sp, -@B.bar.size # Reserve space for stack frame. + sw ra, @B.bar.size-4(sp) # return address + sw fp, @B.bar.size-8(sp) # control link + addi fp, sp, @B.bar.size # New fp is at old SP. + mv a0, zero # Load None + sw a0, -12(fp) # local variable a + lw a0, -12(fp) # Load var: B.bar.a + bnez a0, label_9 # Ensure not None + j error.None # Go to error handler +label_9: # Not None + sw a0, -28(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: B.bar.self + bnez a0, label_10 # Ensure not None + j error.None # Go to error handler +label_10: # Not None + lw a0, 16(a0) # Get attribute: B.b + jal makebool # Box boolean + sw a0, -32(fp) # Push argument 0 from last. + lw a0, -28(fp) # Peek stack slot 6 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 4(a1) # Load address of method: A.foo + addi sp, fp, -32 # Set SP to last argument. + jalr a1 # Invoke method: A.foo + addi sp, fp, -@B.bar.size # Set SP to stack frame top. + j label_8 # Go to return + mv a0, zero # Load None + j label_8 # Jump to function epilogue +label_8: # Epilogue + .equiv @B.bar.size, 32 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @B.bar.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_6 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "B" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/object_method_override.py.ast.typed.s b/src/test/data/pa3/sample/object_method_override.py.ast.typed.s new file mode 100644 index 0000000..2de48d1 --- /dev/null +++ b/src/test/data/pa3/sample/object_method_override.py.ast.typed.s @@ -0,0 +1,803 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $A$prototype +$A$prototype: + .word 4 # Type tag for class: A + .word 4 # Object size + .word $A$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .align 2 + +.globl $B$prototype +$B$prototype: + .word 5 # Type tag for class: B + .word 5 # Object size + .word $B$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .word 1 # Initial value of attribute: b + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $A$dispatchTable +$A$dispatchTable: + .word $object.__init__ # Implementation for method: A.__init__ + .word $A.foo # Implementation for method: A.foo + +.globl $B$dispatchTable +$B$dispatchTable: + .word $B.__init__ # Implementation for method: B.__init__ + .word $B.foo # Implementation for method: B.foo + .word $B.bar # Implementation for method: B.bar + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + la a0, $B$prototype # Load pointer to prototype of: B + jal alloc # Allocate new object in A0 + sw a0, -20(fp) # Push on stack slot 5 + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 0(a1) # Load address of method: B.__init__ + jalr a1 # Invoke method: B.__init__ + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, -20(fp) # Pop stack slot 5 + bnez a0, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + sw a0, -32(fp) # Push argument 0 from last. + lw a0, -32(fp) # Peek stack slot 7 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 8(a1) # Load address of method: B.bar + addi sp, fp, -32 # Set SP to last argument. + jalr a1 # Invoke method: B.bar + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $A.foo +$A.foo: + addi sp, sp, -@A.foo.size # Reserve space for stack frame. + sw ra, @A.foo.size-4(sp) # return address + sw fp, @A.foo.size-8(sp) # control link + addi fp, sp, @A.foo.size # New fp is at old SP. + lw a0, 4(fp) # Load var: A.foo.self + bnez a0, label_4 # Ensure not None + j error.None # Go to error handler +label_4: # Not None + lw a0, 12(a0) # Get attribute: A.a + j label_3 # Go to return + mv a0, zero # Load None + j label_3 # Jump to function epilogue +label_3: # Epilogue + .equiv @A.foo.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @A.foo.size # Restore stack pointer + jr ra # Return to caller + +.globl $B.__init__ +$B.__init__: + addi sp, sp, -@B.__init__.size # Reserve space for stack frame. + sw ra, @B.__init__.size-4(sp) # return address + sw fp, @B.__init__.size-8(sp) # control link + addi fp, sp, @B.__init__.size # New fp is at old SP. + la a0, const_5 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@B.__init__.size # Set SP to stack frame top. + mv a0, zero # Load None + j label_6 # Jump to function epilogue +label_6: # Epilogue + .equiv @B.__init__.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @B.__init__.size # Restore stack pointer + jr ra # Return to caller + +.globl $B.bar +$B.bar: + addi sp, sp, -@B.bar.size # Reserve space for stack frame. + sw ra, @B.bar.size-4(sp) # return address + sw fp, @B.bar.size-8(sp) # control link + addi fp, sp, @B.bar.size # New fp is at old SP. + lw a0, 0(fp) # Load var: B.bar.self + bnez a0, label_9 # Ensure not None + j error.None # Go to error handler +label_9: # Not None + sw a0, -12(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: B.bar.self + bnez a0, label_10 # Ensure not None + j error.None # Go to error handler +label_10: # Not None + lw a0, 16(a0) # Get attribute: B.b + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + lw a0, -12(fp) # Peek stack slot 2 + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 4(a1) # Load address of method: B.foo + addi sp, fp, -16 # Set SP to last argument. + jalr a1 # Invoke method: B.foo + addi sp, fp, -@B.bar.size # Set SP to stack frame top. + j label_8 # Go to return + mv a0, zero # Load None + j label_8 # Jump to function epilogue +label_8: # Epilogue + .equiv @B.bar.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @B.bar.size # Restore stack pointer + jr ra # Return to caller + +.globl $B.foo +$B.foo: + addi sp, sp, -@B.foo.size # Reserve space for stack frame. + sw ra, @B.foo.size-4(sp) # return address + sw fp, @B.foo.size-8(sp) # control link + addi fp, sp, @B.foo.size # New fp is at old SP. + li a0, 1 # Load integer literal 1 + j label_12 # Go to return + mv a0, zero # Load None + j label_12 # Jump to function epilogue +label_12: # Epilogue + .equiv @B.foo.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @B.foo.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_6 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "B" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/op_add.py.ast.typed.s b/src/test/data/pa3/sample/op_add.py.ast.typed.s new file mode 100644 index 0000000..8a5e0da --- /dev/null +++ b/src/test/data/pa3/sample/op_add.py.ast.typed.s @@ -0,0 +1,659 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 1 # Load integer literal 1 + sw a0, -20(fp) # Push on stack slot 5 + li a0, 100 # Load integer literal 100 + lw t0, -20(fp) # Pop stack slot 5 + add a0, t0, a0 # Operator + + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/op_cmp_bool.py.ast.typed.s b/src/test/data/pa3/sample/op_cmp_bool.py.ast.typed.s new file mode 100644 index 0000000..39ed0f2 --- /dev/null +++ b/src/test/data/pa3/sample/op_cmp_bool.py.ast.typed.s @@ -0,0 +1,745 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 1 # Load boolean literal: true + sw a0, -20(fp) # Push on stack slot 5 + li a0, 1 # Load boolean literal: true + lw t0, -20(fp) # Pop stack slot 5 + snez t0, t0 # Ensure that operand for == is 1 or 0 + seqz a0, a0 # Ensure that operand for == is 0 or 1 (flipped) + xor a0, t0, a0 # Operator == + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + li a0, 1 # Load boolean literal: true + sw a0, -20(fp) # Push on stack slot 5 + li a0, 0 # Load boolean literal: false + lw t0, -20(fp) # Pop stack slot 5 + snez t0, t0 # Ensure that operand for == is 1 or 0 + seqz a0, a0 # Ensure that operand for == is 0 or 1 (flipped) + xor a0, t0, a0 # Operator == + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + li a0, 0 # Load boolean literal: false + sw a0, -20(fp) # Push on stack slot 5 + li a0, 1 # Load boolean literal: true + lw t0, -20(fp) # Pop stack slot 5 + snez t0, t0 # Ensure that operand for == is 1 or 0 + seqz a0, a0 # Ensure that operand for == is 0 or 1 (flipped) + xor a0, t0, a0 # Operator == + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + li a0, 0 # Load boolean literal: false + sw a0, -20(fp) # Push on stack slot 5 + li a0, 0 # Load boolean literal: false + lw t0, -20(fp) # Pop stack slot 5 + snez t0, t0 # Ensure that operand for == is 1 or 0 + seqz a0, a0 # Ensure that operand for == is 0 or 1 (flipped) + xor a0, t0, a0 # Operator == + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + li a0, 1 # Load boolean literal: true + sw a0, -20(fp) # Push on stack slot 5 + li a0, 1 # Load boolean literal: true + lw t0, -20(fp) # Pop stack slot 5 + snez t0, t0 # Ensure that operand for != is 1 or 0 + snez a0, a0 # Ensure that operand for != is 1 or 0 + xor a0, t0, a0 # Operator != + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + li a0, 1 # Load boolean literal: true + sw a0, -20(fp) # Push on stack slot 5 + li a0, 0 # Load boolean literal: false + lw t0, -20(fp) # Pop stack slot 5 + snez t0, t0 # Ensure that operand for != is 1 or 0 + snez a0, a0 # Ensure that operand for != is 1 or 0 + xor a0, t0, a0 # Operator != + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + li a0, 0 # Load boolean literal: false + sw a0, -20(fp) # Push on stack slot 5 + li a0, 1 # Load boolean literal: true + lw t0, -20(fp) # Pop stack slot 5 + snez t0, t0 # Ensure that operand for != is 1 or 0 + snez a0, a0 # Ensure that operand for != is 1 or 0 + xor a0, t0, a0 # Operator != + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + li a0, 0 # Load boolean literal: false + sw a0, -20(fp) # Push on stack slot 5 + li a0, 0 # Load boolean literal: false + lw t0, -20(fp) # Pop stack slot 5 + snez t0, t0 # Ensure that operand for != is 1 or 0 + snez a0, a0 # Ensure that operand for != is 1 or 0 + xor a0, t0, a0 # Operator != + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/op_cmp_int.py.ast.typed.s b/src/test/data/pa3/sample/op_cmp_int.py.ast.typed.s new file mode 100644 index 0000000..432f5dd --- /dev/null +++ b/src/test/data/pa3/sample/op_cmp_int.py.ast.typed.s @@ -0,0 +1,785 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 42 # Initial value of global var: x + +.globl $y +$y: + .word 7 # Initial value of global var: y + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + lw a0, $y # Load global: y + lw t0, -20(fp) # Pop stack slot 5 + xor a0, t0, a0 # Operator == + seqz a0, a0 # Operator == (..contd) + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + lw a0, $y # Load global: y + lw t0, -20(fp) # Pop stack slot 5 + xor a0, t0, a0 # Operator != + snez a0, a0 # Operator != (..contd) + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + lw a0, $y # Load global: y + lw t0, -20(fp) # Pop stack slot 5 + slt a0, t0, a0 # Operator < + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + lw a0, $y # Load global: y + lw t0, -20(fp) # Pop stack slot 5 + slt a0, a0, t0 # Operator <= + seqz a0, a0 # Operator <= (..contd) + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + lw a0, $y # Load global: y + lw t0, -20(fp) # Pop stack slot 5 + slt a0, a0, t0 # Operator > + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + lw a0, $y # Load global: y + lw t0, -20(fp) # Pop stack slot 5 + slt a0, t0, a0 # Operator >= + seqz a0, a0 # Operator >= (..contd) + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + lw a0, $x # Load global: x + lw t0, -20(fp) # Pop stack slot 5 + xor a0, t0, a0 # Operator == + seqz a0, a0 # Operator == (..contd) + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + lw a0, $x # Load global: x + lw t0, -20(fp) # Pop stack slot 5 + xor a0, t0, a0 # Operator != + snez a0, a0 # Operator != (..contd) + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + lw a0, $x # Load global: x + lw t0, -20(fp) # Pop stack slot 5 + slt a0, t0, a0 # Operator < + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + lw a0, $x # Load global: x + lw t0, -20(fp) # Pop stack slot 5 + slt a0, a0, t0 # Operator <= + seqz a0, a0 # Operator <= (..contd) + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + lw a0, $x # Load global: x + lw t0, -20(fp) # Pop stack slot 5 + slt a0, a0, t0 # Operator > + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + lw a0, $x # Load global: x + lw t0, -20(fp) # Pop stack slot 5 + slt a0, t0, a0 # Operator >= + seqz a0, a0 # Operator >= (..contd) + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/op_div_mod.py.ast.typed.s b/src/test/data/pa3/sample/op_div_mod.py.ast.typed.s new file mode 100644 index 0000000..4769581 --- /dev/null +++ b/src/test/data/pa3/sample/op_div_mod.py.ast.typed.s @@ -0,0 +1,702 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 42 # Initial value of global var: x + +.globl $y +$y: + .word 9 # Initial value of global var: y + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + lw a0, $y # Load global: y + lw t0, -20(fp) # Pop stack slot 5 + bnez a0, label_1 # Ensure non-zero divisor + j error.Div # Go to error handler +label_1: # Divisor is non-zero + xor t2, t0, a0 # Check for same sign + bltz t2, label_3 # If !=, need to adjust left operand + div a0, t0, a0 # Operator // + j label_2 +label_3: # Operands have differing signs + slt t2, zero, a0 # tmp = 1 if right > 0 else 0 + add t2, t2, t2 # tmp *= 2 + addi t2, t2, -1 # tmp = 1 if right>=0 else -1 + add t2, t0, t2 # Adjust left operand + div t2, t2, a0 # Adjusted division, toward 0 + addi a0, t2, -1 # Complete division when signs != +label_2: # End of // + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + lw a0, $y # Load global: y + lw t0, -20(fp) # Pop stack slot 5 + bnez a0, label_4 # Ensure non-zero divisor + j error.Div # Go to error handler +label_4: # Divisor is non-zero + rem t2, t0, a0 # Operator rem + beqz t2, label_5 # If no remainder, no adjustment + xor t3, t2, a0 # Check for differing signs. + bgez t3, label_5 # Don't adjust if signs equal. + add a0, t2, a0 # Adjust + j label_6 +label_5: # Store result + mv a0, t2 +label_6: # End of % + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/op_is.py.ast.typed.s b/src/test/data/pa3/sample/op_is.py.ast.typed.s new file mode 100644 index 0000000..e2e8d2e --- /dev/null +++ b/src/test/data/pa3/sample/op_is.py.ast.typed.s @@ -0,0 +1,778 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $A$prototype +$A$prototype: + .word 4 # Type tag for class: A + .word 4 # Object size + .word $A$dispatchTable # Pointer to dispatch table + .word 42 # Initial value of attribute: a + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $A$dispatchTable +$A$dispatchTable: + .word $object.__init__ # Implementation for method: A.__init__ + +.globl $a1 +$a1: + .word 0 # Initial value of global var: a1 + +.globl $a2 +$a2: + .word 0 # Initial value of global var: a2 + +.globl $a3 +$a3: + .word 0 # Initial value of global var: a3 + +.globl $a4 +$a4: + .word 0 # Initial value of global var: a4 + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + la a0, $A$prototype # Load pointer to prototype of: A + jal alloc # Allocate new object in A0 + sw a0, -12(fp) # Push on stack slot 3 + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 0(a1) # Load address of method: A.__init__ + jalr a1 # Invoke method: A.__init__ + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, -12(fp) # Pop stack slot 3 + sw a0, $a1, t0 # Assign global: a1 (using tmp register) + lw a0, $a1 # Load global: a1 + sw a0, $a2, t0 # Assign global: a2 (using tmp register) + la a0, $A$prototype # Load pointer to prototype of: A + jal alloc # Allocate new object in A0 + sw a0, -12(fp) # Push on stack slot 3 + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 0(a1) # Load address of method: A.__init__ + jalr a1 # Invoke method: A.__init__ + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, -12(fp) # Pop stack slot 3 + sw a0, $a3, t0 # Assign global: a3 (using tmp register) + lw a0, $a1 # Load global: a1 + sw a0, -20(fp) # Push on stack slot 5 + lw a0, $a1 # Load global: a1 + lw t0, -20(fp) # Pop stack slot 5 + xor a0, t0, a0 # Compare references + seqz a0, a0 # Operator is + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $a1 # Load global: a1 + sw a0, -20(fp) # Push on stack slot 5 + lw a0, $a2 # Load global: a2 + lw t0, -20(fp) # Pop stack slot 5 + xor a0, t0, a0 # Compare references + seqz a0, a0 # Operator is + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $a1 # Load global: a1 + sw a0, -20(fp) # Push on stack slot 5 + lw a0, $a3 # Load global: a3 + lw t0, -20(fp) # Pop stack slot 5 + xor a0, t0, a0 # Compare references + seqz a0, a0 # Operator is + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $a1 # Load global: a1 + sw a0, -20(fp) # Push on stack slot 5 + lw a0, $a4 # Load global: a4 + lw t0, -20(fp) # Pop stack slot 5 + xor a0, t0, a0 # Compare references + seqz a0, a0 # Operator is + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $a1 # Load global: a1 + sw a0, -20(fp) # Push on stack slot 5 + mv a0, zero # Load None + lw t0, -20(fp) # Pop stack slot 5 + xor a0, t0, a0 # Compare references + seqz a0, a0 # Operator is + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $a4 # Load global: a4 + sw a0, -20(fp) # Push on stack slot 5 + mv a0, zero # Load None + lw t0, -20(fp) # Pop stack slot 5 + xor a0, t0, a0 # Compare references + seqz a0, a0 # Operator is + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + mv a0, zero # Load None + sw a0, -20(fp) # Push on stack slot 5 + mv a0, zero # Load None + lw t0, -20(fp) # Pop stack slot 5 + xor a0, t0, a0 # Compare references + seqz a0, a0 # Operator is + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/op_logical.py.ast.typed.s b/src/test/data/pa3/sample/op_logical.py.ast.typed.s new file mode 100644 index 0000000..d25a10d --- /dev/null +++ b/src/test/data/pa3/sample/op_logical.py.ast.typed.s @@ -0,0 +1,765 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + addi sp, fp, -16 # Set SP to last argument. + jal $f # Invoke function: f + addi sp, fp, -@..main.size # Set SP to stack frame top. + bnez a0, label_2 # Branch on true. + addi sp, fp, -16 # Set SP to last argument. + jal $g # Invoke function: g + addi sp, fp, -@..main.size # Set SP to stack frame top. + beqz a0, label_1 # Branch on false. +label_2:: + addi sp, fp, -16 # Set SP to last argument. + jal $g # Invoke function: g + addi sp, fp, -@..main.size # Set SP to stack frame top. + beqz a0, label_4 # Branch on false. + addi sp, fp, -16 # Set SP to last argument. + jal $f # Invoke function: f + addi sp, fp, -@..main.size # Set SP to stack frame top. + beqz a0, label_4 # Branch on false. + la a0, const_2 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + j label_3 # Then body complete; jump to end-if +label_4: # Else body + addi sp, fp, -16 # Set SP to last argument. + jal $f # Invoke function: f + addi sp, fp, -@..main.size # Set SP to stack frame top. + beqz a0, label_5 # Operator and: short-circuit left operand + addi sp, fp, -16 # Set SP to last argument. + jal $g # Invoke function: g + addi sp, fp, -@..main.size # Set SP to stack frame top. + bnez a0, label_6 # Operator or: short-circuit left operand + addi sp, fp, -16 # Set SP to last argument. + jal $f # Invoke function: f + addi sp, fp, -@..main.size # Set SP to stack frame top. +label_6: # Done evaluating operator: or +label_5: # Done evaluating operator: and + seqz a0, a0 # Logical not + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. +label_3: # End of if-else statement +label_1: # End of if-else statement + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_3 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_4 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_5 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_3 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $f +$f: + addi sp, sp, -@f.size # Reserve space for stack frame. + sw ra, @f.size-4(sp) # return address + sw fp, @f.size-8(sp) # control link + addi fp, sp, @f.size # New fp is at old SP. + la a0, const_6 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@f.size # Set SP to stack frame top. + li a0, 1 # Load boolean literal: true + j label_8 # Go to return + mv a0, zero # Load None + j label_8 # Jump to function epilogue +label_8: # Epilogue + .equiv @f.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @f.size # Restore stack pointer + jr ra # Return to caller + +.globl $g +$g: + addi sp, sp, -@g.size # Reserve space for stack frame. + sw ra, @g.size-4(sp) # return address + sw fp, @g.size-8(sp) # control link + addi fp, sp, @g.size # New fp is at old SP. + la a0, const_7 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@g.size # Set SP to stack frame top. + li a0, 0 # Load boolean literal: false + j label_10 # Go to return + mv a0, zero # Load None + j label_10 # Jump to function epilogue +label_10: # Epilogue + .equiv @g.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @g.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_8 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_10 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_11 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_10 +const_10: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "Never" # Constant value of attribute: __str__ + .align 2 + +.globl const_11 +const_11: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 7 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 8 # Constant value of attribute: __len__ + .string "f called" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 7 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 8 # Constant value of attribute: __len__ + .string "g called" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/op_mul.py.ast.typed.s b/src/test/data/pa3/sample/op_mul.py.ast.typed.s new file mode 100644 index 0000000..cbd8e4c --- /dev/null +++ b/src/test/data/pa3/sample/op_mul.py.ast.typed.s @@ -0,0 +1,663 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 6 # Load integer literal 6 + sw a0, -20(fp) # Push on stack slot 5 + li a0, 9 # Load integer literal 9 + lw t0, -20(fp) # Pop stack slot 5 + mul a0, t0, a0 # Operator * + sw a0, -20(fp) # Push on stack slot 5 + li a0, 2 # Load integer literal 2 + lw t0, -20(fp) # Pop stack slot 5 + mul a0, t0, a0 # Operator * + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/op_negate.py.ast.typed.s b/src/test/data/pa3/sample/op_negate.py.ast.typed.s new file mode 100644 index 0000000..43422bf --- /dev/null +++ b/src/test/data/pa3/sample/op_negate.py.ast.typed.s @@ -0,0 +1,660 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 42 # Initial value of global var: x + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $x # Load global: x + sub a0, zero, a0 # Unary negation + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/op_sub.py.ast.typed.s b/src/test/data/pa3/sample/op_sub.py.ast.typed.s new file mode 100644 index 0000000..a445117 --- /dev/null +++ b/src/test/data/pa3/sample/op_sub.py.ast.typed.s @@ -0,0 +1,659 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 1 # Load integer literal 1 + sw a0, -20(fp) # Push on stack slot 5 + li a0, 100 # Load integer literal 100 + lw t0, -20(fp) # Pop stack slot 5 + sub a0, t0, a0 # Operator - + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/pass.py.ast.typed.s b/src/test/data/pa3/sample/pass.py.ast.typed.s new file mode 100644 index 0000000..e16f865 --- /dev/null +++ b/src/test/data/pa3/sample/pass.py.ast.typed.s @@ -0,0 +1,649 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/predef_constructors.py.ast.typed.s b/src/test/data/pa3/sample/predef_constructors.py.ast.typed.s new file mode 100644 index 0000000..a592c9f --- /dev/null +++ b/src/test/data/pa3/sample/predef_constructors.py.ast.typed.s @@ -0,0 +1,695 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + la a0, $object$prototype # Load pointer to prototype of: object + jal alloc # Allocate new object in A0 + sw a0, -20(fp) # Push on stack slot 5 + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 0(a1) # Load address of method: object.__init__ + jalr a1 # Invoke method: object.__init__ + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, -20(fp) # Pop stack slot 5 + sw a0, -20(fp) # Push on stack slot 5 + mv a0, zero # Load None + lw t0, -20(fp) # Pop stack slot 5 + xor a0, t0, a0 # Compare references + seqz a0, a0 # Operator is + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + mv a0, zero # Special cases: int and bool unboxed. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + la a0, $str$prototype # Load pointer to prototype of: str + jal alloc # Allocate new object in A0 + sw a0, -20(fp) # Push on stack slot 5 + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + lw a1, 8(a0) # Load address of object's dispatch table + lw a1, 0(a1) # Load address of method: str.__init__ + jalr a1 # Invoke method: str.__init__ + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, -20(fp) # Pop stack slot 5 + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + mv a0, zero # Special cases: int and bool unboxed. + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/stmt_for_list.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_list.py.ast.typed.s new file mode 100644 index 0000000..876f5bf --- /dev/null +++ b/src/test/data/pa3/sample/stmt_for_list.py.ast.typed.s @@ -0,0 +1,697 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.globl $z +$z: + .word 0 # Initial value of global var: z + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 1 # Load integer literal 1 + sw a0, -20(fp) # Push argument 3 from last. + li a0, 2 # Load integer literal 2 + sw a0, -24(fp) # Push argument 2 from last. + li a0, 3 # Load integer literal 3 + sw a0, -28(fp) # Push argument 1 from last. + li a0, 3 # Pass list length + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $z, t0 # Assign global: z (using tmp register) + lw a0, $z # Load global: z + bnez a0, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + sw a0, -12(fp) # Push on stack slot 3 + mv t1, zero # Initialize for-loop index + sw t1, -16(fp) # Push on stack slot 4 +label_2: # for-loop header + lw t1, -16(fp) # Pop stack slot 4 + lw t0, -12(fp) # Peek stack slot 2 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_3 # Exit loop if idx >= len(iter) + addi t1, t1, 1 # Increment idx + sw t1, -16(fp) # Push on stack slot 4 + addi t1, t1, 3 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul t1, t1, t2 # Compute list element offset in bytes + add t1, t0, t1 # Pointer to list element + lw t0, 0(t1) # Get list element + sw t0, $x, t1 # Assign global: x (using tmp register) + lw a0, $x # Load global: x + jal makeint # Box integer + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + j label_2 # Loop back to header +label_3: # for-loop footer + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/stmt_for_list_empty.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_list_empty.py.ast.typed.s new file mode 100644 index 0000000..2b2a470 --- /dev/null +++ b/src/test/data/pa3/sample/stmt_for_list_empty.py.ast.typed.s @@ -0,0 +1,747 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.globl $y +$y: + .word 0 # Initial value of global var: y + +.globl $z +$z: + .word 0 # Initial value of global var: z + +.globl $e +$e: + .word 0 # Initial value of global var: e + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 1 # Load integer literal 1 + sw a0, -20(fp) # Push argument 3 from last. + li a0, 2 # Load integer literal 2 + sw a0, -24(fp) # Push argument 2 from last. + li a0, 3 # Load integer literal 3 + sw a0, -28(fp) # Push argument 1 from last. + li a0, 3 # Pass list length + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $z, t0 # Assign global: z (using tmp register) + li a0, 0 # Pass list length + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $e, t0 # Assign global: e (using tmp register) + lw a0, $z # Load global: z + bnez a0, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + sw a0, -12(fp) # Push on stack slot 3 + mv t1, zero # Initialize for-loop index + sw t1, -16(fp) # Push on stack slot 4 +label_2: # for-loop header + lw t1, -16(fp) # Pop stack slot 4 + lw t0, -12(fp) # Peek stack slot 2 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_3 # Exit loop if idx >= len(iter) + addi t1, t1, 1 # Increment idx + sw t1, -16(fp) # Push on stack slot 4 + addi t1, t1, 3 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul t1, t1, t2 # Compute list element offset in bytes + add t1, t0, t1 # Pointer to list element + lw t0, 0(t1) # Get list element + sw t0, $x, t1 # Assign global: x (using tmp register) + lw a0, $e # Load global: e + bnez a0, label_4 # Ensure not None + j error.None # Go to error handler +label_4: # Not None + sw a0, -20(fp) # Push on stack slot 5 + mv t1, zero # Initialize for-loop index + sw t1, -24(fp) # Push on stack slot 6 +label_5: # for-loop header + lw t1, -24(fp) # Pop stack slot 6 + lw t0, -20(fp) # Peek stack slot 4 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_6 # Exit loop if idx >= len(iter) + addi t1, t1, 1 # Increment idx + sw t1, -24(fp) # Push on stack slot 6 + addi t1, t1, 3 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul t1, t1, t2 # Compute list element offset in bytes + add t1, t0, t1 # Pointer to list element + lw t0, 0(t1) # Get list element + sw t0, $y, t1 # Assign global: y (using tmp register) + la a0, const_2 # Load string literal + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + j label_5 # Loop back to header +label_6: # for-loop footer + lw a0, $x # Load global: x + jal makeint # Box integer + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + j label_2 # Loop back to header +label_3: # for-loop footer + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_3 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_4 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_5 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_3 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_6 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "Never" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/stmt_for_list_eval.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_list_eval.py.ast.typed.s new file mode 100644 index 0000000..fd3e718 --- /dev/null +++ b/src/test/data/pa3/sample/stmt_for_list_eval.py.ast.typed.s @@ -0,0 +1,703 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.globl $z +$z: + .word 0 # Initial value of global var: z + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 1 # Load integer literal 1 + sw a0, -20(fp) # Push argument 3 from last. + li a0, 2 # Load integer literal 2 + sw a0, -24(fp) # Push argument 2 from last. + li a0, 3 # Load integer literal 3 + sw a0, -28(fp) # Push argument 1 from last. + li a0, 3 # Pass list length + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $z, t0 # Assign global: z (using tmp register) + lw a0, $z # Load global: z + bnez a0, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + sw a0, -12(fp) # Push on stack slot 3 + mv t1, zero # Initialize for-loop index + sw t1, -16(fp) # Push on stack slot 4 +label_2: # for-loop header + lw t1, -16(fp) # Pop stack slot 4 + lw t0, -12(fp) # Peek stack slot 2 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_3 # Exit loop if idx >= len(iter) + addi t1, t1, 1 # Increment idx + sw t1, -16(fp) # Push on stack slot 4 + addi t1, t1, 3 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul t1, t1, t2 # Compute list element offset in bytes + add t1, t0, t1 # Pointer to list element + lw t0, 0(t1) # Get list element + sw t0, $x, t1 # Assign global: x (using tmp register) + li a0, 0 # Pass list length + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $z, t0 # Assign global: z (using tmp register) + lw a0, $x # Load global: x + jal makeint # Box integer + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + j label_2 # Loop back to header +label_3: # for-loop footer + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/stmt_for_list_modify.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_list_modify.py.ast.typed.s new file mode 100644 index 0000000..d5a78a7 --- /dev/null +++ b/src/test/data/pa3/sample/stmt_for_list_modify.py.ast.typed.s @@ -0,0 +1,716 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.globl $z +$z: + .word 0 # Initial value of global var: z + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 1 # Load integer literal 1 + sw a0, -20(fp) # Push argument 3 from last. + li a0, 2 # Load integer literal 2 + sw a0, -24(fp) # Push argument 2 from last. + li a0, 1 # Load integer literal 1 + sw a0, -28(fp) # Push argument 1 from last. + li a0, 3 # Pass list length + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $z, t0 # Assign global: z (using tmp register) + lw a0, $z # Load global: z + bnez a0, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + sw a0, -12(fp) # Push on stack slot 3 + mv t1, zero # Initialize for-loop index + sw t1, -16(fp) # Push on stack slot 4 +label_2: # for-loop header + lw t1, -16(fp) # Pop stack slot 4 + lw t0, -12(fp) # Peek stack slot 2 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_3 # Exit loop if idx >= len(iter) + addi t1, t1, 1 # Increment idx + sw t1, -16(fp) # Push on stack slot 4 + addi t1, t1, 3 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul t1, t1, t2 # Compute list element offset in bytes + add t1, t0, t1 # Pointer to list element + lw t0, 0(t1) # Get list element + sw t0, $x, t1 # Assign global: x (using tmp register) + lw a0, $x # Load global: x + sw a0, -20(fp) # Push on stack slot 5 + lw a0, $z # Load global: z + sw a0, -24(fp) # Push on stack slot 6 + lw a0, $x # Load global: x + lw t0, -24(fp) # Pop stack slot 6 + lw t1, -20(fp) # Pop stack slot 5 + bnez t0, label_4 # Ensure not None + j error.None # Go to error handler +label_4: # Not None + lw t2, 12(t0) # Load attribute: __len__ + bltu a0, t2, label_5 # Ensure 0 <= index < len + j error.OOB # Go to error handler +label_5: # Index within bounds + addi a0, a0, 4 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul a0, a0, t2 # Compute list element offset in bytes + add a0, t0, a0 # Pointer to list element + sw t1, 0(a0) # Set list element + lw a0, $x # Load global: x + jal makeint # Box integer + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + j label_2 # Loop back to header +label_3: # for-loop footer + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/stmt_for_list_nested.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_list_nested.py.ast.typed.s new file mode 100644 index 0000000..8408245 --- /dev/null +++ b/src/test/data/pa3/sample/stmt_for_list_nested.py.ast.typed.s @@ -0,0 +1,727 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.globl $y +$y: + .word 0 # Initial value of global var: y + +.globl $z +$z: + .word 0 # Initial value of global var: z + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 1 # Load integer literal 1 + sw a0, -20(fp) # Push argument 3 from last. + li a0, 2 # Load integer literal 2 + sw a0, -24(fp) # Push argument 2 from last. + li a0, 3 # Load integer literal 3 + sw a0, -28(fp) # Push argument 1 from last. + li a0, 3 # Pass list length + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $z, t0 # Assign global: z (using tmp register) + lw a0, $z # Load global: z + bnez a0, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + sw a0, -12(fp) # Push on stack slot 3 + mv t1, zero # Initialize for-loop index + sw t1, -16(fp) # Push on stack slot 4 +label_2: # for-loop header + lw t1, -16(fp) # Pop stack slot 4 + lw t0, -12(fp) # Peek stack slot 2 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_3 # Exit loop if idx >= len(iter) + addi t1, t1, 1 # Increment idx + sw t1, -16(fp) # Push on stack slot 4 + addi t1, t1, 3 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul t1, t1, t2 # Compute list element offset in bytes + add t1, t0, t1 # Pointer to list element + lw t0, 0(t1) # Get list element + sw t0, $x, t1 # Assign global: x (using tmp register) + lw a0, $z # Load global: z + bnez a0, label_4 # Ensure not None + j error.None # Go to error handler +label_4: # Not None + sw a0, -20(fp) # Push on stack slot 5 + mv t1, zero # Initialize for-loop index + sw t1, -24(fp) # Push on stack slot 6 +label_5: # for-loop header + lw t1, -24(fp) # Pop stack slot 6 + lw t0, -20(fp) # Peek stack slot 4 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_6 # Exit loop if idx >= len(iter) + addi t1, t1, 1 # Increment idx + sw t1, -24(fp) # Push on stack slot 6 + addi t1, t1, 3 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul t1, t1, t2 # Compute list element offset in bytes + add t1, t0, t1 # Pointer to list element + lw t0, 0(t1) # Get list element + sw t0, $y, t1 # Assign global: y (using tmp register) + lw a0, $x # Load global: x + sw a0, -36(fp) # Push on stack slot 9 + lw a0, $y # Load global: y + lw t0, -36(fp) # Pop stack slot 9 + mul a0, t0, a0 # Operator * + jal makeint # Box integer + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + j label_5 # Loop back to header +label_6: # for-loop footer + j label_2 # Loop back to header +label_3: # for-loop footer + .equiv @..main.size, 48 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/stmt_for_list_nested_same_var.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_list_nested_same_var.py.ast.typed.s new file mode 100644 index 0000000..76aae48 --- /dev/null +++ b/src/test/data/pa3/sample/stmt_for_list_nested_same_var.py.ast.typed.s @@ -0,0 +1,723 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.globl $y +$y: + .word 0 # Initial value of global var: y + +.globl $z +$z: + .word 0 # Initial value of global var: z + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 1 # Load integer literal 1 + sw a0, -20(fp) # Push argument 3 from last. + li a0, 2 # Load integer literal 2 + sw a0, -24(fp) # Push argument 2 from last. + li a0, 3 # Load integer literal 3 + sw a0, -28(fp) # Push argument 1 from last. + li a0, 3 # Pass list length + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $z, t0 # Assign global: z (using tmp register) + lw a0, $z # Load global: z + bnez a0, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + sw a0, -12(fp) # Push on stack slot 3 + mv t1, zero # Initialize for-loop index + sw t1, -16(fp) # Push on stack slot 4 +label_2: # for-loop header + lw t1, -16(fp) # Pop stack slot 4 + lw t0, -12(fp) # Peek stack slot 2 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_3 # Exit loop if idx >= len(iter) + addi t1, t1, 1 # Increment idx + sw t1, -16(fp) # Push on stack slot 4 + addi t1, t1, 3 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul t1, t1, t2 # Compute list element offset in bytes + add t1, t0, t1 # Pointer to list element + lw t0, 0(t1) # Get list element + sw t0, $x, t1 # Assign global: x (using tmp register) + lw a0, $z # Load global: z + bnez a0, label_4 # Ensure not None + j error.None # Go to error handler +label_4: # Not None + sw a0, -20(fp) # Push on stack slot 5 + mv t1, zero # Initialize for-loop index + sw t1, -24(fp) # Push on stack slot 6 +label_5: # for-loop header + lw t1, -24(fp) # Pop stack slot 6 + lw t0, -20(fp) # Peek stack slot 4 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_6 # Exit loop if idx >= len(iter) + addi t1, t1, 1 # Increment idx + sw t1, -24(fp) # Push on stack slot 6 + addi t1, t1, 3 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul t1, t1, t2 # Compute list element offset in bytes + add t1, t0, t1 # Pointer to list element + lw t0, 0(t1) # Get list element + sw t0, $x, t1 # Assign global: x (using tmp register) + lw a0, $x # Load global: x + jal makeint # Box integer + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + j label_5 # Loop back to header +label_6: # for-loop footer + j label_2 # Loop back to header +label_3: # for-loop footer + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/stmt_for_list_none.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_list_none.py.ast.typed.s new file mode 100644 index 0000000..bedf91d --- /dev/null +++ b/src/test/data/pa3/sample/stmt_for_list_none.py.ast.typed.s @@ -0,0 +1,685 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.globl $z +$z: + .word 0 # Initial value of global var: z + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $z # Load global: z + bnez a0, label_1 # Ensure not None + j error.None # Go to error handler +label_1: # Not None + sw a0, -12(fp) # Push on stack slot 3 + mv t1, zero # Initialize for-loop index + sw t1, -16(fp) # Push on stack slot 4 +label_2: # for-loop header + lw t1, -16(fp) # Pop stack slot 4 + lw t0, -12(fp) # Peek stack slot 2 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_3 # Exit loop if idx >= len(iter) + addi t1, t1, 1 # Increment idx + sw t1, -16(fp) # Push on stack slot 4 + addi t1, t1, 3 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul t1, t1, t2 # Compute list element offset in bytes + add t1, t0, t1 # Pointer to list element + lw t0, 0(t1) # Get list element + sw t0, $x, t1 # Assign global: x (using tmp register) + lw a0, $x # Load global: x + jal makeint # Box integer + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + j label_2 # Loop back to header +label_3: # for-loop footer + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/stmt_for_list_nonlocal.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_list_nonlocal.py.ast.typed.s new file mode 100644 index 0000000..8c5e299 --- /dev/null +++ b/src/test/data/pa3/sample/stmt_for_list_nonlocal.py.ast.typed.s @@ -0,0 +1,791 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 1 # Load integer literal 1 + sw a0, -56(fp) # Push argument 2 from last. + li a0, 2 # Load integer literal 2 + sw a0, -60(fp) # Push argument 1 from last. + li a0, 2 # Pass list length + sw a0, -64(fp) # Push argument 0 from last. + addi sp, fp, -64 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -32(fp) # Push argument 4 from last. + li a0, 2 # Load integer literal 2 + sw a0, -56(fp) # Push argument 2 from last. + li a0, 3 # Load integer literal 3 + sw a0, -60(fp) # Push argument 1 from last. + li a0, 2 # Pass list length + sw a0, -64(fp) # Push argument 0 from last. + addi sp, fp, -64 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -36(fp) # Push argument 3 from last. + li a0, 4 # Load integer literal 4 + sw a0, -56(fp) # Push argument 2 from last. + li a0, 5 # Load integer literal 5 + sw a0, -60(fp) # Push argument 1 from last. + li a0, 2 # Pass list length + sw a0, -64(fp) # Push argument 0 from last. + addi sp, fp, -64 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -40(fp) # Push argument 2 from last. + li a0, 6 # Load integer literal 6 + sw a0, -56(fp) # Push argument 2 from last. + li a0, 7 # Load integer literal 7 + sw a0, -60(fp) # Push argument 1 from last. + li a0, 2 # Pass list length + sw a0, -64(fp) # Push argument 0 from last. + addi sp, fp, -64 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -44(fp) # Push argument 1 from last. + li a0, 4 # Pass list length + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $crunch # Invoke function: crunch + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $x # Load global: x + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 64 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $crunch.make_z +$crunch.make_z: + addi sp, sp, -@crunch.make_z.size # Reserve space for stack frame. + sw ra, @crunch.make_z.size-4(sp) # return address + sw fp, @crunch.make_z.size-8(sp) # control link + addi fp, sp, @crunch.make_z.size # New fp is at old SP. + lw t0, 0(fp) # Load static link from crunch.make_z to crunch + lw a0, 0(t0) # Load var: crunch.zz + bnez a0, label_3 # Ensure not None + j error.None # Go to error handler +label_3: # Not None + sw a0, -12(fp) # Push on stack slot 3 + mv t1, zero # Initialize for-loop index + sw t1, -16(fp) # Push on stack slot 4 +label_4: # for-loop header + lw t1, -16(fp) # Pop stack slot 4 + lw t0, -12(fp) # Peek stack slot 2 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_5 # Exit loop if idx >= len(iter) + addi t1, t1, 1 # Increment idx + sw t1, -16(fp) # Push on stack slot 4 + addi t1, t1, 3 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul t1, t1, t2 # Compute list element offset in bytes + add t1, t0, t1 # Pointer to list element + lw t0, 0(t1) # Get list element + lw t1, 0(fp) # Load static link from crunch.make_z to crunch + sw t0, -12(t1) # Assign var: crunch.z + j label_4 # Loop back to header +label_5: # for-loop footer + mv a0, zero # Load None + j label_2 # Jump to function epilogue +label_2: # Epilogue + .equiv @crunch.make_z.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @crunch.make_z.size # Restore stack pointer + jr ra # Return to caller + +.globl $crunch +$crunch: + addi sp, sp, -@crunch.size # Reserve space for stack frame. + sw ra, @crunch.size-4(sp) # return address + sw fp, @crunch.size-8(sp) # control link + addi fp, sp, @crunch.size # New fp is at old SP. + mv a0, zero # Load None + sw a0, -12(fp) # local variable z + mv t0, fp # Get static link to crunch + sw t0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $crunch.make_z # Invoke function: crunch.make_z + addi sp, fp, -@crunch.size # Set SP to stack frame top. + lw a0, -12(fp) # Load var: crunch.z + bnez a0, label_8 # Ensure not None + j error.None # Go to error handler +label_8: # Not None + sw a0, -16(fp) # Push on stack slot 4 + mv t1, zero # Initialize for-loop index + sw t1, -20(fp) # Push on stack slot 5 +label_9: # for-loop header + lw t1, -20(fp) # Pop stack slot 5 + lw t0, -16(fp) # Peek stack slot 3 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_10 # Exit loop if idx >= len(iter) + addi t1, t1, 1 # Increment idx + sw t1, -20(fp) # Push on stack slot 5 + addi t1, t1, 3 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul t1, t1, t2 # Compute list element offset in bytes + add t1, t0, t1 # Pointer to list element + lw t0, 0(t1) # Get list element + sw t0, $x, t1 # Assign global: x (using tmp register) + j label_9 # Loop back to header +label_10: # for-loop footer + mv a0, zero # Load None + j label_7 # Jump to function epilogue +label_7: # Epilogue + .equiv @crunch.size, 32 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @crunch.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/stmt_for_list_return.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_list_return.py.ast.typed.s new file mode 100644 index 0000000..825a597 --- /dev/null +++ b/src/test/data/pa3/sample/stmt_for_list_return.py.ast.typed.s @@ -0,0 +1,719 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 10 # Load integer literal 10 + sw a0, -32(fp) # Push argument 4 from last. + li a0, 20 # Load integer literal 20 + sw a0, -36(fp) # Push argument 3 from last. + li a0, 30 # Load integer literal 30 + sw a0, -40(fp) # Push argument 2 from last. + li a0, 40 # Load integer literal 40 + sw a0, -44(fp) # Push argument 1 from last. + li a0, 4 # Pass list length + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal conslist # Move values to new list object + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print_list # Invoke function: print_list + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 48 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $print_list +$print_list: + addi sp, sp, -@print_list.size # Reserve space for stack frame. + sw ra, @print_list.size-4(sp) # return address + sw fp, @print_list.size-8(sp) # control link + addi fp, sp, @print_list.size # New fp is at old SP. + li a0, 0 # Load integer literal 0 + sw a0, -12(fp) # local variable x + lw a0, 0(fp) # Load var: print_list.z + bnez a0, label_3 # Ensure not None + j error.None # Go to error handler +label_3: # Not None + sw a0, -16(fp) # Push on stack slot 4 + mv t1, zero # Initialize for-loop index + sw t1, -20(fp) # Push on stack slot 5 +label_4: # for-loop header + lw t1, -20(fp) # Pop stack slot 5 + lw t0, -16(fp) # Peek stack slot 3 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_5 # Exit loop if idx >= len(iter) + addi t1, t1, 1 # Increment idx + sw t1, -20(fp) # Push on stack slot 5 + addi t1, t1, 3 # Compute list element offset in words + li t2, 4 # Word size in bytes + mul t1, t1, t2 # Compute list element offset in bytes + add t1, t0, t1 # Pointer to list element + lw t0, 0(t1) # Get list element + sw t0, -12(fp) # Assign var: print_list.x + lw a0, -12(fp) # Load var: print_list.x + jal makeint # Box integer + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@print_list.size # Set SP to stack frame top. + lw a0, -12(fp) # Load var: print_list.x + sw a0, -24(fp) # Push on stack slot 6 + li a0, 30 # Load integer literal 30 + lw t0, -24(fp) # Pop stack slot 6 + blt t0, a0, label_6 # Branch on not >= + mv a0, zero # Returning None implicitly + j label_2 # Go to return +label_6: # End of if-else statement + j label_4 # Loop back to header +label_5: # for-loop footer + mv a0, zero # Load None + j label_2 # Jump to function epilogue +label_2: # Epilogue + .equiv @print_list.size, 32 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @print_list.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/stmt_for_str.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_str.py.ast.typed.s new file mode 100644 index 0000000..bd0f21d --- /dev/null +++ b/src/test/data/pa3/sample/stmt_for_str.py.ast.typed.s @@ -0,0 +1,726 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word const_2 # Initial value of global var: x + +.globl $z +$z: + .word const_3 # Initial value of global var: z + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $z # Load global: z + sw a0, -12(fp) # Push on stack slot 3 + mv t1, zero # Initialize for-loop index + sw t1, -16(fp) # Push on stack slot 4 +label_1: # for-loop header + lw t1, -16(fp) # Peek stack slot 3 + lw t0, -12(fp) # Peek stack slot 2 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_2 # Exit loop if idx >= len(iter) + lw t0, -16(fp) # Pop stack slot 4 + lw a1, -12(fp) # Peek stack slot 2 + addi t1, t0, 1 # Increment index for next iteration + sw t1, -16(fp) # Push on stack slot 4 + addi t0, t0, 16 # Convert index to offset to char in bytes + add t0, a1, t0 # Get pointer to char + lbu t0, 0(t0) # Load character + li t1, 20 + mul t0, t0, t1 # Multiply by size of string object + la a0, allChars # Index into single-char table + add a0, a0, t0 + sw a0, $x, t0 # Assign global: x (using tmp register) + lw a0, $x # Load global: x + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + j label_1 # Loop back to header +label_2: # for-loop footer + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_4 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_5 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_6 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_4 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_7 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + la a0, $str$prototype + lw t0, 0(a0) + lw t1, 4(a0) + lw t2, 8(a0) + li t3, 1 + la a0, allChars + li t4, 256 + mv t5, zero +initchars_1: + sw t0, 0(a0) + sw t1, 4(a0) + sw t2, 8(a0) + sw t3, 12(a0) + sw t5, 16(a0) + addi a0, a0, 20 + addi t5, t5, 1 + bne t4, t5, initchars_1 + jr ra + .data + .align 2 + .globl allChars +allChars: + .space 5120 + .text + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_10 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __len__ + .string "" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 3 # Constant value of attribute: __len__ + .string "abc" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_10 +const_10: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/stmt_for_str_empty.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_str_empty.py.ast.typed.s new file mode 100644 index 0000000..1518234 --- /dev/null +++ b/src/test/data/pa3/sample/stmt_for_str_empty.py.ast.typed.s @@ -0,0 +1,767 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word const_2 # Initial value of global var: x + +.globl $y +$y: + .word const_3 # Initial value of global var: y + +.globl $z +$z: + .word const_4 # Initial value of global var: z + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $z # Load global: z + sw a0, -12(fp) # Push on stack slot 3 + mv t1, zero # Initialize for-loop index + sw t1, -16(fp) # Push on stack slot 4 +label_1: # for-loop header + lw t1, -16(fp) # Peek stack slot 3 + lw t0, -12(fp) # Peek stack slot 2 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_2 # Exit loop if idx >= len(iter) + lw t0, -16(fp) # Pop stack slot 4 + lw a1, -12(fp) # Peek stack slot 2 + addi t1, t0, 1 # Increment index for next iteration + sw t1, -16(fp) # Push on stack slot 4 + addi t0, t0, 16 # Convert index to offset to char in bytes + add t0, a1, t0 # Get pointer to char + lbu t0, 0(t0) # Load character + li t1, 20 + mul t0, t0, t1 # Multiply by size of string object + la a0, allChars # Index into single-char table + add a0, a0, t0 + sw a0, $x, t0 # Assign global: x (using tmp register) + lw a0, $x # Load global: x + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + la a0, const_2 # Load string literal + sw a0, -20(fp) # Push on stack slot 5 + mv t1, zero # Initialize for-loop index + sw t1, -24(fp) # Push on stack slot 6 +label_3: # for-loop header + lw t1, -24(fp) # Peek stack slot 5 + lw t0, -20(fp) # Peek stack slot 4 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_4 # Exit loop if idx >= len(iter) + lw t0, -24(fp) # Pop stack slot 6 + lw a1, -20(fp) # Peek stack slot 4 + addi t1, t0, 1 # Increment index for next iteration + sw t1, -24(fp) # Push on stack slot 6 + addi t0, t0, 16 # Convert index to offset to char in bytes + add t0, a1, t0 # Get pointer to char + lbu t0, 0(t0) # Load character + li t1, 20 + mul t0, t0, t1 # Multiply by size of string object + la a0, allChars # Index into single-char table + add a0, a0, t0 + sw a0, $x, t0 # Assign global: x (using tmp register) + lw a0, $x # Load global: x + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + j label_3 # Loop back to header +label_4: # for-loop footer + j label_1 # Loop back to header +label_2: # for-loop footer + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_6 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_7 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_8 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + la a0, $str$prototype + lw t0, 0(a0) + lw t1, 4(a0) + lw t2, 8(a0) + li t3, 1 + la a0, allChars + li t4, 256 + mv t5, zero +initchars_1: + sw t0, 0(a0) + sw t1, 4(a0) + sw t2, 8(a0) + sw t3, 12(a0) + sw t5, 16(a0) + addi a0, a0, 20 + addi t5, t5, 1 + bne t4, t5, initchars_1 + jr ra + .data + .align 2 + .globl allChars +allChars: + .space 5120 + .text + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_10 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_11 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __len__ + .string "" # Constant value of attribute: __str__ + .align 2 + +.globl const_10 +const_10: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 3 # Constant value of attribute: __len__ + .string "123" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 3 # Constant value of attribute: __len__ + .string "abc" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_11 +const_11: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/stmt_for_str_eval.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_str_eval.py.ast.typed.s new file mode 100644 index 0000000..c240950 --- /dev/null +++ b/src/test/data/pa3/sample/stmt_for_str_eval.py.ast.typed.s @@ -0,0 +1,737 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word const_2 # Initial value of global var: x + +.globl $z +$z: + .word const_3 # Initial value of global var: z + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $z # Load global: z + sw a0, -12(fp) # Push on stack slot 3 + mv t1, zero # Initialize for-loop index + sw t1, -16(fp) # Push on stack slot 4 +label_1: # for-loop header + lw t1, -16(fp) # Peek stack slot 3 + lw t0, -12(fp) # Peek stack slot 2 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_2 # Exit loop if idx >= len(iter) + lw t0, -16(fp) # Pop stack slot 4 + lw a1, -12(fp) # Peek stack slot 2 + addi t1, t0, 1 # Increment index for next iteration + sw t1, -16(fp) # Push on stack slot 4 + addi t0, t0, 16 # Convert index to offset to char in bytes + add t0, a1, t0 # Get pointer to char + lbu t0, 0(t0) # Load character + li t1, 20 + mul t0, t0, t1 # Multiply by size of string object + la a0, allChars # Index into single-char table + add a0, a0, t0 + sw a0, $x, t0 # Assign global: x (using tmp register) + la a0, const_4 # Load string literal + sw a0, $z, t0 # Assign global: z (using tmp register) + lw a0, $x # Load global: x + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + j label_1 # Loop back to header +label_2: # for-loop footer + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_6 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_7 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_8 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + la a0, $str$prototype + lw t0, 0(a0) + lw t1, 4(a0) + lw t2, 8(a0) + li t3, 1 + la a0, allChars + li t4, 256 + mv t5, zero +initchars_1: + sw t0, 0(a0) + sw t1, 4(a0) + sw t2, 8(a0) + sw t3, 12(a0) + sw t5, 16(a0) + addi a0, a0, 20 + addi t5, t5, 1 + bne t4, t5, initchars_1 + jr ra + .data + .align 2 + .globl allChars +allChars: + .space 5120 + .text + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_10 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_11 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __len__ + .string "" # Constant value of attribute: __str__ + .align 2 + +.globl const_10 +const_10: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 14 # Constant value of attribute: __len__ + .string "doesn't matter" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 3 # Constant value of attribute: __len__ + .string "abc" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_11 +const_11: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/stmt_for_str_nested.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_str_nested.py.ast.typed.s new file mode 100644 index 0000000..8f53930 --- /dev/null +++ b/src/test/data/pa3/sample/stmt_for_str_nested.py.ast.typed.s @@ -0,0 +1,767 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word const_2 # Initial value of global var: x + +.globl $y +$y: + .word const_3 # Initial value of global var: y + +.globl $z +$z: + .word const_4 # Initial value of global var: z + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $z # Load global: z + sw a0, -12(fp) # Push on stack slot 3 + mv t1, zero # Initialize for-loop index + sw t1, -16(fp) # Push on stack slot 4 +label_1: # for-loop header + lw t1, -16(fp) # Peek stack slot 3 + lw t0, -12(fp) # Peek stack slot 2 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_2 # Exit loop if idx >= len(iter) + lw t0, -16(fp) # Pop stack slot 4 + lw a1, -12(fp) # Peek stack slot 2 + addi t1, t0, 1 # Increment index for next iteration + sw t1, -16(fp) # Push on stack slot 4 + addi t0, t0, 16 # Convert index to offset to char in bytes + add t0, a1, t0 # Get pointer to char + lbu t0, 0(t0) # Load character + li t1, 20 + mul t0, t0, t1 # Multiply by size of string object + la a0, allChars # Index into single-char table + add a0, a0, t0 + sw a0, $x, t0 # Assign global: x (using tmp register) + lw a0, $x # Load global: x + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $y # Load global: y + sw a0, -20(fp) # Push on stack slot 5 + mv t1, zero # Initialize for-loop index + sw t1, -24(fp) # Push on stack slot 6 +label_3: # for-loop header + lw t1, -24(fp) # Peek stack slot 5 + lw t0, -20(fp) # Peek stack slot 4 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_4 # Exit loop if idx >= len(iter) + lw t0, -24(fp) # Pop stack slot 6 + lw a1, -20(fp) # Peek stack slot 4 + addi t1, t0, 1 # Increment index for next iteration + sw t1, -24(fp) # Push on stack slot 6 + addi t0, t0, 16 # Convert index to offset to char in bytes + add t0, a1, t0 # Get pointer to char + lbu t0, 0(t0) # Load character + li t1, 20 + mul t0, t0, t1 # Multiply by size of string object + la a0, allChars # Index into single-char table + add a0, a0, t0 + sw a0, $x, t0 # Assign global: x (using tmp register) + lw a0, $x # Load global: x + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + j label_3 # Loop back to header +label_4: # for-loop footer + j label_1 # Loop back to header +label_2: # for-loop footer + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_6 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_7 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_8 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + la a0, $str$prototype + lw t0, 0(a0) + lw t1, 4(a0) + lw t2, 8(a0) + li t3, 1 + la a0, allChars + li t4, 256 + mv t5, zero +initchars_1: + sw t0, 0(a0) + sw t1, 4(a0) + sw t2, 8(a0) + sw t3, 12(a0) + sw t5, 16(a0) + addi a0, a0, 20 + addi t5, t5, 1 + bne t4, t5, initchars_1 + jr ra + .data + .align 2 + .globl allChars +allChars: + .space 5120 + .text + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_10 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_11 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __len__ + .string "" # Constant value of attribute: __str__ + .align 2 + +.globl const_10 +const_10: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 3 # Constant value of attribute: __len__ + .string "123" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 3 # Constant value of attribute: __len__ + .string "abc" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_11 +const_11: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/stmt_for_str_same_var.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_str_same_var.py.ast.typed.s new file mode 100644 index 0000000..d5e1171 --- /dev/null +++ b/src/test/data/pa3/sample/stmt_for_str_same_var.py.ast.typed.s @@ -0,0 +1,713 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word const_2 # Initial value of global var: x + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $x # Load global: x + sw a0, -12(fp) # Push on stack slot 3 + mv t1, zero # Initialize for-loop index + sw t1, -16(fp) # Push on stack slot 4 +label_1: # for-loop header + lw t1, -16(fp) # Peek stack slot 3 + lw t0, -12(fp) # Peek stack slot 2 + lw t2, 12(t0) # Get attribute __len__ + bgeu t1, t2, label_2 # Exit loop if idx >= len(iter) + lw t0, -16(fp) # Pop stack slot 4 + lw a1, -12(fp) # Peek stack slot 2 + addi t1, t0, 1 # Increment index for next iteration + sw t1, -16(fp) # Push on stack slot 4 + addi t0, t0, 16 # Convert index to offset to char in bytes + add t0, a1, t0 # Get pointer to char + lbu t0, 0(t0) # Load character + li t1, 20 + mul t0, t0, t1 # Multiply by size of string object + la a0, allChars # Index into single-char table + add a0, a0, t0 + sw a0, $x, t0 # Assign global: x (using tmp register) + lw a0, $x # Load global: x + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + j label_1 # Loop back to header +label_2: # for-loop footer + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_3 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_4 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_5 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_3 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_6 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + la a0, $str$prototype + lw t0, 0(a0) + lw t1, 4(a0) + lw t2, 8(a0) + li t3, 1 + la a0, allChars + li t4, 256 + mv t5, zero +initchars_1: + sw t0, 0(a0) + sw t1, 4(a0) + sw t2, 8(a0) + sw t3, 12(a0) + sw t5, 16(a0) + addi a0, a0, 20 + addi t5, t5, 1 + bne t4, t5, initchars_1 + jr ra + .data + .align 2 + .globl allChars +allChars: + .space 5120 + .text + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 3 # Constant value of attribute: __len__ + .string "xXx" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/stmt_if.py.ast.typed.s b/src/test/data/pa3/sample/stmt_if.py.ast.typed.s new file mode 100644 index 0000000..e287a90 --- /dev/null +++ b/src/test/data/pa3/sample/stmt_if.py.ast.typed.s @@ -0,0 +1,683 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + j label_2 # Branch on false. + la a0, const_2 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + j label_1 # Then body complete; jump to end-if +label_2: # Else body + la a0, const_3 # Load string literal + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. +label_4: # End of if-else statement +label_3: # End of if-else statement +label_1: # End of if-else statement + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_4 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_5 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_6 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_4 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_7 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_10 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 2 # Constant value of attribute: __len__ + .string "No" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 3 # Constant value of attribute: __len__ + .string "Yes" # Constant value of attribute: __str__ + .align 2 + +.globl const_10 +const_10: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/stmt_return_early.py.ast.typed.s b/src/test/data/pa3/sample/stmt_return_early.py.ast.typed.s new file mode 100644 index 0000000..97d0dbc --- /dev/null +++ b/src/test/data/pa3/sample/stmt_return_early.py.ast.typed.s @@ -0,0 +1,680 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + addi sp, fp, -16 # Set SP to last argument. + jal $f # Invoke function: f + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $f +$f: + addi sp, sp, -@f.size # Reserve space for stack frame. + sw ra, @f.size-4(sp) # return address + sw fp, @f.size-8(sp) # control link + addi fp, sp, @f.size # New fp is at old SP. + j label_4 # Jump to loop test +label_3: # Top of while loop + li a0, 1 # Load integer literal 1 + j label_2 # Go to return +label_4: # Test loop condition + j label_3 # Branch on true. + li a0, 0 # Load integer literal 0 + j label_2 # Go to return + mv a0, zero # Load None + j label_2 # Jump to function epilogue +label_2: # Epilogue + .equiv @f.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @f.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/stmt_while.py.ast.typed.s b/src/test/data/pa3/sample/stmt_while.py.ast.typed.s new file mode 100644 index 0000000..3efd2e2 --- /dev/null +++ b/src/test/data/pa3/sample/stmt_while.py.ast.typed.s @@ -0,0 +1,673 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 1 # Initial value of global var: x + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + j label_2 # Jump to loop test +label_1: # Top of while loop + lw a0, $x # Load global: x + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $x # Load global: x + sw a0, -12(fp) # Push on stack slot 3 + li a0, 1 # Load integer literal 1 + lw t0, -12(fp) # Pop stack slot 3 + add a0, t0, a0 # Operator + + sw a0, $x, t0 # Assign global: x (using tmp register) +label_2: # Test loop condition + lw a0, $x # Load global: x + sw a0, -12(fp) # Push on stack slot 3 + li a0, 10 # Load integer literal 10 + lw t0, -12(fp) # Pop stack slot 3 + blt t0, a0, label_1 # Branch on < + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_3 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_4 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_2 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_6 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/str_cat.py.ast.typed.s b/src/test/data/pa3/sample/str_cat.py.ast.typed.s new file mode 100644 index 0000000..91620c9 --- /dev/null +++ b/src/test/data/pa3/sample/str_cat.py.ast.typed.s @@ -0,0 +1,835 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $a +$a: + .word const_2 # Initial value of global var: a + +.globl $b +$b: + .word const_3 # Initial value of global var: b + +.globl $c +$c: + .word const_4 # Initial value of global var: c + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $a # Load global: a + sw a0, -28(fp) # Push argument 1 from last. + lw a0, $b # Load global: b + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $cat2 # Invoke function: cat2 + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + la a0, const_5 # Load string literal + sw a0, -28(fp) # Push argument 1 from last. + lw a0, $c # Load global: c + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $cat2 # Invoke function: cat2 + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $a # Load global: a + sw a0, -24(fp) # Push argument 2 from last. + la a0, const_6 # Load string literal + sw a0, -28(fp) # Push argument 1 from last. + lw a0, $c # Load global: c + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $cat3 # Invoke function: cat3 + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $a # Load global: a + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $len # Invoke function: len + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $a # Load global: a + sw a0, -44(fp) # Push argument 1 from last. + lw a0, $a # Load global: a + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal $cat2 # Invoke function: cat2 + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $len # Invoke function: len + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + la a0, const_5 # Load string literal + sw a0, -44(fp) # Push argument 1 from last. + la a0, const_5 # Load string literal + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal $cat2 # Invoke function: cat2 + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $len # Invoke function: len + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 48 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_7 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_8 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_9 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_7 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $cat2 +$cat2: + addi sp, sp, -@cat2.size # Reserve space for stack frame. + sw ra, @cat2.size-4(sp) # return address + sw fp, @cat2.size-8(sp) # control link + addi fp, sp, @cat2.size # New fp is at old SP. + lw a0, 4(fp) # Load var: cat2.a + sw a0, -12(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: cat2.b + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal strcat # Call string concatenation function + addi sp, fp, -@cat2.size # Set SP to stack frame top. + j label_2 # Go to return + mv a0, zero # Load None + j label_2 # Jump to function epilogue +label_2: # Epilogue + .equiv @cat2.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @cat2.size # Restore stack pointer + jr ra # Return to caller + +.globl $cat3 +$cat3: + addi sp, sp, -@cat3.size # Reserve space for stack frame. + sw ra, @cat3.size-4(sp) # return address + sw fp, @cat3.size-8(sp) # control link + addi fp, sp, @cat3.size # New fp is at old SP. + lw a0, 8(fp) # Load var: cat3.a + sw a0, -28(fp) # Push argument 1 from last. + lw a0, 4(fp) # Load var: cat3.b + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal strcat # Call string concatenation function + addi sp, fp, -@cat3.size # Set SP to stack frame top. + sw a0, -12(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: cat3.c + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal strcat # Call string concatenation function + addi sp, fp, -@cat3.size # Set SP to stack frame top. + j label_4 # Go to return + mv a0, zero # Load None + j label_4 # Jump to function epilogue +label_4: # Epilogue + .equiv @cat3.size, 32 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @cat3.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_10 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_11 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_12 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_13 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __len__ + .string "" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string " " # Constant value of attribute: __str__ + .align 2 + +.globl const_12 +const_12: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "Hello" # Constant value of attribute: __str__ + .align 2 + +.globl const_10 +const_10: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_13 +const_13: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_11 +const_11: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 7 # Constant value of attribute: __len__ + .string "ChocoPy" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "World" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/str_cat_2.py.ast.typed.s b/src/test/data/pa3/sample/str_cat_2.py.ast.typed.s new file mode 100644 index 0000000..cb90a71 --- /dev/null +++ b/src/test/data/pa3/sample/str_cat_2.py.ast.typed.s @@ -0,0 +1,795 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $a +$a: + .word const_2 # Initial value of global var: a + +.globl $b +$b: + .word const_3 # Initial value of global var: b + +.globl $c +$c: + .word const_4 # Initial value of global var: c + +.globl $d +$d: + .word const_4 # Initial value of global var: d + +.globl $e +$e: + .word const_4 # Initial value of global var: e + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $b # Load global: b + sw a0, -12(fp) # Push argument 1 from last. + lw a0, $a # Load global: a + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $cat2 # Invoke function: cat2 + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $c, t0 # Assign global: c (using tmp register) + lw a0, $a # Load global: a + sw a0, -12(fp) # Push argument 1 from last. + lw a0, $a # Load global: a + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $cat2 # Invoke function: cat2 + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $d, t0 # Assign global: d (using tmp register) + lw a0, $a # Load global: a + sw a0, -24(fp) # Push argument 2 from last. + lw a0, $b # Load global: b + sw a0, -28(fp) # Push argument 1 from last. + lw a0, $b # Load global: b + sw a0, -44(fp) # Push argument 1 from last. + lw a0, $b # Load global: b + sw a0, -48(fp) # Push argument 0 from last. + addi sp, fp, -48 # Set SP to last argument. + jal $cat2 # Invoke function: cat2 + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $cat3 # Invoke function: cat3 + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $e, t0 # Assign global: e (using tmp register) + lw a0, $c # Load global: c + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $d # Load global: d + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $e # Load global: e + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 48 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_6 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_7 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $cat2 +$cat2: + addi sp, sp, -@cat2.size # Reserve space for stack frame. + sw ra, @cat2.size-4(sp) # return address + sw fp, @cat2.size-8(sp) # control link + addi fp, sp, @cat2.size # New fp is at old SP. + lw a0, 4(fp) # Load var: cat2.a + sw a0, -12(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: cat2.b + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal strcat # Call string concatenation function + addi sp, fp, -@cat2.size # Set SP to stack frame top. + j label_2 # Go to return + mv a0, zero # Load None + j label_2 # Jump to function epilogue +label_2: # Epilogue + .equiv @cat2.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @cat2.size # Restore stack pointer + jr ra # Return to caller + +.globl $cat3 +$cat3: + addi sp, sp, -@cat3.size # Reserve space for stack frame. + sw ra, @cat3.size-4(sp) # return address + sw fp, @cat3.size-8(sp) # control link + addi fp, sp, @cat3.size # New fp is at old SP. + lw a0, 8(fp) # Load var: cat3.a + sw a0, -28(fp) # Push argument 1 from last. + lw a0, 4(fp) # Load var: cat3.b + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal strcat # Call string concatenation function + addi sp, fp, -@cat3.size # Set SP to stack frame top. + sw a0, -12(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: cat3.c + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal strcat # Call string concatenation function + addi sp, fp, -@cat3.size # Set SP to stack frame top. + j label_4 # Go to return + mv a0, zero # Load None + j label_4 # Jump to function epilogue +label_4: # Epilogue + .equiv @cat3.size, 32 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @cat3.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_8 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_10 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_11 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __len__ + .string "" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 2 # Constant value of attribute: __len__ + .string "no" # Constant value of attribute: __str__ + .align 2 + +.globl const_10 +const_10: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_11 +const_11: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __len__ + .string "o" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/str_cmp.py.ast.typed.s b/src/test/data/pa3/sample/str_cmp.py.ast.typed.s new file mode 100644 index 0000000..c06cce6 --- /dev/null +++ b/src/test/data/pa3/sample/str_cmp.py.ast.typed.s @@ -0,0 +1,806 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $a +$a: + .word const_2 # Initial value of global var: a + +.globl $b +$b: + .word const_3 # Initial value of global var: b + +.globl $c +$c: + .word const_4 # Initial value of global var: c + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $a # Load global: a + sw a0, -28(fp) # Push argument 1 from last. + lw a0, $a # Load global: a + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $eq # Invoke function: eq + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $a # Load global: a + sw a0, -28(fp) # Push argument 1 from last. + lw a0, $b # Load global: b + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $eq # Invoke function: eq + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $a # Load global: a + sw a0, -28(fp) # Push argument 1 from last. + lw a0, $b # Load global: b + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $neq # Invoke function: neq + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $b # Load global: b + sw a0, -28(fp) # Push argument 1 from last. + lw a0, $b # Load global: b + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $neq # Invoke function: neq + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $c # Load global: c + sw a0, -28(fp) # Push argument 1 from last. + lw a0, $a # Load global: a + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $eq # Invoke function: eq + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $c # Load global: c + sw a0, -28(fp) # Push argument 1 from last. + lw a0, $b # Load global: b + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $neq # Invoke function: neq + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makebool # Box boolean + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_6 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_7 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_5 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $eq +$eq: + addi sp, sp, -@eq.size # Reserve space for stack frame. + sw ra, @eq.size-4(sp) # return address + sw fp, @eq.size-8(sp) # control link + addi fp, sp, @eq.size # New fp is at old SP. + lw a0, 4(fp) # Load var: eq.a + sw a0, -12(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: eq.b + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal streql # Call string == function + addi sp, fp, -@eq.size # Set SP to stack frame top. + j label_2 # Go to return + mv a0, zero # Load None + j label_2 # Jump to function epilogue +label_2: # Epilogue + .equiv @eq.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @eq.size # Restore stack pointer + jr ra # Return to caller + +.globl $neq +$neq: + addi sp, sp, -@neq.size # Reserve space for stack frame. + sw ra, @neq.size-4(sp) # return address + sw fp, @neq.size-8(sp) # control link + addi fp, sp, @neq.size # New fp is at old SP. + lw a0, 4(fp) # Load var: neq.a + sw a0, -12(fp) # Push argument 1 from last. + lw a0, 0(fp) # Load var: neq.b + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal strneql # Call string == function + addi sp, fp, -@neq.size # Set SP to stack frame top. + j label_4 # Go to return + mv a0, zero # Load None + j label_4 # Jump to function epilogue +label_4: # Epilogue + .equiv @neq.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @neq.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_8 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_10 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_11 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_10 +const_10: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "Hello" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_11 +const_11: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 7 # Constant value of attribute: __len__ + .string "ChocoPy" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "World" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/str_get_element.py.ast.typed.s b/src/test/data/pa3/sample/str_get_element.py.ast.typed.s new file mode 100644 index 0000000..11529aa --- /dev/null +++ b/src/test/data/pa3/sample/str_get_element.py.ast.typed.s @@ -0,0 +1,779 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word const_2 # Initial value of global var: x + +.globl $a +$a: + .word const_3 # Initial value of global var: a + +.globl $b +$b: + .word const_3 # Initial value of global var: b + +.globl $c +$c: + .word const_3 # Initial value of global var: c + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $x # Load global: x + sw a0, -12(fp) # Push argument 1 from last. + li a0, 0 # Load integer literal 0 + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $str_get # Invoke function: str_get + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $a, t0 # Assign global: a (using tmp register) + lw a0, $x # Load global: x + sw a0, -12(fp) # Push argument 1 from last. + li a0, 1 # Load integer literal 1 + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $str_get # Invoke function: str_get + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $b, t0 # Assign global: b (using tmp register) + lw a0, $x # Load global: x + sw a0, -12(fp) # Push argument 1 from last. + li a0, 2 # Load integer literal 2 + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $str_get # Invoke function: str_get + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $c, t0 # Assign global: c (using tmp register) + lw a0, $a # Load global: a + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $b # Load global: b + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + lw a0, $c # Load global: c + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_4 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_5 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_6 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_4 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $str_get +$str_get: + addi sp, sp, -@str_get.size # Reserve space for stack frame. + sw ra, @str_get.size-4(sp) # return address + sw fp, @str_get.size-8(sp) # control link + addi fp, sp, @str_get.size # New fp is at old SP. + lw a0, 4(fp) # Load var: str_get.s + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 0(fp) # Load var: str_get.i + lw a1, -12(fp) # Peek stack slot 2 + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_3 # Ensure 0 <= idx < len + j error.OOB # Go to error handler +label_3: # Index within bounds + sw a0, -16(fp) # Push on stack slot 4 + lw t0, -16(fp) # Pop stack slot 4 + lw a1, -12(fp) # Peek stack slot 2 + addi t0, t0, 16 # Convert index to offset to char in bytes + add t0, a1, t0 # Get pointer to char + lbu t0, 0(t0) # Load character + li t1, 20 + mul t0, t0, t1 # Multiply by size of string object + la a0, allChars # Index into single-char table + add a0, a0, t0 + j label_2 # Go to return + mv a0, zero # Load None + j label_2 # Jump to function epilogue +label_2: # Epilogue + .equiv @str_get.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @str_get.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_7 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + la a0, $str$prototype + lw t0, 0(a0) + lw t1, 4(a0) + lw t2, 8(a0) + li t3, 1 + la a0, allChars + li t4, 256 + mv t5, zero +initchars_1: + sw t0, 0(a0) + sw t1, 4(a0) + sw t2, 8(a0) + sw t3, 12(a0) + sw t5, 16(a0) + addi a0, a0, 20 + addi t5, t5, 1 + bne t4, t5, initchars_1 + jr ra + .data + .align 2 + .globl allChars +allChars: + .space 5120 + .text + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_10 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __len__ + .string "" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 3 # Constant value of attribute: __len__ + .string "abc" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_10 +const_10: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/str_get_element_oob_1.py.ast.typed.s b/src/test/data/pa3/sample/str_get_element_oob_1.py.ast.typed.s new file mode 100644 index 0000000..1390d56 --- /dev/null +++ b/src/test/data/pa3/sample/str_get_element_oob_1.py.ast.typed.s @@ -0,0 +1,746 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word const_2 # Initial value of global var: x + +.globl $a +$a: + .word const_3 # Initial value of global var: a + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $x # Load global: x + sw a0, -12(fp) # Push argument 1 from last. + li a0, 1 # Load integer literal 1 + sub a0, zero, a0 # Unary negation + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $str_get # Invoke function: str_get + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $a, t0 # Assign global: a (using tmp register) + lw a0, $a # Load global: a + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_4 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_5 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_6 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_4 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $str_get +$str_get: + addi sp, sp, -@str_get.size # Reserve space for stack frame. + sw ra, @str_get.size-4(sp) # return address + sw fp, @str_get.size-8(sp) # control link + addi fp, sp, @str_get.size # New fp is at old SP. + lw a0, 4(fp) # Load var: str_get.s + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 0(fp) # Load var: str_get.i + lw a1, -12(fp) # Peek stack slot 2 + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_3 # Ensure 0 <= idx < len + j error.OOB # Go to error handler +label_3: # Index within bounds + sw a0, -16(fp) # Push on stack slot 4 + lw t0, -16(fp) # Pop stack slot 4 + lw a1, -12(fp) # Peek stack slot 2 + addi t0, t0, 16 # Convert index to offset to char in bytes + add t0, a1, t0 # Get pointer to char + lbu t0, 0(t0) # Load character + li t1, 20 + mul t0, t0, t1 # Multiply by size of string object + la a0, allChars # Index into single-char table + add a0, a0, t0 + j label_2 # Go to return + mv a0, zero # Load None + j label_2 # Jump to function epilogue +label_2: # Epilogue + .equiv @str_get.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @str_get.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_7 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + la a0, $str$prototype + lw t0, 0(a0) + lw t1, 4(a0) + lw t2, 8(a0) + li t3, 1 + la a0, allChars + li t4, 256 + mv t5, zero +initchars_1: + sw t0, 0(a0) + sw t1, 4(a0) + sw t2, 8(a0) + sw t3, 12(a0) + sw t5, 16(a0) + addi a0, a0, 20 + addi t5, t5, 1 + bne t4, t5, initchars_1 + jr ra + .data + .align 2 + .globl allChars +allChars: + .space 5120 + .text + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_10 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __len__ + .string "" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 3 # Constant value of attribute: __len__ + .string "abc" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_10 +const_10: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/str_get_element_oob_2.py.ast.typed.s b/src/test/data/pa3/sample/str_get_element_oob_2.py.ast.typed.s new file mode 100644 index 0000000..5f681e7 --- /dev/null +++ b/src/test/data/pa3/sample/str_get_element_oob_2.py.ast.typed.s @@ -0,0 +1,745 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word const_2 # Initial value of global var: x + +.globl $a +$a: + .word const_3 # Initial value of global var: a + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $x # Load global: x + sw a0, -12(fp) # Push argument 1 from last. + li a0, 3 # Load integer literal 3 + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $str_get # Invoke function: str_get + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $a, t0 # Assign global: a (using tmp register) + lw a0, $a # Load global: a + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_4 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_5 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_6 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_4 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $str_get +$str_get: + addi sp, sp, -@str_get.size # Reserve space for stack frame. + sw ra, @str_get.size-4(sp) # return address + sw fp, @str_get.size-8(sp) # control link + addi fp, sp, @str_get.size # New fp is at old SP. + lw a0, 4(fp) # Load var: str_get.s + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 0(fp) # Load var: str_get.i + lw a1, -12(fp) # Peek stack slot 2 + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_3 # Ensure 0 <= idx < len + j error.OOB # Go to error handler +label_3: # Index within bounds + sw a0, -16(fp) # Push on stack slot 4 + lw t0, -16(fp) # Pop stack slot 4 + lw a1, -12(fp) # Peek stack slot 2 + addi t0, t0, 16 # Convert index to offset to char in bytes + add t0, a1, t0 # Get pointer to char + lbu t0, 0(t0) # Load character + li t1, 20 + mul t0, t0, t1 # Multiply by size of string object + la a0, allChars # Index into single-char table + add a0, a0, t0 + j label_2 # Go to return + mv a0, zero # Load None + j label_2 # Jump to function epilogue +label_2: # Epilogue + .equiv @str_get.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @str_get.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_7 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + la a0, $str$prototype + lw t0, 0(a0) + lw t1, 4(a0) + lw t2, 8(a0) + li t3, 1 + la a0, allChars + li t4, 256 + mv t5, zero +initchars_1: + sw t0, 0(a0) + sw t1, 4(a0) + sw t2, 8(a0) + sw t3, 12(a0) + sw t5, 16(a0) + addi a0, a0, 20 + addi t5, t5, 1 + bne t4, t5, initchars_1 + jr ra + .data + .align 2 + .globl allChars +allChars: + .space 5120 + .text + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_10 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __len__ + .string "" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 3 # Constant value of attribute: __len__ + .string "abc" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_10 +const_10: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/str_get_element_oob_3.py.ast.typed.s b/src/test/data/pa3/sample/str_get_element_oob_3.py.ast.typed.s new file mode 100644 index 0000000..05d59e9 --- /dev/null +++ b/src/test/data/pa3/sample/str_get_element_oob_3.py.ast.typed.s @@ -0,0 +1,736 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word const_2 # Initial value of global var: x + +.globl $a +$a: + .word const_2 # Initial value of global var: a + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + lw a0, $x # Load global: x + sw a0, -12(fp) # Push argument 1 from last. + li a0, 0 # Load integer literal 0 + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $str_get # Invoke function: str_get + addi sp, fp, -@..main.size # Set SP to stack frame top. + sw a0, $a, t0 # Assign global: a (using tmp register) + lw a0, $a # Load global: a + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_3 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_4 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_5 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_3 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl $str_get +$str_get: + addi sp, sp, -@str_get.size # Reserve space for stack frame. + sw ra, @str_get.size-4(sp) # return address + sw fp, @str_get.size-8(sp) # control link + addi fp, sp, @str_get.size # New fp is at old SP. + lw a0, 4(fp) # Load var: str_get.s + sw a0, -12(fp) # Push on stack slot 3 + lw a0, 0(fp) # Load var: str_get.i + lw a1, -12(fp) # Peek stack slot 2 + lw t0, 12(a1) # Load attribute: __len__ + bltu a0, t0, label_3 # Ensure 0 <= idx < len + j error.OOB # Go to error handler +label_3: # Index within bounds + sw a0, -16(fp) # Push on stack slot 4 + lw t0, -16(fp) # Pop stack slot 4 + lw a1, -12(fp) # Peek stack slot 2 + addi t0, t0, 16 # Convert index to offset to char in bytes + add t0, a1, t0 # Get pointer to char + lbu t0, 0(t0) # Load character + li t1, 20 + mul t0, t0, t1 # Multiply by size of string object + la a0, allChars # Index into single-char table + add a0, a0, t0 + j label_2 # Go to return + mv a0, zero # Load None + j label_2 # Jump to function epilogue +label_2: # Epilogue + .equiv @str_get.size, 16 + lw ra, -4(fp) # Get return address + lw fp, -8(fp) # Use control link to restore caller's fp + addi sp, sp, @str_get.size # Restore stack pointer + jr ra # Return to caller + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_6 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + la a0, $str$prototype + lw t0, 0(a0) + lw t1, 4(a0) + lw t2, 8(a0) + li t3, 1 + la a0, allChars + li t4, 256 + mv t5, zero +initchars_1: + sw t0, 0(a0) + sw t1, 4(a0) + sw t2, 8(a0) + sw t3, 12(a0) + sw t5, 16(a0) + addi a0, a0, 20 + addi t5, t5, 1 + bne t4, t5, initchars_1 + jr ra + .data + .align 2 + .globl allChars +allChars: + .space 5120 + .text + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __len__ + .string "" # Constant value of attribute: __str__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/str_len.py.ast.typed.s b/src/test/data/pa3/sample/str_len.py.ast.typed.s new file mode 100644 index 0000000..fc08fea --- /dev/null +++ b/src/test/data/pa3/sample/str_len.py.ast.typed.s @@ -0,0 +1,668 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + la a0, const_2 # Load string literal + sw a0, -32(fp) # Push argument 0 from last. + addi sp, fp, -32 # Set SP to last argument. + jal $len # Invoke function: len + addi sp, fp, -@..main.size # Set SP to stack frame top. + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 32 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_3 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_4 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_5 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_3 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_6 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 7 # Constant value of attribute: __len__ + .string "ChocoPy" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 diff --git a/src/test/data/pa3/sample/var_assign.py.ast.typed.s b/src/test/data/pa3/sample/var_assign.py.ast.typed.s new file mode 100644 index 0000000..79635df --- /dev/null +++ b/src/test/data/pa3/sample/var_assign.py.ast.typed.s @@ -0,0 +1,677 @@ + .equiv @sbrk, 9 + .equiv @print_string, 4 + .equiv @print_char, 11 + .equiv @print_int, 1 + .equiv @exit2, 17 + .equiv @read_string, 8 + .equiv @fill_line_buffer, 18 + .equiv @.__obj_size__, 4 + .equiv @.__len__, 12 + .equiv @.__int__, 12 + .equiv @.__bool__, 12 + .equiv @.__str__, 16 + .equiv @.__elts__, 16 + .equiv @error_div_zero, 2 + .equiv @error_arg, 1 + .equiv @error_oob, 3 + .equiv @error_none, 4 + .equiv @error_oom, 5 + .equiv @error_nyi, 6 + .equiv @listHeaderWords, 4 + .equiv @strHeaderWords, 4 + .equiv @bool.True, const_1 + .equiv @bool.False, const_0 + +.data + +.globl $object$prototype +$object$prototype: + .word 0 # Type tag for class: object + .word 3 # Object size + .word $object$dispatchTable # Pointer to dispatch table + .align 2 + +.globl $int$prototype +$int$prototype: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __int__ + .align 2 + +.globl $bool$prototype +$bool$prototype: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __bool__ + .align 2 + +.globl $str$prototype +$str$prototype: + .word 3 # Type tag for class: str + .word 5 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .word 0 # Initial value of attribute: __str__ + .align 2 + +.globl $.list$prototype +$.list$prototype: + .word -1 # Type tag for class: .list + .word 4 # Object size + .word 0 # Pointer to dispatch table + .word 0 # Initial value of attribute: __len__ + .align 2 + +.globl $object$dispatchTable +$object$dispatchTable: + .word $object.__init__ # Implementation for method: object.__init__ + +.globl $int$dispatchTable +$int$dispatchTable: + .word $object.__init__ # Implementation for method: int.__init__ + +.globl $bool$dispatchTable +$bool$dispatchTable: + .word $object.__init__ # Implementation for method: bool.__init__ + +.globl $str$dispatchTable +$str$dispatchTable: + .word $object.__init__ # Implementation for method: str.__init__ + +.globl $x +$x: + .word 0 # Initial value of global var: x + +.globl $y +$y: + .word const_2 # Initial value of global var: y + +.text + +.globl main +main: + lui a0, 8192 # Initialize heap size (in multiples of 4KB) + add s11, s11, a0 # Save heap size + jal heap.init # Call heap.init routine + mv gp, a0 # Initialize heap pointer + mv s10, gp # Set beginning of heap + add s11, s10, s11 # Set end of heap (= start of heap + heap size) + mv ra, zero # No normal return from main program. + mv fp, zero # No preceding frame. + addi sp, sp, -@..main.size # Reserve space for stack frame. + sw ra, @..main.size-4(sp) # return address + sw fp, @..main.size-8(sp) # control link + addi fp, sp, @..main.size # New fp is at old SP. + jal initchars # Initialize one-character strings. + li a0, 42 # Load integer literal 42 + sw a0, -12(fp) # Push on stack slot 3 + sw a0, $x, t0 # Assign global: x (using tmp register) + lw a0, -12(fp) # Pop stack slot 3 + jal makeint # Box integer + sw a0, $y, t0 # Assign global: y (using tmp register) + lw a0, $x # Load global: x + jal makeint # Box integer + sw a0, -16(fp) # Push argument 0 from last. + addi sp, fp, -16 # Set SP to last argument. + jal $print # Invoke function: print + addi sp, fp, -@..main.size # Set SP to stack frame top. + .equiv @..main.size, 16 +label_0: # End of program + li a0, 10 # Code for ecall: exit + ecall + +.globl $object.__init__ +$object.__init__: +# Init method for type object. + mv a0, zero # `None` constant + jr ra # Return + +.globl $print +$print: +# Function print + lw a0, 0(sp) # Load arg + beq a0, zero, print_6 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 1 # Load type tag of `int` + beq t0, t1, print_7 # Go to print(int) + li t1, 3 # Load type tag of `str` + beq t0, t1, print_8 # Go to print(str) + li t1, 2 # Load type tag of `bool` + beq t0, t1, print_9 # Go to print(bool) +print_6: # Invalid argument + li a0, 1 # Exit code for: Invalid argument + la a1, const_3 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +# Printing bools +print_9: # Print bool object in A0 + lw a0, @.__bool__(a0) # Load attribute __bool__ + beq a0, zero, print_10 # Go to: print(False) + la a0, const_4 # String representation: True + j print_8 # Go to: print(str) +print_10: # Print False object in A0 + la a0, const_5 # String representation: False + j print_8 # Go to: print(str) + +# Printing strs. +print_8: # Print str object in A0 + addi a1, a0, @.__str__ # Load address of attribute __str__ + j print_11 # Print the null-terminated string is now in A1 + mv a0, zero # Load None + j print_5 # Go to return +print_11: # Print null-terminated string in A1 + li a0, @print_string # Code for ecall: print_string + ecall # Print string + li a1, 10 # Load newline character + li a0, @print_char # Code for ecall: print_char + ecall # Print character + j print_5 # Go to return + +# Printing ints. +print_7: # Print int object in A0 + lw a1, @.__int__(a0) # Load attribute __int__ + li a0, @print_int # Code for ecall: print_int + ecall # Print integer + li a1, 10 # Load newline character + li a0, 11 # Code for ecall: print_char + ecall # Print character + +print_5: # End of function + mv a0, zero # Load None + jr ra # Return to caller + +.globl $len +$len: +# Function len + # We do not save/restore fp/ra for this function + # because we know that it does not use the stack or does not + # call other functions. + + lw a0, 0(sp) # Load arg + beq a0, zero, len_12 # None is an illegal argument + lw t0, 0(a0) # Get type tag of arg + li t1, 3 # Load type tag of `str` + beq t0, t1, len_13 # Go to len(str) + li t1, -1 # Load type tag for list objects + beq t0, t1, len_13 # Go to len(list) +len_12: # Invalid argument + li a0, @error_arg # Exit code for: Invalid argument + la a1, const_3 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort +len_13: # Get length of string + lw a0, @.__len__(a0) # Load attribute: __len__ + jr ra # Return to caller + +.globl $input +$input: +# Function input + addi sp, sp, -16 # Reserve stack + sw ra, 12(sp) # Save registers + sw fp, 8(sp) + sw s1, 4(sp) + addi fp, sp, 16 # Set fp + + li a0, @fill_line_buffer # Fill the internal line buffer. + ecall + bgez a0, input_nonempty # More input found + la a0, $str$prototype # EOF: Return empty string. + j input_done + +input_nonempty: + mv s1, a0 + addi t0, s1, 5 # Compute bytes for string (+NL+NUL), + addi t0, t0, @.__str__ # Including header. + srli a1, t0, 2 # Convert to words. + la a0, $str$prototype # Load address of string prototype. + jal ra, alloc2 # Allocate string. + sw s1, @.__len__(a0) # Store string length. + mv a2, s1 # Pass length. + mv s1, a0 # Save string object address. + addi a1, a0, @.__str__ # Pass address of string data. + li a0, @read_string # ecall to read from internal buffer. + ecall + addi a0, a0, 1 # Actual length (including NL). + sw a0, @.__len__(s1) # Store actual length. + add t0, a0, s1 + li t1, 10 # Store newline and null byte + sb t1, @.__str__-1(t0) + sb zero, @.__str__(t0) # Store null byte at end. + mv a0, s1 # Return string object. + +input_done: + lw s1, -12(fp) + lw ra, -4(fp) + lw fp, -8(fp) + addi sp, sp, 16 + jr ra + +.globl alloc +alloc: +# Runtime support function alloc. + # Prototype address is in a0. + lw a1, 4(a0) # Get size of object in words + j alloc2 # Allocate object with exact size + +.globl alloc2 +alloc2: +# Runtime support function alloc2 (realloc). + # Prototype address is in a0. + # Number of words to allocate is in a1. + li a2, 4 # Word size in bytes + mul a2, a1, a2 # Calculate number of bytes to allocate + add a2, gp, a2 # Estimate where GP will move + bgeu a2, s11, alloc2_15 # Go to OOM handler if too large + lw t0, @.__obj_size__(a0) # Get size of object in words + mv t2, a0 # Initialize src ptr + mv t3, gp # Initialize dest ptr +alloc2_16: # Copy-loop header + lw t1, 0(t2) # Load next word from src + sw t1, 0(t3) # Store next word to dest + addi t2, t2, 4 # Increment src + addi t3, t3, 4 # Increment dest + addi t0, t0, -1 # Decrement counter + bne t0, zero, alloc2_16 # Loop if more words left to copy + mv a0, gp # Save new object's address to return + sw a1, @.__obj_size__(a0) # Set size of new object in words + # (same as requested size) + mv gp, a2 # Set next free slot in the heap + jr ra # Return to caller +alloc2_15: # OOM handler + li a0, @error_oom # Exit code for: Out of memory + la a1, const_6 # Load error message as str + addi a1, a1, @.__str__ # Load address of attribute __str__ + j abort # Abort + +.globl abort +abort: +# Runtime support function abort (does not return). + mv t0, a0 # Save exit code in temp + li a0, @print_string # Code for print_string ecall + ecall # Print error message in a1 + li a1, 10 # Load newline character + li a0, @print_char # Code for print_char ecall + ecall # Print newline + mv a1, t0 # Move exit code to a1 + li a0, @exit2 # Code for exit2 ecall + ecall # Exit with code +abort_17: # Infinite loop + j abort_17 # Prevent fallthrough + +.globl heap.init +heap.init: +# Runtime support function heap.init. + mv a1, a0 # Move requested size to A1 + li a0, @sbrk # Code for ecall: sbrk + ecall # Request A1 bytes + jr ra # Return to caller + +.globl concat +concat: + + 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 + + +.globl conslist +conslist: + + 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 + + +.globl strcat +strcat: + + 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 + + +.globl streql +streql: + + 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 + + +.globl strneql +strneql: + + 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 + + +.globl makeint +makeint: + + 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 + + +.globl makebool +makebool: + + slli a0, a0, 4 + la t0, @bool.False + add a0, a0, t0 + jr ra + + +.globl noconv +noconv: + + jr ra + + +.globl initchars +initchars: + + jr ra + + +.globl error.None +error.None: + li a0, 4 # Exit code for: Operation on None + la a1, const_7 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.Div +error.Div: + li a0, 2 # Exit code for: Division by zero + la a1, const_8 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.globl error.OOB +error.OOB: + li a0, 3 # Exit code for: Index out of bounds + la a1, const_9 # Load error message as str + addi a1, a1, 16 # Load address of attribute __str__ + j abort # Abort + +.data + +.globl const_0 +const_0: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 0 # Constant value of attribute: __bool__ + .align 2 + +.globl const_1 +const_1: + .word 2 # Type tag for class: bool + .word 4 # Object size + .word $bool$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __bool__ + .align 2 + +.globl const_8 +const_8: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Division by zero" # Constant value of attribute: __str__ + .align 2 + +.globl const_6 +const_6: + .word 3 # Type tag for class: str + .word 8 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 13 # Constant value of attribute: __len__ + .string "Out of memory" # Constant value of attribute: __str__ + .align 2 + +.globl const_9 +const_9: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 19 # Constant value of attribute: __len__ + .string "Index out of bounds" # Constant value of attribute: __str__ + .align 2 + +.globl const_4 +const_4: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 4 # Constant value of attribute: __len__ + .string "True" # Constant value of attribute: __str__ + .align 2 + +.globl const_7 +const_7: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 17 # Constant value of attribute: __len__ + .string "Operation on None" # Constant value of attribute: __str__ + .align 2 + +.globl const_3 +const_3: + .word 3 # Type tag for class: str + .word 9 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 16 # Constant value of attribute: __len__ + .string "Invalid argument" # Constant value of attribute: __str__ + .align 2 + +.globl const_5 +const_5: + .word 3 # Type tag for class: str + .word 6 # Object size + .word $str$dispatchTable # Pointer to dispatch table + .word 5 # Constant value of attribute: __len__ + .string "False" # Constant value of attribute: __str__ + .align 2 + +.globl const_2 +const_2: + .word 1 # Type tag for class: int + .word 4 # Object size + .word $int$dispatchTable # Pointer to dispatch table + .word 1 # Constant value of attribute: __int__ + .align 2 diff --git a/web/WebCompiler.py.ast b/web/WebCompiler.py.ast new file mode 100644 index 0000000..e69de29