mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-28 11:51:09 +00:00
#815 working on generalizing the control flow graph and control flow block into an interface.
This commit is contained in:
parent
5a74d14b41
commit
416184894f
@ -2,7 +2,6 @@ package dk.camelot64.kickc.model;
|
||||
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
import dk.camelot64.kickc.model.values.ProcedureRef;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@ -103,55 +102,4 @@ public class ControlFlowGraph implements Graph {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all statements executed between two statements (none of these are included in the result)
|
||||
*
|
||||
* @param from The statement to start at
|
||||
* @param to The statement to end at
|
||||
* @return All statements executed between the two passed statements
|
||||
*/
|
||||
public Collection<Statement> getStatementsBetween(Statement from, Statement to, StatementInfos statementInfos) {
|
||||
Collection<Statement> between = new LinkedHashSet<>();
|
||||
final Graph.Block block = statementInfos.getBlock(from);
|
||||
populateStatementsBetween(from, to, false, between, block);
|
||||
return between;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the between collection with all statements executed between two statements (none of these are included in the result)
|
||||
*
|
||||
* @param from The statement to start at
|
||||
* @param to The statement to end at
|
||||
* @param between The between collection
|
||||
* @param block The block to start from
|
||||
*/
|
||||
private void populateStatementsBetween(Statement from, Statement to, boolean isBetween, Collection<Statement> between, Graph.Block block) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(between.contains(statement))
|
||||
// Stop infinite recursion
|
||||
return;
|
||||
if(isBetween) {
|
||||
if(statement.equals(to))
|
||||
// The end was reached!
|
||||
isBetween = false;
|
||||
else
|
||||
// We are between - add the statement
|
||||
between.add(statement);
|
||||
} else {
|
||||
if(statement.equals(from))
|
||||
// We are now between!
|
||||
isBetween = true;
|
||||
}
|
||||
}
|
||||
if(isBetween) {
|
||||
// Recurse to successor blocks
|
||||
final Collection<LabelRef> successors = block.getSuccessors();
|
||||
for(LabelRef successor : successors) {
|
||||
if(successor.getFullName().equals(ProcedureRef.PROCEXIT_BLOCK_NAME))
|
||||
continue;
|
||||
final ControlFlowBlock successorBlock = getBlock(successor);
|
||||
populateStatementsBetween(from, to, true, between, successorBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -157,6 +157,22 @@ public interface Graph {
|
||||
return successors;
|
||||
}
|
||||
|
||||
public List<Comment> getComments();
|
||||
|
||||
void setComments(List<Comment> comments);
|
||||
|
||||
void setDefaultSuccessor(LabelRef defaultSuccessor);
|
||||
|
||||
void setConditionalSuccessor(LabelRef conditionalSuccessor);
|
||||
|
||||
void setCallSuccessor(LabelRef callSuccessor);
|
||||
|
||||
void addStatement(Statement statement);
|
||||
|
||||
void addStatementAfter(Statement newStatement, Statement predecessor);
|
||||
|
||||
void addStatementBeforeCall(Statement newStatement);
|
||||
|
||||
|
||||
String toString(Program program, Graph graph);
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import dk.camelot64.kickc.model.statements.*;
|
||||
import java.util.Collection;
|
||||
|
||||
/** Base visitor for iterating through a control flow graph */
|
||||
public class ControlFlowGraphBaseVisitor<T> {
|
||||
public class GraphBaseVisitor<T> {
|
||||
|
||||
public T visitGraph(Graph graph) {
|
||||
Collection<Graph.Block> blocks = graph.getAllBlocks();
|
@ -0,0 +1,62 @@
|
||||
package dk.camelot64.kickc.model;
|
||||
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
import dk.camelot64.kickc.model.values.ProcedureRef;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
public class StatementsBetween {
|
||||
/**
|
||||
* Get all statements executed between two statements (none of these are included in the result)
|
||||
*
|
||||
* @param from The statement to start at
|
||||
* @param to The statement to end at
|
||||
* @return All statements executed between the two passed statements
|
||||
*/
|
||||
public static Collection<Statement> find(Statement from, Graph.Block fromBlock, Statement to, Graph graph) {
|
||||
Collection<Statement> between = new LinkedHashSet<>();
|
||||
populateStatementsBetween(fromBlock, from, to, false, between, graph);
|
||||
return between;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the between collection with all statements executed between two statements (none of these are included in the result)
|
||||
*
|
||||
* @param block The block to start from
|
||||
* @param from The statement where we start counting (not included)
|
||||
* @param to The statement to end at (not included)
|
||||
* @param isBetween Are we already between from and to?
|
||||
* @param between The between collection, being populated
|
||||
*/
|
||||
private static void populateStatementsBetween(Graph.Block block, Statement from, Statement to, boolean isBetween, Collection<Statement> between, Graph graph) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(between.contains(statement))
|
||||
// Stop infinite recursion
|
||||
return;
|
||||
if(isBetween) {
|
||||
if(statement.equals(to))
|
||||
// The end was reached!
|
||||
isBetween = false;
|
||||
else
|
||||
// We are between - add the statement
|
||||
between.add(statement);
|
||||
} else {
|
||||
if(statement.equals(from))
|
||||
// We are now between!
|
||||
isBetween = true;
|
||||
}
|
||||
}
|
||||
if(isBetween) {
|
||||
// Recurse to successor blocks
|
||||
final Collection<LabelRef> successors = block.getSuccessors();
|
||||
for(LabelRef successor : successors) {
|
||||
if(successor.getFullName().equals(ProcedureRef.PROCEXIT_BLOCK_NAME))
|
||||
continue;
|
||||
final Graph.Block successorBlock = graph.getBlock(successor);
|
||||
populateStatementsBetween(successorBlock, from, to, true, between, graph);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -33,7 +33,7 @@ public class Pass2AssertBlocks extends Pass2SsaAssertion {
|
||||
}
|
||||
}
|
||||
|
||||
private static class BlockReferenceChecker extends ControlFlowGraphBaseVisitor<Void> {
|
||||
private static class BlockReferenceChecker extends GraphBaseVisitor<Void> {
|
||||
|
||||
Set<LabelRef> seenBlocks;
|
||||
private Graph graph;
|
||||
|
@ -1,6 +1,6 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowGraphBaseVisitor;
|
||||
import dk.camelot64.kickc.model.GraphBaseVisitor;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.StatementCall;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
@ -15,7 +15,7 @@ public class Pass2AssertNoCallLvalues extends Pass2SsaAssertion {
|
||||
@Override
|
||||
public void check() throws AssertionFailed {
|
||||
|
||||
ControlFlowGraphBaseVisitor<Void> checkCalls = new ControlFlowGraphBaseVisitor<Void>() {
|
||||
GraphBaseVisitor<Void> checkCalls = new GraphBaseVisitor<Void>() {
|
||||
@Override
|
||||
public Void visitCall(StatementCall call) {
|
||||
Procedure procedure = getScope().getProcedure(call.getProcedure());
|
||||
|
@ -1,6 +1,6 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowGraphBaseVisitor;
|
||||
import dk.camelot64.kickc.model.GraphBaseVisitor;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.StatementCall;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
@ -17,7 +17,7 @@ public class Pass2AssertNoCallParameters extends Pass2SsaAssertion {
|
||||
|
||||
@Override
|
||||
public void check() throws AssertionFailed {
|
||||
ControlFlowGraphBaseVisitor<Void> checkCalls = new ControlFlowGraphBaseVisitor<Void>() {
|
||||
GraphBaseVisitor<Void> checkCalls = new GraphBaseVisitor<Void>() {
|
||||
@Override
|
||||
public Void visitCall(StatementCall call) {
|
||||
Procedure procedure = getScope().getProcedure(call.getProcedure());
|
||||
|
@ -1,6 +1,6 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowGraphBaseVisitor;
|
||||
import dk.camelot64.kickc.model.GraphBaseVisitor;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.StatementLabel;
|
||||
|
||||
@ -14,7 +14,7 @@ public class Pass2AssertNoLabels extends Pass2SsaAssertion {
|
||||
@Override
|
||||
public void check() throws AssertionFailed {
|
||||
|
||||
ControlFlowGraphBaseVisitor<Void> checkCalls = new ControlFlowGraphBaseVisitor<Void>() {
|
||||
GraphBaseVisitor<Void> checkCalls = new GraphBaseVisitor<Void>() {
|
||||
|
||||
@Override
|
||||
public Void visitJumpTarget(StatementLabel jumpTarget) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowGraphBaseVisitor;
|
||||
import dk.camelot64.kickc.model.GraphBaseVisitor;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.StatementProcedureBegin;
|
||||
import dk.camelot64.kickc.model.statements.StatementProcedureEnd;
|
||||
@ -15,7 +15,7 @@ public class Pass2AssertNoProcs extends Pass2SsaAssertion {
|
||||
@Override
|
||||
public void check() throws AssertionFailed {
|
||||
|
||||
ControlFlowGraphBaseVisitor<Void> checkCalls = new ControlFlowGraphBaseVisitor<Void>() {
|
||||
GraphBaseVisitor<Void> checkCalls = new GraphBaseVisitor<Void>() {
|
||||
|
||||
@Override
|
||||
public Void visitProcedureBegin(StatementProcedureBegin procedureBegin) {
|
||||
|
@ -120,14 +120,14 @@ public class Pass2ConditionalJumpSimplification extends Pass2SsaOptimization {
|
||||
// Found referenced load/store variables
|
||||
// Examine all statements between the conditionAssignment and conditionalJump for modifications
|
||||
final StatementInfos statementInfos = getProgram().getStatementInfos();
|
||||
Collection<Statement> statementsBetween = getGraph().getStatementsBetween(simpleCondition.conditionAssignment, simpleCondition.conditionalJump, statementInfos);
|
||||
final Graph.Block conditionDefineBlock = statementInfos.getBlock(simpleCondition.conditionAssignment);
|
||||
Collection<Statement> statementsBetween = StatementsBetween.find(simpleCondition.conditionAssignment, conditionDefineBlock, simpleCondition.conditionalJump, getGraph());
|
||||
for(Statement statementBetween : statementsBetween) {
|
||||
for(Variable referencedLoadStoreVariable : referencedLoadStoreVariables) {
|
||||
if(variableReferenceInfos.getDefinedVars(statementBetween).contains(referencedLoadStoreVariable.getVariableRef())) {
|
||||
// A referenced load/store-variable is modified in a statement between the assignment and the condition!
|
||||
getLog().append("Condition not simple " + simpleCondition.conditionVar.toString(getProgram()) + " " + simpleCondition.conditionalJump.toString(getProgram(), false));
|
||||
// Create an intermediate variable copy of the load/store-variable at the position of the condition-variable to preserve the value
|
||||
final Graph.Block conditionDefineBlock = statementInfos.getBlock(simpleCondition.conditionAssignment);
|
||||
final ScopeRef conditionDefineScopeRef = conditionDefineBlock.getScope();
|
||||
final Scope conditionDefineScope = getProgramScope().getScope(conditionDefineScopeRef);
|
||||
SymbolType typeQualified = referencedLoadStoreVariable.getType().getQualified(false, referencedLoadStoreVariable.getType().isNomodify());
|
||||
|
@ -103,8 +103,8 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
|
||||
*/
|
||||
private Set<LabelRef> getReferencedBlocks() {
|
||||
Set<LabelRef> referencedBlocks = new LinkedHashSet<>();
|
||||
List<ControlFlowBlock> entryPointBlocks = getProgram().getEntryPointBlocks();
|
||||
for(ControlFlowBlock entryPointBlock : entryPointBlocks) {
|
||||
List<Graph.Block> entryPointBlocks = getProgram().getEntryPointBlocks();
|
||||
for(var entryPointBlock : entryPointBlocks) {
|
||||
findReferencedBlocks(entryPointBlock, referencedBlocks);
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ public abstract class Pass2SsaOptimization extends Pass1Base implements PassStep
|
||||
* @param replacements Variables that have alias values.
|
||||
*/
|
||||
public void replaceLabels(Graph.Block block, final Map<LabelRef, LabelRef> replacements) {
|
||||
ControlFlowGraphBaseVisitor<Void> visitor = getLabelReplaceVisitor(replacements);
|
||||
GraphBaseVisitor<Void> visitor = getLabelReplaceVisitor(replacements);
|
||||
visitor.visitBlock(block);
|
||||
}
|
||||
|
||||
@ -67,13 +67,13 @@ public abstract class Pass2SsaOptimization extends Pass1Base implements PassStep
|
||||
* @param replacements Variables that have alias values.
|
||||
*/
|
||||
public void replaceLabels(Statement statement, final Map<LabelRef, LabelRef> replacements) {
|
||||
ControlFlowGraphBaseVisitor<Void> visitor = getLabelReplaceVisitor(replacements);
|
||||
GraphBaseVisitor<Void> visitor = getLabelReplaceVisitor(replacements);
|
||||
visitor.visitStatement(statement);
|
||||
}
|
||||
|
||||
/** Creates a visitor that can replace labels. */
|
||||
private ControlFlowGraphBaseVisitor<Void> getLabelReplaceVisitor(final Map<LabelRef, LabelRef> replacements) {
|
||||
return new ControlFlowGraphBaseVisitor<Void>() {
|
||||
private GraphBaseVisitor<Void> getLabelReplaceVisitor(final Map<LabelRef, LabelRef> replacements) {
|
||||
return new GraphBaseVisitor<Void>() {
|
||||
|
||||
@Override
|
||||
public Void visitConditionalJump(StatementConditionalJump conditionalJump) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowGraphBaseVisitor;
|
||||
import dk.camelot64.kickc.model.GraphBaseVisitor;
|
||||
import dk.camelot64.kickc.model.LiveRangeEquivalenceClass;
|
||||
import dk.camelot64.kickc.model.LiveRangeEquivalenceClassSet;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
@ -52,7 +52,7 @@ public class Pass3PhiMemCoalesce extends Pass2SsaOptimization {
|
||||
/**
|
||||
* Creates initial live range equivalence classes from program phi statements.
|
||||
*/
|
||||
public static class EquivalenceClassPhiInitializer extends ControlFlowGraphBaseVisitor<Void> {
|
||||
public static class EquivalenceClassPhiInitializer extends GraphBaseVisitor<Void> {
|
||||
|
||||
private Program program;
|
||||
|
||||
@ -99,7 +99,7 @@ public class Pass3PhiMemCoalesce extends Pass2SsaOptimization {
|
||||
}
|
||||
|
||||
/** Coalesces phi equivalence classes when they do not overlap based on assignments to variables in phi statements. */
|
||||
private class PhiMemCoalescer extends ControlFlowGraphBaseVisitor<Void> {
|
||||
private class PhiMemCoalescer extends GraphBaseVisitor<Void> {
|
||||
|
||||
private LiveRangeEquivalenceClassSet phiEquivalenceClassSet;
|
||||
private List<VariableRef> remove;
|
||||
|
@ -109,7 +109,7 @@ public class Pass4LiveRangeEquivalenceClassesFinalize extends Pass2Base {
|
||||
/**
|
||||
* Add all variables to a non-overlapping equivalence or create a new one.
|
||||
*/
|
||||
private class EquivalenceClassAdder extends ControlFlowGraphBaseVisitor<Void> {
|
||||
private class EquivalenceClassAdder extends GraphBaseVisitor<Void> {
|
||||
|
||||
private LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet;
|
||||
|
||||
|
@ -20,9 +20,9 @@ public class PassNBlockSequencePlanner extends Pass2SsaOptimization {
|
||||
@Override
|
||||
public boolean step() {
|
||||
|
||||
List<ControlFlowBlock> entryPointBlocks = getProgram().getEntryPointBlocks();
|
||||
List<Graph.Block> entryPointBlocks = getProgram().getEntryPointBlocks();
|
||||
|
||||
for(ControlFlowBlock entryPointBlock : entryPointBlocks) {
|
||||
for(var entryPointBlock : entryPointBlocks) {
|
||||
pushTodo(entryPointBlock);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.ControlFlowGraphBaseVisitor;
|
||||
import dk.camelot64.kickc.model.GraphBaseVisitor;
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
|
||||
@ -62,7 +61,7 @@ public class PassNCullEmptyBlocks extends Pass2SsaOptimization {
|
||||
continue;
|
||||
|
||||
// In all phi functions of a successor blocks make a copy of the phi assignment for each predecessor
|
||||
ControlFlowGraphBaseVisitor<Void> phiFixVisitor = new ControlFlowGraphBaseVisitor<Void>() {
|
||||
GraphBaseVisitor<Void> phiFixVisitor = new GraphBaseVisitor<Void>() {
|
||||
@Override
|
||||
public Void visitPhiBlock(StatementPhiBlock phi) {
|
||||
for(StatementPhiBlock.PhiVariable phiVariable : phi.getPhiVariables()) {
|
||||
|
Loading…
Reference in New Issue
Block a user