1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-12-26 18:29:54 +00:00

Unrolled condition variables are now converted to SSA automatically in pass 1.

This commit is contained in:
jespergravgaard 2020-02-14 15:55:04 +01:00
parent d0bc5af94b
commit 3770874860
9 changed files with 116 additions and 39 deletions

View File

@ -225,6 +225,8 @@ public class Compiler {
new Pass1ExtractInlineStrings(program).execute();
new PassNCullEmptyBlocks(program).execute();
new Pass1UnrollConditionVariableSsa(program).step();
new Pass1ModifiedVarsAnalysis(program).execute();
if(getLog().isVerbosePass1CreateSsa()) {
getLog().append("PROCEDURE MODIFY VARIABLE ANALYSIS");

View File

@ -182,20 +182,15 @@ public class AsmFragmentInstanceSpec {
public boolean equals(Object o) {
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
AsmFragmentInstanceSpec that = (AsmFragmentInstanceSpec) o;
if(signature != null ? !signature.equals(that.signature) : that.signature != null) return false;
if(bindings != null ? !bindings.equals(that.bindings) : that.bindings != null) return false;
return codeScopeRef != null ? codeScopeRef.equals(that.codeScopeRef) : that.codeScopeRef == null;
return
Objects.equals(signature, that.signature) &&
Objects.equals(bindings, that.bindings) &&
Objects.equals(codeScopeRef, that.codeScopeRef);
}
@Override
public int hashCode() {
int result = signature != null ? signature.hashCode() : 0;
result = 31 * result + (bindings != null ? bindings.hashCode() : 0);
result = 31 * result + (codeScopeRef != null ? codeScopeRef.hashCode() : 0);
return result;
return Objects.hash(signature, bindings, codeScopeRef);
}
}

View File

@ -165,28 +165,20 @@ class AsmFragmentTemplateSynthesisRule {
public boolean equals(Object o) {
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
AsmFragmentTemplateSynthesisRule that = (AsmFragmentTemplateSynthesisRule) o;
if(mapSignature != that.mapSignature) return false;
if(sigMatch != null ? !sigMatch.equals(that.sigMatch) : that.sigMatch != null) return false;
if(sigAvoid != null ? !sigAvoid.equals(that.sigAvoid) : that.sigAvoid != null) return false;
if(asmPrefix != null ? !asmPrefix.equals(that.asmPrefix) : that.asmPrefix != null) return false;
if(sigReplace != null ? !sigReplace.equals(that.sigReplace) : that.sigReplace != null) return false;
if(asmPostfix != null ? !asmPostfix.equals(that.asmPostfix) : that.asmPostfix != null) return false;
return bindMappings != null ? bindMappings.equals(that.bindMappings) : that.bindMappings == null;
return mapSignature == that.mapSignature &&
Objects.equals(sigMatch, that.sigMatch) &&
Objects.equals(sigAvoid, that.sigAvoid) &&
Objects.equals(asmPrefix, that.asmPrefix) &&
Objects.equals(sigReplace, that.sigReplace) &&
Objects.equals(asmPostfix, that.asmPostfix) &&
Objects.equals(bindMappings, that.bindMappings) &&
Objects.equals(subDontClobber, that.subDontClobber);
}
@Override
public int hashCode() {
int result = sigMatch != null ? sigMatch.hashCode() : 0;
result = 31 * result + (sigAvoid != null ? sigAvoid.hashCode() : 0);
result = 31 * result + (asmPrefix != null ? asmPrefix.hashCode() : 0);
result = 31 * result + (sigReplace != null ? sigReplace.hashCode() : 0);
result = 31 * result + (asmPostfix != null ? asmPostfix.hashCode() : 0);
result = 31 * result + (bindMappings != null ? bindMappings.hashCode() : 0);
result = 31 * result + (mapSignature ? 1 : 0);
return result;
return Objects.hash(sigMatch, sigAvoid, asmPrefix, sigReplace, asmPostfix, bindMappings, mapSignature, subDontClobber);
}
/** All the synthesize rules available. */

View File

@ -306,6 +306,10 @@ public class Variable implements Symbol {
public void setKind(Kind kind) {
this.kind = kind;
if(kind.equals(Kind.PHI_MASTER)) {
this.nextPhiVersionNumber = 0;
} else
this.nextPhiVersionNumber = null;
}
public boolean isKindConstant() {

View File

@ -0,0 +1,80 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.VariableReferenceInfos;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.statements.StatementAssignment;
import dk.camelot64.kickc.model.statements.StatementConditionalJump;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.values.RValue;
import dk.camelot64.kickc.model.values.VariableRef;
import dk.camelot64.kickc.passes.utils.VarAssignments;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
/**
* Convert condition variables in unrolled jumps to single-static-assignment
*/
public class Pass1UnrollConditionVariableSsa extends Pass2SsaOptimization {
public Pass1UnrollConditionVariableSsa(Program program) {
super(program);
}
@Override
public boolean step() {
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
for(Statement statement : block.getStatements()) {
if(statement instanceof StatementConditionalJump) {
final StatementConditionalJump conditionalJump = (StatementConditionalJump) statement;
if(conditionalJump.isDeclaredUnroll()) {
Collection<VariableRef> referencedVars = new LinkedHashSet<>();
findAllReferencedVars(referencedVars, conditionalJump.getrValue1());
findAllReferencedVars(referencedVars, conditionalJump.getrValue2());
for(VariableRef referencedVar : referencedVars) {
final Variable variable = getScope().getVariable(referencedVar);
if(variable.isKindLoadStore()) {
// Convert the variable to versioned if it is load/store
getLog().append("Converting unrolled condition variable to single-static-assignment "+variable);
variable.setKind(Variable.Kind.PHI_MASTER);
}
}
}
}
}
}
return false;
}
/**
* Find all referenced variables in a value. If an intermediate variable is referenced this recurses to the definition of the intermediate.
* @param referencedVars The collection to fill
* @param rValue The value to find references in
*/
private void findAllReferencedVars(Collection<VariableRef> referencedVars, RValue rValue) {
Collection<VariableRef> directReferenced = VariableReferenceInfos.getReferencedVars(rValue);
referencedVars.addAll(directReferenced);
for(VariableRef varRef : directReferenced) {
if(varRef.isIntermediate()) {
// Found an intermediate variable - recurse to the definition
final List<VarAssignments.VarAssignment> varAssignments = VarAssignments.get(varRef, getGraph(), getScope());
for(VarAssignments.VarAssignment varAssignment : varAssignments) {
if(VarAssignments.VarAssignment.Type.STATEMENT_LVALUE.equals(varAssignment.type)) {
if(varAssignment.statementLValue instanceof StatementAssignment) {
findAllReferencedVars(referencedVars, ((StatementAssignment) varAssignment.statementLValue).getrValue1());
findAllReferencedVars(referencedVars, ((StatementAssignment) varAssignment.statementLValue).getrValue2());
} else {
throw new InternalError("Not implemented!");
}
} else {
throw new InternalError("Not implemented!");
}
}
}
}
}
}

View File

@ -23,7 +23,7 @@ public class Pass2LoopUnrollAssertComplete extends Pass2SsaOptimization {
for(Statement statement : block.getStatements()) {
if(statement instanceof StatementConditionalJump) {
if(((StatementConditionalJump) statement).isWasUnrolled()) {
throw new CompileError("Loop cannot be unrolled. Condition not resolvable to a constant true/false. "+statement.toString(getProgram(), false));
throw new CompileError("Loop cannot be unrolled. Condition not resolvable to a constant true/false. ", statement);
}
}
}

View File

@ -106,9 +106,9 @@ public class PassNCalcVariableReferenceInfos extends PassNCalcBase<VariableRefer
} else if(statementLValue instanceof StatementCallPointer) {
usedVars.addAll(getReferenced(((StatementCallPointer) statementLValue).getProcedure()));
if(((StatementCallPointer) statement).getParameters() != null)
for(RValue parameter : ((StatementCallPointer) statementLValue).getParameters()) {
usedVars.addAll(getReferenced(parameter));
}
for(RValue parameter : ((StatementCallPointer) statementLValue).getParameters()) {
usedVars.addAll(getReferenced(parameter));
}
} else if(statementLValue instanceof StatementCallFinalize) {
// No vars
} else {
@ -172,11 +172,12 @@ public class PassNCalcVariableReferenceInfos extends PassNCalcBase<VariableRefer
*/
private static Collection<SymbolVariableRef> getReferenced(RValue rValue) {
Collection<SymbolVariableRef> referenced = new LinkedHashSet<>();
ProgramValueIterator.execute(new ProgramValue.GenericValue(rValue), (programValue, currentStmt, stmtIt, currentBlock) -> {
if(programValue.get() instanceof SymbolVariableRef) {
referenced.add((SymbolVariableRef) programValue.get());
}
}, null, null, null);
if(rValue != null)
ProgramValueIterator.execute(new ProgramValue.GenericValue(rValue), (programValue, currentStmt, stmtIt, currentBlock) -> {
if(programValue.get() instanceof SymbolVariableRef) {
referenced.add((SymbolVariableRef) programValue.get());
}
}, null, null, null);
return referenced;
}

View File

@ -218,7 +218,7 @@ public class Unroller {
}
/**
* Create new versions of all symbols assigned inside some blocks to be unrolled
* Create new versions of all symbols defined inside some blocks to be unrolled
*
* @param unrollBlocks The blocks being unrolled
* @return A map from variables assigned inside the unroll blocks to the new copy of the variable
@ -233,12 +233,15 @@ public class Unroller {
String name = scope.allocateIntermediateVariableName();
newVar = Variable.createCopy(name, scope, definedVar);
scope.add(newVar);
definedToNewVar.put(definedVarRef, newVar.getRef());
} else if(definedVarRef.isVersion()) {
newVar = (definedVar).getPhiMaster().createVersion();
definedToNewVar.put(definedVarRef, newVar.getRef());
} else if(definedVar.isKindLoadStore()) {
// New version not needed for load/store
} else {
throw new RuntimeException("Error! Variable is not versioned or intermediate " + definedVar.toString(program));
}
definedToNewVar.put(definedVarRef, newVar.getRef());
//getLog().append("Defined in loop: " + definedVarRef.getFullName() + " -> " + newVar.getRef().getFullName());
}
return definedToNewVar;

View File

@ -1,6 +1,6 @@
// Minimal unrolled ranged for() loop
void main() {
char* SCREEN = $400;
char* SCREEN = 0x0400;
inline for(char i : 0..2) {
SCREEN[i] = 'a';
}