Skip to content

Commit b979315

Browse files
#57 Implement phase 1 of SSA Exit - make conventional SSA
1 parent 109fdc2 commit b979315

File tree

3 files changed

+195
-0
lines changed

3 files changed

+195
-0
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,11 @@ public int whichPred(BasicBlock pred) {
158158
}
159159
throw new IllegalStateException();
160160
}
161+
public BasicBlock predecessor(int i) {
162+
if (i >= predecessors.size())
163+
return null;
164+
return predecessors.get(i);
165+
}
161166
public int whichSucc(BasicBlock succ) {
162167
int i = 0;
163168
for (BasicBlock s: successors) {
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package com.compilerprogramming.ezlang.compiler;
2+
3+
import java.util.*;
4+
5+
/**
6+
* Implement method to exit SSA by converting to conventional SSA,
7+
* without coalescing. This is the basic form.
8+
*/
9+
public class ExitSSA2 {
10+
11+
CompiledFunction function;
12+
Map<BasicBlock,PCopy> parallelCopies = new HashMap<>();
13+
List<BasicBlock> allBlocks;
14+
15+
public ExitSSA2(CompiledFunction function, EnumSet<Options> options) {
16+
this.function = function;
17+
allBlocks = function.getBlocks();
18+
insertPCopiesForEachBlock();
19+
makeConventionalSSA();
20+
removePhis();
21+
sequentialzeParallelCopies();
22+
}
23+
24+
private void insertPCopiesForEachBlock() {
25+
// We do not actually insert pcopy instruction until needed
26+
// but we create an auxiliary data structure to help us track these
27+
for (BasicBlock block: allBlocks) {
28+
parallelCopies.put(block,new PCopy(block));
29+
}
30+
}
31+
private void insertAtEnd(BasicBlock bb, Instruction i) {
32+
assert bb.instructions.size() > 0;
33+
// Last instruction is a branch - so new instruction will
34+
// go before that
35+
int pos = bb.instructions.size()-1;
36+
bb.add(pos, i);
37+
}
38+
39+
private Instruction.ParallelCopyInstruction getParallelCopyAtEnd(BasicBlock block) {
40+
PCopy pcopy = parallelCopies.get(block);
41+
if (pcopy.pCopyEnd == null) {
42+
pcopy.pCopyEnd = new Instruction.ParallelCopyInstruction();
43+
insertAtEnd(block,pcopy.pCopyEnd);
44+
}
45+
return pcopy.pCopyEnd;
46+
}
47+
48+
private void insertAfterPhis(BasicBlock bb, Instruction newInst) {
49+
assert bb.instructions.size() > 0;
50+
int insertionPos = -1;
51+
for (int pos = 0; pos < bb.instructions.size(); pos++) {
52+
Instruction i = bb.instructions.get(pos);
53+
if (i instanceof Instruction.Phi) {
54+
insertionPos = pos+1; // After phi
55+
}
56+
else
57+
break;
58+
}
59+
if (insertionPos < 0) {
60+
throw new IllegalStateException();
61+
}
62+
bb.add(insertionPos, newInst);
63+
}
64+
65+
private Instruction.ParallelCopyInstruction getParallelCopyAtBegin(BasicBlock block) {
66+
PCopy pcopy = parallelCopies.get(block);
67+
if (pcopy.pCopyBegin == null) {
68+
pcopy.pCopyBegin = new Instruction.ParallelCopyInstruction();
69+
insertAfterPhis(block,pcopy.pCopyBegin);
70+
}
71+
return pcopy.pCopyBegin;
72+
}
73+
74+
/**
75+
* Isolate phi nodes to make SSA conventionalS
76+
* This is Phase 1 as described in Engineering a Compiler 3rd Edition, p490.
77+
*/
78+
private void makeConventionalSSA() {
79+
var blocks = function.getBlocks();
80+
for (BasicBlock block: blocks) {
81+
var phis = block.phis();
82+
if (phis.isEmpty())
83+
continue;
84+
for (var phi: phis) {
85+
for (int j = 0; j < phi.numInputs(); j++) {
86+
BasicBlock pred = block.predecessor(j);
87+
var pCopyBEnd = getParallelCopyAtEnd(pred);
88+
var oldInput = phi.input(j);
89+
var newInput = function.registerPool.newTempReg(oldInput.type);
90+
pCopyBEnd.addCopy(oldInput,new Operand.RegisterOperand(newInput));
91+
phi.replaceInput(j,newInput);
92+
}
93+
var oldPhiVar = phi.value();
94+
var newPhiVar = function.registerPool.newTempReg(oldPhiVar.type);
95+
phi.replaceValue(newPhiVar);
96+
var pCopyBBegin = getParallelCopyAtBegin(block);
97+
pCopyBBegin.addCopy(new Operand.RegisterOperand(newPhiVar),new Operand.RegisterOperand(oldPhiVar));
98+
}
99+
}
100+
}
101+
102+
private void removePhis() {
103+
104+
}
105+
106+
private void sequentialzeParallelCopies() {
107+
108+
}
109+
110+
static final class PCopy {
111+
BasicBlock block;
112+
/**
113+
* Parallel copy instruction after any Phi instructions
114+
* in the block, null if not present
115+
*/
116+
Instruction.ParallelCopyInstruction pCopyBegin = null;
117+
/**
118+
* Parallel copy instruction at the end of a block,
119+
* null if not present
120+
*/
121+
Instruction.ParallelCopyInstruction pCopyEnd = null;
122+
123+
public PCopy(BasicBlock block) {
124+
this.block = block;
125+
}
126+
}
127+
}

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

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public abstract class Instruction {
2525
static final int I_ARRAY_LOAD = 13;
2626
static final int I_FIELD_GET = 14;
2727
static final int I_FIELD_SET = 15;
28+
static final int I_PARALLEL_COPY = 16;
2829

2930
public final int opcode;
3031
protected Operand.RegisterOperand def;
@@ -477,5 +478,67 @@ public StringBuilder toStr(StringBuilder sb) {
477478
}
478479
}
479480

481+
/**
482+
* The parallel copy instruction is only used temporarily to exit
483+
* SSA form. It represents the parallel copy semantics of phi instructions.
484+
*/
485+
public static class ParallelCopyInstruction extends Instruction {
486+
487+
List<Operand> sourceOperands = new ArrayList<>();
488+
List<Operand.RegisterOperand> destOperands = new ArrayList<>();
489+
490+
protected ParallelCopyInstruction() {
491+
super(I_PARALLEL_COPY);
492+
}
493+
494+
@Override
495+
public StringBuilder toStr(StringBuilder sb) {
496+
sb.append("(");
497+
for (int i = 0; i < destOperands.size(); i++) {
498+
if (i > 0)
499+
sb.append(",");
500+
sb.append(destOperands.get(i));
501+
}
502+
sb.append(") = (");
503+
for (int i = 0; i < sourceOperands.size(); i++) {
504+
if (i > 0)
505+
sb.append(",");
506+
sb.append(sourceOperands.get(i));
507+
}
508+
sb.append(")");
509+
return sb;
510+
}
511+
512+
public void addCopy(Operand sourceOperand, Operand.RegisterOperand destOperand) {
513+
sourceOperands.add(sourceOperand);
514+
destOperands.add(destOperand);
515+
}
516+
517+
@Override
518+
public Register def() {
519+
throw new UnsupportedOperationException();
520+
}
521+
@Override
522+
public void replaceDef(Register newDef) {
523+
throw new UnsupportedOperationException();
524+
}
525+
@Override
526+
public boolean definesVar() {
527+
return false;
528+
}
529+
@Override
530+
public List<Register> uses() {
531+
return Collections.emptyList();
532+
}
533+
@Override
534+
public void replaceUses(Register[] newUses) {
535+
throw new UnsupportedOperationException();
536+
}
537+
@Override
538+
public boolean replaceUse(Register source, Register target) {
539+
throw new UnsupportedOperationException();
540+
}
541+
}
542+
480543
public abstract StringBuilder toStr(StringBuilder sb);
481544
}

0 commit comments

Comments
 (0)