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:
parent
665b9adbfb
commit
bf9a414099
@ -0,0 +1,4 @@
|
|||||||
|
lda {z1}+1
|
||||||
|
pha
|
||||||
|
lda {z1}
|
||||||
|
pha
|
7
src/main/fragment/mos6502-common/vwuz1=vwuz2_minus_2.asm
Normal file
7
src/main/fragment/mos6502-common/vwuz1=vwuz2_minus_2.asm
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
lda {z2}
|
||||||
|
sec
|
||||||
|
sbc #2
|
||||||
|
sta {z1}
|
||||||
|
lda {z2}+1
|
||||||
|
sbc #0
|
||||||
|
sta {z1}+1
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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());
|
||||||
|
15
src/test/kc/procedure-callingconvention-stack-6.kc
Normal file
15
src/test/kc/procedure-callingconvention-stack-6.kc
Normal 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));
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user