mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-01-11 20:30:08 +00:00
Implemented phi transition reuse when transitions are identical
This commit is contained in:
parent
23d9af8420
commit
83edd3e21b
@ -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));
|
||||
|
@ -1,8 +1,6 @@
|
||||
jsr main
|
||||
main: {
|
||||
jsr prepare
|
||||
ldx #$19
|
||||
jmp b3
|
||||
b3_from_b11:
|
||||
ldx #$19
|
||||
b3:
|
||||
|
@ -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
@ -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 ]
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user