1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-07-01 22:29:45 +00:00

Added support for calling a pointer to function without(*). Closes #692

This commit is contained in:
jespergravgaard 2021-08-08 13:47:48 +02:00
parent 8514c9942e
commit 77db0e8701
10 changed files with 133 additions and 87 deletions

View File

@ -120,10 +120,10 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
}
final StatementSequence statementSequence = procedureCompilation.getStatementSequence();
List<Statement> statements = statementSequence.getStatements();
if(statements.size()==0)
if(statements.size() == 0)
return null;
else
return statements.get(statements.size()-1);
return statements.get(statements.size() - 1);
}
@ -198,13 +198,13 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
if(initCompilation != null)
startSequence.addStatement(new StatementCall(null, SymbolRef.INIT_PROC_NAME, new ArrayList<>(), new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
final Procedure mainProc = program.getScope().getLocalProcedure(SymbolRef.MAIN_PROC_NAME);
if(mainProc==null)
if(mainProc == null)
throw new CompileError("Required main() not defined in program.");
if(!SymbolType.VOID.equals(mainProc.getReturnType()) && !SymbolType.SWORD.equals(mainProc.getReturnType()))
throw new CompileError("return of main() must be 'void' or of type 'int'.", mainProc.getDefinitionSource());
if(mainProc.getParameterNames().size()==0) {
if(mainProc.getParameterNames().size() == 0) {
startSequence.addStatement(new StatementCall(null, SymbolRef.MAIN_PROC_NAME, new ArrayList<>(), new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
} else if(mainProc.getParameterNames().size()==2) {
} else if(mainProc.getParameterNames().size() == 2) {
final List<Variable> parameters = mainProc.getParameters();
final Variable argc = parameters.get(0);
if(!SymbolType.SWORD.equals(argc.getType()))
@ -537,7 +537,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
throw new CompileError("Illegal void parameter.", statementSource);
// Handle parameters without a name in the declaration
if(parameter.name==null)
if(parameter.name == null)
throw new CompileError("Illegal unnamed parameter.", statementSource);
VariableBuilder varBuilder = new VariableBuilder(parameter.name, getCurrentScope(), true, false, parameter.type, null, currentDataSegment, program.getTargetPlatform().getVariableBuilderConfig());
@ -1051,7 +1051,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
}
Statement initStmt;
if(previousAssignment!=null) {
if(previousAssignment != null) {
previousAssignment.setlValue(variable.getVariableRef());
previousAssignment.setInitialAssignment(true);
previousAssignment.setSource(declSource);
@ -1742,8 +1742,8 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
@Override
public Object visitStmtLabel(KickCParser.StmtLabelContext ctx) {
String labelName = ctx.NAME().getText();
if(getCurrentScope().getLocalLabel(labelName)!=null)
throw new CompileError("label already defined '"+labelName+"'.", new StatementSource(ctx));
if(getCurrentScope().getLocalLabel(labelName) != null)
throw new CompileError("label already defined '" + labelName + "'.", new StatementSource(ctx));
Scope procedureScope = getCurrentProcedure();
Label label = procedureScope.addLabel(labelName);
addStatement(new StatementLabel(label.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS));
@ -1915,13 +1915,13 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
public Object visitTypeSimple(KickCParser.TypeSimpleContext ctx) {
String typeName = "";
for(TerminalNode simpleTypeNode : ctx.SIMPLETYPE()) {
if(typeName.length()>0)
if(typeName.length() > 0)
typeName += " ";
typeName += simpleTypeNode.getText();
}
final SymbolType typeSimple = SymbolType.get(typeName);
if(typeSimple==null)
throw new CompileError("Unknown type '" +typeName+"'" , new StatementSource(ctx));
if(typeSimple == null)
throw new CompileError("Unknown type '" + typeName + "'", new StatementSource(ctx));
varDecl.setDeclType(typeSimple);
return null;
}
@ -1929,7 +1929,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
@Override
public Object visitStructDef(KickCParser.StructDefContext ctx) {
boolean isUnion = ctx.UNION()!=null;
boolean isUnion = ctx.UNION() != null;
String structDefName;
if(ctx.NAME() != null) {
@ -1988,7 +1988,8 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
this.currentEnum = null;
// Copy all members to upper-level scope
Scope parentScope = getCurrentScope();
while(parentScope instanceof StructDefinition || parentScope instanceof TypeDefsScope) parentScope = parentScope.getScope();
while(parentScope instanceof StructDefinition || parentScope instanceof TypeDefsScope)
parentScope = parentScope.getScope();
for(Variable member : enumDefinition.getAllConstants(false)) {
parentScope.add(Variable.createConstant(member.getLocalName(), SymbolType.BYTE, parentScope, member.getInitValue(), currentDataSegment));
}
@ -2150,7 +2151,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
varDeclPush();
ParameterDecl paramDecl = (ParameterDecl) this.visit(parameterDeclContext);
// Handle parameter list with "VOID"
if(SymbolType.VOID.equals(paramDecl.type) && ctx.parameterListDecl().parameterDecl().size()==1)
if(SymbolType.VOID.equals(paramDecl.type) && ctx.parameterListDecl().parameterDecl().size() == 1)
; // Ignore the void parameter
else {
paramTypes.add(paramDecl.type);
@ -2174,7 +2175,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
varDeclPush();
ParameterDecl paramDecl = (ParameterDecl) this.visit(parameterDeclContext);
// Handle parameter list with "VOID"
if(SymbolType.VOID.equals(paramDecl.type) && ctx.parameterListDecl().parameterDecl().size()==1)
if(SymbolType.VOID.equals(paramDecl.type) && ctx.parameterListDecl().parameterDecl().size() == 1)
; // Ignore the void parameter
else {
paramTypes.add(paramDecl.type);
@ -2424,44 +2425,81 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
parameters = new ArrayList<>();
}
String procedureName;
RValue result;
if(ctx.expr() instanceof KickCParser.ExprIdContext) {
procedureName = ctx.expr().getText();
// Handle the special BYTE0/1/2/3/WORD0/1/MAKEWORD/MAKEDWORD calls
if(Pass1ByteXIntrinsicRewrite.INTRINSIC_BYTE0_NAME.equals(procedureName) && parameters.size() == 1) {
result = addExprUnary(ctx, Operators.BYTE0, parameters.get(0));
} else if(Pass1ByteXIntrinsicRewrite.INTRINSIC_BYTE1_NAME.equals(procedureName) && parameters.size() == 1) {
result = addExprUnary(ctx, Operators.BYTE1, parameters.get(0));
} else if(Pass1ByteXIntrinsicRewrite.INTRINSIC_BYTE2_NAME.equals(procedureName) && parameters.size() == 1) {
result = addExprUnary(ctx, Operators.BYTE2, parameters.get(0));
} else if(Pass1ByteXIntrinsicRewrite.INTRINSIC_BYTE3_NAME.equals(procedureName) && parameters.size() == 1) {
result = addExprUnary(ctx, Operators.BYTE3, parameters.get(0));
} else if(Pass1ByteXIntrinsicRewrite.INTRINSIC_WORD0_NAME.equals(procedureName) && parameters.size() == 1) {
result = addExprUnary(ctx, Operators.WORD0, parameters.get(0));
} else if(Pass1ByteXIntrinsicRewrite.INTRINSIC_WORD1_NAME.equals(procedureName) && parameters.size() == 1) {
result = addExprUnary(ctx, Operators.WORD1, parameters.get(0));
} else if(Pass1ByteXIntrinsicRewrite.INTRINSIC_MAKEWORD.equals(procedureName) && parameters.size() == 2) {
result = addExprBinary(ctx, parameters.get(0), Operators.WORD, parameters.get(1));
} else if(Pass1ByteXIntrinsicRewrite.INTRINSIC_MAKELONG.equals(procedureName) && parameters.size() == 2) {
result = addExprBinary(ctx, parameters.get(0), Operators.DWORD, parameters.get(1));
} else {
// A normal named call
result = addIntermediateVar().getRef();
addStatement(new StatementCall((LValue) result, procedureName, parameters, new StatementSource(ctx), ensureUnusedComments(getCommentsSymbol(ctx))));
}
} else {
RValue procedurePointer = (RValue) this.visit(ctx.expr());
result = addIntermediateVar().getRef();
addStatement(new StatementCallPointer((LValue) result, procedurePointer, parameters, new StatementSource(ctx), ensureUnusedComments(getCommentsSymbol(ctx))));
consumeExpr(procedurePointer);
Label afterCallLabel = getCurrentScope().addLabelIntermediate();
addStatement(new StatementLabel(afterCallLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS));
}
for(RValue parameter : parameters) {
consumeExpr(parameter);
}
return result;
if(ctx.expr() instanceof KickCParser.ExprIdContext) {
String procedureName = ctx.expr().getText();
// Handle the special BYTE0/1/2/3/WORD0/1/MAKEWORD/MAKEDWORD calls
if(Pass1ByteXIntrinsicRewrite.INTRINSIC_BYTE0_NAME.equals(procedureName) && parameters.size() == 1) {
return addExprUnary(ctx, Operators.BYTE0, parameters.get(0));
} else if(Pass1ByteXIntrinsicRewrite.INTRINSIC_BYTE1_NAME.equals(procedureName) && parameters.size() == 1) {
return addExprUnary(ctx, Operators.BYTE1, parameters.get(0));
} else if(Pass1ByteXIntrinsicRewrite.INTRINSIC_BYTE2_NAME.equals(procedureName) && parameters.size() == 1) {
return addExprUnary(ctx, Operators.BYTE2, parameters.get(0));
} else if(Pass1ByteXIntrinsicRewrite.INTRINSIC_BYTE3_NAME.equals(procedureName) && parameters.size() == 1) {
return addExprUnary(ctx, Operators.BYTE3, parameters.get(0));
} else if(Pass1ByteXIntrinsicRewrite.INTRINSIC_WORD0_NAME.equals(procedureName) && parameters.size() == 1) {
return addExprUnary(ctx, Operators.WORD0, parameters.get(0));
} else if(Pass1ByteXIntrinsicRewrite.INTRINSIC_WORD1_NAME.equals(procedureName) && parameters.size() == 1) {
return addExprUnary(ctx, Operators.WORD1, parameters.get(0));
} else if(Pass1ByteXIntrinsicRewrite.INTRINSIC_MAKEWORD.equals(procedureName) && parameters.size() == 2) {
return addExprBinary(ctx, parameters.get(0), Operators.WORD, parameters.get(1));
} else if(Pass1ByteXIntrinsicRewrite.INTRINSIC_MAKELONG.equals(procedureName) && parameters.size() == 2) {
return addExprBinary(ctx, parameters.get(0), Operators.DWORD, parameters.get(1));
} else if(Pass1ByteXIntrinsicRewrite.INTRINSIC_MAKELONG4.equals(procedureName)) {
// Handle the intrinsic MAKELONG4()
if(program.getScope().getGlobalSymbol(Pass1ByteXIntrinsicRewrite.INTRINSIC_MAKELONG4) == null) {
// Add the intrinsic MAKEWORD4() to the global scope
final Procedure makeword4 = new Procedure(
Pass1ByteXIntrinsicRewrite.INTRINSIC_MAKELONG4,
new SymbolTypeProcedure(SymbolType.DWORD, Arrays.asList(new SymbolType[]{SymbolType.BYTE, SymbolType.BYTE, SymbolType.BYTE, SymbolType.BYTE})),
program.getScope(),
Scope.SEGMENT_CODE_DEFAULT, Scope.SEGMENT_DATA_DEFAULT,
Procedure.CallingConvention.INTRINSIC_CALL);
makeword4.setDeclaredIntrinsic(true);
final Variable hihi = new Variable("hihi", Variable.Kind.PHI_MASTER, SymbolType.BYTE, makeword4, Variable.MemoryArea.ZEROPAGE_MEMORY, Scope.SEGMENT_DATA_DEFAULT, null);
makeword4.add(hihi);
final Variable hilo = new Variable("hilo", Variable.Kind.PHI_MASTER, SymbolType.BYTE, makeword4, Variable.MemoryArea.ZEROPAGE_MEMORY, Scope.SEGMENT_DATA_DEFAULT, null);
makeword4.add(hilo);
final Variable lohi = new Variable("lohi", Variable.Kind.PHI_MASTER, SymbolType.BYTE, makeword4, Variable.MemoryArea.ZEROPAGE_MEMORY, Scope.SEGMENT_DATA_DEFAULT, null);
makeword4.add(lohi);
final Variable lolo = new Variable("lolo", Variable.Kind.PHI_MASTER, SymbolType.BYTE, makeword4, Variable.MemoryArea.ZEROPAGE_MEMORY, Scope.SEGMENT_DATA_DEFAULT, null);
makeword4.add(lolo);
makeword4.setParameters(Arrays.asList(hihi, hilo, lohi, lolo));
program.getScope().add(makeword4);
}
// Add the call
LValue result = (LValue) addIntermediateVar().getRef();
addStatement(new StatementCall(result, procedureName, parameters, new StatementSource(ctx), ensureUnusedComments(getCommentsSymbol(ctx))));
return result;
}
}
// Examine if the procedureName references a variable
RValue procedurePointer = (RValue) this.visit(ctx.expr());
if(procedurePointer instanceof ProcedureRef) {
// A normal named call
LValue result = (LValue) addIntermediateVar().getRef();
String procedureName = ((ProcedureRef) procedurePointer).getLocalName();
addStatement(new StatementCall(result, procedureName, parameters, new StatementSource(ctx), ensureUnusedComments(getCommentsSymbol(ctx))));
return result;
} else if(procedurePointer instanceof ForwardVariableRef) {
// TODO: Remove the need for forward references!
// Assume this is a named call to a yet undeclared function.
LValue result = (LValue) addIntermediateVar().getRef();
String procedureName = ((ForwardVariableRef) procedurePointer).getName();
addStatement(new StatementCall(result, procedureName, parameters, new StatementSource(ctx), ensureUnusedComments(getCommentsSymbol(ctx))));
return result;
} else {
LValue result = (LValue) addIntermediateVar().getRef();
addStatement(new StatementCallPointer(result, procedurePointer, parameters, new StatementSource(ctx), ensureUnusedComments(getCommentsSymbol(ctx))));
consumeExpr(procedurePointer);
Label afterCallLabel = getCurrentScope().addLabelIntermediate();
addStatement(new StatementLabel(afterCallLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS));
return result;
}
}
@Override

View File

@ -22,6 +22,8 @@ public class Pass1AssertJumpLabels extends Pass1Base {
@Override
public boolean step() {
for(Procedure procedure : getProgram().getScope().getAllProcedures(true)) {
if(procedure.isDeclaredIntrinsic())
continue;
final ProcedureCompilation procedureCompilation = getProgram().getProcedureCompilation(procedure.getRef());
StatementSequence statementSequence = procedureCompilation.getStatementSequence();
for(Statement statement : statementSequence.getStatements()) {

View File

@ -29,6 +29,8 @@ public class Pass1GenerateControlFlowGraph extends Pass1Base {
ProgramScope programScope = getScope();
final Collection<Procedure> allProcedures = getProgram().getScope().getAllProcedures(true);
for(Procedure procedure : allProcedures) {
if(procedure.isDeclaredIntrinsic())
continue;
final ProcedureCompilation procedureCompilation = getProgram().getProcedureCompilation(procedure.getRef());
final StatementSequence sequence = procedureCompilation.getStatementSequence();
if(sequence.getStatements().size()==0)

View File

@ -8,11 +8,6 @@ import dk.camelot64.kickc.model.statements.StatementCall;
import dk.camelot64.kickc.model.symbols.Procedure;
import dk.camelot64.kickc.model.symbols.Scope;
import dk.camelot64.kickc.model.symbols.Symbol;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypeProcedure;
import java.util.Arrays;
/**
* Updates procedure calls to point to the actual procedure called.
@ -30,29 +25,6 @@ public class Pass1Procedures extends Pass2SsaOptimization {
if(statement instanceof StatementCall) {
StatementCall call = (StatementCall) statement;
String procedureName = call.getProcedureName();
if(procedureName.equals(Pass1ByteXIntrinsicRewrite.INTRINSIC_MAKELONG4)) {
if(getScope().getGlobalSymbol(Pass1ByteXIntrinsicRewrite.INTRINSIC_MAKELONG4) == null) {
// Add the intrinsic MAKEWORD4()
final Procedure makeword4 = new Procedure(
Pass1ByteXIntrinsicRewrite.INTRINSIC_MAKELONG4,
new SymbolTypeProcedure(SymbolType.DWORD, Arrays.asList(new SymbolType[]{ SymbolType.BYTE, SymbolType.BYTE, SymbolType.BYTE, SymbolType.BYTE})),
getScope(),
Scope.SEGMENT_CODE_DEFAULT, Scope.SEGMENT_DATA_DEFAULT,
Procedure.CallingConvention.INTRINSIC_CALL);
makeword4.setDeclaredIntrinsic(true);
final Variable hihi = new Variable("hihi", Variable.Kind.PHI_MASTER, SymbolType.BYTE, makeword4, Variable.MemoryArea.ZEROPAGE_MEMORY, Scope.SEGMENT_DATA_DEFAULT, null);
makeword4.add(hihi);
final Variable hilo = new Variable("hilo", Variable.Kind.PHI_MASTER, SymbolType.BYTE, makeword4, Variable.MemoryArea.ZEROPAGE_MEMORY, Scope.SEGMENT_DATA_DEFAULT, null);
makeword4.add(hilo);
final Variable lohi = new Variable("lohi", Variable.Kind.PHI_MASTER, SymbolType.BYTE, makeword4, Variable.MemoryArea.ZEROPAGE_MEMORY, Scope.SEGMENT_DATA_DEFAULT, null);
makeword4.add(lohi);
final Variable lolo = new Variable("lolo", Variable.Kind.PHI_MASTER, SymbolType.BYTE, makeword4, Variable.MemoryArea.ZEROPAGE_MEMORY, Scope.SEGMENT_DATA_DEFAULT, null);
makeword4.add(lolo);
makeword4.setParameters(Arrays.asList(hihi, hilo, lohi, lolo));
getScope().add(makeword4);
}
}
Scope localScope = (Scope) getScope().getSymbol(block.getScope());
final Symbol procedureSymbol = localScope.findSymbol(procedureName);
if(procedureSymbol == null)

View File

@ -1,12 +1,16 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.CompileError;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.iterator.ProgramExpressionBinary;
import dk.camelot64.kickc.model.iterator.ProgramExpressionIterator;
import dk.camelot64.kickc.model.iterator.ProgramValue;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.statements.StatementCallPointer;
import dk.camelot64.kickc.model.types.*;
import dk.camelot64.kickc.model.values.ConstantSymbolPointer;
import dk.camelot64.kickc.model.values.PointerDereferenceSimple;
import dk.camelot64.kickc.model.values.RValue;
import dk.camelot64.kickc.model.values.SymbolRef;
@ -14,7 +18,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
/**
* Add a cast a variable is assigned something of a convertible type.
* Also allows pointers to be assigned integer values.
*/
public class PassNAddTypeConversionAssignment extends Pass2SsaOptimization {
@ -65,6 +68,24 @@ public class PassNAddTypeConversionAssignment extends Pass2SsaOptimization {
}
}
});
// Add dereference to call to pointer to function
for(ControlFlowBlock block : getProgram().getGraph().getAllBlocks()) {
for(Statement statement : block.getStatements()) {
if(statement instanceof StatementCallPointer) {
RValue procedure = ((StatementCallPointer) statement).getProcedure();
SymbolType procType = SymbolTypeInference.inferType(getScope(), procedure);
if(procType instanceof SymbolTypePointer && ((SymbolTypePointer) procType).getElementType() instanceof SymbolTypeProcedure) {
// Allow calling pointer to procedure directly
// Add an automatic dereference to a pointer to procedure
if(!pass1 || getLog().isVerbosePass1CreateSsa())
getLog().append("Adding dereference to call function pointer " + procedure.toString() + " in " + statement.toString(getProgram(), false));
((StatementCallPointer) statement).setProcedure(new PointerDereferenceSimple(procedure));
}
}
}
}
return modified.get();
}

View File

@ -88,6 +88,9 @@ public class PassNTypeInference extends Pass2SsaOptimization {
Variable symbol = programScope.getVariable((VariableRef) lValue);
if(SymbolType.VAR.equals(symbol.getType()) || SymbolType.NUMBER.equals(symbol.getType())|| SymbolType.UNUMBER.equals(symbol.getType())|| SymbolType.SNUMBER.equals(symbol.getType())) {
SymbolType procedureType = SymbolTypeInference.inferType(programScope, call.getProcedure());
if(procedureType instanceof SymbolTypePointer)
// Handle call to pointer to function
procedureType = ((SymbolTypePointer) procedureType).getElementType();
if(procedureType instanceof SymbolTypeProcedure) {
SymbolType returnType = ((SymbolTypeProcedure) procedureType).getReturnType();
setInferedType(program, call, symbol, returnType);

View File

@ -271,7 +271,7 @@ public class TestProgramsFast extends TestPrograms {
@Test
public void testLocalVarShadowingProcedure() throws IOException {
assertError("local-var-shadowing-procedure.c", "Called symbol is not a procedure. main::doit");
assertError("local-var-shadowing-procedure.c", "Called object is not a function or function pointer main::doit");
}
@Test

View File

@ -13,11 +13,13 @@ char fn2() {
}
void set_border(char (*fn)(void)) {
*BORDER = (*fn)();
// Call pointer to a function without *
*BORDER = fn();
}
void main() {
for(;;) {
// Create pointer to function without &
set_border(fn1);
set_border(fn2);
}

View File

@ -15,6 +15,7 @@
main: {
__b1:
// set_border(fn1)
// Create pointer to function without &
lda #<fn1
sta.z set_border.fn
lda #>fn1
@ -49,11 +50,12 @@ fn1: {
// set_border(byte()* zp(2) fn)
set_border: {
.label fn = 2
// (*fn)()
// fn()
pha
jsr bi_fn
pla
// *BORDER = (*fn)()
// *BORDER = fn()
// Call pointer to a function without *
sta BORDER
// }
rts

View File

@ -263,6 +263,7 @@ main: {
// main::@1
__b1:
// [2] call set_border
// Create pointer to function without &
// [11] phi from main::@1 to set_border [phi:main::@1->set_border]
set_border_from___b1:
// [11] phi set_border::fn#2 = &fn1 [phi:main::@1->set_border#0] -- pprz1=pprc1
@ -329,6 +330,7 @@ set_border: {
// set_border::@1
__b1:
// [15] *BORDER = set_border::$0 -- _deref_pbuc1=vbuaa
// Call pointer to a function without *
sta BORDER
jmp __breturn
// set_border::@return
@ -351,10 +353,10 @@ Succesful ASM optimization Pass5NextJumpElimination
Replacing label __b1_from___b2 with __b1
Removing instruction __b1_from_main:
Removing instruction __b1_from___b2:
Removing instruction set_border_from___b1:
Removing instruction __b2_from___b1:
Removing instruction set_border_from___b2:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction set_border_from___b1:
Removing instruction __b2:
Removing instruction __breturn:
Removing instruction __breturn:
@ -412,6 +414,7 @@ main: {
__b1:
// set_border(fn1)
// [2] call set_border
// Create pointer to function without &
// [11] phi from main::@1 to set_border [phi:main::@1->set_border]
// [11] phi set_border::fn#2 = &fn1 [phi:main::@1->set_border#0] -- pprz1=pprc1
lda #<fn1
@ -463,7 +466,7 @@ fn1: {
// set_border(byte()* zp(2) fn)
set_border: {
.label fn = 2
// (*fn)()
// fn()
// sideeffect stackpushbytes(1) -- _stackpushbyte_1
pha
// [13] callexecute *set_border::fn#2
@ -471,8 +474,9 @@ set_border: {
// [14] set_border::$0 = stackpull(byte) -- vbuaa=_stackpullbyte_
pla
// set_border::@1
// *BORDER = (*fn)()
// *BORDER = fn()
// [15] *BORDER = set_border::$0 -- _deref_pbuc1=vbuaa
// Call pointer to a function without *
sta BORDER
// set_border::@return
// }