mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-01-12 11:31:11 +00:00
Working on static initialization rewrite _init(). #257
This commit is contained in:
parent
dc4102d680
commit
5779f3169b
@ -754,3 +754,9 @@ tay
|
|||||||
ldy {z1}
|
ldy {z1}
|
||||||
//FRAGMENT pbuc1_derefidx_vbuyy=vbuaa
|
//FRAGMENT pbuc1_derefidx_vbuyy=vbuaa
|
||||||
sta {c1},y
|
sta {c1},y
|
||||||
|
//FRAGMENT vbuaa=vbuaa_plus_vbuc1
|
||||||
|
clc
|
||||||
|
adc #{c1}
|
||||||
|
//FRAGMENT vbuaa=_inc_vbuaa
|
||||||
|
clc
|
||||||
|
adc #1
|
||||||
|
1570
src/main/fragment/cache/fragment-cache-mos6502x.asm
vendored
1570
src/main/fragment/cache/fragment-cache-mos6502x.asm
vendored
File diff suppressed because it is too large
Load Diff
@ -390,6 +390,7 @@ public class Compiler {
|
|||||||
optimizations.add(new PassNSimplifyExpressionWithZero(program));
|
optimizations.add(new PassNSimplifyExpressionWithZero(program));
|
||||||
optimizations.add(new PassNEliminateUnusedVars(program, true));
|
optimizations.add(new PassNEliminateUnusedVars(program, true));
|
||||||
optimizations.add(new Pass2EliminateUnusedBlocks(program));
|
optimizations.add(new Pass2EliminateUnusedBlocks(program));
|
||||||
|
optimizations.add(new PassNEliminateEmptyProcedure(program));
|
||||||
optimizations.add(new PassNEliminateEmptyStart(program));
|
optimizations.add(new PassNEliminateEmptyStart(program));
|
||||||
if(enableLoopHeadConstant) {
|
if(enableLoopHeadConstant) {
|
||||||
optimizations.add(new PassNStatementIndices(program));
|
optimizations.add(new PassNStatementIndices(program));
|
||||||
|
@ -89,7 +89,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
// Statement outside procedure declaration - put into the _init procedure
|
// Statement outside procedure declaration - put into the _init procedure
|
||||||
Procedure initProc = program.getScope().getLocalProcedure(SymbolRef.INIT_PROC_NAME);
|
Procedure initProc = program.getScope().getLocalProcedure(SymbolRef.INIT_PROC_NAME);
|
||||||
if(initProc == null) {
|
if(initProc == null) {
|
||||||
initProc = new Procedure(SymbolRef.INIT_PROC_NAME, SymbolType.VOID, program.getScope(), Scope.SEGMENT_CODE_DEFAULT, Scope.SEGMENT_DATA_DEFAULT, Procedure.CallingConvention.STACK_CALL);
|
initProc = new Procedure(SymbolRef.INIT_PROC_NAME, SymbolType.VOID, program.getScope(), Scope.SEGMENT_CODE_DEFAULT, Scope.SEGMENT_DATA_DEFAULT, Procedure.CallingConvention.PHI_CALL);
|
||||||
initProc.setParameters(new ArrayList<>());
|
initProc.setParameters(new ArrayList<>());
|
||||||
program.getScope().add(initProc);
|
program.getScope().add(initProc);
|
||||||
program.createProcedureCompilation(initProc.getRef());
|
program.createProcedureCompilation(initProc.getRef());
|
||||||
|
@ -52,29 +52,20 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Set<LabelRef> unusedProcedureBlocks = new HashSet<>();
|
Set<LabelRef> removedBlocks = new HashSet<>();
|
||||||
for(LabelRef unusedBlock : unusedBlocks) {
|
for(LabelRef unusedBlock : unusedBlocks) {
|
||||||
Symbol unusedSymbol = getScope().getSymbol(unusedBlock);
|
Symbol unusedSymbol = getScope().getSymbol(unusedBlock);
|
||||||
if(unusedSymbol instanceof Label) {
|
if(unusedSymbol instanceof Label) {
|
||||||
getGraph().remove(unusedBlock);
|
getGraph().remove(unusedBlock);
|
||||||
Label label = getScope().getLabel(unusedBlock);
|
Label label = getScope().getLabel(unusedBlock);
|
||||||
label.getScope().remove(label);
|
label.getScope().remove(label);
|
||||||
removePhiRValues(unusedBlock);
|
removePhiRValues(unusedBlock, getProgram());
|
||||||
|
removedBlocks.add(unusedBlock);
|
||||||
getLog().append("Removing unused block " + unusedBlock);
|
getLog().append("Removing unused block " + unusedBlock);
|
||||||
} else if(unusedSymbol instanceof Procedure) {
|
} else if(unusedSymbol instanceof Procedure) {
|
||||||
ProcedureRef unusedProcedureRef = ((Procedure) unusedSymbol).getRef();
|
ProcedureRef unusedProcedureRef = ((Procedure) unusedSymbol).getRef();
|
||||||
getLog().append("Removing unused procedure " + unusedProcedureRef);
|
removeProcedure(unusedProcedureRef, removedBlocks, getProgram());
|
||||||
Procedure unusedProcedure = getProgram().getScope().getProcedure(unusedProcedureRef);
|
} else if(removedBlocks.contains(unusedBlock)) {
|
||||||
List<ControlFlowBlock> procedureBlocks = getProgram().getGraph().getScopeBlocks(unusedProcedureRef);
|
|
||||||
for(ControlFlowBlock procedureBlock : procedureBlocks) {
|
|
||||||
LabelRef blockLabelRef = procedureBlock.getLabel();
|
|
||||||
getLog().append("Removing unused procedure block " + blockLabelRef);
|
|
||||||
getProgram().getGraph().remove(blockLabelRef);
|
|
||||||
removePhiRValues(blockLabelRef);
|
|
||||||
unusedProcedureBlocks.add(blockLabelRef);
|
|
||||||
}
|
|
||||||
unusedProcedure.getScope().remove(unusedProcedure);
|
|
||||||
} else if(unusedProcedureBlocks.contains(unusedBlock)) {
|
|
||||||
// Already removed - we are happy!
|
// Already removed - we are happy!
|
||||||
} else {
|
} else {
|
||||||
throw new CompileError("Unable to remove unused block " + unusedBlock);
|
throw new CompileError("Unable to remove unused block " + unusedBlock);
|
||||||
@ -84,6 +75,25 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
|
|||||||
return unusedBlocks.size() > 0;
|
return unusedBlocks.size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an entire procedure from the program (control flow graph and symbol table)
|
||||||
|
* @param procedureRef The procedure to remove
|
||||||
|
* @param removedBlocks A set where all removed blocks are added to.
|
||||||
|
*/
|
||||||
|
public static void removeProcedure(ProcedureRef procedureRef, Set<LabelRef> removedBlocks, Program program) {
|
||||||
|
program.getLog().append("Removing unused procedure " + procedureRef);
|
||||||
|
Procedure unusedProcedure = program.getScope().getProcedure(procedureRef);
|
||||||
|
List<ControlFlowBlock> procedureBlocks = program.getGraph().getScopeBlocks(procedureRef);
|
||||||
|
for(ControlFlowBlock procedureBlock : procedureBlocks) {
|
||||||
|
LabelRef blockLabelRef = procedureBlock.getLabel();
|
||||||
|
program.getLog().append("Removing unused procedure block " + blockLabelRef);
|
||||||
|
program.getGraph().remove(blockLabelRef);
|
||||||
|
removePhiRValues(blockLabelRef, program);
|
||||||
|
removedBlocks.add(blockLabelRef);
|
||||||
|
}
|
||||||
|
unusedProcedure.getScope().remove(unusedProcedure);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all referenced blocks in the entire program
|
* Get all referenced blocks in the entire program
|
||||||
*
|
*
|
||||||
@ -104,9 +114,9 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
|
|||||||
*
|
*
|
||||||
* @param removeBlock The block to remove from PHI RValues
|
* @param removeBlock The block to remove from PHI RValues
|
||||||
*/
|
*/
|
||||||
private void removePhiRValues(LabelRef removeBlock) {
|
private static void removePhiRValues(LabelRef removeBlock, Program program) {
|
||||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
for(ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
||||||
removePhiRValues(removeBlock, block, getLog());
|
removePhiRValues(removeBlock, block, program.getLog());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
package dk.camelot64.kickc.passes;
|
||||||
|
|
||||||
|
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||||
|
import dk.camelot64.kickc.model.Program;
|
||||||
|
import dk.camelot64.kickc.model.statements.*;
|
||||||
|
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||||
|
import dk.camelot64.kickc.model.values.ProcedureRef;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ListIterator;
|
||||||
|
|
||||||
|
/** Eliminates procedures that have empty bodies. Also removes any calls to the empty procedures. */
|
||||||
|
public class PassNEliminateEmptyProcedure extends Pass2SsaOptimization {
|
||||||
|
|
||||||
|
public PassNEliminateEmptyProcedure(Program program) {
|
||||||
|
super(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean step() {
|
||||||
|
final Collection<Procedure> allProcedures = getScope().getAllProcedures(true);
|
||||||
|
boolean optimized = false;
|
||||||
|
for(Procedure procedure : allProcedures) {
|
||||||
|
if(hasEmptyBody(procedure.getRef())) {
|
||||||
|
// Remove all calls
|
||||||
|
removeAllCalls(procedure.getRef());
|
||||||
|
// Remove the procedure
|
||||||
|
Pass2EliminateUnusedBlocks.removeProcedure(procedure.getRef(), new HashSet<>(),getProgram() );
|
||||||
|
optimized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return optimized;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeAllCalls(ProcedureRef ref) {
|
||||||
|
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||||
|
final ListIterator<Statement> stmtIt = block.getStatements().listIterator();
|
||||||
|
while(stmtIt.hasNext()) {
|
||||||
|
Statement statement = stmtIt.next();
|
||||||
|
if(statement instanceof StatementCalling && ((StatementCalling) statement).getProcedure().equals(ref)) {
|
||||||
|
getLog().append("Removing call to empty procedure "+statement.toString(getProgram(), false));
|
||||||
|
stmtIt.remove();
|
||||||
|
} else if(statement instanceof StatementCallPrepare && ((StatementCallPrepare) statement).getProcedure().equals(ref)) {
|
||||||
|
getLog().append("Removing call to empty procedure "+statement.toString(getProgram(), false));
|
||||||
|
stmtIt.remove();
|
||||||
|
} else if(statement instanceof StatementCallFinalize && ((StatementCallFinalize) statement).getProcedure().equals(ref)) {
|
||||||
|
getLog().append("Removing call to empty procedure "+statement.toString(getProgram(), false));
|
||||||
|
stmtIt.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Looks through a procedure to determine if it has an empty body.
|
||||||
|
*
|
||||||
|
* @param procedureRef The procedure to look through
|
||||||
|
* @return true if the procedure body is empty.
|
||||||
|
*/
|
||||||
|
private boolean hasEmptyBody(ProcedureRef procedureRef) {
|
||||||
|
final List<ControlFlowBlock> procedureBlocks = getGraph().getScopeBlocks(procedureRef);
|
||||||
|
// The single no-args no-return call of the procedure (if found)
|
||||||
|
for(ControlFlowBlock block : procedureBlocks) {
|
||||||
|
for(Statement statement : block.getStatements()) {
|
||||||
|
if(statement instanceof StatementReturn && ((StatementReturn) statement).getValue() == null) {
|
||||||
|
// An empty return is OK
|
||||||
|
} else
|
||||||
|
// Any other statement is not an empty body
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we get this far we have an empty body
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -8,6 +8,7 @@ import dk.camelot64.kickc.model.statements.StatementReturn;
|
|||||||
import dk.camelot64.kickc.model.values.ProcedureRef;
|
import dk.camelot64.kickc.model.values.ProcedureRef;
|
||||||
import dk.camelot64.kickc.model.values.SymbolRef;
|
import dk.camelot64.kickc.model.values.SymbolRef;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/** Pass that eliminates the __start() procedure if it is empty (ie. only contains a call to main() ). */
|
/** Pass that eliminates the __start() procedure if it is empty (ie. only contains a call to main() ). */
|
||||||
@ -24,7 +25,8 @@ public class PassNEliminateEmptyStart extends Pass2SsaOptimization {
|
|||||||
if(singleCall != null) {
|
if(singleCall != null) {
|
||||||
// Start only has a single call
|
// Start only has a single call
|
||||||
getProgram().setStartProcedure(singleCall.getProcedure());
|
getProgram().setStartProcedure(singleCall.getProcedure());
|
||||||
Pass1EliminateUncalledProcedures.removeProcedure(getProgram(), startProcRef);
|
Pass2EliminateUnusedBlocks.removeProcedure(startProcRef, new HashSet<>(), getProgram());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ public class TestPrograms {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStaticInitCode2() throws IOException, URISyntaxException {
|
public void testStaticInitCode2() throws IOException, URISyntaxException {
|
||||||
compileAndCompare("static-init-code-2.c", log());
|
compileAndCompare("static-init-code-2.c");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
x
Reference in New Issue
Block a user