1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-12-28 16:31:36 +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);
for(Procedure procedure : procedures) {
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());
}
}

View File

@ -26,7 +26,7 @@ public class Pass1ModifiedVarsAnalysis extends Pass1Base {
Map<ProcedureRef, Set<VariableRef>> modified = new LinkedHashMap<>();
Collection<Procedure> allProcedures = getScope().getAllProcedures(true);
for(Procedure procedure : allProcedures) {
Set<VariableRef> modifiedVars = getModifiedVars(procedure);
Set<VariableRef> modifiedVars = getModifiedVars(procedure, new HashSet<>());
modified.put(procedure.getRef(), modifiedVars);
}
getProgram().setProcedureModifiedVars(new ProcedureModifiedVars(modified));
@ -39,7 +39,12 @@ public class Pass1ModifiedVarsAnalysis extends Pass1Base {
* @param procedure The procedure to examine
* @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<>();
ScopeRef procScope = procedure.getRef();
List<ControlFlowBlock> procBlocks = getProgram().getGraph().getScopeBlocks(procScope);
@ -56,7 +61,7 @@ public class Pass1ModifiedVarsAnalysis extends Pass1Base {
if(statement instanceof StatementCalling) {
ProcedureRef called = ((StatementCalling) statement).getProcedure();
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
int callingDepth = getCallingDepth(currentScope);
int callingDepth = getCallingDepth(currentScope, new HashSet<>());
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;
Collection<ScopeRef> callingScopes = callGraph.getCallingBlocks(currentScope);
for(ScopeRef callingScope : callingScopes) {
@ -82,7 +87,7 @@ public class Pass3LoopDepthAnalysis extends Pass2Base {
}
}
// Also look through all callers
int superCallingDepth = getCallingDepth(callingScope);
int superCallingDepth = getCallingDepth(callingScope, visited);
if(superCallingDepth>callingDepth) {
callingDepth= superCallingDepth;
}

View File

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

View File

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