mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-01-26 15:30:28 +00:00
Working on static initialization rewrite _init(). #257
This commit is contained in:
parent
d129efb95f
commit
a989e63f5b
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user