1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-09-08 17:54:40 +00:00

Implemented phi transition reuse when transitions are identical

This commit is contained in:
jespergravgaard 2017-08-26 01:15:57 +02:00
parent 23d9af8420
commit 83edd3e21b
6 changed files with 1043 additions and 926 deletions

View File

@ -68,7 +68,8 @@ public class Pass4CodeGeneration {
/**
* Add label declarations for all scope variables assigned to ZP registers
* @param asm The ASM program
*
* @param asm The ASM program
* @param scope The scope
*/
private void addZpLabels(AsmProgram asm, ScopeRef scope) {
@ -76,10 +77,10 @@ public class Pass4CodeGeneration {
Set<String> added = new LinkedHashSet<>();
for (Variable scopeVar : scopeVars) {
Registers.Register register = scopeVar.getAllocation();
if(register!=null && register.isZp()) {
if (register != null && register.isZp()) {
Registers.RegisterZp registerZp = (Registers.RegisterZp) register;
String asmName = scopeVar.getAsmName();
if(asmName !=null && !added.contains(asmName)) {
if (asmName != null && !added.contains(asmName)) {
asm.addLabelDecl(asmName, registerZp.getZp());
added.add(asmName);
}
@ -170,7 +171,6 @@ public class Pass4CodeGeneration {
}
}
/**
* Contains previous assignment added to the ALU register between calls to generateStatementAsm
*/
@ -195,45 +195,157 @@ public class Pass4CodeGeneration {
}
}
private void genBlockEntryPoints(AsmProgram asm, ControlFlowBlock block) {
if (block.hasPhiBlock()) {
List<ControlFlowBlock> predecessors = new ArrayList<>(getGraph().getPredecessors(block));
Collections.sort(predecessors, new Comparator<ControlFlowBlock>() {
@Override
public int compare(ControlFlowBlock o1, ControlFlowBlock o2) {
return o1.getLabel().getFullName().compareTo(o2.getLabel().getFullName());
}
});
for (ControlFlowBlock predecessor : predecessors) {
if (block.getLabel().equals(predecessor.getConditionalSuccessor())) {
genBlockPhiTransition(asm, predecessor, block, block.getScope());
asm.addInstruction("JMP", AsmAddressingMode.ABS, block.getLabel().getLocalName().replace('@', 'b').replace(':', '_'), false);
}
/**
* Generate all block entry points (phi transitions) which have not already been generated.
*
* @param asm The ASM program to generate into
* @param toBlock The block to generate remaining entry points for.
*/
private void genBlockEntryPoints(AsmProgram asm, ControlFlowBlock toBlock) {
PhiTransitions transitions = getTransitions(toBlock);
for (ControlFlowBlock fromBlock : transitions.getFromBlocks()) {
PhiTransitions.PhiTransition transition = transitions.getTransition(fromBlock);
if (!transition.isGenerated() && toBlock.getLabel().equals(fromBlock.getConditionalSuccessor())) {
genBlockPhiTransition(asm, fromBlock, toBlock, toBlock.getScope());
asm.addInstruction("JMP", AsmAddressingMode.ABS, toBlock.getLabel().getLocalName().replace('@', 'b').replace(':', '_'), false);
}
}
}
/**
* Generate a phi block transition. The transition performs all necessary assignment operations when moving from one block to another.
* The transition can be inserted either at the start of the to-block (used for conditional jumps)
* or at the end of the from-block ( used at default block transitions and before JMP/JSR)
*
* @param asm The ASP program to generate the transition into.
* @param fromBlock The from-block
* @param toBlock The to-block
* @param scope The scope where the ASM code is being inserted. Used to ensure that labels inserted in the code reference the right variables.
* If the transition code is inserted in the to-block, this is the scope of the to-block.
* If the transition code is inserted in the from-block this is the scope of the from-block.
*/
private void genBlockPhiTransition(AsmProgram asm, ControlFlowBlock fromBlock, ControlFlowBlock toBlock, ScopeRef scope) {
PhiTransitions transitions = getTransitions(toBlock);
PhiTransitions.PhiTransition transition = transitions.getTransition(fromBlock);
if (!transition.isGenerated()) {
/** Keeps track of the phi transitions into blocks during code generation.
Statement toFirstStatement = toBlock.getStatements().get(0);
String segmentSrc = "[" + toFirstStatement.getIndex() + "] phi from ";
for (ControlFlowBlock fBlock : transition.getFromBlocks()) {
segmentSrc += fBlock.getLabel().getFullName() + " ";
}
segmentSrc += "to " + toBlock.getLabel().getFullName();
asm.startSegment(toFirstStatement.getIndex(), segmentSrc);
for (ControlFlowBlock fBlock : transition.getFromBlocks()) {
asm.addLabel((toBlock.getLabel().getLocalName() + "_from_" + fBlock.getLabel().getLocalName()).replace('@', 'b').replace(':', '_'));
}
List<PhiTransitions.PhiTransition.PhiAssignment> assignments = transition.getAssignments();
for (PhiTransitions.PhiTransition.PhiAssignment assignment : assignments) {
genAsmMove(asm, assignment.getVariable(), assignment.getrValue(), assignment.getPhiBlock(), scope);
}
transition.setGenerated(true);
}
}
/**
* Keeps track of the phi transitions into blocks during code generation.
* Used to ensure that duplicate transitions are only code generated once.
* Maps to-block label to the transition information*/
private Map<LabelRef, PhiTransitions> transitions;
* Maps to-blocks to the transition information for the block
*/
private Map<ControlFlowBlock, PhiTransitions> blockTransitions = new LinkedHashMap<>();
/**
* Get phi transitions for a specific to-block.
*
* @param toBlock The block
* @return The transitions into the block
*/
private PhiTransitions getTransitions(ControlFlowBlock toBlock) {
PhiTransitions transitions = this.blockTransitions.get(toBlock);
if (transitions == null) {
transitions = new PhiTransitions(toBlock);
this.blockTransitions.put(toBlock, transitions);
}
return transitions;
}
/**
* Keeps track of the phi transitions into a single block during code generation.
* Used to ensure that duplicate transitions are only code generated once.
*/
public static class PhiTransitions {
public class PhiTransitions {
/** Label of the to-block. */
/**
* Label of the to-block.
*/
private ControlFlowBlock toBlock;
/** The phi-block of the to-block. */
/**
* The phi-block of the to-block.
*/
private StatementPhiBlock phiBlock;
public PhiTransition getTransition(LabelRef fromBlock) {
return null;
/**
* Maps from-block to the transition from the from-block to the to-block.
*/
private Map<ControlFlowBlock, PhiTransition> transitions;
public PhiTransitions(ControlFlowBlock toBlock) {
this.toBlock = toBlock;
this.transitions = new LinkedHashMap<>();
if (toBlock.hasPhiBlock()) {
this.phiBlock = toBlock.getPhiBlock();
List<ControlFlowBlock> predecessors = new ArrayList<>(getGraph().getPredecessors(toBlock));
Collections.sort(predecessors, new Comparator<ControlFlowBlock>() {
@Override
public int compare(ControlFlowBlock o1, ControlFlowBlock o2) {
return o1.getLabel().getFullName().compareTo(o2.getLabel().getFullName());
}
});
for (ControlFlowBlock predecessor : predecessors) {
PhiTransition transition = findTransition(predecessor);
transitions.put(predecessor, transition);
}
}
}
/**
* Find the transition from a specific fromBlock.
* If another transition already has the same assignments it is reused. If not a new transition is created.
* @param fromBlock
* @return
*/
private PhiTransition findTransition(ControlFlowBlock fromBlock) {
PhiTransition transition = new PhiTransition(fromBlock);
for (PhiTransition candidate : transitions.values()) {
if(candidate.equalAssignments(transition)) {
candidate.addFromBlock(fromBlock);
return candidate;
}
}
return transition;
}
public Collection<ControlFlowBlock> getFromBlocks() {
return transitions.keySet();
}
/**
* Get the transition into the to-block from a specific from-block
*
* @param fromBlock The from-block
* @return The transition from the from-block into the to-block
*/
public PhiTransition getTransition(ControlFlowBlock fromBlock) {
PhiTransition transition = transitions.get(fromBlock);
if (transition == null) {
transition = findTransition(fromBlock);
transitions.put(fromBlock, transition);
}
return transition;
}
@ -246,10 +358,41 @@ public class Pass4CodeGeneration {
private List<ControlFlowBlock> fromBlocks;
private List<PhiAssignment> assignments;
private boolean generated;
public PhiTransition(ControlFlowBlock fromBlock) {
this.fromBlocks = new ArrayList<>();
this.fromBlocks.add(fromBlock);
this.generated = false;
initAssignments(fromBlock);
}
private void initAssignments(ControlFlowBlock fromBlock) {
this.assignments = new ArrayList<>();
if (phiBlock != null) {
List<StatementPhiBlock.PhiVariable> phiVariables = new ArrayList<>(phiBlock.getPhiVariables());
Collections.reverse(phiVariables);
for (StatementPhiBlock.PhiVariable phiVariable : phiVariables) {
List<StatementPhiBlock.PhiRValue> phiRValues = new ArrayList<>(phiVariable.getValues());
Collections.sort(phiRValues, new Comparator<StatementPhiBlock.PhiRValue>() {
@Override
public int compare(StatementPhiBlock.PhiRValue o1, StatementPhiBlock.PhiRValue o2) {
return o1.getPredecessor().getFullName().compareTo(o2.getPredecessor().getFullName());
}
});
for (StatementPhiBlock.PhiRValue phiRValue : phiRValues) {
if (phiRValue.getPredecessor().equals(fromBlock.getLabel())) {
this.assignments.add(new PhiAssignment(phiVariable, phiRValue));
}
}
}
}
}
public List<PhiAssignment> getAssignments() {
return null;
return assignments;
}
public boolean isGenerated() {
@ -260,6 +403,37 @@ public class Pass4CodeGeneration {
this.generated = generated;
}
public void addFromBlock(ControlFlowBlock fromBlock) {
fromBlocks.add(fromBlock);
}
/**
* Determines if another transition has the exact same assignments as this block
* @param other The other transition to examine
* @return true if the assignments are identical
*/
public boolean equalAssignments(PhiTransition other) {
List<PhiAssignment> otherAssignments = other.getAssignments();
if(assignments.size()!=otherAssignments.size()) {
return false;
}
for (int i = 0; i < assignments.size(); i++) {
PhiAssignment assignment = assignments.get(i);
PhiAssignment otherAssignment = otherAssignments.get(i);
if(!assignment.getVariable().equals(otherAssignment.getVariable())) {
return false;
}
if(!assignment.getrValue().equals(otherAssignment.getrValue())) {
return false;
}
}
return true;
}
public List<ControlFlowBlock> getFromBlocks() {
return fromBlocks;
}
/**
* Assignment of a single value during a phi transition
*/
@ -269,52 +443,30 @@ public class Pass4CodeGeneration {
private StatementPhiBlock.PhiRValue phiRValue;
}
}
}
/**
* Generate a phi block transition. The transition performs all necessary assignment operations when moving from one block to another.
* The transition can be inserted either at the start of the to-block (used for conditional jumps)
* or at the end of the from-block ( used at default block transitions and before JMP/JSR)
* @param asm The ASP program to generate the transition into.
* @param fromBlock The from-block
* @param toBlock The to-block
* @param scope The scope where the ASM code is being inserted. Used to ensure that labels inserted in the code reference the right variables.
* If the transition code is inserted in the to-block, this is the scope of the to-block.
* If the transition code is inserted in the from-block this is the scope of the from-block.
*/
private void genBlockPhiTransition(AsmProgram asm, ControlFlowBlock fromBlock, ControlFlowBlock toBlock, ScopeRef scope) {
Statement toFirstStatement = toBlock.getStatements().get(0);
asm.startSegment(toFirstStatement.getIndex(), "[" + toFirstStatement.getIndex() + "]" + " phi from " + fromBlock.getLabel().getFullName() + " to " + toBlock.getLabel().getFullName());
asm.addLabel((toBlock.getLabel().getLocalName() + "_from_" + fromBlock.getLabel().getLocalName()).replace('@', 'b').replace(':', '_'));
if (toBlock.hasPhiBlock()) {
StatementPhiBlock phiBlock = toBlock.getPhiBlock();
List<StatementPhiBlock.PhiVariable> phiVariables = new ArrayList<>(phiBlock.getPhiVariables());
Collections.reverse(phiVariables);
for (StatementPhiBlock.PhiVariable phiVariable : phiVariables) {
List<StatementPhiBlock.PhiRValue> phiRValues = phiVariable.getValues();
Collections.sort(phiRValues, new Comparator<StatementPhiBlock.PhiRValue>() {
@Override
public int compare(StatementPhiBlock.PhiRValue o1, StatementPhiBlock.PhiRValue o2) {
return o1.getPredecessor().getFullName().compareTo(o2.getPredecessor().getFullName());
}
});
for (StatementPhiBlock.PhiRValue phiRValue : phiRValues) {
if (phiRValue.getPredecessor().equals(fromBlock.getLabel())) {
genAsmMove(asm, phiVariable.getVariable(), phiRValue.getrValue(), phiBlock, scope);
break;
}
public PhiAssignment(StatementPhiBlock.PhiVariable phiVariable, StatementPhiBlock.PhiRValue phiRValue) {
this.phiVariable = phiVariable;
this.phiRValue = phiRValue;
}
public LValue getVariable() {
return phiVariable.getVariable();
}
public RValue getrValue() {
return phiRValue.getrValue();
}
public Statement getPhiBlock() {
return phiBlock;
}
}
}
}
private Registers.Register getRegister(RValue rValue) {
if (rValue instanceof VariableRef) {
VariableRef rValueRef = (VariableRef) rValue;
@ -326,11 +478,12 @@ public class Pass4CodeGeneration {
/**
* Generate ASM assigning a value (rValue) to a variable (lValue).
* @param asm The ASM program to generate into
* @param lValue The lValue that should be assigned the value
* @param rValue The rValue to assign to the lValue.
*
* @param asm The ASM program to generate into
* @param lValue The lValue that should be assigned the value
* @param rValue The rValue to assign to the lValue.
* @param statement The ICL statement that is the cause of the assignment.
* @param scope The scope where the ASM code is being inserted. Used to ensure that labels inserted in the code reference the right variables.
* @param scope The scope where the ASM code is being inserted. Used to ensure that labels inserted in the code reference the right variables.
*/
private void genAsmMove(AsmProgram asm, LValue lValue, RValue rValue, Statement statement, ScopeRef scope) {
asm.startSegment(statement.getIndex(), "[" + statement.getIndex() + "] phi " + lValue.toString(program) + " = " + rValue.toString(program));

View File

@ -1,8 +1,6 @@
jsr main
main: {
jsr prepare
ldx #$19
jmp b3
b3_from_b11:
ldx #$19
b3:

View File

@ -6,7 +6,7 @@ main: scope:[main] from @begin
[1] call prepare param-assignment [ ]
to:main::@3
main::@3: scope:[main] from main main::@11 main::@3 main::@6
[2] (byte) main::c#2 ← phi( main/(byte) 25 main::@11/(byte) 25 main::@6/(byte) main::c#1 ) [ main::c#2 ]
[2] (byte) main::c#2 ← phi( main/(byte) 25 main::@6/(byte) main::c#1 main::@11/(byte) 25 ) [ main::c#2 ]
[3] (byte~) main::$1 ← * (word) 53266 [ main::$1 main::c#2 ]
[4] if((byte~) main::$1!=(byte) 254) goto main::@3 [ main::c#2 ]
to:main::@4

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,7 @@ main::@1: scope:[main] from main main::@1
[4] if((byte) main::i#1!=(byte) 0) goto main::@1 [ main::i#1 ]
to:main::@2
main::@2: scope:[main] from main::@1 main::@2
[5] (byte) main::j#2 ← phi( main::@1/(byte) 100 main::@2/(byte) main::j#1 ) [ main::j#2 ]
[5] (byte) main::j#2 ← phi( main::@2/(byte) main::j#1 main::@1/(byte) 100 ) [ main::j#2 ]
[6] *((word) 1280 + (byte) main::j#2) ← (byte) main::j#2 [ main::j#2 ]
[7] (byte) main::j#1 ← -- (byte) main::j#2 [ main::j#1 ]
[8] if((byte) main::j#1!=(byte) 255) goto main::@2 [ main::j#1 ]

View File

@ -138,7 +138,7 @@ findcol::@9: scope:[findcol] from findcol::@1
[68] if((byte) findcol::y#0!=(byte) findcol::yp#0) goto findcol::@2 [ render::x#2 render::y#2 render::colline#2 findcol::i#12 findcol::x#0 findcol::xp#0 findcol::y#0 findcol::yp#0 findcol::mindiff#10 findcol::mincol#11 numpoints#1 ]
to:findcol::@return
findcol::@return: scope:[findcol] from findcol::@8 findcol::@9
[69] (byte) findcol::return#0 ← phi( findcol::@8/(byte) findcol::mincol#2 findcol::@9/(byte) 0 ) [ render::x#2 render::y#2 findcol::return#0 render::colline#2 ]
[69] (byte) findcol::return#0 ← phi( findcol::@9/(byte) 0 findcol::@8/(byte) findcol::mincol#2 ) [ render::x#2 render::y#2 findcol::return#0 render::colline#2 ]
[70] return [ render::x#2 render::y#2 findcol::return#0 render::colline#2 ]
to:@return
findcol::@2: scope:[findcol] from findcol::@1 findcol::@9