1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-08-03 01:29:04 +00:00

Working on static initialization rewrite _init(). #257

This commit is contained in:
jespergravgaard 2020-06-19 01:23:34 +02:00
parent dc4102d680
commit 5779f3169b
8 changed files with 1688 additions and 20 deletions

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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));

View File

@ -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());

View File

@ -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());
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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