1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-10-11 12:23:45 +00:00

Improved phi lifting by introducing new blocks when lifting back to blocks with conditional jumps. Improved sequence planner to ensure blocks in the same scopes are kept together.

This commit is contained in:
jespergravgaard 2017-07-26 15:09:00 +02:00
parent c43ab3acef
commit bebf020364
7 changed files with 126 additions and 30 deletions

View File

@ -12,7 +12,7 @@ public class CompileLog {
public void append(String msg) {
log.append(msg);
log.append("\n");
//System.out.printf(msg+"\n");
System.out.printf(msg+"\n");
}
public StringBuilder getLog() {

View File

@ -101,19 +101,20 @@ public class Compiler {
Pass3BlockSequencePlanner pass3BlockSequencePlanner = new Pass3BlockSequencePlanner(program, log);
pass3BlockSequencePlanner.plan();
//Pass3PhiLifting pass3PhiLifting = new Pass3PhiLifting(program, log);
//pass3PhiLifting.perform();
Pass3PhiLifting pass3PhiLifting = new Pass3PhiLifting(program, log);
pass3PhiLifting.perform();
pass3BlockSequencePlanner.plan();
log.append("CONTROL FLOW GRAPH - PHI LIFTED");
log.append(program.getGraph().toString(program.getScope()));
pass2AssertSSA(program, log);
Pass3IdentifyAliveRanges pass3IdentifyAliveRanges = new Pass3IdentifyAliveRanges(program, log);
pass3IdentifyAliveRanges.findLiveRanges();
log.append("CONTROL FLOW GRAPH - LIVE RANGES");
log.append(program.getGraph().toString(program.getScope()));
log.append("SYMBOLS - LIVE RANGES");
log.append(program.getScope().getSymbolTableContents());
pass2AssertSSA(program, log);
}
@ -127,15 +128,9 @@ public class Compiler {
optimizations.add(new Pass2SelfPhiElimination(program, log));
optimizations.add(new Pass2ConditionalJumpSimplification(program, log));
List<Pass2SsaAssertion> assertions = new ArrayList<>();
assertions.add(new Pass2AssertSymbols(program));
assertions.add(new Pass2AssertBlocks(program));
boolean ssaOptimized = true;
while (ssaOptimized) {
for (Pass2SsaAssertion assertion : assertions) {
assertion.check();
}
pass2AssertSSA(program, log);
ssaOptimized = false;
for (Pass2SsaOptimization optimization : optimizations) {
boolean stepOptimized = optimization.optimize();
@ -149,6 +144,15 @@ public class Compiler {
}
}
public void pass2AssertSSA(Program program, CompileLog log) {
List<Pass2SsaAssertion> assertions = new ArrayList<>();
assertions.add(new Pass2AssertSymbols(program));
assertions.add(new Pass2AssertBlocks(program));
for (Pass2SsaAssertion assertion : assertions) {
assertion.check();
}
}
public Program pass1GenerateSSA(KickCParser.FileContext file, CompileLog log) {
Pass1GenerateStatementSequence pass1GenerateStatementSequence1 = new Pass1GenerateStatementSequence(log);
pass1GenerateStatementSequence1.generate(file);

View File

@ -137,9 +137,11 @@ public class AsmFragment {
signature.append("_then_");
LabelRef destination = conditionalJump.getDestination();
ControlFlowBlock destinationBlock = graph.getBlock(destination);
String destinationLabel = destination.getFullName();
String destinationLabel;
if (destinationBlock.hasPhiBlock()) {
destinationLabel = (destinationBlock.getLabel().getLocalName() + "_from_" + block.getLabel().getLocalName()).replace('@', 'B').replace(':','_');
} else {
destinationLabel = destination.getLocalName();
}
Symbol destSymbol = symbols.getSymbol(destination);
signature.append(bind(new Label(destinationLabel, destSymbol.getScope(),false)));

View File

@ -0,0 +1 @@
sty {zpby1}

View File

@ -33,6 +33,10 @@ public class ControlFlowGraph {
return blocks.get(symbol);
}
public void addBlock(ControlFlowBlock block) {
blocks.put(block.getLabel(), block);
}
@JsonIgnore
public ControlFlowBlock getFirstBlock() {
return getBlock(firstBlockRef);
@ -170,4 +174,5 @@ public class ControlFlowGraph {
result = 31 * result + (sequence != null ? sequence.hashCode() : 0);
return result;
}
}

View File

@ -3,9 +3,7 @@ package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.CompileLog;
import dk.camelot64.kickc.icl.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.*;
/** Plan the optimal sequence for the blocks of the control flow graph */
public class Pass3BlockSequencePlanner {
@ -21,15 +19,14 @@ public class Pass3BlockSequencePlanner {
}
public void plan() {
Stack<ControlFlowBlock> todo = new Stack<>();
ControlFlowBlock mainBlock = graph.getMainBlock();
if (mainBlock != null) {
todo.push(mainBlock);
pushTodo(mainBlock);
}
todo.push(graph.getFirstBlock());
pushTodo(graph.getFirstBlock());
List<LabelRef> sequence = new ArrayList<>();
while(!todo.empty()){
ControlFlowBlock block = todo.pop();
while(hasTodo()){
ControlFlowBlock block = popTodo();
if(block==null) {
break;
}
@ -39,14 +36,15 @@ public class Pass3BlockSequencePlanner {
}
sequence.add(block.getLabel());
if(block.getCallSuccessor()!=null) {
todo.push(graph.getCallSuccessor(block));
pushTodo(graph.getCallSuccessor(block));
}
if(block.getConditionalSuccessor()!=null) {
todo.push(graph.getConditionalSuccessor(block));
pushTodo(graph.getConditionalSuccessor(block));
}
if(graph.getDefaultSuccessor(block)!=null) {
todo.push(graph.getDefaultSuccessor(block));
pushTodo(graph.getDefaultSuccessor(block));
}
}
graph.setSequence(sequence);
@ -57,6 +55,53 @@ public class Pass3BlockSequencePlanner {
}
log.append(entry.toString());
}
Deque<ScopeTodo> todoScopes = new ArrayDeque<>();
void pushTodo(ControlFlowBlock block) {
LabelRef blockRef = block.getLabel();
Scope blockScope = this.scope.getSymbol(blockRef).getScope();
for (ScopeTodo todoScope : todoScopes) {
if(todoScope.scope.equals(blockScope)) {
todoScope.addTodo(block);
return;
}
}
ScopeTodo newScopeTodo = new ScopeTodo(blockScope);
todoScopes.push(newScopeTodo);
newScopeTodo.addTodo(block);
}
boolean hasTodo() {
return !todoScopes.isEmpty();
}
ControlFlowBlock popTodo() {
ScopeTodo scopeTodo = todoScopes.peek();
ControlFlowBlock block = scopeTodo.todo.pop();
if(scopeTodo.todo.isEmpty()) {
todoScopes.pop();
}
return block;
}
private static class ScopeTodo {
Scope scope;
Stack<ControlFlowBlock> todo;
public ScopeTodo(Scope scope) {
this.scope = scope;
this.todo = new Stack<>();
}
public void addTodo(ControlFlowBlock block) {
todo.push(block);
}
}
}

View File

@ -4,7 +4,9 @@ import dk.camelot64.kickc.CompileLog;
import dk.camelot64.kickc.icl.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Perform PhiLifting to greatly reduce overlapping of alive intervals for variables.
@ -29,6 +31,8 @@ public class Pass3PhiLifting {
ProgramScope programScope = program.getScope();
Collection<ControlFlowBlock> blocks = graph.getAllBlocks();
for (ControlFlowBlock block : blocks) {
// Maps old predecessors to new blocks created
Map<LabelRef, LabelRef> newBlocks = new HashMap<>();
if (block.hasPhiBlock()) {
StatementPhiBlock phiBlock = block.getPhiBlock();
for (StatementPhiBlock.PhiVariable phiVariable : phiBlock.getPhiVariables()) {
@ -36,20 +40,55 @@ public class Pass3PhiLifting {
if (!(phiRValue.getrValue() instanceof Constant)) {
LabelRef predecessorRef = phiRValue.getPredecessor();
ControlFlowBlock predecessorBlock = graph.getBlock(predecessorRef);
Symbol predecessorSymbol = programScope.getSymbol(predecessorRef);
VariableIntermediate newVar = predecessorSymbol.getScope().addVariableIntermediate();
VariableRef rValVarRef = (VariableRef) phiRValue.getrValue();
Variable newVar;
if(rValVarRef.isVersion()) {
Variable rValVar = program.getScope().getVariable(rValVarRef);
newVar = ((VariableVersion) rValVar).getVersionOf().createVersion();
} else {
Symbol predecessorSymbol = programScope.getSymbol(predecessorRef);
newVar = predecessorSymbol.getScope().addVariableIntermediate();
}
Symbol phiLValue = programScope.getSymbol(phiVariable.getVariable());
newVar.setType(phiLValue.getType());
newVar.setInferredType(true);
List<Statement> predecessorStatements = predecessorBlock.getStatements();
Statement lastPredecessorStatement = predecessorStatements.get(predecessorStatements.size() - 1);
StatementAssignment newAssignment = new StatementAssignment(newVar, phiRValue.getrValue());
if (lastPredecessorStatement instanceof StatementConditionalJump || lastPredecessorStatement instanceof StatementCall) {
predecessorStatements.add(predecessorStatements.size() - 1, newAssignment);
if (lastPredecessorStatement instanceof StatementConditionalJump) {
// Use or Create a new block between the predecessor and this one - replace labels where appropriate
ControlFlowBlock newBlock;
LabelRef newBlockRef = newBlocks.get(predecessorRef);
if(newBlockRef==null) {
// Create new block
LabelRef currentBlockLabel = block.getLabel();
Scope currentScope = programScope.getSymbol(currentBlockLabel).getScope();
Label newBlockLabel = currentScope.addLabelIntermediate();
newBlock = new ControlFlowBlock(newBlockLabel.getRef());
graph.addBlock(newBlock);
newBlock.setDefaultSuccessor(block.getLabel());
newBlocks.put(predecessorRef, newBlock.getLabel());
StatementConditionalJump previousConditionalJump = (StatementConditionalJump) lastPredecessorStatement;
LabelRef previousConditionalDestination = previousConditionalJump.getDestination();
if(block.getLabel().equals(previousConditionalDestination)) {
previousConditionalJump.setDestination(newBlock.getLabel());
predecessorBlock.setConditionalSuccessor(newBlock.getLabel());
}
if(block.getLabel().equals(predecessorBlock.getDefaultSuccessor())) {
predecessorBlock.setDefaultSuccessor(newBlock.getLabel());
}
log.append("Added new block during phi lifting "+newBlock.getLabel() + "(between "+predecessorRef+" and "+block.getLabel()+")");
} else {
newBlock = graph.getBlock(newBlockRef);
}
List<Statement> newBlockStatements = newBlock.getStatements();
newBlockStatements.add(newAssignment);
phiRValue.setrValue(newVar.getRef());
phiRValue.setPredecessor(newBlock.getLabel());
} else {
predecessorBlock.addStatement(newAssignment);
phiRValue.setrValue(newVar.getRef());
}
phiRValue.setrValue(newVar.getRef());
}
}
}