From 5f0e84198a16ee8923daa47bf7c784e887cb4f95 Mon Sep 17 00:00:00 2001 From: nitrix Date: Thu, 23 Mar 2023 22:49:36 +0100 Subject: [PATCH] GenASM+Void: Generate an implicit return Void functions are allowed to be completely free of return statements. The problem is that this does not work on its own in assembler. We have to generate a return statement at the end of the function body if there is no return statement already. --- .../hsrm/compiler/Klang/visitors/GenASM.java | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java index b5e7e08..7848143 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java @@ -71,7 +71,7 @@ public class GenASM implements Visitor { private int lCount = 0; private int currentFunctionStartLabel = 0; private long bytesToClearFromTheStack = 0; - private Parameter[] currentFunctionParams; + private FunctionDefinition currentFunctionDef; public GenASM(String mainName, Map structs) { this.mainName = mainName; @@ -543,9 +543,23 @@ public class GenASM implements Visitor { @Override public Void visit(Block e) { - for (var statement : e.statementsOrFunctionCalls) { - statement.welcome(this); + for (var statementOrFunctionCall : e.statementsOrFunctionCalls) { + statementOrFunctionCall.welcome(this); } + + // It's possible (and allowed -> void functions) that there is no return statement + // in the outermost block of a function body. In this case, no + // direct descendant of Block will be a return statement. + // This means we have to generate an implicit return, otherwise + // the code would fall through to the next function below :D + // We also have to clean up the stack which is the ReturnStatement's job. + + // Check if we have to generate an implicit return + var lastStatementOrFunctionCall = e.statementsOrFunctionCalls[e.statementsOrFunctionCalls.length - 1]; + if (currentFunctionDef.block == e && !(lastStatementOrFunctionCall instanceof ReturnStatement)) { + visit(new ReturnStatement()); + } + return null; } @@ -558,9 +572,11 @@ public class GenASM implements Visitor { e.name = "main_by_user"; } + // Remember the current function definition so everyone below us knows where they belong to. + currentFunctionDef = e; + var lblStart = ++lCount; currentFunctionStartLabel = lblStart; - currentFunctionParams = e.parameters; asm.functionHead(e.name); asm.push("q", "%rbp"); asm.mov("q", "%rsp", "%rbp"); @@ -675,10 +691,10 @@ public class GenASM implements Visitor { // push args into local var locations, last arg is on top of the stack for (int i = e.arguments.length - 1; i >= 0; i--) { - asm.pop("q", this.env.get(this.currentFunctionParams[i].name) + "(%rbp)"); + asm.pop("q", env.get(currentFunctionDef.parameters[i].name) + "(%rbp)"); } - asm.jmp(this.currentFunctionStartLabel); + asm.jmp(currentFunctionStartLabel); return null; }