1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-08-02 09:29:35 +00:00

Eliminated AliasReplacers separate implementation of the execution. Now using a clean ValueReplacer. Also fixed Pass1GenerateSSA to use a clean ValueReplacer.

This commit is contained in:
Jesper Gravgaard 2018-07-22 14:14:15 +09:00
parent f9449997cb
commit a14fa4dec3
6 changed files with 182 additions and 146 deletions

View File

@ -1,10 +1,10 @@
package dk.camelot64.kickc.model.iterator;
import dk.camelot64.kickc.model.statements.*;
import dk.camelot64.kickc.model.symbols.ConstantVar;
import dk.camelot64.kickc.model.types.SymbolTypeArray;
import dk.camelot64.kickc.model.values.*;
import java.util.Collection;
/**
* Interface representing an RValue that can be replaced.
* The value may have sub-values that can also be replaced.
@ -15,6 +15,45 @@ public abstract class ReplaceableValue {
public abstract void set(RValue value);
public static class ConstantVariableValue extends ReplaceableValue {
private final ConstantVar constantVar;
public ConstantVariableValue(ConstantVar constantVar) {
this.constantVar = constantVar;
}
@Override
public RValue get() {
return constantVar.getValue();
}
@Override
public void set(RValue val) {
constantVar.setValue((ConstantValue) val);
}
}
/** Replaceable size inside a fixed size array. */
public static class TypeArraySize extends ReplaceableValue {
private final SymbolTypeArray array;
public TypeArraySize(SymbolTypeArray array) {
this.array = array;
}
@Override
public RValue get() {
return array.getSize();
}
@Override
public void set(RValue val) {
array.setSize(val);
}
}
/** Replaceable value inside a array filled expression. */
public static class ArrayFilledSize extends ReplaceableValue {
private final ArrayFilled array;
@ -272,6 +311,26 @@ public abstract class ReplaceableValue {
}
public static class ConstantArrayElement extends ReplaceableValue {
private final ConstantArrayList arrayList;
private final int idx;
public ConstantArrayElement(ConstantArrayList arrayList, int idx) {
this.arrayList = arrayList;
this.idx = idx;
}
@Override
public RValue get() {
return arrayList.getElements().get(idx);
}
@Override
public void set(RValue value) {
arrayList.getElements().set(idx, (ConstantValue) value);
}
}
public static class ListElement extends ReplaceableValue {
private ValueList list;
private int idx;
@ -466,4 +525,23 @@ public abstract class ReplaceableValue {
}
}
/** A generic replaceable value. */
public static class GenericValue extends ReplaceableValue {
private ConstantValue constantValue;
public GenericValue(ConstantValue constantValue) {
this.constantValue = constantValue;
}
@Override
public RValue get() {
return constantValue;
}
@Override
public void set(RValue value) {
this.constantValue = (ConstantValue) value;
}
}
}

View File

