mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-04-22 18:37:29 +00:00
Added support for calling a pointer to function without(*). Closes #692
This commit is contained in:
parent
8514c9942e
commit
77db0e8701
@ -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
|
||||
|
@ -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()) {
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
// }
|
||||
|
Loading…
x
Reference in New Issue
Block a user