mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-04-07 06:37:31 +00:00
Created "loop-unroll" branch.
This commit is contained in:
parent
a87da922f8
commit
b19bf2246e
src
main/java/dk/camelot64/kickc
CompileLog.javaCompiler.java
model
parser
passes
Pass0GenerateStatementSequence.javaPass1AssertUsedVars.javaPass1ProcedureInline.javaPass2ConditionalAndOrRewriting.javaPass2DominatorsAnalysis.javaPass2LoopAnalysis.javaPass2LoopUnroll.javaPass3StatementInfos.javaPassNEliminateUnusedVars.javaPassNStatementIndices.javaPassNVariableReferenceInfos.java
test/java/dk/camelot64/kickc/test
@ -30,12 +30,12 @@ public class CompileLog {
|
||||
/**
|
||||
* Should SSA optimization be verbose.
|
||||
*/
|
||||
private boolean verboseSSAOptimize = false;
|
||||
private boolean verboseSSAOptimize = true;
|
||||
|
||||
/**
|
||||
* Should the log be output to System.out while being built
|
||||
*/
|
||||
private boolean sysOut = false;
|
||||
private boolean sysOut = true;
|
||||
|
||||
public CompileLog() {
|
||||
this.log = new StringBuilder();
|
||||
|
@ -94,6 +94,8 @@ public class Compiler {
|
||||
|
||||
pass1GenerateSSA();
|
||||
pass2OptimizeSSA();
|
||||
pass2UnrollLoops();
|
||||
pass2InlineConstants();
|
||||
pass3Analysis();
|
||||
pass4RegisterAllocation();
|
||||
pass5GenerateAndOptimizeAsm();
|
||||
@ -201,9 +203,30 @@ public class Compiler {
|
||||
optimizations.add(new Pass2NopCastElimination(program));
|
||||
optimizations.add(new Pass2EliminateUnusedBlocks(program));
|
||||
optimizations.add(new Pass2RangeResolving(program));
|
||||
|
||||
pass2OptimizeSSA(optimizations);
|
||||
|
||||
}
|
||||
|
||||
private void pass2UnrollLoops() {
|
||||
getLog().append("CONTROL FLOW GRAPH BEFORE UNROLLING");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
|
||||
new Pass2DominatorsAnalysis(program).step();
|
||||
getLog().append("NATURAL LOOPS");
|
||||
new Pass2LoopAnalysis(program).step();
|
||||
getLog().append(program.getLoopSet().toString());
|
||||
|
||||
List<Pass2SsaOptimization> loopUnrolling = new ArrayList<>();
|
||||
loopUnrolling.add(new PassNStatementIndices(program));
|
||||
loopUnrolling.add(new PassNVariableReferenceInfos(program));
|
||||
loopUnrolling.add(new Pass3StatementInfos(program));
|
||||
loopUnrolling.add(new Pass2DominatorsAnalysis(program));
|
||||
loopUnrolling.add(new Pass2LoopAnalysis(program));
|
||||
loopUnrolling.add(new Pass2LoopUnroll(program));
|
||||
pass2OptimizeSSA(loopUnrolling);
|
||||
}
|
||||
|
||||
private void pass2InlineConstants() {
|
||||
// Constant inlining optimizations - as the last step to ensure that constant identification has been completed
|
||||
List<Pass2SsaOptimization> constantOptimizations = new ArrayList<>();
|
||||
constantOptimizations.add(new Pass2ConstantInlining(program));
|
||||
@ -212,7 +235,6 @@ public class Compiler {
|
||||
constantOptimizations.add(new Pass2ConstantAdditionElimination(program));
|
||||
constantOptimizations.add(new Pass2ConstantIfs(program));
|
||||
pass2OptimizeSSA(constantOptimizations);
|
||||
|
||||
}
|
||||
|
||||
private void pass2OptimizeSSA(List<Pass2SsaOptimization> optimizations) {
|
||||
@ -252,7 +274,7 @@ public class Compiler {
|
||||
//getLog().append(program.getGraph().toString(program));
|
||||
pass2AssertSSA();
|
||||
new Pass3AddNopBeforeCallOns(program).generate();
|
||||
new PassNStatementIndices(program).generateStatementIndices();
|
||||
new PassNStatementIndices(program).execute();
|
||||
|
||||
getLog().append("CALL GRAPH");
|
||||
new Pass3CallGraphAnalysis(program).findCallGraph();
|
||||
@ -260,8 +282,8 @@ public class Compiler {
|
||||
|
||||
//getLog().setVerboseLiveRanges(true);
|
||||
|
||||
new Pass3StatementInfos(program).generateStatementInfos();
|
||||
new PassNVariableReferenceInfos(program).generateVariableReferenceInfos();
|
||||
new Pass3StatementInfos(program).execute();
|
||||
new PassNVariableReferenceInfos(program).execute();
|
||||
new Pass3LiveRangesAnalysis(program).findLiveRanges();
|
||||
//getLog().append("CONTROL FLOW GRAPH - LIVE RANGES FOUND");
|
||||
//getLog().append(program.getGraph().toString(program));
|
||||
@ -274,10 +296,10 @@ public class Compiler {
|
||||
new Pass2CullEmptyBlocks(program).step();
|
||||
new Pass3BlockSequencePlanner(program).plan();
|
||||
new Pass3AddNopBeforeCallOns(program).generate();
|
||||
new PassNStatementIndices(program).generateStatementIndices();
|
||||
new PassNStatementIndices(program).execute();
|
||||
new Pass3CallGraphAnalysis(program).findCallGraph();
|
||||
new Pass3StatementInfos(program).generateStatementInfos();
|
||||
new PassNVariableReferenceInfos(program).generateVariableReferenceInfos();
|
||||
new Pass3StatementInfos(program).execute();
|
||||
new PassNVariableReferenceInfos(program).execute();
|
||||
new Pass3SymbolInfos(program).generateSymbolInfos();
|
||||
new Pass3LiveRangesAnalysis(program).findLiveRanges();
|
||||
//getLog().append("CONTROL FLOW GRAPH - BEFORE EFFECTIVE LIVE RANGES");
|
||||
@ -294,11 +316,11 @@ public class Compiler {
|
||||
private void pass4RegisterAllocation() {
|
||||
|
||||
getLog().append("DOMINATORS");
|
||||
new Pass3DominatorsAnalysis(program).findDominators();
|
||||
new Pass2DominatorsAnalysis(program).step();
|
||||
getLog().append(program.getDominators().toString());
|
||||
|
||||
getLog().append("NATURAL LOOPS");
|
||||
new Pass3LoopAnalysis(program).findLoops();
|
||||
new Pass2LoopAnalysis(program).step();
|
||||
getLog().append(program.getLoopSet().toString());
|
||||
|
||||
getLog().append("NATURAL LOOPS WITH DEPTH");
|
||||
|
@ -151,7 +151,9 @@ public class ControlFlowGraphCopyVisitor extends ControlFlowGraphBaseVisitor<Obj
|
||||
Operator operator = origConditionalJump.getOperator();
|
||||
RValue rValue2 = origConditionalJump.getrValue2();
|
||||
LabelRef destination = origConditionalJump.getDestination();
|
||||
return new StatementConditionalJump(rValue1, operator, rValue2, destination, origConditionalJump.getSource());
|
||||
StatementConditionalJump conditionalJump = new StatementConditionalJump(rValue1, operator, rValue2, destination, origConditionalJump.getSource());
|
||||
conditionalJump.setDeclaredUnroll(origConditionalJump.isDeclaredUnroll());
|
||||
return conditionalJump;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,13 +1,14 @@
|
||||
package dk.camelot64.kickc.model;
|
||||
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
import dk.camelot64.kickc.passes.Pass2LoopAnalysis;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A set of natural loops in a control flow graph.
|
||||
* <p>For definitions and more see http://www.cs.colostate.edu/~cs553/ClassNotes/lecture09-control-dominators.ppt.pdf
|
||||
* <p>Created by {@link dk.camelot64.kickc.passes.Pass3LoopAnalysis}
|
||||
* <p>Created by {@link Pass2LoopAnalysis}
|
||||
*/
|
||||
public class NaturalLoopSet {
|
||||
|
||||
|
@ -230,6 +230,23 @@ public class VariableReferenceInfos {
|
||||
return stmts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all statements referencing a variable
|
||||
*
|
||||
* @param varRef The variable to look for
|
||||
* @return Index of all statements referencing the constant
|
||||
*/
|
||||
public Collection<Integer> getVarRefStatements(VariableRef varRef) {
|
||||
Collection<ReferenceToSymbolVar> refs = symbolVarReferences.get(varRef);
|
||||
LinkedHashSet<Integer> stmts = new LinkedHashSet<>();
|
||||
refs.stream()
|
||||
.filter(referenceToSymbolVar -> referenceToSymbolVar instanceof ReferenceInStatement)
|
||||
.forEach(referenceToSymbolVar -> stmts.add(((ReferenceInStatement) referenceToSymbolVar).getStatementIdx()));
|
||||
return stmts;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get all constatns referencing another constant
|
||||
*
|
||||
|
@ -6,8 +6,7 @@ import dk.camelot64.kickc.model.operators.Operator;
|
||||
import dk.camelot64.kickc.model.values.RValue;
|
||||
|
||||
/**
|
||||
* Intermediate Compiler Form Statement with a conditional jump.
|
||||
* Intermediate form used for compiler optimization.
|
||||
* SSA form conditional jump. Intermediate form used for compiler optimization.
|
||||
* <br>
|
||||
* <i> if ( Y<sub>j</sub> ) goto XX </i>
|
||||
* <br>
|
||||
@ -19,6 +18,7 @@ public class StatementConditionalJump extends StatementBase {
|
||||
private Operator operator;
|
||||
private RValue rValue2;
|
||||
private LabelRef destination;
|
||||
private boolean declaredUnroll;
|
||||
|
||||
public StatementConditionalJump(RValue condition, LabelRef destination,StatementSource source) {
|
||||
super(null, source);
|
||||
@ -34,17 +34,7 @@ public class StatementConditionalJump extends StatementBase {
|
||||
RValue rValue2,
|
||||
LabelRef destination,
|
||||
StatementSource source) {
|
||||
this(rValue1, operator, rValue2, destination, null, source);
|
||||
}
|
||||
|
||||
public StatementConditionalJump(
|
||||
RValue rValue1,
|
||||
Operator operator,
|
||||
RValue rValue2,
|
||||
LabelRef destination,
|
||||
Integer index,
|
||||
StatementSource source) {
|
||||
super(index, source);
|
||||
super(null, source);
|
||||
this.rValue1 = rValue1;
|
||||
this.operator = operator;
|
||||
this.rValue2 = rValue2;
|
||||
@ -83,10 +73,22 @@ public class StatementConditionalJump extends StatementBase {
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public boolean isDeclaredUnroll() {
|
||||
return declaredUnroll;
|
||||
}
|
||||
|
||||
public void setDeclaredUnroll(boolean declaredUnroll) {
|
||||
this.declaredUnroll = declaredUnroll;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(Program program, boolean aliveInfo) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
out.append(super.idxString());
|
||||
if(declaredUnroll) {
|
||||
out.append("unroll ");
|
||||
|
||||
}
|
||||
out.append("if(");
|
||||
if(rValue1 != null) {
|
||||
out.append(rValue1.toString(program));
|
||||
|
@ -68,7 +68,7 @@ public class StatementInfos {
|
||||
/**
|
||||
* Get statement from index
|
||||
*
|
||||
* @param Statement index
|
||||
* @param index Statement index
|
||||
* @return The statement with the passed index
|
||||
*/
|
||||
public Statement getStatement(int index) {
|
||||
|
@ -54,7 +54,7 @@ public class StatementPhiBlock extends StatementBase {
|
||||
return getPhiVariable(variable).getrValue(predecessor);
|
||||
}
|
||||
|
||||
private PhiVariable getPhiVariable(VariableRef variable) {
|
||||
public PhiVariable getPhiVariable(VariableRef variable) {
|
||||
for(PhiVariable phiVariable : phiVariables) {
|
||||
if(phiVariable.getVariable().equals(variable)) {
|
||||
return phiVariable;
|
||||
|
@ -77,9 +77,9 @@ stmt
|
||||
| '{' stmtSeq? '}' #stmtBlock
|
||||
| expr ';' #stmtExpr
|
||||
| 'if' '(' expr ')' stmt ( 'else' stmt )? #stmtIfElse
|
||||
| directive? 'while' '(' expr ')' stmt #stmtWhile
|
||||
| directive? 'do' stmt 'while' '(' expr ')' ';' #stmtDoWhile
|
||||
| directive? 'for' '(' forDeclaration? forIteration ')' stmt #stmtFor
|
||||
| directive* 'while' '(' expr ')' stmt #stmtWhile
|
||||
| directive* 'do' stmt 'while' '(' expr ')' ';' #stmtDoWhile
|
||||
| directive* 'for' '(' forDeclaration? forIteration ')' stmt #stmtFor
|
||||
| 'return' expr? ';' #stmtReturn
|
||||
| 'asm' '{' asmLines '}' #stmtAsm
|
||||
| declKasm #stmtDeclKasm
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -359,6 +359,28 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add declared directives to a conditional jump (as part of a loop).
|
||||
*
|
||||
* @param conditional The loop conditional
|
||||
* @param directivesCtx The directives to add
|
||||
*/
|
||||
private void addDirectives(StatementConditionalJump conditional, List<KickCParser.DirectiveContext> directivesCtx) {
|
||||
List<Directive> directives = new ArrayList<>();
|
||||
for(KickCParser.DirectiveContext directiveContext : directivesCtx) {
|
||||
directives.add((Directive) this.visit(directiveContext));
|
||||
}
|
||||
for(Directive directive : directives) {
|
||||
StatementSource source = new StatementSource(directivesCtx.get(0));
|
||||
if(directive instanceof DirectiveInline) {
|
||||
conditional.setDeclaredUnroll(true);
|
||||
} else {
|
||||
throw new CompileError("Unsupported loop directive " + directive, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Directive visitDirectiveConst(KickCParser.DirectiveConstContext ctx) {
|
||||
return new DirectiveConst();
|
||||
@ -466,7 +488,7 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
PrePostModifierHandler.addPreModifiers(this, ctx.expr());
|
||||
RValue rValue = (RValue) this.visit(ctx.expr());
|
||||
PrePostModifierHandler.addPostModifiers(this, ctx.expr());
|
||||
Statement doJmpStmt = new StatementConditionalJump(rValue, doJumpLabel.getRef(), new StatementSource(ctx));
|
||||
StatementConditionalJump doJmpStmt = new StatementConditionalJump(rValue, doJumpLabel.getRef(), new StatementSource(ctx));
|
||||
sequence.addStatement(doJmpStmt);
|
||||
Statement endJmpStmt = new StatementJump(endJumpLabel.getRef(), new StatementSource(ctx));
|
||||
sequence.addStatement(endJmpStmt);
|
||||
@ -477,6 +499,9 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
sequence.addStatement(beginJmpStmt);
|
||||
StatementLabel endJumpTarget = new StatementLabel(endJumpLabel.getRef(), new StatementSource(ctx));
|
||||
sequence.addStatement(endJumpTarget);
|
||||
|
||||
// Add directives
|
||||
addDirectives(doJmpStmt, ctx.directive());
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -491,8 +516,11 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
PrePostModifierHandler.addPreModifiers(this, ctx.expr());
|
||||
RValue rValue = (RValue) this.visit(ctx.expr());
|
||||
PrePostModifierHandler.addPostModifiers(this, ctx.expr());
|
||||
Statement doJmpStmt = new StatementConditionalJump(rValue, beginJumpLabel.getRef(), new StatementSource(ctx));
|
||||
StatementConditionalJump doJmpStmt = new StatementConditionalJump(rValue, beginJumpLabel.getRef(), new StatementSource(ctx));
|
||||
sequence.addStatement(doJmpStmt);
|
||||
|
||||
addDirectives(doJmpStmt, ctx.directive());
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -536,8 +564,9 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
RValue rValue = (RValue) this.visit(ctx.expr(0));
|
||||
PrePostModifierHandler.addPostModifiers(this, ctx.expr(0));
|
||||
// Add jump if condition was met
|
||||
Statement doJmpStmt = new StatementConditionalJump(rValue, repeatLabel.getRef(), new StatementSource(ctx));
|
||||
StatementConditionalJump doJmpStmt = new StatementConditionalJump(rValue, repeatLabel.getRef(), new StatementSource(ctx));
|
||||
sequence.addStatement(doJmpStmt);
|
||||
addDirectives(doJmpStmt, stmtForCtx.directive());
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -572,8 +601,9 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
Statement stmtTmpVar = new StatementAssignment(tmpVarRef, lValue.getRef(), Operators.NEQ, beyondLastVal, new StatementSource(ctx));
|
||||
sequence.addStatement(stmtTmpVar);
|
||||
// Add jump if condition was met
|
||||
Statement doJmpStmt = new StatementConditionalJump(tmpVarRef, repeatLabel.getRef(), new StatementSource(ctx));
|
||||
StatementConditionalJump doJmpStmt = new StatementConditionalJump(tmpVarRef, repeatLabel.getRef(), new StatementSource(ctx));
|
||||
sequence.addStatement(doJmpStmt);
|
||||
addDirectives(doJmpStmt, stmtForCtx.directive());
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -24,8 +24,8 @@ public class Pass1AssertUsedVars extends Pass1Base {
|
||||
@Override
|
||||
public boolean step() {
|
||||
|
||||
new PassNStatementIndices(getProgram()).generateStatementIndices();
|
||||
new PassNVariableReferenceInfos(getProgram()).generateVariableReferenceInfos();
|
||||
new PassNStatementIndices(getProgram()).execute();
|
||||
new PassNVariableReferenceInfos(getProgram()).execute();
|
||||
VariableReferenceInfos referenceInfos = getProgram().getVariableReferenceInfos();
|
||||
|
||||
ControlFlowBlock beginBlock = getProgram().getGraph().getBlock(new LabelRef(SymbolRef.BEGIN_BLOCK_NAME));
|
||||
|
@ -40,82 +40,7 @@ public class Pass1ProcedureInline extends Pass1Base {
|
||||
if(procedure.getInterruptType()!=null) {
|
||||
throw new CompileError("Error! Interrupts cannot be inlined. "+procedure.getRef().toString());
|
||||
}
|
||||
Scope callScope = getScope().getScope(block.getScope());
|
||||
// Remove call
|
||||
statementsIt.remove();
|
||||
// Find call serial number (handles when multiple calls to the same procedure is made in the call scope)
|
||||
int serial = nextSerial(procedure, callScope);
|
||||
// Copy all procedure symbols
|
||||
inlineSymbols(procedure, callScope, serial);
|
||||
// Generate parameter assignments
|
||||
inlineParameterAssignments(statementsIt, call, procedure, callScope, serial);
|
||||
// Create a new block label for the rest of the calling block
|
||||
Label restBlockLabel = callScope.addLabelIntermediate();
|
||||
// Copy all procedure blocks
|
||||
List<ControlFlowBlock> procedureBlocks = getGraph().getScopeBlocks(procedure.getRef());
|
||||
for(ControlFlowBlock procedureBlock : procedureBlocks) {
|
||||
LabelRef procBlockLabelRef = procedureBlock.getLabel();
|
||||
Symbol procBlockLabel = getScope().getSymbol(procBlockLabelRef);
|
||||
Label inlinedBlockLabel;
|
||||
if(procedure.equals(procBlockLabel)) {
|
||||
inlinedBlockLabel = callScope.getLabel(procedure.getLocalName() + serial);
|
||||
} else {
|
||||
String inlinedBlockLabelName = getInlineSymbolName(procedure, procBlockLabel, serial);
|
||||
inlinedBlockLabel = callScope.getLabel(inlinedBlockLabelName);
|
||||
}
|
||||
ControlFlowBlock inlineBlock = new ControlFlowBlock(inlinedBlockLabel.getRef(), callScope.getRef());
|
||||
blocksIt.add(inlineBlock);
|
||||
for(Statement procStatement : procedureBlock.getStatements()) {
|
||||
Statement inlinedStatement = inlineStatement(procStatement, procedure, callScope, serial);
|
||||
if(inlinedStatement != null) {
|
||||
inlineBlock.addStatement(inlinedStatement);
|
||||
}
|
||||
}
|
||||
// Set successors
|
||||
if(procedureBlock.getDefaultSuccessor() != null) {
|
||||
LabelRef procBlockSuccessorRef = procedureBlock.getDefaultSuccessor();
|
||||
LabelRef inlinedSuccessor = inlineSuccessor(procBlockSuccessorRef, procedure, callScope, serial, restBlockLabel);
|
||||
inlineBlock.setDefaultSuccessor(inlinedSuccessor);
|
||||
}
|
||||
if(procedureBlock.getConditionalSuccessor() != null) {
|
||||
LabelRef procBlockSuccessorRef = procedureBlock.getConditionalSuccessor();
|
||||
LabelRef inlinedSuccessor = inlineSuccessor(procBlockSuccessorRef, procedure, callScope, serial, restBlockLabel);
|
||||
inlineBlock.setConditionalSuccessor(inlinedSuccessor);
|
||||
}
|
||||
}
|
||||
// Create a new block for the rest of the calling block
|
||||
ControlFlowBlock restBlock = new ControlFlowBlock(restBlockLabel.getRef(), callScope.getRef());
|
||||
blocksIt.add(restBlock);
|
||||
// Generate return assignment
|
||||
if(!procedure.getReturnType().equals(SymbolType.VOID)) {
|
||||
Variable procReturnVar = procedure.getVariable("return");
|
||||
String inlinedReturnVarName = getInlineSymbolName(procedure, procReturnVar, serial);
|
||||
Variable inlinedReturnVar = callScope.getVariable(inlinedReturnVarName);
|
||||
restBlock.addStatement(new StatementAssignment(call.getlValue(), inlinedReturnVar.getRef(), call.getSource()));
|
||||
} else {
|
||||
// Remove the tmp var receiving the result
|
||||
LValue lValue = call.getlValue();
|
||||
if(lValue instanceof VariableRef) {
|
||||
callScope.remove(getScope().getVariable((VariableRef) lValue));
|
||||
call.setlValue(null);
|
||||
}
|
||||
}
|
||||
// Copy the rest of the calling block to the new block
|
||||
while(statementsIt.hasNext()) {
|
||||
Statement restStatement = statementsIt.next();
|
||||
statementsIt.remove();
|
||||
restBlock.addStatement(restStatement);
|
||||
}
|
||||
// Set the successors for the rest block
|
||||
restBlock.setDefaultSuccessor(block.getDefaultSuccessor());
|
||||
restBlock.setConditionalSuccessor(block.getConditionalSuccessor());
|
||||
// Set default successor to the original block to the inlined procedure block
|
||||
Label inlinedProcLabel = callScope.getLabel(procedure.getLocalName() + serial);
|
||||
block.setDefaultSuccessor(inlinedProcLabel.getRef());
|
||||
// Set conditional successor of original block to null (as any condition has been moved to the rest block)
|
||||
block.setConditionalSuccessor(null);
|
||||
// Log the inlining
|
||||
getLog().append("Inlined call " + call.toString(getProgram(), false));
|
||||
inlineProcedureCall(call, procedure, statementsIt, block, blocksIt);
|
||||
// Exit and restart
|
||||
return true;
|
||||
}
|
||||
@ -125,6 +50,94 @@ public class Pass1ProcedureInline extends Pass1Base {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline a specific call to a procedure.
|
||||
*
|
||||
* @param call The call to inline
|
||||
* @param procedure The procedure being called
|
||||
* @param statementsIt The statement iterator pointing to the call statement
|
||||
* @param block The block containing the call
|
||||
* @param blocksIt The block iterator pointing to the block containing the call
|
||||
*/
|
||||
private void inlineProcedureCall(StatementCall call, Procedure procedure, ListIterator<Statement> statementsIt, ControlFlowBlock block, ListIterator<ControlFlowBlock> blocksIt) {
|
||||
Scope callScope = getScope().getScope(block.getScope());
|
||||
// Remove call
|
||||
statementsIt.remove();
|
||||
// Find call serial number (handles when multiple calls to the same procedure is made in the call scope)
|
||||
int serial = nextSerial(procedure, callScope);
|
||||
// Copy all procedure symbols
|
||||
inlineSymbols(procedure, callScope, serial);
|
||||
// Generate parameter assignments
|
||||
inlineParameterAssignments(statementsIt, call, procedure, callScope, serial);
|
||||
// Create a new block label for the rest of the calling block
|
||||
Label restBlockLabel = callScope.addLabelIntermediate();
|
||||
// Copy all procedure blocks
|
||||
List<ControlFlowBlock> procedureBlocks = getGraph().getScopeBlocks(procedure.getRef());
|
||||
for(ControlFlowBlock procedureBlock : procedureBlocks) {
|
||||
LabelRef procBlockLabelRef = procedureBlock.getLabel();
|
||||
Symbol procBlockLabel = getScope().getSymbol(procBlockLabelRef);
|
||||
Label inlinedBlockLabel;
|
||||
if(procedure.equals(procBlockLabel)) {
|
||||
inlinedBlockLabel = callScope.getLabel(procedure.getLocalName() + serial);
|
||||
} else {
|
||||
String inlinedBlockLabelName = getInlineSymbolName(procedure, procBlockLabel, serial);
|
||||
inlinedBlockLabel = callScope.getLabel(inlinedBlockLabelName);
|
||||
}
|
||||
ControlFlowBlock inlineBlock = new ControlFlowBlock(inlinedBlockLabel.getRef(), callScope.getRef());
|
||||
blocksIt.add(inlineBlock);
|
||||
for(Statement procStatement : procedureBlock.getStatements()) {
|
||||
Statement inlinedStatement = inlineStatement(procStatement, procedure, callScope, serial);
|
||||
if(inlinedStatement != null) {
|
||||
inlineBlock.addStatement(inlinedStatement);
|
||||
}
|
||||
}
|
||||
// Set successors
|
||||
if(procedureBlock.getDefaultSuccessor() != null) {
|
||||
LabelRef procBlockSuccessorRef = procedureBlock.getDefaultSuccessor();
|
||||
LabelRef inlinedSuccessor = inlineSuccessor(procBlockSuccessorRef, procedure, callScope, serial, restBlockLabel);
|
||||
inlineBlock.setDefaultSuccessor(inlinedSuccessor);
|
||||
}
|
||||
if(procedureBlock.getConditionalSuccessor() != null) {
|
||||
LabelRef procBlockSuccessorRef = procedureBlock.getConditionalSuccessor();
|
||||
LabelRef inlinedSuccessor = inlineSuccessor(procBlockSuccessorRef, procedure, callScope, serial, restBlockLabel);
|
||||
inlineBlock.setConditionalSuccessor(inlinedSuccessor);
|
||||
}
|
||||
}
|
||||
// Create a new block for the rest of the calling block
|
||||
ControlFlowBlock restBlock = new ControlFlowBlock(restBlockLabel.getRef(), callScope.getRef());
|
||||
blocksIt.add(restBlock);
|
||||
// Generate return assignment
|
||||
if(!procedure.getReturnType().equals(SymbolType.VOID)) {
|
||||
Variable procReturnVar = procedure.getVariable("return");
|
||||
String inlinedReturnVarName = getInlineSymbolName(procedure, procReturnVar, serial);
|
||||
Variable inlinedReturnVar = callScope.getVariable(inlinedReturnVarName);
|
||||
restBlock.addStatement(new StatementAssignment(call.getlValue(), inlinedReturnVar.getRef(), call.getSource()));
|
||||
} else {
|
||||
// Remove the tmp var receiving the result
|
||||
LValue lValue = call.getlValue();
|
||||
if(lValue instanceof VariableRef) {
|
||||
callScope.remove(getScope().getVariable((VariableRef) lValue));
|
||||
call.setlValue(null);
|
||||
}
|
||||
}
|
||||
// Copy the rest of the calling block to the new block
|
||||
while(statementsIt.hasNext()) {
|
||||
Statement restStatement = statementsIt.next();
|
||||
statementsIt.remove();
|
||||
restBlock.addStatement(restStatement);
|
||||
}
|
||||
// Set the successors for the rest block
|
||||
restBlock.setDefaultSuccessor(block.getDefaultSuccessor());
|
||||
restBlock.setConditionalSuccessor(block.getConditionalSuccessor());
|
||||
// Set default successor to the original block to the inlined procedure block
|
||||
Label inlinedProcLabel = callScope.getLabel(procedure.getLocalName() + serial);
|
||||
block.setDefaultSuccessor(inlinedProcLabel.getRef());
|
||||
// Set conditional successor of original block to null (as any condition has been moved to the rest block)
|
||||
block.setConditionalSuccessor(null);
|
||||
// Log the inlining
|
||||
getLog().append("Inlined call " + call.toString(getProgram(), false));
|
||||
}
|
||||
|
||||
private LabelRef inlineSuccessor(LabelRef procBlockSuccessorRef, Procedure procedure, Scope callScope, int serial, Label restBlockLabel) {
|
||||
LabelRef inlinedSuccessor;
|
||||
if(procBlockSuccessorRef.getFullName().equals(SymbolRef.PROCEXIT_BLOCK_NAME)) {
|
||||
@ -188,7 +201,9 @@ public class Pass1ProcedureInline extends Pass1Base {
|
||||
String inlineSymbolName = getInlineSymbolName(procedure, procDestination, serial);
|
||||
inlinedDest = callScope.getLabel(inlineSymbolName);
|
||||
}
|
||||
inlinedStatement = new StatementConditionalJump(procConditional.getrValue1(), procConditional.getOperator(), procConditional.getrValue2(), inlinedDest.getRef(), procConditional.getSource());
|
||||
StatementConditionalJump inlinedConditionalJump = new StatementConditionalJump(procConditional.getrValue1(), procConditional.getOperator(), procConditional.getrValue2(), inlinedDest.getRef(), procConditional.getSource());
|
||||
inlinedConditionalJump.setDeclaredUnroll(procConditional.isDeclaredUnroll());
|
||||
inlinedStatement = inlinedConditionalJump;
|
||||
} else if(procStatement instanceof StatementReturn) {
|
||||
// No statement needed
|
||||
return null;
|
||||
|
@ -89,7 +89,9 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
|
||||
ControlFlowBlock newBlock = new ControlFlowBlock(newBlockLabel.getRef(), currentScopeRef);
|
||||
getGraph().addBlock(newBlock);
|
||||
LabelRef destLabel = conditional.getDestination();
|
||||
newBlock.getStatements().add(new StatementConditionalJump(conditionAssignment.getrValue2(), destLabel, conditional.getSource()));
|
||||
StatementConditionalJump newConditional = new StatementConditionalJump(conditionAssignment.getrValue2(), destLabel, conditional.getSource());
|
||||
newConditional.setDeclaredUnroll(conditional.isDeclaredUnroll());
|
||||
newBlock.getStatements().add(newConditional);
|
||||
newBlock.setDefaultSuccessor(block.getDefaultSuccessor());
|
||||
newBlock.setConditionalSuccessor(destLabel);
|
||||
// Rewrite the conditional to use only the first part of the && condition expression
|
||||
@ -119,13 +121,17 @@ public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
|
||||
Label newBlockLabel = currentScope.addLabelIntermediate();
|
||||
ControlFlowBlock newBlock = new ControlFlowBlock(newBlockLabel.getRef(), currentScopeRef);
|
||||
getGraph().addBlock(newBlock);
|
||||
newBlock.getStatements().add(new StatementConditionalJump(conditionAssignment.getrValue2(), conditional.getDestination(), conditional.getSource()));
|
||||
StatementConditionalJump newConditional = new StatementConditionalJump(conditionAssignment.getrValue2(), conditional.getDestination(), conditional.getSource());
|
||||
// Copy unrolling to the new conditional
|
||||
newConditional.setDeclaredUnroll(conditional.isDeclaredUnroll());
|
||||
newBlock.getStatements().add(newConditional);
|
||||
newBlock.setConditionalSuccessor(conditional.getDestination());
|
||||
newBlock.setDefaultSuccessor(block.getDefaultSuccessor());
|
||||
// Rewrite the conditional to use only the first part of the && condition expression
|
||||
block.setDefaultSuccessor(newBlockLabel.getRef());
|
||||
conditional.setrValue2(conditionAssignment.getrValue1());
|
||||
|
||||
// Remove any unrolling from the original conditional as only the new one leaves the loop
|
||||
conditional.setDeclaredUnroll(false);
|
||||
|
||||
// TODO: Fix phi-values inside the destination phi-blocks to reflect the new control flow! Use replaceLabels(block, replacement)
|
||||
ControlFlowBlock conditionalDestBlock = getGraph().getBlock(conditional.getDestination());
|
||||
|
@ -7,9 +7,9 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** Finds the dominators for the control flow graph. */
|
||||
public class Pass3DominatorsAnalysis extends Pass2Base {
|
||||
public class Pass2DominatorsAnalysis extends Pass2SsaOptimization {
|
||||
|
||||
public Pass3DominatorsAnalysis(Program program) {
|
||||
public Pass2DominatorsAnalysis(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
@ -19,10 +19,9 @@ public class Pass3DominatorsAnalysis extends Pass2Base {
|
||||
* Definition: d dom i if all paths from entry to node i include d
|
||||
* <p>
|
||||
* See http://www.cs.colostate.edu/~cs553/ClassNotes/lecture09-control-dominators.ppt.pdf
|
||||
*
|
||||
* @return The graph dominators
|
||||
*/
|
||||
public void findDominators() {
|
||||
@Override
|
||||
public boolean step() {
|
||||
DominatorsGraph dominatorsGraph = new DominatorsGraph();
|
||||
|
||||
// Initialize dominators: Dom[first]={first}, Dom[block]={all}
|
||||
@ -75,6 +74,7 @@ public class Pass3DominatorsAnalysis extends Pass2Base {
|
||||
|
||||
} while(change);
|
||||
getProgram().setDominators(dominatorsGraph);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -11,19 +11,21 @@ import java.util.*;
|
||||
* <p>
|
||||
* See http://www.cs.colostate.edu/~cs553/ClassNotes/lecture09-control-dominators.ppt.pdf
|
||||
*/
|
||||
public class Pass3LoopAnalysis extends Pass2Base {
|
||||
public class Pass2LoopAnalysis extends Pass2SsaOptimization {
|
||||
|
||||
public Pass3LoopAnalysis(Program program) {
|
||||
public Pass2LoopAnalysis(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds loops and nested loops in the control flow graph.
|
||||
* Uses the dominators of the graph to find loops.
|
||||
* <p>
|
||||
* See http://www.cs.colostate.edu/~cs553/ClassNotes/lecture09-control-dominators.ppt.pdf
|
||||
*/
|
||||
public void findLoops() {
|
||||
@Override
|
||||
public boolean step() {
|
||||
DominatorsGraph dominators = getProgram().getDominators();
|
||||
Collection<ControlFlowBlock> blocks = getGraph().getAllBlocks();
|
||||
|
||||
@ -35,7 +37,9 @@ public class Pass3LoopAnalysis extends Pass2Base {
|
||||
if(blockDominators.contains(successor)) {
|
||||
// Found a loop back edge!
|
||||
NaturalLoop loop = new NaturalLoop(successor, block.getLabel());
|
||||
getLog().append("Found back edge: " + loop.toString());
|
||||
if(getLog().isVerboseSSAOptimize()) {
|
||||
getLog().append("Found back edge: " + loop.toString());
|
||||
}
|
||||
loopSet.addLoop(loop);
|
||||
}
|
||||
}
|
||||
@ -61,15 +65,17 @@ public class Pass3LoopAnalysis extends Pass2Base {
|
||||
}
|
||||
}
|
||||
loop.setBlocks(loopBlocks);
|
||||
getLog().append("Populated: " + loop.toString());
|
||||
if(getLog().isVerboseSSAOptimize()) {
|
||||
getLog().append("Populated: " + loop.toString());
|
||||
}
|
||||
}
|
||||
|
||||
boolean coalesceMore = true;
|
||||
while(coalesceMore) {
|
||||
coalesceMore = coalesceLoops(loopSet);
|
||||
}
|
||||
|
||||
getProgram().setLoopSet(loopSet);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
230
src/main/java/dk/camelot64/kickc/passes/Pass2LoopUnroll.java
Normal file
230
src/main/java/dk/camelot64/kickc/passes/Pass2LoopUnroll.java
Normal file
@ -0,0 +1,230 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementConditionalJump;
|
||||
import dk.camelot64.kickc.model.statements.StatementInfos;
|
||||
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
|
||||
import dk.camelot64.kickc.model.symbols.Label;
|
||||
import dk.camelot64.kickc.model.symbols.Variable;
|
||||
import dk.camelot64.kickc.model.symbols.VariableVersion;
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
import dk.camelot64.kickc.model.values.RValue;
|
||||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/** Unroll Loops declared as inline. */
|
||||
public class Pass2LoopUnroll extends Pass2SsaOptimization {
|
||||
|
||||
public Pass2LoopUnroll(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean step() {
|
||||
// Look for loops to unroll
|
||||
NaturalLoopSet loops = getProgram().getLoopSet();
|
||||
List<NaturalLoop> unrollLoopCandidates = findUnrollLoopCandidates(loops);
|
||||
// Is there any unrolling to do?
|
||||
if(unrollLoopCandidates.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
// Choose the candidate loop with the fewest blocks (and if several have the same number of blocks the first one encountered)
|
||||
NaturalLoop unrollLoop = chooseUnrollLoop(unrollLoopCandidates);
|
||||
getLog().append("Unrolling loop " + unrollLoop);
|
||||
|
||||
List<ControlFlowBlock> unrollBlocks = new ArrayList<>();
|
||||
for(ControlFlowBlock block : getProgram().getGraph().getAllBlocks()) {
|
||||
if(unrollLoop.getBlocks().contains(block.getLabel())) {
|
||||
unrollBlocks.add(block);
|
||||
}
|
||||
}
|
||||
|
||||
// Unroll the first iteration of the loop
|
||||
|
||||
// 0. Unroll Symbols
|
||||
// - Create new versions of all symbols assigned inside the loop
|
||||
Map<VariableRef, VariableRef> definedToNewVar = new LinkedHashMap<>();
|
||||
VariableReferenceInfos variableReferenceInfos = getProgram().getVariableReferenceInfos();
|
||||
for(ControlFlowBlock block : unrollBlocks) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
Collection<VariableRef> definedVars = variableReferenceInfos.getDefinedVars(statement);
|
||||
for(VariableRef definedVarRef : definedVars) {
|
||||
Variable definedVar = getScope().getVariable(definedVarRef);
|
||||
Variable newVar;
|
||||
if(definedVarRef.isIntermediate()) {
|
||||
newVar = definedVar.getScope().addVariableIntermediate();
|
||||
} else if(definedVarRef.isVersion()) {
|
||||
newVar = ((VariableVersion) definedVar).getVersionOf().createVersion();
|
||||
} else {
|
||||
throw new RuntimeException("Error! Variable is not versioned or intermediate " + definedVar.toString(getProgram()));
|
||||
}
|
||||
definedToNewVar.put(definedVarRef, newVar.getRef());
|
||||
getLog().append("Defined in loop: " + definedVarRef.getFullName() + " -> " + newVar.getRef().getFullName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - Ensure that all variables assigned inside the loop has a PHI in successor blocks to the loop
|
||||
// - Find loop successor blocks
|
||||
List<LabelRef> loopSuccessors = new ArrayList<>();
|
||||
List<LabelRef> loopSuccessorPredecessors = new ArrayList<>();
|
||||
for(ControlFlowBlock block : unrollBlocks) {
|
||||
if(block.getDefaultSuccessor() != null && !unrollLoop.getBlocks().contains(block.getDefaultSuccessor())) {
|
||||
// Default successor is outside
|
||||
loopSuccessors.add(block.getDefaultSuccessor());
|
||||
loopSuccessorPredecessors.add(block.getLabel());
|
||||
}
|
||||
if(block.getConditionalSuccessor() != null && !unrollLoop.getBlocks().contains(block.getConditionalSuccessor())) {
|
||||
// Default successor is outside
|
||||
loopSuccessors.add(block.getConditionalSuccessor());
|
||||
loopSuccessorPredecessors.add(block.getLabel());
|
||||
}
|
||||
}
|
||||
// - Add any needed PHI-statements to the successors
|
||||
StatementInfos statementInfos = getProgram().getStatementInfos();
|
||||
for(VariableRef definedVarRef : definedToNewVar.keySet()) {
|
||||
|
||||
// Find out if the variable is ever referenced outside the loop
|
||||
boolean referencedOutsideLoop = false;
|
||||
Collection<Integer> varRefStatements = variableReferenceInfos.getVarRefStatements(definedVarRef);
|
||||
for(Integer varRefStatement : varRefStatements) {
|
||||
ControlFlowBlock refBlock = statementInfos.getBlock(varRefStatement);
|
||||
if(!unrollLoop.getBlocks().contains(refBlock.getLabel())) {
|
||||
referencedOutsideLoop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(referencedOutsideLoop) {
|
||||
for(int i = 0; i < loopSuccessors.size(); i++) {
|
||||
LabelRef successorBlockRef = loopSuccessors.get(i);
|
||||
LabelRef successorPredecessorRef = loopSuccessorPredecessors.get(i);
|
||||
ControlFlowBlock successorBlock = getGraph().getBlock(successorBlockRef);
|
||||
StatementPhiBlock phiBlock = successorBlock.getPhiBlock();
|
||||
|
||||
// Look for a phi-variable
|
||||
boolean phiFound = false;
|
||||
for(StatementPhiBlock.PhiVariable phiVariable : phiBlock.getPhiVariables()) {
|
||||
if(phiVariable.getVariable().isVersion() && definedVarRef.isVersion()) {
|
||||
if(phiVariable.getVariable().getFullNameUnversioned().equals(definedVarRef.getFullNameUnversioned())) {
|
||||
phiFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!phiFound) {
|
||||
Variable definedVar = getScope().getVariable(definedVarRef);
|
||||
Variable newVar = ((VariableVersion) definedVar).getVersionOf().createVersion();
|
||||
StatementPhiBlock.PhiVariable newPhiVar = phiBlock.addPhiVariable(newVar.getRef());
|
||||
newPhiVar.setrValue(successorPredecessorRef, definedVarRef);
|
||||
getLog().append("Missing PHI for " + definedVarRef.getFullName() + " in block " + successorBlock.getLabel() + " - " + phiBlock.toString(getProgram(), false));
|
||||
|
||||
// TODO: Replace all references to definedVarRef outside loop to newVar!
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getLog().append(getGraph().toString(getProgram()));
|
||||
|
||||
// 1. Copy all loop blocks to create the "rest of the loop" and modifying the existing loop to only be the first iteration)
|
||||
// - Unroll Statements (copy all statements, replace symbols properly (with the new versions / the versions assigned in the existing loop)
|
||||
// - Includes unrolling PHI-statements properly
|
||||
// - Unroll Successors (loop-exit successors should point to the same exit, loop-internal successors should point to the new loop-internal block)
|
||||
for(ControlFlowBlock block : unrollBlocks) {
|
||||
// Find the serial number
|
||||
int unrollSerial = 1;
|
||||
String unrollLabelName = block.getLabel() + "_" + unrollSerial;
|
||||
while(getScope().getLabel(unrollLabelName) != null) {
|
||||
unrollSerial++;
|
||||
}
|
||||
// Create a label
|
||||
Label unrollLabel = getScope().getScope(block.getScope()).addLabel(unrollLabelName);
|
||||
// Create the new block
|
||||
ControlFlowBlock unrollBlock = new ControlFlowBlock(unrollLabel.getRef(), block.getScope());
|
||||
getProgram().getGraph().addBlock(unrollBlock);
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementPhiBlock) {
|
||||
StatementPhiBlock phiBlock = (StatementPhiBlock) statement;
|
||||
StatementPhiBlock unrollPhiBlock = new StatementPhiBlock();
|
||||
for(StatementPhiBlock.PhiVariable phiVariable : phiBlock.getPhiVariables()) {
|
||||
VariableRef phiVar = phiVariable.getVariable();
|
||||
VariableRef newVar = definedToNewVar.get(phiVar);
|
||||
StatementPhiBlock.PhiVariable unrollPhiVariable = unrollPhiBlock.addPhiVariable(newVar);
|
||||
for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
|
||||
/* FIX */
|
||||
LabelRef predecessor = phiRValue.getPredecessor();
|
||||
/* FIX */
|
||||
RValue rValue = phiRValue.getrValue();
|
||||
unrollPhiVariable.setrValue(predecessor, rValue);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Statement not handled by unroll " + statement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Patch the "old loop" to only contain the first iteration
|
||||
// - All successors in the old loop to the loop head should point to the new loop head instead.
|
||||
// - Remove phi-variables in the old head from looping. (as this predecessor now no longer exists)
|
||||
// - Remove the "unroll" directive on the condition in the old loop (as it is already unrolled).
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Choose which loop to unroll first from a candidate set.
|
||||
* The smallest loop (fewest control flow blocks) is chosen.
|
||||
* If multiple loops have the same size the first one is chosen.
|
||||
*
|
||||
* @param unrollLoopCandidates All loops that are decalred to be unrolled
|
||||
* @return The loop to unroll first.
|
||||
*/
|
||||
private NaturalLoop chooseUnrollLoop(List<NaturalLoop> unrollLoopCandidates) {
|
||||
NaturalLoop unrollLoop = null;
|
||||
for(NaturalLoop unrollLoopCandidate : unrollLoopCandidates) {
|
||||
if(unrollLoop == null) {
|
||||
unrollLoop = unrollLoopCandidate;
|
||||
} else {
|
||||
if(unrollLoopCandidate.getBlocks().size() < unrollLoop.getBlocks().size()) {
|
||||
unrollLoop = unrollLoopCandidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
return unrollLoop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all loops declared for unrolling. This is done by examining all conditional jumps, which hold the loop unroll declaration.
|
||||
*
|
||||
* @param loops All loops identified in the program
|
||||
* @return All loops declared to be unrolled
|
||||
*/
|
||||
private List<NaturalLoop> findUnrollLoopCandidates(NaturalLoopSet loops) {
|
||||
List<NaturalLoop> unrollLoopCandidates = new ArrayList<>();
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementConditionalJump) {
|
||||
if(((StatementConditionalJump) statement).isDeclaredUnroll()) {
|
||||
// Found a candidate for unrolling - identify the loop
|
||||
for(NaturalLoop loopCandidate : loops.getLoopsContainingBlock(block.getLabel())) {
|
||||
if(!loopCandidate.getBlocks().contains(block.getConditionalSuccessor())) {
|
||||
// The conditional jump exits the loopCandidate - so we have identified the right one!
|
||||
unrollLoopCandidates.add(loopCandidate);
|
||||
break;
|
||||
} else if(!loopCandidate.getBlocks().contains(block.getDefaultSuccessor())) {
|
||||
// The default successor of the conditional exits the loopCandidate - so we have identified the right one!
|
||||
unrollLoopCandidates.add(loopCandidate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return unrollLoopCandidates;
|
||||
}
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementInfos;
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
@ -11,16 +12,18 @@ import java.util.LinkedHashMap;
|
||||
/**
|
||||
* Identify the block for each statement.
|
||||
*/
|
||||
public class Pass3StatementInfos extends Pass2Base {
|
||||
public class Pass3StatementInfos extends Pass2SsaOptimization {
|
||||
|
||||
public Pass3StatementInfos(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create map from statement index to block
|
||||
*/
|
||||
public void generateStatementInfos() {
|
||||
@Override
|
||||
public boolean step() {
|
||||
LinkedHashMap<Integer, LabelRef> stmtBlocks = new LinkedHashMap<>();
|
||||
LinkedHashMap<Integer, Statement> stmtIdx = new LinkedHashMap<>();
|
||||
for(ControlFlowBlock block : getProgram().getGraph().getAllBlocks()) {
|
||||
@ -30,6 +33,7 @@ public class Pass3StatementInfos extends Pass2Base {
|
||||
}
|
||||
}
|
||||
getProgram().setStatementInfos(new StatementInfos(getProgram(), stmtBlocks, stmtIdx));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,8 +24,8 @@ public class PassNEliminateUnusedVars extends Pass2SsaOptimization {
|
||||
|
||||
@Override
|
||||
public boolean step() {
|
||||
new PassNStatementIndices(getProgram()).generateStatementIndices();
|
||||
new PassNVariableReferenceInfos(getProgram()).generateVariableReferenceInfos();
|
||||
new PassNStatementIndices(getProgram()).execute();
|
||||
new PassNVariableReferenceInfos(getProgram()).execute();
|
||||
VariableReferenceInfos referenceInfos = getProgram().getVariableReferenceInfos();
|
||||
boolean modified = false;
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
|
@ -8,22 +8,25 @@ import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
|
||||
public class PassNStatementIndices extends Pass2Base {
|
||||
public class PassNStatementIndices extends Pass2SsaOptimization {
|
||||
|
||||
public PassNStatementIndices(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create index numbers for all statements in the control flow graph.
|
||||
*/
|
||||
public void generateStatementIndices() {
|
||||
@Override
|
||||
public boolean step() {
|
||||
int currentIdx = 0;
|
||||
for(ControlFlowBlock block : getProgram().getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
statement.setIndex(currentIdx++);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -17,62 +17,15 @@ import java.util.*;
|
||||
/**
|
||||
* Identify variables defined/referenced for each block & statement.
|
||||
*/
|
||||
public class PassNVariableReferenceInfos extends Pass2Base {
|
||||
public class PassNVariableReferenceInfos extends Pass2SsaOptimization {
|
||||
|
||||
public PassNVariableReferenceInfos(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all variables referenced in an rValue
|
||||
*
|
||||
* @param rValue The rValue
|
||||
* @return All referenced variables
|
||||
*/
|
||||
public static Collection<VariableRef> getReferencedVars(RValue rValue) {
|
||||
LinkedHashSet<VariableRef> referencedVars = new LinkedHashSet<>();
|
||||
for(SymbolRef symbolRef : getReferenced(rValue)) {
|
||||
if(symbolRef instanceof VariableRef) {
|
||||
referencedVars.add((VariableRef) symbolRef);
|
||||
}
|
||||
}
|
||||
return referencedVars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all constants referenced in an rValue
|
||||
*
|
||||
* @param rValue The rValue
|
||||
* @return All referenced constants
|
||||
*/
|
||||
public static Collection<ConstantRef> getReferencedConsts(RValue rValue) {
|
||||
LinkedHashSet<ConstantRef> referencedConsts = new LinkedHashSet<>();
|
||||
for(SymbolRef symbolRef : getReferenced(rValue)) {
|
||||
if(symbolRef instanceof ConstantRef) {
|
||||
referencedConsts.add((ConstantRef) symbolRef);
|
||||
}
|
||||
}
|
||||
return referencedConsts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all variables /constants referenced in an rValue
|
||||
*
|
||||
* @param rValue The rValue
|
||||
* @return All referenced variables / constants
|
||||
*/
|
||||
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);
|
||||
return referenced;
|
||||
}
|
||||
|
||||
/** Create defined/referenced maps */
|
||||
public void generateVariableReferenceInfos() {
|
||||
@Override
|
||||
public boolean step() {
|
||||
LinkedHashMap<LabelRef, Collection<VariableRef>> blockReferencedVars = new LinkedHashMap<>();
|
||||
LinkedHashMap<LabelRef, Collection<VariableRef>> blockUsedVars = new LinkedHashMap<>();
|
||||
LinkedHashMap<Integer, Collection<VariableRef>> stmtReferenced = new LinkedHashMap<>();
|
||||
@ -128,6 +81,56 @@ public class PassNVariableReferenceInfos extends Pass2Base {
|
||||
});
|
||||
}
|
||||
getProgram().setVariableReferenceInfos(new VariableReferenceInfos(blockReferencedVars, blockUsedVars, stmtReferenced, stmtDefined, symbolVarReferences));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get all variables referenced in an rValue
|
||||
*
|
||||
* @param rValue The rValue
|
||||
* @return All referenced variables
|
||||
*/
|
||||
public static Collection<VariableRef> getReferencedVars(RValue rValue) {
|
||||
LinkedHashSet<VariableRef> referencedVars = new LinkedHashSet<>();
|
||||
for(SymbolRef symbolRef : getReferenced(rValue)) {
|
||||
if(symbolRef instanceof VariableRef) {
|
||||
referencedVars.add((VariableRef) symbolRef);
|
||||
}
|
||||
}
|
||||
return referencedVars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all constants referenced in an rValue
|
||||
*
|
||||
* @param rValue The rValue
|
||||
* @return All referenced constants
|
||||
*/
|
||||
public static Collection<ConstantRef> getReferencedConsts(RValue rValue) {
|
||||
LinkedHashSet<ConstantRef> referencedConsts = new LinkedHashSet<>();
|
||||
for(SymbolRef symbolRef : getReferenced(rValue)) {
|
||||
if(symbolRef instanceof ConstantRef) {
|
||||
referencedConsts.add((ConstantRef) symbolRef);
|
||||
}
|
||||
}
|
||||
return referencedConsts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all variables /constants referenced in an rValue
|
||||
*
|
||||
* @param rValue The rValue
|
||||
* @return All referenced variables / constants
|
||||
*/
|
||||
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);
|
||||
return referenced;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,10 +46,20 @@ public class TestPrograms {
|
||||
AsmFragmentTemplateUsages.logUsages(log, false, false, false, false, false, false);
|
||||
}
|
||||
|
||||
// @Test
|
||||
// public void testUnrollScreenFill() throws IOException, URISyntaxException {
|
||||
// compileAndCompare("unroll-screenfill");
|
||||
// }
|
||||
@Test
|
||||
public void testUnusedBlockProblem() throws IOException, URISyntaxException {
|
||||
compileAndCompare("unusedblockproblem");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnrollScreenFill() throws IOException, URISyntaxException {
|
||||
compileAndCompare("unroll-screenfill");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoop100() throws IOException, URISyntaxException {
|
||||
compileAndCompare("loop100");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIrqHardwareClobberJsr() throws IOException, URISyntaxException {
|
||||
|
4
src/test/java/dk/camelot64/kickc/test/kc/loop100.kc
Normal file
4
src/test/java/dk/camelot64/kickc/test/kc/loop100.kc
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
void main() {
|
||||
for(byte i=0; i<100; i++) { }
|
||||
}
|
@ -2,9 +2,34 @@
|
||||
|
||||
void main() {
|
||||
byte* SCREEN = $400;
|
||||
|
||||
byte a=3;
|
||||
inline do {
|
||||
SCREEN[a]=a;
|
||||
a++;
|
||||
} while(a<14);
|
||||
SCREEN[a]=a;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
for(byte x: 0..39) {
|
||||
|
||||
inline for(byte line: 0..24) {
|
||||
(SCREEN+line*40)[x] = x;
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
for(byte x: 0..39) {
|
||||
byte line = 0;
|
||||
inline while(line!=25 || x<10) {
|
||||
(SCREEN+line*40)[x] = x;
|
||||
line++;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
// Problem with eliminating unused blocks/vars after the infinite loop (symbol line#2 not removed from symbol table)
|
||||
|
||||
void main() {
|
||||
byte* SCREEN = $400;
|
||||
while(true) {
|
||||
(*SCREEN)++;
|
||||
}
|
||||
for(byte line: 0..24) {
|
||||
SCREEN[line] = line;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user