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:
parent
d0bc5af94b
commit
3770874860
@ -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");
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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. */
|
||||
|
@ -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() {
|
||||
|
@ -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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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';
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user