@ -21,11 +21,21 @@ public class ValueReplacer {
*/
public static void executeAll(ControlFlowGraph graph, Replacer replacer) {
for(ControlFlowBlock block : graph.getAllBlocks()) {
ListIterator<Statement> statementsIt = block.getStatements().listIterator();
while(statementsIt.hasNext()) {
Statement statement = statementsIt.next();
executeAll(statement, replacer, statementsIt, block);
}
executeAll(block, replacer);
}
}
/**
* Execute a replacer on all replaceable values in a block of the control flow graph
*
* @param block The control flow graph block
* @param replacer The replacer to execute
*/
public static void executeAll(ControlFlowBlock block, Replacer replacer) {
ListIterator<Statement> statementsIt = block.getStatements().listIterator();
while(statementsIt.hasNext()) {
Statement statement = statementsIt.next();
executeAll(statement, replacer, statementsIt, block);
}
}
@ -37,11 +47,11 @@ public class ValueReplacer {
*/
public static void executeAll(Statement statement, Replacer replacer, ListIterator<Statement> statementsIt, ControlFlowBlock block) {
if(statement instanceof StatementAssignment) {
executeAll(new ReplaceableValue.LValue((StatementLValue) statement), replacer, statement, statementsIt, block);
// The sequence RValue1, RValue2, LValue is important - as it is essential for {@link dk.camelot64.kickc.passes.Pass1GenerateSingleStaticAssignmentForm} to create the correct SSA
executeAll(new ReplaceableValue.RValue1((StatementAssignment) statement), replacer, statement, statementsIt, block);
executeAll(new ReplaceableValue.RValue2((StatementAssignment) statement), replacer, statement, statementsIt, block);
} else if(statement instanceof StatementCall) {
executeAll(new ReplaceableValue.LValue((StatementLValue) statement), replacer, statement, statementsIt, block);
} else if(statement instanceof StatementCall) {
StatementCall call = (StatementCall) statement;
if(call.getParameters() != null) {
int size = call.getParameters().size();
@ -49,6 +59,7 @@ public class ValueReplacer {
executeAll(new ReplaceableValue.CallParameter(call, i), replacer, statement, statementsIt, block);
}
}
executeAll(new ReplaceableValue.LValue((StatementLValue) statement), replacer, statement, statementsIt, block);
} else if(statement instanceof StatementConditionalJump) {
executeAll(new ReplaceableValue.CondRValue1((StatementConditionalJump) statement), replacer, statement, statementsIt, block);
executeAll(new ReplaceableValue.CondRValue2((StatementConditionalJump) statement), replacer, statement, statementsIt, block);
@ -56,11 +67,11 @@ public class ValueReplacer {
executeAll(new ReplaceableValue.Return((StatementReturn) statement), replacer, statement, statementsIt, block);
} else if(statement instanceof StatementPhiBlock) {
for(StatementPhiBlock.PhiVariable phiVariable : ((StatementPhiBlock) statement).getPhiVariables()) {
executeAll(new ReplaceableValue.PhiVariable(phiVariable), replacer, statement, statementsIt, block);
int size = phiVariable.getValues().size();
for(int i = 0; i < size; i++) {
executeAll(new ReplaceableValue.PhiValue(phiVariable, i), replacer, statement, statementsIt, block);
}
executeAll(new ReplaceableValue.PhiVariable(phiVariable), replacer, statement, statementsIt, block);
}
}
}
@ -78,7 +89,12 @@ public class ValueReplacer {
}
}
public static Collection<ReplaceableValue> getSubValues(RValue value) {
/**
* Get the sub values for an RValue.
* @param value The RValue
* @return The sub-values of the RValue (only one level down, recursion is needed to get all contained sub-values)
*/
private static Collection<ReplaceableValue> getSubValues(RValue value) {
ArrayList<ReplaceableValue> subValues = new ArrayList<>();
if(value instanceof PointerDereferenceIndexed) {
subValues.add(new ReplaceableValue.Pointer((PointerDereference) value));
@ -91,6 +107,12 @@ public class ValueReplacer {
for(int i = 0; i < size; i++) {
subValues.add(new ReplaceableValue.ListElement(valueList, i));
}
} else if(value instanceof ConstantArrayList) {
ConstantArrayList constantArrayList = (ConstantArrayList) value;
int size = constantArrayList.getElements().size();
for(int i=0;i<size;i++) {
subValues.add(new ReplaceableValue.ConstantArrayElement(constantArrayList, i));
}
} else if(value instanceof CastValue) {
subValues.add(new ReplaceableValue.CastValue((CastValue) value));
} else if(value instanceof ConstantCastValue) {

View File

@ -1,99 +1,33 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.iterator.ReplaceableValue;
import dk.camelot64.kickc.model.iterator.Replacer;
import dk.camelot64.kickc.model.iterator.ValueReplacer;
import dk.camelot64.kickc.model.values.*;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.values.RValue;
import dk.camelot64.kickc.model.values.SymbolRef;
import java.util.ArrayList;
import java.util.ListIterator;
import java.util.Map;
/** A {@link ValueReplacer} that replaces symbols with their alias. */
public class AliasReplacer implements Replacer {
/** true if anything has ben replaced. */
private boolean replaced;
/** The alias map. */
private Map<? extends SymbolRef, ? extends RValue> aliases;
public AliasReplacer(Map<? extends SymbolRef, ? extends RValue> aliases) {
this.aliases = aliases;
this.replaced = false;
}
/**
* Get the alias to use for an RValue.
* Also looks inside any constant values for replacements.
* If a replacement is found the replacement is performed and the new value is returned. If no replacement is found null is returned.
*
* @param rValue The RValue to find an alias for
* @return The alias to use. Null if no alias exists.
*/
public static RValue getReplacement(RValue rValue, Map<? extends SymbolRef, ? extends RValue> aliases) {
if(rValue instanceof SymbolRef) {
RValue alias = aliases.get(rValue);
if(alias != null) {
if(alias.equals(rValue)) {
return alias;
}
RValue replacement = getReplacement(alias, aliases);
if(replacement != null) {
return replacement;
} else {
return alias;
}
}
} else if(rValue instanceof ConstantUnary) {
ConstantUnary constantUnary = (ConstantUnary) rValue;
ConstantValue alias = (ConstantValue) getReplacement(constantUnary.getOperand(), aliases);
if(alias != null) {
return new ConstantUnary(constantUnary.getOperator(), alias);
}
} else if(rValue instanceof ConstantCastValue) {
ConstantCastValue constantCastValue = (ConstantCastValue) rValue;
ConstantValue alias = (ConstantValue) getReplacement(constantCastValue.getValue(), aliases);
if(alias != null) {
return new ConstantCastValue(constantCastValue.getToType(), alias);
}
} else if(rValue instanceof ConstantArrayFilled) {
ConstantArrayFilled arrayFilled = (ConstantArrayFilled) rValue;
ConstantValue alias = (ConstantValue) getReplacement(arrayFilled.getSize(), aliases);
if(alias != null) {
return new ConstantArrayFilled(arrayFilled.getElementType(), alias);
}
} else if(rValue instanceof ConstantBinary) {
ConstantBinary constantBinary = (ConstantBinary) rValue;
ConstantValue aliasLeft = (ConstantValue) getReplacement(constantBinary.getLeft(), aliases);
ConstantValue aliasRight = (ConstantValue) getReplacement(constantBinary.getRight(), aliases);
if(aliasLeft != null || aliasRight != null) {
if(aliasLeft == null) {
aliasLeft = constantBinary.getLeft();
}
if(aliasRight == null) {
aliasRight = constantBinary.getRight();
}
return new ConstantBinary(aliasLeft, constantBinary.getOperator(), aliasRight);
}
} else if(rValue instanceof ConstantArrayList) {
ConstantArrayList constantArrayList = (ConstantArrayList) rValue;
ArrayList<ConstantValue> replacementList = new ArrayList<>();
boolean any = false;
for(ConstantValue elemValue : constantArrayList.getElements()) {
RValue elemReplacement = getReplacement(elemValue, aliases);
if(elemReplacement != null) {
replacementList.add((ConstantValue) elemReplacement);
any = true;
} else {
replacementList.add(elemValue);
}
}
if(any) {
return new ConstantArrayList(replacementList, constantArrayList.getElementType());
}
}
// No replacement found - return null
return null;
public boolean isReplaced() {
return replaced;
}
/**
@ -107,8 +41,32 @@ public class AliasReplacer implements Replacer {
RValue replacement = getReplacement(replaceable.get(), aliases);
if(replacement != null) {
replaceable.set(replacement);
this.replaced = true;
}
}
}
/**
* Get the alias to use for an RValue.
* Also looks inside any constant values for replacements.
* If a replacement is found the replacement is performed and the new value is returned. If no replacement is found null is returned.
*
* @param rValue The RValue to find an alias for
* @return The alias to use. Null if no alias exists.
*/
private static RValue getReplacement(RValue rValue, Map<? extends SymbolRef, ? extends RValue> aliases) {
if(rValue instanceof SymbolRef) {
RValue alias = aliases.get(rValue);
if(alias != null) {
RValue replacement = getReplacement(alias, aliases);
if(replacement != null) {
return replacement;
} else {
return alias;
}
}
}
return null;
}
}

View File

@ -1,16 +1,22 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.CompileError;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.iterator.ReplaceableValue;
import dk.camelot64.kickc.model.iterator.ValueReplacer;
import dk.camelot64.kickc.model.values.LabelRef;
import dk.camelot64.kickc.model.values.RValue;
import dk.camelot64.kickc.model.values.VariableRef;
import dk.camelot64.kickc.model.statements.*;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.statements.StatementAssignment;
import dk.camelot64.kickc.model.statements.StatementLValue;
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
import dk.camelot64.kickc.model.symbols.Scope;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.symbols.VariableUnversioned;
import dk.camelot64.kickc.model.symbols.VariableVersion;
import dk.camelot64.kickc.model.values.LValue;
import dk.camelot64.kickc.model.values.LabelRef;
import dk.camelot64.kickc.model.values.RValue;
import dk.camelot64.kickc.model.values.VariableRef;
import java.util.Collection;
import java.util.LinkedHashMap;
@ -74,27 +80,6 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
}
}
/**
* Version all variable uses in the replaceable value
*
* @param replaceableValue The value to version variable usages in
* @param blockVersions Newest version of variables in the block.
* @param blockNewPhis New phi functions introduced in the block to create versions of variables.
*/
private void execute(
ReplaceableValue replaceableValue,
Map<VariableUnversioned, VariableVersion> blockVersions,
Map<VariableUnversioned, VariableVersion> blockNewPhis) {
RValue value = replaceableValue.get();
VariableVersion version = findOrCreateVersion(value, blockVersions, blockNewPhis);
if(version != null) {
replaceableValue.set(version.getRef());
}
for(ReplaceableValue subValue : ValueReplacer.getSubValues(replaceableValue.get())) {
execute(subValue, blockVersions, blockNewPhis);
}
}
/**
* Version all uses of non-versioned non-intermediary variables
*/
@ -104,29 +89,26 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
Map<VariableUnversioned, VariableVersion> blockVersions = new LinkedHashMap<>();
// New phi functions introduced in the block to create versions of variables.
Map<VariableUnversioned, VariableVersion> blockNewPhis = new LinkedHashMap<>();
for(Statement statement : block.getStatements()) {
if(statement instanceof StatementReturn) {
execute(new ReplaceableValue.Return((StatementReturn) statement), blockVersions, blockNewPhis);
} else if(statement instanceof StatementConditionalJump) {
execute(new ReplaceableValue.CondRValue2((StatementConditionalJump) statement), blockVersions, blockNewPhis);
} else if(statement instanceof StatementAssignment) {
StatementAssignment assignment = (StatementAssignment) statement;
execute(new ReplaceableValue.RValue1(assignment), blockVersions, blockNewPhis);
execute(new ReplaceableValue.RValue2(assignment), blockVersions, blockNewPhis);
execute(new ReplaceableValue.LValue(assignment), blockVersions, blockNewPhis);
// Update map of versions encountered in the block
dk.camelot64.kickc.model.values.LValue lValue = assignment.getlValue();
ValueReplacer.executeAll(block, (replaceable, currentStmt, stmtIt, currentBlock) -> {
RValue value = replaceable.get();
VariableVersion version = findOrCreateVersion(value, blockVersions, blockNewPhis);
if(version != null) {
replaceable.set(version.getRef());
}
// Update map of versions encountered in the block
if(currentStmt instanceof StatementAssignment && replaceable instanceof ReplaceableValue.LValue) {
StatementAssignment assignment = (StatementAssignment) currentStmt;
LValue lValue = assignment.getlValue();
if(lValue instanceof VariableRef) {
VariableRef lValueRef = (VariableRef) lValue;
Variable variable = getScope().getVariable(lValueRef);
Variable variable = Pass1GenerateSingleStaticAssignmentForm.this.getScope().getVariable(lValueRef);
if(variable instanceof VariableVersion) {
VariableVersion versioned = (VariableVersion) variable;
blockVersions.put(versioned.getVersionOf(), versioned);
}
}
}
}
});
// Add new Phi functions to block
for(VariableUnversioned symbol : blockNewPhis.keySet()) {
block.getPhiBlock().addPhiVariable(blockNewPhis.get(symbol).getRef());

View File

@ -1,6 +1,8 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.iterator.ReplaceableValue;
import dk.camelot64.kickc.model.iterator.ValueReplacer;
import dk.camelot64.kickc.model.types.SymbolTypeArray;
import dk.camelot64.kickc.model.values.*;
import dk.camelot64.kickc.model.symbols.ConstantVar;
@ -35,7 +37,7 @@ public class Pass2ConstantInlining extends Pass2SsaOptimization {
inline.putAll(findUnnamedConstants());
inline.putAll(findAliasConstants());
inline.putAll(findConstVarVersions());
// Remove all string constants
List<ConstantRef> refs = new ArrayList(inline.keySet());
for(ConstantRef constantRef : refs) {
@ -75,18 +77,12 @@ public class Pass2ConstantInlining extends Pass2SsaOptimization {
SymbolType constantType = constantVar.getType();
if(constantType instanceof SymbolTypeArray) {
SymbolTypeArray arrayType = (SymbolTypeArray) constantType;
RValue arraySize = arrayType.getSize();
RValue sizeReplacement = AliasReplacer.getReplacement(arraySize, inline);
if(sizeReplacement != null) {
arrayType.setSize(sizeReplacement);
}
ReplaceableValue.TypeArraySize replaceableArrayType = new ReplaceableValue.TypeArraySize(arrayType);
ValueReplacer.executeAll(replaceableArrayType, new AliasReplacer(inline), null, null, null);
}
ConstantValue constantValue = constantVar.getValue();
RValue replacement = AliasReplacer.getReplacement(constantValue, inline);
if(replacement != null) {
constantVar.setValue((ConstantValue) replacement);
}
ReplaceableValue.ConstantVariableValue replaceableConstantVal = new ReplaceableValue.ConstantVariableValue(constantVar);
ValueReplacer.executeAll(replaceableConstantVal, new AliasReplacer(inline), null, null, null);
}
}
@ -101,10 +97,11 @@ public class Pass2ConstantInlining extends Pass2SsaOptimization {
replaced = false;
for(ConstantRef constantRef : inline.keySet()) {
ConstantValue constantValue = inline.get(constantRef);
ConstantValue replacement = (ConstantValue) AliasReplacer.getReplacement(constantValue, inline);
if(replacement != null) {
replaced = true;
inline.put(constantRef, replacement);
ReplaceableValue.GenericValue replaceable = new ReplaceableValue.GenericValue(constantValue);
AliasReplacer replacer = new AliasReplacer(inline);
ValueReplacer.executeAll(replaceable, replacer, null, null, null);
if(replacer.isReplaced()) {
inline.put(constantRef, (ConstantValue) replaceable.get());
}
}
}
@ -190,5 +187,4 @@ public class Pass2ConstantInlining extends Pass2SsaOptimization {
return aliases;
}
}

View File

@ -7,8 +7,8 @@ void main() {
const byte* screen = $400;
const byte b = 'a';
Resolved forward reference screen to (byte*) screen
Resolved forward reference b to (byte) b
Resolved forward reference screen to (byte*) screen
SYMBOLS
(label) @1
(label) @begin