1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-02-13 13:33:32 +00:00

Eliminated VariableVersion.

This commit is contained in:
jespergravgaard 2019-09-27 23:37:24 +02:00
parent dd2b23bc33
commit 51d3d8e7d5
12 changed files with 88 additions and 124 deletions

View File

@ -1,6 +1,5 @@
package dk.camelot64.kickc.fragment;
import dk.camelot64.kickc.parser.AsmParser;
import dk.camelot64.kickc.asm.AsmClobber;
import dk.camelot64.kickc.asm.AsmProgram;
import dk.camelot64.kickc.model.Program;
@ -8,11 +7,12 @@ import dk.camelot64.kickc.model.Registers;
import dk.camelot64.kickc.model.statements.StatementSource;
import dk.camelot64.kickc.model.symbols.Label;
import dk.camelot64.kickc.model.symbols.ProgramScope;
import dk.camelot64.kickc.model.symbols.VariableVersion;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.values.ConstantInteger;
import dk.camelot64.kickc.model.values.ScopeRef;
import dk.camelot64.kickc.model.values.Value;
import dk.camelot64.kickc.parser.AsmParser;
import dk.camelot64.kickc.parser.KickCParser;
import java.util.LinkedHashMap;
@ -80,18 +80,12 @@ public class AsmFragmentTemplate {
// Generate a dummy instance to find clobber & cycles
ProgramScope scope = new ProgramScope();
LinkedHashMap<String, Value> bindings = new LinkedHashMap<>();
VariableVersion v1 = new VariableVersion("$tmp1", SymbolType.BYTE, null);
VariableVersion v2 = new VariableVersion("$tmp2", SymbolType.BYTE, null);
VariableVersion v3 = new VariableVersion("$tmp3", SymbolType.BYTE, null);
VariableVersion v4 = new VariableVersion("$tmp4", SymbolType.BYTE, null);
VariableVersion v5 = new VariableVersion("$tmp5", SymbolType.BYTE, null);
VariableVersion v6 = new VariableVersion("$tmp6", SymbolType.BYTE, null);
v1.setScope(scope);
v2.setScope(scope);
v3.setScope(scope);
v4.setScope(scope);
v5.setScope(scope);
v6.setScope(scope);
Variable v1 = new Variable("$tmp1", scope, SymbolType.BYTE, null, false, true);
Variable v2 = new Variable("$tmp2", scope, SymbolType.BYTE, null, false, true);
Variable v3 = new Variable("$tmp3", scope, SymbolType.BYTE, null, false, true);
Variable v4 = new Variable("$tmp4", scope, SymbolType.BYTE, null, false, true);
Variable v5 = new Variable("$tmp5", scope, SymbolType.BYTE, null, false, true);
Variable v6 = new Variable("$tmp6", scope, SymbolType.BYTE, null, false, true);
v1.setAllocation(new Registers.RegisterZpByte(2));
v2.setAllocation(new Registers.RegisterZpByte(4));
v3.setAllocation(new Registers.RegisterZpByte(6));

View File

@ -604,7 +604,7 @@ public interface ProgramValue {
@Override
public void set(Value val) {
varPointer.setToSymbol((VariableRef) val);
varPointer.setToSymbol((SymbolRef) val);
}
}

View File

@ -250,7 +250,6 @@ public class ProgramValueIterator {
subValues.add(new ProgramValue.ProgramValueStackIdxValue((StackIdxValue) value));
} else if(value == null ||
value instanceof VariableRef ||
value instanceof VariableVersion ||
value instanceof Variable ||
value instanceof ProcedureRef ||
value instanceof ConstantLiteral ||

View File

@ -114,13 +114,13 @@ public abstract class Scope implements Symbol, Serializable {
* @param unversioned The unversioned variable
* @return All versions of the variable
*/
public Collection<VariableVersion> getVersions(VariableUnversioned unversioned) {
LinkedHashSet<VariableVersion> versions = new LinkedHashSet<>();
public Collection<Variable> getVersions(VariableUnversioned unversioned) {
LinkedHashSet<Variable> versions = new LinkedHashSet<>();
for(Symbol symbol : symbols.values()) {
if(symbol instanceof VariableVersion) {
if(((VariableVersion) symbol).isVersioned()) {
if(((VariableVersion) symbol).getVersionOf().equals(unversioned)) {
versions.add((VariableVersion) symbol);
if(symbol instanceof Variable) {
if(((Variable) symbol).isVersioned()) {
if(((Variable) symbol).getVersionOf().equals(unversioned)) {
versions.add((Variable) symbol);
}
}
}

View File

@ -4,6 +4,8 @@ import dk.camelot64.kickc.model.Registers;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.values.VariableRef;
import java.util.Objects;
/** A Variable (or a Constant) */
public class Variable extends SymbolVariable {
@ -22,6 +24,24 @@ public class Variable extends SymbolVariable {
this.isVersion = isVersion;
}
public Variable(VariableUnversioned versionOf, int version) {
super(versionOf.getName()+"#"+version, versionOf.getScope(), versionOf.getType(), versionOf.getDataSegment());
this.setDeclaredAlignment(versionOf.getDeclaredAlignment());
this.setDeclaredAsRegister(versionOf.isDeclaredAsRegister());
this.setDeclaredAsMemory(versionOf.isDeclaredAsMemory());
this.setDeclaredRegister(versionOf.getDeclaredRegister());
this.setDeclaredMemoryAddress(versionOf.getDeclaredMemoryAddress());
this.setStorageStrategy(versionOf.getStorageStrategy());
this.setDeclaredVolatile(versionOf.isDeclaredVolatile());
this.setDeclaredExport(versionOf.isDeclaredExport());
this.setInferedVolatile(versionOf.isInferedVolatile());
this.setInferredType(versionOf.isInferredType());
this.setComments(versionOf.getComments());
this.isIntermediate = false;
this.isVersion = true;
}
public Registers.Register getAllocation() {
return allocation;
}
@ -38,6 +58,20 @@ public class Variable extends SymbolVariable {
return isIntermediate;
}
/**
* If the variable is a version of a variable returns the original variable.
* @return The original variable. Null if this is not a version.
*/
public VariableUnversioned getVersionOf() {
if(isVersioned()) {
String name = getName();
String versionOfName = name.substring(0, name.indexOf("#"));
return (VariableUnversioned) getScope().getVariable(versionOfName);
} else {
return null;
}
}
public VariableRef getRef() {
return new VariableRef(this);
}
@ -48,14 +82,13 @@ public class Variable extends SymbolVariable {
if(o == null || getClass() != o.getClass()) return false;
if(!super.equals(o)) return false;
Variable variable = (Variable) o;
return allocation != null ? allocation.equals(variable.allocation) : variable.allocation == null;
return isIntermediate == variable.isIntermediate &&
isVersion == variable.isVersion &&
Objects.equals(allocation, variable.allocation);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (allocation != null ? allocation.hashCode() : 0);
return result;
return Objects.hash(super.hashCode(), isIntermediate, isVersion, allocation);
}
}

View File

@ -22,8 +22,8 @@ public class VariableUnversioned extends Variable {
return nextVersionNumber++;
}
public VariableVersion createVersion() {
VariableVersion version = new VariableVersion(this, this.getNextVersionNumber());
public Variable createVersion() {
Variable version = new Variable(this, this.getNextVersionNumber());
getScope().add(version);
return version;
}

View File

@ -1,59 +0,0 @@
package dk.camelot64.kickc.model.symbols;
import dk.camelot64.kickc.model.types.SymbolType;
/** A Versioned variable. Versions are created for REGISTER-variables that are handled through PHI-nodes. */
public class VariableVersion extends Variable {
private String versionOfName;
public VariableVersion(VariableUnversioned versionOf, int version) {
super(versionOf.getLocalName() + "#" + version, versionOf.getScope(), versionOf.getType(), versionOf.getDataSegment(), false, true);
this.setDeclaredAlignment(versionOf.getDeclaredAlignment());
this.setDeclaredAsRegister(versionOf.isDeclaredAsRegister());
this.setDeclaredAsMemory(versionOf.isDeclaredAsMemory());
this.setDeclaredRegister(versionOf.getDeclaredRegister());
this.setDeclaredMemoryAddress(versionOf.getDeclaredMemoryAddress());
this.setStorageStrategy(versionOf.getStorageStrategy());
this.setDeclaredVolatile(versionOf.isDeclaredVolatile());
this.setDeclaredExport(versionOf.isDeclaredExport());
this.setInferedVolatile(versionOf.isInferedVolatile());
this.setInferredType(versionOf.isInferredType());
this.versionOfName = versionOf.getLocalName();
this.setComments(versionOf.getComments());
}
public VariableVersion(
String name,
SymbolType type,
String versionOfName) {
super(name, null, type, Scope.SEGMENT_DATA_DEFAULT, false, true);
this.versionOfName = versionOfName;
}
public VariableUnversioned getVersionOf() {
return (VariableUnversioned) getScope().getVariable(versionOfName);
}
@Override
public boolean equals(Object o) {
if(this == o) {
return true;
}
if(o == null || getClass() != o.getClass()) {
return false;
}
if(!super.equals(o)) {
return false;
}
VariableVersion that = (VariableVersion) o;
return versionOfName != null ? versionOfName.equals(that.versionOfName) : that.versionOfName == null;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (versionOfName != null ? versionOfName.hashCode() : 0);
return result;
}
}

View File

@ -79,9 +79,9 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
if(assignedVar instanceof VariableUnversioned) {
// Assignment to a non-versioned non-intermediary variable
VariableUnversioned assignedSymbol = (VariableUnversioned) assignedVar;
VariableVersion version;
Variable version;
if(assignedSymbol.isDeclaredConstant() || earlyIdentifiedConstants.contains(assignedSymbol.getRef())) {
Collection<VariableVersion> versions = assignedVar.getScope().getVersions(assignedSymbol);
Collection<Variable> versions = assignedVar.getScope().getVersions(assignedSymbol);
if(versions.size() != 0) {
throw new CompileError("Error! Constants can not be modified", source);
}
@ -100,16 +100,16 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
private void versionAllUses() {
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
// Newest version of variables in the block.
Map<VariableUnversioned, VariableVersion> blockVersions = new LinkedHashMap<>();
Map<VariableUnversioned, Variable> blockVersions = new LinkedHashMap<>();
// New phi functions introduced in the block to create versions of variables.
Map<VariableUnversioned, VariableVersion> blockNewPhis = new LinkedHashMap<>();
Map<VariableUnversioned, Variable> blockNewPhis = new LinkedHashMap<>();
ProgramValueIterator.execute(block, (programValue, currentStmt, stmtIt, currentBlock) -> {
if(programValue instanceof ProgramValue.ProgramValueParamValue) {
// Call parameter values should not be versioned
return;
}
Value value = programValue.get();
VariableVersion version = findOrCreateVersion(value, blockVersions, blockNewPhis);
Variable version = findOrCreateVersion(value, blockVersions, blockNewPhis);
if(version != null) {
programValue.set(version.getRef());
}
@ -137,7 +137,7 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
if(assignedVarType instanceof SymbolTypeArray) {
SymbolTypeArray assignedArrayType = (SymbolTypeArray) assignedVarType;
RValue arraySize = assignedArrayType.getSize();
VariableVersion vrs = findOrCreateVersion(arraySize, blockVersions, blockNewPhis);
Variable vrs = findOrCreateVersion(arraySize, blockVersions, blockNewPhis);
if(vrs != null) {
assignedArrayType.setSize(vrs.getRef());
}
@ -152,12 +152,11 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
}
}
private void updateBlockVersions(VariableRef lValue, Map<VariableUnversioned, VariableVersion> blockVersions) {
private void updateBlockVersions(VariableRef lValue, Map<VariableUnversioned, Variable> blockVersions) {
VariableRef lValueRef = lValue;
Variable variable = Pass1GenerateSingleStaticAssignmentForm.this.getScope().getVariable(lValueRef);
if(variable instanceof VariableVersion) {
VariableVersion versioned = (VariableVersion) variable;
blockVersions.put(versioned.getVersionOf(), versioned);
if(variable.isVersioned()) {
blockVersions.put(variable.getVersionOf(), variable);
}
}
@ -170,12 +169,12 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
* @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 VariableVersion findOrCreateVersion(
private Variable findOrCreateVersion(
Value rValue,
Map<VariableUnversioned, VariableVersion> blockVersions,
Map<VariableUnversioned, VariableVersion> blockNewPhis) {
Map<VariableUnversioned, Variable> blockVersions,
Map<VariableUnversioned, Variable> blockNewPhis) {
Collection<VariableRef> earlyIdentifiedConstants = getProgram().getEarlyIdentifiedConstants();
VariableVersion version = null;
Variable version = null;
if(rValue instanceof VariableRef) {
Variable rValueVar = getScope().getVariable((VariableRef) rValue);
if(rValueVar instanceof VariableUnversioned) {
@ -184,7 +183,7 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
if(rSymbol.isDeclaredConstant() || earlyIdentifiedConstants.contains(rSymbol.getRef())) {
// A constant - find the single created version
Scope scope = rSymbol.getScope();
Collection<VariableVersion> versions = scope.getVersions(rSymbol);
Collection<Variable> versions = scope.getVersions(rSymbol);
if(versions.size() != 1) {
throw new CompileError("Error! Constants must have exactly one version " + rSymbol);
}
@ -214,8 +213,8 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
* false if new phis were added, meaning another iteration is needed.
*/
private boolean completePhiFunctions() {
Map<LabelRef, Map<VariableUnversioned, VariableVersion>> newPhis = new LinkedHashMap<>();
Map<LabelRef, Map<VariableUnversioned, VariableVersion>> symbolMap = buildSymbolMap();
Map<LabelRef, Map<VariableUnversioned, Variable>> newPhis = new LinkedHashMap<>();
Map<LabelRef, Map<VariableUnversioned, Variable>> symbolMap = buildSymbolMap();
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
for(Statement statement : block.getStatements()) {
@ -224,19 +223,19 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
for(StatementPhiBlock.PhiVariable phiVariable : phiBlock.getPhiVariables()) {
if(phiVariable.isEmpty()) {
VariableRef phiLValVarRef = phiVariable.getVariable();
VariableVersion versioned = (VariableVersion) getScope().getVariable(phiLValVarRef);
Variable versioned = getScope().getVariable(phiLValVarRef);
VariableUnversioned unversioned = versioned.getVersionOf();
List<ControlFlowBlock> predecessors = getPhiPredecessors(block, getProgram());
for(ControlFlowBlock predecessor : predecessors) {
LabelRef predecessorLabel = predecessor.getLabel();
Map<VariableUnversioned, VariableVersion> predecessorMap = symbolMap.get(predecessorLabel);
VariableVersion previousSymbol = null;
Map<VariableUnversioned, Variable> predecessorMap = symbolMap.get(predecessorLabel);
Variable previousSymbol = null;
if(predecessorMap != null) {
previousSymbol = predecessorMap.get(unversioned);
}
if(previousSymbol == null) {
// No previous symbol found in predecessor block. Look in new phi functions.
Map<VariableUnversioned, VariableVersion> predecessorNewPhis = newPhis.get(predecessorLabel);
Map<VariableUnversioned, Variable> predecessorNewPhis = newPhis.get(predecessorLabel);
if(predecessorNewPhis == null) {
predecessorNewPhis = new LinkedHashMap<>();
newPhis.put(predecessorLabel, predecessorNewPhis);
@ -257,7 +256,7 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
}
// Ads new phi functions to blocks
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
Map<VariableUnversioned, VariableVersion> blockNewPhis = newPhis.get(block.getLabel());
Map<VariableUnversioned, Variable> blockNewPhis = newPhis.get(block.getLabel());
if(blockNewPhis != null) {
for(VariableUnversioned symbol : blockNewPhis.keySet()) {
StatementPhiBlock phiBlock = block.getPhiBlock();
@ -298,8 +297,8 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
* 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<LabelRef, Map<VariableUnversioned, VariableVersion>> buildSymbolMap() {
Map<LabelRef, Map<VariableUnversioned, VariableVersion>> symbolMap = new LinkedHashMap<>();
private Map<LabelRef, Map<VariableUnversioned, Variable>> buildSymbolMap() {
Map<LabelRef, Map<VariableUnversioned, Variable>> symbolMap = new LinkedHashMap<>();
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
for(Statement statement : block.getStatements()) {
if(statement instanceof StatementLValue) {
@ -316,14 +315,14 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
return symbolMap;
}
private void addSymbolToMap(LValue lValue, ControlFlowBlock block, Map<LabelRef, Map<VariableUnversioned, VariableVersion>> symbolMap) {
private void addSymbolToMap(LValue lValue, ControlFlowBlock block, Map<LabelRef, Map<VariableUnversioned, Variable>> symbolMap) {
if(lValue instanceof VariableRef) {
Variable lValueVar = getScope().getVariable((VariableRef) lValue);
if(lValueVar instanceof VariableVersion) {
VariableVersion versioned = (VariableVersion) lValueVar;
if(lValueVar.isVersioned()) {
Variable versioned = lValueVar;
LabelRef label = block.getLabel();
VariableUnversioned unversioned = versioned.getVersionOf();
Map<VariableUnversioned, VariableVersion> blockMap = symbolMap.get(label);
Map<VariableUnversioned, Variable> blockMap = symbolMap.get(label);
if(blockMap == null) {
blockMap = new LinkedHashMap<>();
symbolMap.put(label, blockMap);

View File

@ -49,7 +49,7 @@ public class Pass3PhiLifting {
Variable newVar;
if(phiVariable.getVariable().isVersion()) {
Variable lValVar = program.getScope().getVariable(phiVariable.getVariable());
newVar = ((VariableVersion) lValVar).getVersionOf().createVersion();
newVar = lValVar.getVersionOf().createVersion();
} else {
Variable lValVar = program.getScope().getVariable(phiVariable.getVariable());
newVar = lValVar.getScope().addVariableIntermediate();

View File

@ -263,9 +263,9 @@ public class Pass4CodeGeneration {
signature.append(" ").append(procedure.getLocalName()).append("(");
int i = 0;
for(Variable parameter : procedure.getParameters()) {
List<VariableVersion> versions = new ArrayList<>(procedure.getVersions((VariableUnversioned) parameter));
List<Variable> versions = new ArrayList<>(procedure.getVersions((VariableUnversioned) parameter));
if(versions.size() > 0) {
VariableVersion param = versions.get(0);
Variable param = versions.get(0);
Registers.Register allocation = param.getAllocation();
if(i++ > 0) signature.append(", ");
signature.append(param.getType().getTypeName()).append(" ");

View File

@ -3,7 +3,6 @@ package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.statements.StatementCall;
import dk.camelot64.kickc.model.statements.StatementCallFinalize;
import dk.camelot64.kickc.model.symbols.VariableVersion;
import dk.camelot64.kickc.model.values.VariableRef;
import dk.camelot64.kickc.model.statements.StatementAssignment;
import dk.camelot64.kickc.model.symbols.Variable;
@ -38,7 +37,7 @@ public class Pass4LiveRangeEquivalenceClassesFinalize extends Pass2Base {
// Found a volatile non-versioned variable
for(Variable otherVariable : variable.getScope().getAllVariables(false)) {
if(otherVariable.isVersioned()) {
if(((VariableVersion)otherVariable).getVersionOf().equals(((VariableVersion)variable).getVersionOf())) {
if((otherVariable).getVersionOf().equals((variable).getVersionOf())) {
// They share the same main variable
LiveRangeEquivalenceClass varEC = liveRangeEquivalenceClassSet.getOrCreateEquivalenceClass(variable.getRef());
LiveRangeEquivalenceClass otherEC = liveRangeEquivalenceClassSet.getOrCreateEquivalenceClass(otherVariable.getRef());

View File

@ -7,7 +7,6 @@ import dk.camelot64.kickc.model.statements.*;
import dk.camelot64.kickc.model.symbols.Label;
import dk.camelot64.kickc.model.symbols.Scope;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.symbols.VariableVersion;
import dk.camelot64.kickc.model.values.*;
import dk.camelot64.kickc.passes.Pass1GenerateSingleStaticAssignmentForm;
import dk.camelot64.kickc.passes.calcs.PassNCalcVariableReferenceInfos;
@ -177,7 +176,7 @@ public class Unroller {
if(origVarRef.isIntermediate()) {
newVarRef = scope.addVariableIntermediate().getRef();
} else {
newVarRef = ((VariableVersion) origVar).getVersionOf().createVersion().getRef();
newVarRef = (origVar).getVersionOf().createVersion().getRef();
}
return newVarRef;
}
@ -243,7 +242,7 @@ public class Unroller {
newVar.setDeclaredAlignment(definedVar.getDeclaredAlignment());
newVar.setInferredType(definedVar.isInferredType());
} else if(definedVarRef.isVersion()) {
newVar = ((VariableVersion) definedVar).getVersionOf().createVersion();
newVar = (definedVar).getVersionOf().createVersion();
} else {
throw new RuntimeException("Error! Variable is not versioned or intermediate " + definedVar.toString(program));
}