Skip to content

Commit 3a9e584

Browse files
Merge pull request #23 from CompilerProgramming/sccp
Sparse Conditional Constant Propagation - apply the changes after analysis
2 parents 3b4e65e + 5584b4d commit 3a9e584

File tree

14 files changed

+471
-46
lines changed

14 files changed

+471
-46
lines changed

optvm/src/main/java/com/compilerprogramming/ezlang/compiler/BasicBlock.java

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,19 @@ public void add(Instruction instruction) {
9898
instructions.add(instruction);
9999
instruction.block = this;
100100
}
101+
public void deleteInstruction(Instruction instruction) {
102+
instructions.remove(instruction);
103+
}
101104
public void addSuccessor(BasicBlock successor) {
105+
assert successors.contains(successor) == false;
102106
successors.add(successor);
107+
assert successor.predecessors.contains(this) == false;
103108
successor.predecessors.add(this);
104109
}
110+
public void removeSuccessor(BasicBlock successor) {
111+
successors.remove(successor);
112+
successor.predecessors.remove(this);
113+
}
105114

106115
/**
107116
* Initially the phi has the form
@@ -132,15 +141,25 @@ public List<Instruction.Phi> phis() {
132141
}
133142
return list;
134143
}
135-
public int whichPred(BasicBlock s) {
144+
public int whichPred(BasicBlock pred) {
136145
int i = 0;
137-
for (BasicBlock p: s.predecessors) {
138-
if (p == this)
146+
for (BasicBlock p: predecessors) {
147+
if (p == pred)
139148
return i;
140149
i++;
141150
}
142151
throw new IllegalStateException();
143152
}
153+
public int whichSucc(BasicBlock succ) {
154+
int i = 0;
155+
for (BasicBlock s: successors) {
156+
if (s == succ)
157+
return i;
158+
i++;
159+
}
160+
throw new IllegalStateException();
161+
}
162+
144163
public static StringBuilder toStr(StringBuilder sb, BasicBlock bb, BitSet visited, boolean dumpLiveness)
145164
{
146165
if (visited.get(bb.bid))

optvm/src/main/java/com/compilerprogramming/ezlang/compiler/DominatorTree.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,9 @@ private void calculateDominanceFrontiers() {
193193
if (b.predecessors.size() >= 2) {
194194
for (BasicBlock p : b.predecessors) {
195195
BasicBlock runner = p;
196-
while (runner != b.idom) {
196+
// re runner != null: Dominance frontier calc fails in infinite loop
197+
// scenario - need to check what the correct solution is
198+
while (runner != b.idom && runner != null) {
197199
runner.dominationFrontier.add(b);
198200
runner = runner.idom;
199201
}

optvm/src/main/java/com/compilerprogramming/ezlang/compiler/EnterSSA.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,9 @@ void search(BasicBlock block) {
153153
}
154154
// Update phis in successor blocks
155155
for (BasicBlock s: block.successors) {
156-
int j = block.whichPred(s);
156+
int j = s.whichPred(block);
157157
for (Instruction.Phi phi: s.phis()) {
158-
Register oldReg = phi.input(j);
158+
Register oldReg = phi.inputAsRegister(j);
159159
phi.replaceInput(j, stacks[oldReg.nonSSAId()].top());
160160
}
161161
}

optvm/src/main/java/com/compilerprogramming/ezlang/compiler/ExitSSA.java

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ private void insertCopies(BasicBlock block) {
5252
* replace all uses u with stacks[i]
5353
*/
5454
private void replaceUses(Instruction i) {
55+
if (i instanceof Instruction.Phi)
56+
// FIXME check this can never be valid
57+
// tests 8/9 in TestInterpreter invoke on Phi but
58+
// replacements are same as existing inputs
59+
return;
5560
var oldUses = i.uses();
5661
Register[] newUses = new Register[oldUses.size()];
5762
for (int u = 0; u < oldUses.size(); u++) {
@@ -65,13 +70,15 @@ private void replaceUses(Instruction i) {
6570
}
6671

6772
static class CopyItem {
68-
final Register src;
73+
final Operand src;
6974
final Register dest;
75+
final BasicBlock destBlock;
7076
boolean removed;
7177

72-
public CopyItem(Register src, Register dest) {
78+
public CopyItem(Operand src, Register dest, BasicBlock destBlock) {
7379
this.src = src;
7480
this.dest = dest;
81+
this.destBlock = destBlock;
7582
this.removed = false;
7683
}
7784
}
@@ -83,14 +90,17 @@ private void scheduleCopies(BasicBlock block, List<Integer> pushed) {
8390
Map<Integer, Register> map = new HashMap<>();
8491
BitSet usedByAnother = new BitSet(function.registerPool.numRegisters()*2);
8592
for (BasicBlock s: block.successors) {
86-
int j = block.whichPred(s);
93+
int j = s.whichPred(block);
8794
for (Instruction.Phi phi: s.phis()) {
8895
Register dst = phi.value();
89-
Register src = phi.input(j); // jth operand of phi node
90-
copySet.add(new CopyItem(src, dst));
91-
map.put(src.id, src);
96+
Operand srcOperand = phi.input(j); // jth operand of phi node
97+
if (srcOperand instanceof Operand.RegisterOperand srcRegisterOperand) {
98+
Register src = srcRegisterOperand.reg;
99+
map.put(src.id, src);
100+
usedByAnother.set(src.id);
101+
}
102+
copySet.add(new CopyItem(srcOperand, dst, s));
92103
map.put(dst.id, dst);
93-
usedByAnother.set(src.id);
94104
}
95105
}
96106

@@ -111,8 +121,9 @@ private void scheduleCopies(BasicBlock block, List<Integer> pushed) {
111121
while (!workList.isEmpty() || !copySet.isEmpty()) {
112122
while (!workList.isEmpty()) {
113123
final CopyItem copyItem = workList.remove(0);
114-
final Register src = copyItem.src;
124+
final Operand src = copyItem.src;
115125
final Register dest = copyItem.dest;
126+
final BasicBlock destBlock = copyItem.destBlock;
116127
/* Engineering a Compiler: We can avoid the lost copy
117128
problem by checking the liveness of the target name
118129
for each copy that we try to insert. When we discover
@@ -122,18 +133,23 @@ private void scheduleCopies(BasicBlock block, List<Integer> pushed) {
122133
*/
123134
if (block.liveOut.get(dest.id)) {
124135
/* Insert a copy from dest to a new temp t at phi node defining dest */
125-
final Register t = addMoveToTempAfterPhi(block, dest);
136+
final Register t = addMoveToTempAfterPhi(destBlock, dest);
126137
stacks[dest.id].push(t);
127138
pushed.add(dest.id);
128139
}
129140
/* Insert a copy operation from map[src] to dest at end of BB */
130-
addMoveAtBBEnd(block, map.get(src.id), dest);
131-
map.put(src.id, dest);
132-
/* If src is the name of a dest in copySet add item to worklist */
133-
/* see comment on phi cycles below. */
134-
CopyItem item = isCycle(copySet, src);
135-
if (item != null) {
136-
workList.add(item);
141+
if (src instanceof Operand.RegisterOperand srcRegisterOperand) {
142+
addMoveAtBBEnd(block, map.get(srcRegisterOperand.reg.id), dest);
143+
map.put(srcRegisterOperand.reg.id, dest);
144+
/* If src is the name of a dest in copySet add item to worklist */
145+
/* see comment on phi cycles below. */
146+
CopyItem item = isCycle(copySet, srcRegisterOperand.reg);
147+
if (item != null) {
148+
workList.add(item);
149+
}
150+
}
151+
else if (src instanceof Operand.ConstantOperand srcConstantOperand) {
152+
addMoveAtBBEnd(block, srcConstantOperand, dest);
137153
}
138154
}
139155
/* Engineering a Compiler: To solve the swap problem
@@ -204,7 +220,10 @@ private void addMoveAtBBEnd(BasicBlock block, Register src, Register dest) {
204220
var inst = new Instruction.Move(new Operand.RegisterOperand(src), new Operand.RegisterOperand(dest));
205221
insertAtEnd(block, inst);
206222
}
207-
223+
private void addMoveAtBBEnd(BasicBlock block, Operand.ConstantOperand src, Register dest) {
224+
var inst = new Instruction.Move(src, new Operand.RegisterOperand(dest));
225+
insertAtEnd(block, inst);
226+
}
208227
/* Insert a copy dest to a new temp at phi node defining dest, return temp */
209228
private Register addMoveToTempAfterPhi(BasicBlock block, Register dest) {
210229
var temp = function.registerPool.newTempReg(dest.name(), dest.type);

optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Instruction.java

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,21 @@ public abstract class Instruction {
2727
static final int I_FIELD_SET = 16;
2828

2929
public final int opcode;
30-
public Operand.RegisterOperand def;
31-
public Operand[] uses;
30+
protected Operand.RegisterOperand def;
31+
protected Operand[] uses;
3232
public BasicBlock block;
3333

3434
public Instruction(int opcode, Operand... uses) {
3535
this.opcode = opcode;
3636
this.def = null;
37-
this.uses = uses;
37+
this.uses = new Operand[uses.length];
38+
System.arraycopy(uses, 0, this.uses, 0, uses.length);
3839
}
3940
public Instruction(int opcode, Operand.RegisterOperand def, Operand... uses) {
4041
this.opcode = opcode;
4142
this.def = def;
42-
this.uses = uses;
43+
this.uses = new Operand[uses.length];
44+
System.arraycopy(uses, 0, this.uses, 0, uses.length);
4345
}
4446

4547
public boolean isTerminal() { return false; }
@@ -87,7 +89,14 @@ public boolean replaceUse(Register source, Register target) {
8789
}
8890
return replaced;
8991
}
90-
92+
public void replaceWithConstant(Register register, Operand.ConstantOperand constantOperand) {
93+
for (int i = 0; i < uses.length; i++) {
94+
Operand operand = uses[i];
95+
if (operand != null && operand instanceof Operand.RegisterOperand registerOperand && registerOperand.reg.id == register.id) {
96+
uses[i] = constantOperand;
97+
}
98+
}
99+
}
91100
public static class NoOp extends Instruction {
92101
public NoOp() {
93102
super(I_NOOP);
@@ -340,21 +349,35 @@ public StringBuilder toStr(StringBuilder sb) {
340349
/**
341350
* Phi does not generate uses or defs directly, instead
342351
* they are treated as a special case.
343-
* To avoid bugs we do not use the def or uses.
352+
* To avoid bugs we disable the standard interfaces
344353
*/
345354
public static class Phi extends Instruction {
346-
public Register value;
347-
public final Register[] inputs;
355+
private Register value;
348356
public Phi(Register value, List<Register> inputs) {
349357
super(I_PHI);
350358
this.value = value;
351-
this.inputs = inputs.toArray(new Register[inputs.size()]);
359+
this.uses = new Operand[inputs.size()];
360+
for (int i = 0; i < inputs.size(); i++) {
361+
this.uses[i] = new Operand.RegisterOperand(inputs.get(i));
362+
}
352363
}
353364
public void replaceInput(int i, Register newReg) {
354-
inputs[i] = newReg;
365+
uses[i].replaceRegister(newReg);
366+
}
367+
/**
368+
* This will fail in input was replaced by a constant
369+
*/
370+
public Register inputAsRegister(int i) {
371+
return ((Operand.RegisterOperand) uses[i]).reg;
372+
}
373+
public Operand input(int i) {
374+
return uses[i];
375+
}
376+
public boolean isRegisterInput(int i) {
377+
return uses[i] instanceof Operand.RegisterOperand;
355378
}
356-
public Register input(int i) {
357-
return inputs[i];
379+
public Register[] inputRegisters() {
380+
return super.uses().toArray(new Register[super.uses().size()]);
358381
}
359382
@Override
360383
public Register def() {
@@ -368,18 +391,36 @@ public void replaceDef(Register newReg) {
368391
public boolean definesVar() {
369392
return false;
370393
}
394+
@Override
395+
public List<Register> uses() {
396+
return Collections.emptyList();
397+
}
398+
@Override
399+
public void replaceUses(Register[] newUses) {
400+
throw new UnsupportedOperationException();
401+
}
402+
@Override
403+
public boolean replaceUse(Register source, Register target) {
404+
throw new UnsupportedOperationException();
405+
}
371406
public Register value() {
372407
return value;
373408
}
374409
public void replaceValue(Register newReg) {
375410
this.value = newReg;
376411
}
412+
public void removeInput(int i) {
413+
var newUses = new Operand[uses.length - 1];
414+
System.arraycopy(uses, 0, newUses, 0, i);
415+
System.arraycopy(uses, i + 1, newUses, i, uses.length - i - 1);
416+
this.uses = newUses;
417+
}
377418
@Override
378419
public StringBuilder toStr(StringBuilder sb) {
379420
sb.append(value().name()).append(" = phi(");
380-
for (int i = 0; i < inputs.length; i++) {
421+
for (int i = 0; i < uses.length; i++) {
381422
if (i > 0) sb.append(", ");
382-
sb.append(inputs[i].name());
423+
sb.append(uses[i].toString());
383424
}
384425
sb.append(")");
385426
return sb;

optvm/src/main/java/com/compilerprogramming/ezlang/compiler/InterferenceGraph.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ public void rename(Integer source, Integer target) {
6363
// Move all interferences
6464
var fromSet = edges.remove(source);
6565
var toSet = edges.get(target);
66+
if (toSet == null) {
67+
//throw new RuntimeException("Cannot find edge " + target + " from " + source);
68+
return; // FIXME this is workaround to handle sceanrio where target is arg register but we need a better way
69+
}
6670
toSet.addAll(fromSet);
6771
// If any node interfered with from
6872
// it should now interfere with to

optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Liveness.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ private void init(List<BasicBlock> blocks) {
6969
if (instruction instanceof Instruction.Phi phi) {
7070
for (int i = 0; i < block.predecessors.size(); i++) {
7171
BasicBlock pred = block.predecessors.get(i);
72-
Register use = phi.input(i);
72+
if (!phi.isRegisterInput(i))
73+
continue;
74+
Register use = phi.inputAsRegister(i);
7375
// We can have a block referring it its own phis
7476
// if there is loop back and there are cycles
7577
// such as e.g. the swap copy problem

optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Optimizer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ public class Optimizer {
44

55
public void optimize(CompiledFunction function) {
66
new EnterSSA(function);
7-
new SparseConditionalConstantPropagation().constantPropagation(function);
7+
new SparseConditionalConstantPropagation().constantPropagation(function).apply();
88
new ExitSSA(function);
99
new ChaitinGraphColoringRegisterAllocator().assignRegisters(function, 64);
1010
}

optvm/src/main/java/com/compilerprogramming/ezlang/compiler/SSAEdges.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ private static void recordUses(CompiledFunction function, Map<Register, SSADef>
5858
for (BasicBlock block : function.getBlocks()) {
5959
for (Instruction instruction : block.instructions) {
6060
if (instruction instanceof Instruction.Phi phi) {
61-
recordUses(defUseChains, phi.inputs, block, instruction);
61+
recordUses(defUseChains, phi.inputRegisters(), block, instruction);
6262
}
6363
else {
6464
List<Register> uses = instruction.uses();

0 commit comments

Comments
 (0)