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

Implemented phi function completion loop.

This commit is contained in:
Jesper Gravgaard 2017-05-12 10:26:56 +02:00
parent 807198113b
commit 3b8580498b
3 changed files with 141 additions and 17 deletions

View File

@ -21,12 +21,16 @@ public class PassGenerateSingleStaticAssignmentForm {
public void generate() {
versionAllAssignments();
versionAllUses();
boolean done = false;
do {
System.out.println("Completing Phi functions...");
done = completePhiFunctions();
} while (!done);
}
/**
* Version all non-versioned non-intermediary being assigned a value.
*/
/** Version all non-versioned non-intermediary being assigned a value. */
private void versionAllAssignments() {
for (ControlFlowBlock block : controlFlowGraph.getAllBlocks()) {
for (Statement statement : block.getStatements()) {
@ -43,9 +47,7 @@ public class PassGenerateSingleStaticAssignmentForm {
}
}
/**
* Version all uses of non-versioned non-intermediary variables
*/
/** Version all uses of non-versioned non-intermediary variables */
private void versionAllUses() {
for (ControlFlowBlock block : controlFlowGraph.getAllBlocks()) {
// Newest version of variables in the block.
@ -82,6 +84,14 @@ public class PassGenerateSingleStaticAssignmentForm {
}
/**
* Find and return the latest version of an rValue (if it is a non-versioned symbol).
* If a version is needed and no version is found a new version is created as a phi-function.
* @param rValue The rValue to examine
* @param blockVersions The current version defined in the block for each symbol.
* @param blockNewPhis New versions to be created as phi-functions. Modified if a new phi-function needs to be created.
* @return Null if the rValue does not need versioning. The versioned symbol to use if it does.
*/
private Symbol findOrCreateVersion(RValue rValue, Map<Symbol, Symbol> blockVersions, Map<Symbol, Symbol> blockNewPhis) {
Symbol version = null;
if (rValue instanceof Symbol) {
@ -103,5 +113,94 @@ public class PassGenerateSingleStaticAssignmentForm {
return version;
}
/** Look through all new phi-functions and fill out their parameters.
* @return true if all phis were completely filled out.
* false if new phis were added , meaning another iteration is needed.
* */
private boolean completePhiFunctions() {
Map<ControlFlowBlock, Map<Symbol, Symbol>> newPhis = new HashMap<>();
Map<Symbol, Map<Symbol, Symbol>> symbolMap = buildSymbolMap();
for (ControlFlowBlock block : this.controlFlowGraph.getAllBlocks()) {
for (Statement statement : block.getStatements()) {
if (statement instanceof StatementPhi) {
StatementPhi phi = (StatementPhi) statement;
if (phi.getPreviousVersions().isEmpty()) {
Symbol versioned = phi.getlValue();
Symbol unversioned = versioned.getVersionOf();
for (ControlFlowBlock predecessor : block.getPredecessors()) {
Symbol previousSymbol = symbolMap.get(predecessor.getLabel()).get(unversioned);
if (previousSymbol == null) {
// No previous symbol found in predecessor block. Look in new a phi functions.
Map<Symbol, Symbol> predecessorNewPhis = newPhis.get(predecessor);
if (predecessorNewPhis == null) {
predecessorNewPhis = new HashMap<>();
newPhis.put(predecessor, predecessorNewPhis);
}
previousSymbol = predecessorNewPhis.get(unversioned);
if (previousSymbol == null) {
// No previous symbol found in predecessor block. Add a new phi function to the predecessor.
previousSymbol = symbols.createVersion(unversioned);
predecessorNewPhis.put(unversioned, previousSymbol);
}
}
phi.addPreviousVersion(predecessor, previousSymbol);
}
}
}
}
}
// Ads new phi functions to blocks
for (ControlFlowBlock block : controlFlowGraph.getAllBlocks()) {
Map<Symbol, Symbol> blockNewPhis = newPhis.get(block);
if(blockNewPhis!=null) {
for (Symbol symbol : blockNewPhis.keySet()) {
block.addPhiStatement(blockNewPhis.get(symbol));
}
}
}
return (newPhis.size()==0);
}
/**
* Builds a map of all which versions each symbol has in each block.
* Maps Control Flow Block Label -> ( Unversioned Symbol -> Versioned Symbol) for all relevant symbols.
*/
private Map<Symbol, Map<Symbol, Symbol>> buildSymbolMap() {
Map<Symbol, Map<Symbol, Symbol>> symbolMap = new HashMap<>();
for (ControlFlowBlock block : this.controlFlowGraph.getAllBlocks()) {
for (Statement statement : block.getStatements()) {
if(statement instanceof StatementAssignment) {
StatementAssignment assignment = (StatementAssignment) statement;
LValue lValue = assignment.getlValue();
if(lValue instanceof Symbol) {
Symbol symbol = (Symbol) lValue;
if(symbol.isVersioned()) {
Symbol label = block.getLabel();
Symbol unversioned = symbol.getVersionOf();
Symbol versioned = symbol;
Map<Symbol, Symbol> blockMap = symbolMap.get(label);
if(blockMap == null) {
blockMap = new HashMap<>();
symbolMap.put(label, blockMap);
}
blockMap.put(unversioned, versioned);
}
}
} else if(statement instanceof StatementPhi) {
StatementPhi phi = (StatementPhi) statement;
Symbol versioned = phi.getlValue();
Symbol unversioned = versioned.getVersionOf();
Symbol label = block.getLabel();
Map<Symbol, Symbol> blockMap = symbolMap.get(label);
if(blockMap == null) {
blockMap = new HashMap<>();
symbolMap.put(label, blockMap);
}
blockMap.put(unversioned, versioned);
}
}
} return symbolMap;
}
}

View File

@ -15,23 +15,46 @@ public class StatementPhi implements Statement {
private Symbol lValue;
/** The previous version of the symbol from predeccesor control blocks. */
private List<Symbol> previousVersions;
private List<PreviousSymbol> previousVersions;
public StatementPhi(Symbol lValue) {
this.lValue = lValue;
this.previousVersions = new ArrayList<>();
}
public LValue getlValue() {
/**
* A previous version of the symbol that the phi function might take its value from.
* Which value is chosen depends on which block transition was made.
*/
public static class PreviousSymbol {
private ControlFlowBlock block;
private Symbol symbol;
public PreviousSymbol(ControlFlowBlock block, Symbol symbol) {
this.block = block;
this.symbol = symbol;
}
public ControlFlowBlock getBlock() {
return block;
}
public Symbol getSymbol() {
return symbol;
}
}
public Symbol getlValue() {
return lValue;
}
public void addPreviousVersion(Symbol previousVersion) {
previousVersions.add(previousVersion);
public void addPreviousVersion(ControlFlowBlock block, Symbol symbol) {
previousVersions.add(new PreviousSymbol(block, symbol));
}
public List<Symbol> getPreviousVersions() {
public List<PreviousSymbol> getPreviousVersions() {
return previousVersions;
}
@ -39,8 +62,8 @@ public class StatementPhi implements Statement {
public String toString() {
StringBuilder out = new StringBuilder();
out.append(lValue + "" + "phi(");
for (Symbol previousVersion : previousVersions) {
out.append(" "+previousVersion.toString());
for (PreviousSymbol previousSymbol : previousVersions) {
out.append(" "+previousSymbol.getBlock().getLabel().getName()+"/"+previousSymbol.getSymbol().getName());
}
out.append(" )");
return out.toString();

View File

@ -1,7 +1,6 @@
package dk.camelot64.kickc.icl;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.*;
/**
* Manages symbols (variables, labels)
@ -58,7 +57,10 @@ public class SymbolManager {
@Override
public String toString() {
StringBuffer out = new StringBuffer();
for (String name : symbols.keySet()) {
Set<String> names = symbols.keySet();
List<String> sortedNames = new ArrayList<>(names);
Collections.sort(sortedNames);
for (String name : sortedNames) {
Symbol symbol = symbols.get(name);
out.append(symbol.toString() + "\n");
}