mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-26 12:49:21 +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}
|
||||
//FRAGMENT pbuc1_derefidx_vbuyy=vbuaa
|
||||
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 PassNEliminateUnusedVars(program, true));
|
||||
optimizations.add(new Pass2EliminateUnusedBlocks(program));
|
||||
optimizations.add(new PassNEliminateEmptyProcedure(program));
|
||||
optimizations.add(new PassNEliminateEmptyStart(program));
|
||||
if(enableLoopHeadConstant) {
|
||||
optimizations.add(new PassNStatementIndices(program));
|
||||
|
@ -89,7 +89,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
// Statement outside procedure declaration - put into the _init procedure
|
||||
Procedure initProc = program.getScope().getLocalProcedure(SymbolRef.INIT_PROC_NAME);
|
||||
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<>());
|
||||
program.getScope().add(initProc);
|
||||
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) {
|
||||
Symbol unusedSymbol = getScope().getSymbol(unusedBlock);
|
||||
if(unusedSymbol instanceof Label) {
|
||||
getGraph().remove(unusedBlock);
|
||||
Label label = getScope().getLabel(unusedBlock);
|
||||
label.getScope().remove(label);
|
||||
removePhiRValues(unusedBlock);
|
||||
removePhiRValues(unusedBlock, getProgram());
|
||||
removedBlocks.add(unusedBlock);
|
||||
getLog().append("Removing unused block " + unusedBlock);
|
||||
} else if(unusedSymbol instanceof Procedure) {
|
||||
ProcedureRef unusedProcedureRef = ((Procedure) unusedSymbol).getRef();
|
||||
getLog().append("Removing unused procedure " + unusedProcedureRef);
|
||||
Procedure unusedProcedure = getProgram().getScope().getProcedure(unusedProcedureRef);
|
||||
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)) {
|
||||
removeProcedure(unusedProcedureRef, removedBlocks, getProgram());
|
||||
} else if(removedBlocks.contains(unusedBlock)) {
|
||||
// Already removed - we are happy!
|
||||
} else {
|
||||
throw new CompileError("Unable to remove unused block " + unusedBlock);
|
||||
@ -84,6 +75,25 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
|
||||
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
|
||||
*
|
||||
@ -104,9 +114,9 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
|
||||
*
|
||||
* @param removeBlock The block to remove from PHI RValues
|
||||
*/
|
||||
private void removePhiRValues(LabelRef removeBlock) {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
removePhiRValues(removeBlock, block, getLog());
|
||||
private static void removePhiRValues(LabelRef removeBlock, Program program) {
|
||||
for(ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
||||
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.SymbolRef;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
/** 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) {
|
||||
// Start only has a single call
|
||||
getProgram().setStartProcedure(singleCall.getProcedure());
|
||||
Pass1EliminateUncalledProcedures.removeProcedure(getProgram(), startProcRef);
|
||||
Pass2EliminateUnusedBlocks.removeProcedure(startProcRef, new HashSet<>(), getProgram());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ public class TestPrograms {
|
||||
|
||||
@Test
|
||||
public void testStaticInitCode2() throws IOException, URISyntaxException {
|
||||
compileAndCompare("static-init-code-2.c", log());
|
||||
compileAndCompare("static-init-code-2.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Loading…
Reference in New Issue
Block a user