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.
This commit is contained in:
@@ -71,7 +71,7 @@ public class GenASM implements Visitor<Void> {
|
||||
private int lCount = 0;
|
||||
private int currentFunctionStartLabel = 0;
|
||||
private long bytesToClearFromTheStack = 0;
|
||||
private Parameter[] currentFunctionParams;
|
||||
private FunctionDefinition currentFunctionDef;
|
||||
|
||||
public GenASM(String mainName, Map<String, StructDefinition> structs) {
|
||||
this.mainName = mainName;
|
||||
@@ -543,9 +543,23 @@ public class GenASM implements Visitor<Void> {
|
||||
|
||||
@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<Void> {
|
||||
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<Void> {
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user