1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-01-02 05:30:53 +00:00

Java no long does infinite recursion if the C-code does. #316

This commit is contained in:
jespergravgaard 2019-09-23 22:42:07 +02:00
parent 665b9adbfb
commit bf9a414099
8 changed files with 59 additions and 10 deletions

View File

@ -0,0 +1,4 @@
lda {z1}+1
pha
lda {z1}
pha

View File

@ -0,0 +1,7 @@
lda {z2}
sec
sbc #2
sta {z1}
lda {z2}+1
sbc #0
sta {z1}+1

View File

@ -21,7 +21,7 @@ public class Pass1AssertNoRecursion extends Pass1Base {
Collection<Procedure> procedures = getScope().getAllProcedures(true); Collection<Procedure> procedures = getScope().getAllProcedures(true);
for(Procedure procedure : procedures) { for(Procedure procedure : procedures) {
Collection<ScopeRef> recursiveCalls = callGraph.getRecursiveCalls(procedure.getRef()); Collection<ScopeRef> recursiveCalls = callGraph.getRecursiveCalls(procedure.getRef());
if(recursiveCalls.contains(procedure.getRef())) { if(recursiveCalls.contains(procedure.getRef()) && !procedure.getCallingConvension().equals(Procedure.CallingConvension.STACK_CALL)) {
throw new CompileError("ERROR! Recursion not allowed! Occurs in " + procedure.getRef()); throw new CompileError("ERROR! Recursion not allowed! Occurs in " + procedure.getRef());
} }
} }

View File

@ -26,7 +26,7 @@ public class Pass1ModifiedVarsAnalysis extends Pass1Base {
Map<ProcedureRef, Set<VariableRef>> modified = new LinkedHashMap<>(); Map<ProcedureRef, Set<VariableRef>> modified = new LinkedHashMap<>();
Collection<Procedure> allProcedures = getScope().getAllProcedures(true); Collection<Procedure> allProcedures = getScope().getAllProcedures(true);
for(Procedure procedure : allProcedures) { for(Procedure procedure : allProcedures) {
Set<VariableRef> modifiedVars = getModifiedVars(procedure); Set<VariableRef> modifiedVars = getModifiedVars(procedure, new HashSet<>());
modified.put(procedure.getRef(), modifiedVars); modified.put(procedure.getRef(), modifiedVars);
} }
getProgram().setProcedureModifiedVars(new ProcedureModifiedVars(modified)); getProgram().setProcedureModifiedVars(new ProcedureModifiedVars(modified));
@ -39,7 +39,12 @@ public class Pass1ModifiedVarsAnalysis extends Pass1Base {
* @param procedure The procedure to examine * @param procedure The procedure to examine
* @return All variables declared outside the procedure modified inside the procedure. * @return All variables declared outside the procedure modified inside the procedure.
*/ */
public Set<VariableRef> getModifiedVars(Procedure procedure) { private Set<VariableRef> getModifiedVars(Procedure procedure, Set<ProcedureRef> visited) {
// Avoid recursion
if(visited.contains(procedure.getRef()))
return new LinkedHashSet<>();
visited.add(procedure.getRef());
Set<VariableRef> modified = new LinkedHashSet<>(); Set<VariableRef> modified = new LinkedHashSet<>();
ScopeRef procScope = procedure.getRef(); ScopeRef procScope = procedure.getRef();
List<ControlFlowBlock> procBlocks = getProgram().getGraph().getScopeBlocks(procScope); List<ControlFlowBlock> procBlocks = getProgram().getGraph().getScopeBlocks(procScope);
@ -56,7 +61,7 @@ public class Pass1ModifiedVarsAnalysis extends Pass1Base {
if(statement instanceof StatementCalling) { if(statement instanceof StatementCalling) {
ProcedureRef called = ((StatementCalling) statement).getProcedure(); ProcedureRef called = ((StatementCalling) statement).getProcedure();
Procedure calledProc = getScope().getProcedure(called); Procedure calledProc = getScope().getProcedure(called);
modified.addAll(getModifiedVars(calledProc)); modified.addAll(getModifiedVars(calledProc, visited));
} }
} }
} }

View File

@ -54,12 +54,17 @@ public class Pass3LoopDepthAnalysis extends Pass2Base {
} }
} }
// Find the scope blocks calling the current scope block - and the loop depth of the blocks where the call statement is // Find the scope blocks calling the current scope block - and the loop depth of the blocks where the call statement is
int callingDepth = getCallingDepth(currentScope); int callingDepth = getCallingDepth(currentScope, new HashSet<>());
findLoopDepth(currentScope, callingDepth); findLoopDepth(currentScope, callingDepth);
} }
} }
private int getCallingDepth(ScopeRef currentScope) { private int getCallingDepth(ScopeRef currentScope, Set<ScopeRef> visited) {
if(visited.contains(currentScope))
return 10;
visited.add(currentScope);
int callingDepth = 1; int callingDepth = 1;
Collection<ScopeRef> callingScopes = callGraph.getCallingBlocks(currentScope); Collection<ScopeRef> callingScopes = callGraph.getCallingBlocks(currentScope);
for(ScopeRef callingScope : callingScopes) { for(ScopeRef callingScope : callingScopes) {
@ -82,7 +87,7 @@ public class Pass3LoopDepthAnalysis extends Pass2Base {
} }
} }
// Also look through all callers // Also look through all callers
int superCallingDepth = getCallingDepth(callingScope); int superCallingDepth = getCallingDepth(callingScope, visited);
if(superCallingDepth>callingDepth) { if(superCallingDepth>callingDepth) {
callingDepth= superCallingDepth; callingDepth= superCallingDepth;
} }

View File

@ -52,11 +52,16 @@ public class PassNCalcLiveRangesEffective extends PassNCalcBase<LiveRangeVariabl
this.procedureCallPaths = new LinkedHashMap<>(); this.procedureCallPaths = new LinkedHashMap<>();
Collection<Procedure> procedures = getProgram().getScope().getAllProcedures(true); Collection<Procedure> procedures = getProgram().getScope().getAllProcedures(true);
for(Procedure procedure : procedures) { for(Procedure procedure : procedures) {
populateProcedureCallPaths(procedure); populateProcedureCallPaths(procedure, new HashSet<>());
} }
} }
private void populateProcedureCallPaths(Procedure procedure) { private void populateProcedureCallPaths(Procedure procedure, Set<ProcedureRef> visited) {
// Avoid recursion
if(visited.contains(procedure.getRef()))
return;
visited.add(procedure.getRef());
ProcedureRef procedureRef = procedure.getRef(); ProcedureRef procedureRef = procedure.getRef();
LiveRangeVariablesEffective.CallPaths callPaths = procedureCallPaths.get(procedureRef); LiveRangeVariablesEffective.CallPaths callPaths = procedureCallPaths.get(procedureRef);
if(callPaths == null) { if(callPaths == null) {
@ -84,11 +89,12 @@ public class PassNCalcLiveRangesEffective extends PassNCalcBase<LiveRangeVariabl
// Found calling procedure! // Found calling procedure!
Procedure callerProcedure = (Procedure) callScope; Procedure callerProcedure = (Procedure) callScope;
// Make sure we have populated the call-paths of the calling procedure // Make sure we have populated the call-paths of the calling procedure
populateProcedureCallPaths(callerProcedure); populateProcedureCallPaths(callerProcedure, visited);
// Find variables referenced in caller procedure // Find variables referenced in caller procedure
Collection<VariableRef> referencedInCaller = referenceInfo.getReferencedVars(callerProcedure.getRef().getLabelRef()); Collection<VariableRef> referencedInCaller = referenceInfo.getReferencedVars(callerProcedure.getRef().getLabelRef());
// For each caller path - create a new call-path // For each caller path - create a new call-path
LiveRangeVariablesEffective.CallPaths callerPaths = procedureCallPaths.get(callerProcedure.getRef()); LiveRangeVariablesEffective.CallPaths callerPaths = procedureCallPaths.get(callerProcedure.getRef());
if(callerPaths!=null)
for(LiveRangeVariablesEffective.CallPath callerPath : callerPaths.getCallPaths()) { for(LiveRangeVariablesEffective.CallPath callerPath : callerPaths.getCallPaths()) {
ArrayList<CallGraph.CallBlock.Call> path = new ArrayList<>(callerPath.getPath()); ArrayList<CallGraph.CallBlock.Call> path = new ArrayList<>(callerPath.getPath());
path.add(caller); path.add(caller);

View File

@ -35,6 +35,13 @@ public class TestPrograms {
public TestPrograms() { public TestPrograms() {
} }
/*
@Test
public void testProcedureCallingConventionStack6() throws IOException, URISyntaxException {
compileAndCompare("procedure-callingconvention-stack-6", log()); //, log().verboseCreateSsa().verboseParse().verboseStatementSequence());
}
*/
@Test @Test
public void testProcedureCallingConventionStack5() throws IOException, URISyntaxException { public void testProcedureCallingConventionStack5() throws IOException, URISyntaxException {
compileAndCompare("procedure-callingconvention-stack-5"); //, log().verboseCreateSsa().verboseParse().verboseStatementSequence()); compileAndCompare("procedure-callingconvention-stack-5"); //, log().verboseCreateSsa().verboseParse().verboseStatementSequence());

View File

@ -0,0 +1,15 @@
// Test a procedure with calling convention stack
// Recursive fibonacci
const char* SCREEN = 0x0400;
void main(void) {
*SCREEN = fib(5);
}
char __stackcall fib(char n) {
if (n == 0 || n == 1)
return n;
else
return (fib(n-1) + fib(n-2));
}