mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-20 02:32:36 +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:
parent
c43ab3acef
commit
bebf020364
@ -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() {
|
||||
|
@ -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);
|
||||
|
@ -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)));
|
||||
|
1
src/dk/camelot64/kickc/asm/fragment/zpby1=yby.asm
Normal file
1
src/dk/camelot64/kickc/asm/fragment/zpby1=yby.asm
Normal file
@ -0,0 +1 @@
|
||||
sty {zpby1}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user