1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-08-03 01:29:04 +00:00

Working on static initialization rewrite _init(). #257

This commit is contained in:
jespergravgaard 2020-06-21 10:23:04 +02:00
parent d129efb95f
commit a989e63f5b
6 changed files with 131 additions and 42 deletions

View File

@ -69,7 +69,7 @@ public class VariableReferenceInfos {
this.referencedSymbol = referencedSymbol;
}
Integer getStatementIdx() {
public Integer getStatementIdx() {
return statementIdx;
}
@ -102,7 +102,7 @@ public class VariableReferenceInfos {
this.referencedSymbol = referencedSymbol;
}
SymbolVariableRef getReferencingSymbol() {
public SymbolVariableRef getReferencingSymbol() {
return referencingSymbol;
}
@ -296,6 +296,41 @@ public class VariableReferenceInfos {
return stmts;
}
/**
* Get all constants (or symbol definitions) referencing another constant
*
* @param constRef The constant to look for
* @return All constants (or symbol definitions) that reference the constant in their value
*/
public Collection<SymbolVariableRef> getConstRefSymbols(ConstantRef constRef) {
Collection<ReferenceToSymbolVar> refs = symbolVarReferences.get(constRef);
LinkedHashSet<SymbolVariableRef> constRefs = new LinkedHashSet<>();
if(refs != null) {
refs.stream()
.filter(referenceToSymbolVar -> ReferenceToSymbolVar.ReferenceType.USE.equals(referenceToSymbolVar.getReferenceType()))
.filter(referenceToSymbolVar -> referenceToSymbolVar instanceof ReferenceInSymbol)
.forEach(referenceToSymbolVar -> constRefs.add(((ReferenceInSymbol) referenceToSymbolVar).getReferencingSymbol()));
}
return constRefs;
}
/**
* Get all usages of a constant. (only returns places where the constant is used, not where it is defined)
* @param constRef The constant to look for
* @return All statements or other constants that use the constant
*/
public Collection<ReferenceToSymbolVar> getConstRefAllUses(ConstantRef constRef) {
Collection<ReferenceToSymbolVar> refs = symbolVarReferences.get(constRef);
if(refs != null) {
final List<ReferenceToSymbolVar> allUses = refs.stream()
.filter(referenceToSymbolVar -> ReferenceToSymbolVar.ReferenceType.USE.equals(referenceToSymbolVar.getReferenceType()))
.collect(Collectors.toList());
return allUses;
} else
return new ArrayList<>();
}
/**
* Get the index of the statement defining a variable. Only returns if there is exactly one defining statement.
*
@ -366,22 +401,5 @@ public class VariableReferenceInfos {
}
/**
* Get all constants (or symbol definitions) referencing another constant
*
* @param constRef The constant to look for
* @return All constants (or symbol definitions) that reference the constant in their value
*/
public Collection<SymbolVariableRef> getSymbolRefConsts(ConstantRef constRef) {
Collection<ReferenceToSymbolVar> refs = symbolVarReferences.get(constRef);
LinkedHashSet<SymbolVariableRef> constRefs = new LinkedHashSet<>();
if(refs != null) {
refs.stream()
.filter(referenceToSymbolVar -> ReferenceToSymbolVar.ReferenceType.USE.equals(referenceToSymbolVar.getReferenceType()))
.filter(referenceToSymbolVar -> referenceToSymbolVar instanceof ReferenceInSymbol)
.forEach(referenceToSymbolVar -> constRefs.add(((ReferenceInSymbol) referenceToSymbolVar).getReferencingSymbol()));
}
return constRefs;
}
}

View File

@ -80,6 +80,22 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
return program.getProcedureCompilation(currentProcedure.getRef());
}
/**
* Add an intermediate variable to the current scope.
*
* If the current scope is global the variable is added to the _init() scope.
*
* @return The new intermediate variable
*/
private Variable addIntermediateVar() {
Scope currentScope = getCurrentScope();
if(ScopeRef.ROOT.equals(currentScope.getRef())) {
Procedure initProc = program.getScope().getLocalProcedure(SymbolRef.INIT_PROC_NAME);
currentScope = initProc;
}
return currentScope.addVariableIntermediate();
}
/**
* Add a statement to the current procedure.
*/
@ -1249,7 +1265,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
RValue exprVal = (RValue) this.visit(ctx.commaExpr());
if(notConsumed(exprVal)) {
// Make a tmpVar to create the statement
Variable tmpVar = getCurrentScope().addVariableIntermediate();
Variable tmpVar = addIntermediateVar();
List<Comment> comments = ensureUnusedComments(getCommentsSymbol(ctx));
RValue rVal = exprVal;
if(exprVal instanceof LValue) {
@ -1270,7 +1286,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
List<Comment> comments = ensureUnusedComments(getCommentsSymbol(ctx));
if(elseStmt == null) {
// If without else - skip the entire section if condition not met
SymbolVariableRef notExprVar = getCurrentScope().addVariableIntermediate().getRef();
SymbolVariableRef notExprVar = addIntermediateVar().getRef();
addStatement(new StatementAssignment((LValue) notExprVar, null, Operators.LOGIC_NOT, rValue, true, StatementSource.ifThen(ctx), comments));
Label endJumpLabel = getCurrentScope().addLabelIntermediate();
addStatement(new StatementConditionalJump(notExprVar, endJumpLabel.getRef(), StatementSource.ifThen(ctx), Comment.NO_COMMENTS));
@ -1394,7 +1410,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
// If modifiers are present the RValue must be assigned before the post-modifier is executed
if(!(rValue instanceof VariableRef)) {
// Make a new temporary variable and assign that
Variable tmpVar = getCurrentScope().addVariableIntermediate();
Variable tmpVar = addIntermediateVar();
Statement stmtExpr = new StatementAssignment(tmpVar.getVariableRef(), rValue, true, statementSource, Comment.NO_COMMENTS);
addStatement(stmtExpr);
rValue = tmpVar.getRef();
@ -1603,7 +1619,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
addStatement(stmtNxt);
// Add condition i!=last+1 or i!=last-1
RValue beyondLastVal = new RangeComparison(rangeFirstValue, rangeLastValue, lValue.getType());
Variable tmpVar = getCurrentScope().addVariableIntermediate();
Variable tmpVar = addIntermediateVar();
SymbolVariableRef tmpVarRef = tmpVar.getRef();
Statement stmtTmpVar = new StatementAssignment((LValue) tmpVarRef, lValue.getRef(), Operators.NEQ, beyondLastVal, true, statementSource, Comment.NO_COMMENTS);
addStatement(stmtTmpVar);
@ -2221,7 +2237,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
} else {
// sizeof(expression) - add a unary expression to be resolved later
RValue child = (RValue) this.visit(ctx.expr());
Variable tmpVar = getCurrentScope().addVariableIntermediate();
Variable tmpVar = addIntermediateVar();
SymbolVariableRef tmpVarRef = tmpVar.getRef();
Statement stmt = new StatementAssignment((LValue) tmpVarRef, Operators.SIZEOF, child, true, new StatementSource(ctx), ensureUnusedComments(getCommentsSymbol(ctx)));
addStatement(stmt);
@ -2239,7 +2255,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
} else {
// typeid(expression) - add a unary expression to be resolved later
RValue child = (RValue) this.visit(ctx.expr());
Variable tmpVar = getCurrentScope().addVariableIntermediate();
Variable tmpVar = addIntermediateVar();
SymbolVariableRef tmpVarRef = tmpVar.getRef();
Statement stmt = new StatementAssignment((LValue) tmpVarRef, Operators.TYPEID, child, true, new StatementSource(ctx), ensureUnusedComments(getCommentsSymbol(ctx)));
addStatement(stmt);
@ -2257,7 +2273,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
} else {
parameters = new ArrayList<>();
}
Variable tmpVar = getCurrentScope().addVariableIntermediate();
Variable tmpVar = addIntermediateVar();
SymbolVariableRef tmpVarRef = tmpVar.getRef();
String procedureName;
@ -2362,7 +2378,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
if(left instanceof ConstantValue && right instanceof ConstantValue) {
return new ConstantBinary((ConstantValue) left, (OperatorBinary) operator, (ConstantValue) right);
} else {
Variable tmpVar = getCurrentScope().addVariableIntermediate();
Variable tmpVar = addIntermediateVar();
SymbolVariableRef tmpVarRef = tmpVar.getRef();
Statement stmt = new StatementAssignment((LValue) tmpVarRef, left, operator, right, true, new StatementSource(ctx), ensureUnusedComments(getCommentsSymbol(ctx)));
addStatement(stmt);
@ -2396,7 +2412,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
} else if(child instanceof ConstantValue) {
return new ConstantUnary((OperatorUnary) operator, (ConstantValue) child);
} else {
Variable tmpVar = getCurrentScope().addVariableIntermediate();
Variable tmpVar = addIntermediateVar();
SymbolVariableRef tmpVarRef = tmpVar.getRef();
Statement stmt = new StatementAssignment((LValue) tmpVarRef, operator, child, true, new StatementSource(ctx), ensureUnusedComments(getCommentsSymbol(ctx)));
addStatement(stmt);
@ -2453,19 +2469,19 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
addStatement(new StatementConditionalJump(condValue, trueLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS));
addStatement(new StatementLabel(falseLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS));
RValue falseValue = (RValue) this.visit(ctx.expr(2));
SymbolVariableRef falseVar = getCurrentScope().addVariableIntermediate().getRef();
SymbolVariableRef falseVar = addIntermediateVar().getRef();
addStatement(new StatementAssignment((LValue) falseVar, falseValue, true, new StatementSource(ctx), Comment.NO_COMMENTS));
LabelRef falseExitLabel = getCurrentProcedureCompilation().getStatementSequence().getCurrentBlockLabel();
addStatement(new StatementJump(endJumpLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS));
addStatement(new StatementLabel(trueLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS));
RValue trueValue = (RValue) this.visit(ctx.expr(1));
SymbolVariableRef trueVar = getCurrentScope().addVariableIntermediate().getRef();
SymbolVariableRef trueVar = addIntermediateVar().getRef();
addStatement(new StatementAssignment((LValue) trueVar, trueValue, true, new StatementSource(ctx), Comment.NO_COMMENTS));
LabelRef trueExitLabel = getCurrentProcedureCompilation().getStatementSequence().getCurrentBlockLabel();
addStatement(new StatementLabel(endJumpLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS));
StatementPhiBlock phiBlock = new StatementPhiBlock(Comment.NO_COMMENTS);
phiBlock.setSource(new StatementSource(ctx));
SymbolVariableRef finalVar = getCurrentScope().addVariableIntermediate().getRef();
SymbolVariableRef finalVar = addIntermediateVar().getRef();
StatementPhiBlock.PhiVariable phiVariable = phiBlock.addPhiVariable((VariableRef) finalVar);
phiVariable.setrValue(trueExitLabel, trueVar);
phiVariable.setrValue(falseExitLabel, falseVar);

View File

@ -199,6 +199,10 @@ public class Pass1ProcedureInline extends Pass1Base {
StatementAsm procAsm = (StatementAsm) procStatement;
StatementAsm inlinedAsm = new StatementAsm(procAsm.getAsmLines(), new LinkedHashMap<>(procAsm.getReferenced()), procAsm.getDeclaredClobber(), procAsm.getSource(), Comment.NO_COMMENTS);
inlinedStatement = inlinedAsm;
} else if(procStatement instanceof StatementKickAsm) {
StatementKickAsm procKasm = (StatementKickAsm) procStatement;
StatementKickAsm inlinedAsm = new StatementKickAsm(procKasm.getKickAsmCode(), procKasm.getLocation(), procKasm.getBytes(), procKasm.getCycles(), procKasm.getUses(), procKasm.getDeclaredClobber(), procKasm.getSource(), Comment.NO_COMMENTS);
inlinedStatement = inlinedAsm;
} else if(procStatement instanceof StatementConditionalJump) {
StatementConditionalJump procConditional = (StatementConditionalJump) procStatement;
LabelRef procDestinationRef = procConditional.getDestination();

View File

@ -370,7 +370,7 @@ public class Pass4CodeGeneration {
}
}
}
Collection<SymbolVariableRef> symbolRefConsts = program.getVariableReferenceInfos().getSymbolRefConsts(constantVar.getConstantRef());
Collection<SymbolVariableRef> symbolRefConsts = program.getVariableReferenceInfos().getConstRefSymbols(constantVar.getConstantRef());
if(symbolRefConsts != null) {
for(SymbolVariableRef symbolRefConst : symbolRefConsts) {
Variable symbolRefVar = (Variable) program.getScope().getSymbol(symbolRefConst);

View File

@ -2,9 +2,15 @@ package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.StatementInfos;
import dk.camelot64.kickc.model.VariableReferenceInfos;
import dk.camelot64.kickc.model.statements.*;
import dk.camelot64.kickc.model.symbols.Procedure;
import dk.camelot64.kickc.model.symbols.Scope;
import dk.camelot64.kickc.model.symbols.Symbol;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.values.ProcedureRef;
import dk.camelot64.kickc.model.values.SymbolVariableRef;
import java.util.Collection;
import java.util.HashSet;
@ -24,16 +30,58 @@ public class PassNEliminateEmptyProcedure extends Pass2SsaOptimization {
boolean optimized = false;
for(Procedure procedure : allProcedures) {
if(hasEmptyBody(procedure.getRef())) {
// Remove all calls
removeAllCalls(procedure.getRef());
// Remove the procedure
Pass2EliminateUnusedBlocks.removeProcedure(procedure.getRef(), new HashSet<>(), getProgram());
optimized = true;
if(!hasExternalUsages(procedure.getRef(), getProgram())) {
// Remove all calls
removeAllCalls(procedure.getRef());
// Remove the procedure
Pass2EliminateUnusedBlocks.removeProcedure(procedure.getRef(), new HashSet<>(), getProgram());
optimized = true;
}
}
}
return optimized;
}
/**
* Examines whether there are any constants inside a procedure with external usages
*
* @param procedureRef
* @return
*/
protected static boolean hasExternalUsages(ProcedureRef procedureRef, Program program) {
program.clearVariableReferenceInfos();
program.clearStatementInfos();
new PassNStatementIndices(program).execute();
final VariableReferenceInfos variableReferenceInfos = program.getVariableReferenceInfos();
final StatementInfos statementInfos = program.getStatementInfos();
final Procedure startProc = program.getScope().getProcedure(procedureRef);
final Collection<Variable> startConsts = startProc.getAllConstants(true);
for(Variable startConst : startConsts) {
final Collection<VariableReferenceInfos.ReferenceToSymbolVar> uses = variableReferenceInfos.getConstRefAllUses(startConst.getConstantRef());
for(VariableReferenceInfos.ReferenceToSymbolVar use : uses) {
if(use instanceof VariableReferenceInfos.ReferenceInStatement) {
final Integer statementIdx = ((VariableReferenceInfos.ReferenceInStatement) use).getStatementIdx();
final ControlFlowBlock block = statementInfos.getBlock(statementIdx);
final Procedure useProcedure = block.getProcedure(program);
if(!procedureRef.equals(useProcedure.getRef())) {
// Usage in a another procedure
return true;
}
} else if(use instanceof VariableReferenceInfos.ReferenceInSymbol) {
final SymbolVariableRef referencingSymbolRef = ((VariableReferenceInfos.ReferenceInSymbol) use).getReferencingSymbol();
final Symbol referencingSymbol = program.getScope().getSymbol(referencingSymbolRef);
final Scope referencingScope = referencingSymbol.getScope();
if(!procedureRef.equals(referencingScope.getRef())) {
// Usage in a another constant
return true;
}
}
}
}
return false;
}
private void removeAllCalls(ProcedureRef ref) {
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
final ListIterator<Statement> stmtIt = block.getStatements().listIterator();

View File

@ -23,10 +23,13 @@ public class PassNEliminateEmptyStart extends Pass2SsaOptimization {
final ProcedureRef startProcRef = new ProcedureRef(SymbolRef.START_PROC_NAME);
StatementCall singleCall = getSingleCall(startProcRef);
if(singleCall != null) {
// Start only has a single call
getProgram().setStartProcedure(singleCall.getProcedure());
Pass2EliminateUnusedBlocks.removeProcedure(startProcRef, new HashSet<>(), getProgram());
return true;
// Are there any constants in the scope that are used elsewhere?
if(!PassNEliminateEmptyProcedure.hasExternalUsages(startProcRef, getProgram())) {
// Start only has a single call - and no external usages
getProgram().setStartProcedure(singleCall.getProcedure());
Pass2EliminateUnusedBlocks.removeProcedure(startProcRef, new HashSet<>(), getProgram());
return true;
}
}
return false;
}
@ -49,7 +52,7 @@ public class PassNEliminateEmptyStart extends Pass2SsaOptimization {
// Another call already encountered
return null;
final StatementCall call = (StatementCall) statement;
if(call.getParameters()==null && call.getlValue() == null)
if(call.getParameters() == null && call.getlValue() == null)
// Call is no-args no-return
singleCall = call;
else