Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit f73098f

Browse files
Merge pull request #58 from CompilerProgramming/ssaexit
Implement SSA Destruction using Sreedhar / Boissinot method without coalescing
2 parents 109fdc2 + e3ae2f7 commit f73098f

File tree

7 files changed

+649
-272
lines changed

7 files changed

+649
-272
lines changed

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

Lines changed: 16 additions & 1 deletion
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) {
@@ -167,7 +172,17 @@ public int whichSucc(BasicBlock succ) {
167172
}
168173
throw new IllegalStateException();
169174
}
170-
175+
public void replaceInstruction(Instruction instruction, List<Instruction> replacements) {
176+
int i;
177+
for (i = 0; i < instructions.size(); i++)
178+
if (instructions.get(i) == instruction)
179+
break;
180+
assert i < instructions.size();
181+
for (int j = replacements.size()-1; j >= 0; j--) {
182+
instructions.add(i+1, replacements.get(j));
183+
}
184+
instructions.remove(i);
185+
}
171186
public static StringBuilder toStr(StringBuilder sb, BasicBlock bb, BitSet visited, boolean dumpLiveness)
172187
{
173188
if (visited.get(bb.bid))

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

Lines changed: 4 additions & 271 deletions
Original file line numberDiff line numberDiff line change
@@ -4,279 +4,12 @@
44

55
/**
66
* Converts from SSA form to non-SSA form.
7-
* Implementation is based on description in
8-
* 'Practical Improvements to the Construction and Destruction
9-
* of Static Single Assignment Form' by Preston Briggs.
10-
*
11-
* The JikesRVM LeaveSSA implements a version of the
12-
* same algorithm.
137
*/
148
public class ExitSSA {
15-
16-
CompiledFunction function;
17-
NameStack[] stacks;
18-
DominatorTree tree;
19-
209
public ExitSSA(CompiledFunction function, EnumSet<Options> options) {
21-
this.function = function;
22-
if (!function.isSSA) throw new IllegalStateException();
23-
function.livenessAnalysis();
24-
if (options.contains(Options.DUMP_SSA_LIVENESS)) function.dumpIR(true, "SSA Liveness Analysis");
25-
tree = new DominatorTree(function.entry);
26-
if (options.contains(Options.DUMP_SSA_DOMTREE)) {
27-
System.out.println("Pre SSA Dominator Tree");
28-
System.out.println(tree.generateDotOutput());
29-
}
30-
initStack();
31-
insertCopies(function.entry);
32-
removePhis();
33-
function.isSSA = false;
34-
if (options.contains(Options.DUMP_POST_SSA_IR)) function.dumpIR(false, "After exiting SSA");
35-
}
36-
37-
private void removePhis() {
38-
for (BasicBlock block : tree.blocks) {
39-
block.instructions.removeIf(instruction -> instruction instanceof Instruction.Phi);
40-
}
41-
}
42-
43-
/* Algorithm for iterating through blocks to perform phi replacement */
44-
private void insertCopies(BasicBlock block) {
45-
List<Integer> pushed = new ArrayList<>();
46-
for (Instruction i: block.instructions) {
47-
// replace all uses u with stacks[i]
48-
replaceUses(i);
49-
}
50-
scheduleCopies(block, pushed);
51-
for (BasicBlock c: block.dominatedChildren) {
52-
insertCopies(c);
53-
}
54-
for (Integer name: pushed) {
55-
stacks[name].pop();
56-
}
57-
}
58-
59-
/**
60-
* replace all uses u with stacks[i]
61-
*/
62-
private void replaceUses(Instruction i) {
63-
if (i instanceof Instruction.Phi)
64-
// FIXME check this can never be valid
65-
// tests 8/9 in TestInterpreter invoke on Phi but
66-
// replacements are same as existing inputs
67-
return;
68-
var oldUses = i.uses();
69-
Register[] newUses = new Register[oldUses.size()];
70-
for (int u = 0; u < oldUses.size(); u++) {
71-
Register use = oldUses.get(u);
72-
if (!stacks[use.id].isEmpty())
73-
newUses[u] = stacks[use.id].top();
74-
else
75-
newUses[u] = use;
76-
}
77-
i.replaceUses(newUses);
78-
}
79-
80-
static class CopyItem {
81-
/** Phi input can be a register or a constant so we record the operand */
82-
final Operand src;
83-
/** The phi destination */
84-
final Register dest;
85-
/** The basic block where the phi was present */
86-
final BasicBlock destBlock;
87-
boolean removed;
88-
89-
public CopyItem(Operand src, Register dest, BasicBlock destBlock) {
90-
this.src = src;
91-
this.dest = dest;
92-
this.destBlock = destBlock;
93-
this.removed = false;
94-
}
95-
}
96-
97-
private void scheduleCopies(BasicBlock block, List<Integer> pushed) {
98-
/* Pass 1 - Initialize data structures */
99-
/* In this pass we count the number of times a name is used by other phi-nodes */
100-
List<CopyItem> copySet = new ArrayList<>();
101-
Map<Integer, Register> map = new HashMap<>();
102-
BitSet usedByAnother = new BitSet(function.registerPool.numRegisters()*2);
103-
for (BasicBlock s: block.successors) {
104-
int j = s.whichPred(block);
105-
for (Instruction.Phi phi: s.phis()) {
106-
Register dst = phi.value();
107-
Operand srcOperand = phi.input(j); // jth operand of phi node
108-
if (srcOperand instanceof Operand.RegisterOperand srcRegisterOperand) {
109-
Register src = srcRegisterOperand.reg;
110-
map.put(src.id, src);
111-
usedByAnother.set(src.id);
112-
}
113-
copySet.add(new CopyItem(srcOperand, dst, s));
114-
map.put(dst.id, dst);
115-
}
116-
}
117-
118-
/* Pass 2: setup up the worklist of initial copies */
119-
/* In this pass we build a worklist of names that are not used in other phi nodes */
120-
List<CopyItem> workList = new ArrayList<>();
121-
for (CopyItem copyItem: copySet) {
122-
if (usedByAnother.get(copyItem.dest.id) != true) {
123-
copyItem.removed = true;
124-
workList.add(copyItem);
125-
}
126-
}
127-
copySet.removeIf(copyItem -> copyItem.removed);
128-
129-
/* Pass 3: iterate over the worklist, inserting copies */
130-
/* Copy operations whose destinations are not used by other copy operations can be scheduled immediately */
131-
/* Each time we insert a copy operation we add the source of that op to the worklist */
132-
while (!workList.isEmpty() || !copySet.isEmpty()) {
133-
while (!workList.isEmpty()) {
134-
final CopyItem copyItem = workList.remove(0);
135-
final Operand src = copyItem.src;
136-
final Register dest = copyItem.dest;
137-
final BasicBlock destBlock = copyItem.destBlock;
138-
/* Engineering a Compiler: We can avoid the lost copy
139-
problem by checking the liveness of the target name
140-
for each copy that we try to insert. When we discover
141-
a copy target that is live, we must preserve the live
142-
value in a temporary name and rewrite subsequent uses to
143-
refer to the temporary name.
144-
145-
This captures the cases when the result of a phi
146-
in a control successor is live on exit of the current block.
147-
This means that it is incorrect to simply insert a copy
148-
of the destination in the current block. So we rename
149-
the destination to a new temporary, and record the renaming
150-
so that the dominator blocks get the new name. Comment adapted
151-
from JikesRVM LeaveSSA
152-
*/
153-
if (block.liveOut.get(dest.id)) {
154-
/* Insert a copy from dest to a new temp t at phi node defining dest */
155-
final Register t = addMoveToTempAfterPhi(destBlock, dest);
156-
stacks[dest.id].push(t); // record the temp name
157-
pushed.add(dest.id);
158-
}
159-
/* Insert a copy operation from map[src] to dest at end of BB */
160-
if (src instanceof Operand.RegisterOperand srcRegisterOperand) {
161-
addMoveAtBBEnd(block, map.get(srcRegisterOperand.reg.id), dest);
162-
map.put(srcRegisterOperand.reg.id, dest);
163-
/* If src is the name of a dest in copySet add item to worklist */
164-
/* see comment on phi cycles below. */
165-
CopyItem item = isCycle(copySet, srcRegisterOperand.reg);
166-
if (item != null) {
167-
workList.add(item);
168-
}
169-
}
170-
else if (src instanceof Operand.ConstantOperand srcConstantOperand) {
171-
addMoveAtBBEnd(block, srcConstantOperand, dest);
172-
}
173-
}
174-
/* Engineering a Compiler: To solve the swap problem
175-
we can detect cases where phi functions reference the
176-
targets of other phi functions in the same block. For each
177-
cycle of references, it must insert a copy to a temporary
178-
that breaks the cycle. Then we can schedule the copies to
179-
respect the dependencies implied by the phi functions.
180-
181-
An empty work list with work remaining in the copy set
182-
implies a cycle in the dependencies amongst copies. To break
183-
the cycle copy the destination of an arbitrary member of the
184-
copy set to a temporary. This destination has therefore been
185-
saved and can be safely overwritten. So then add the copy to the
186-
work list. Comment adapted from JikesRVM LeaveSSA.
187-
*/
188-
if (!copySet.isEmpty()) {
189-
CopyItem copyItem = copySet.remove(0);
190-
/* Insert a copy from dst to new temp at the end of Block */
191-
Register t = addMoveToTempAtBBEnd(block, copyItem.dest);
192-
map.put(copyItem.dest.id, t);
193-
workList.add(copyItem);
194-
}
195-
}
196-
}
197-
198-
private void insertAtEnd(BasicBlock bb, Instruction i) {
199-
assert bb.instructions.size() > 0;
200-
// Last instruction is a branch - so new instruction will
201-
// go before that
202-
int pos = bb.instructions.size()-1;
203-
bb.add(pos, i);
204-
}
205-
206-
private void insertAfterPhi(BasicBlock bb, Register phiDef, Instruction newInst) {
207-
assert bb.instructions.size() > 0;
208-
int insertionPos = -1;
209-
for (int pos = 0; pos < bb.instructions.size(); pos++) {
210-
Instruction i = bb.instructions.get(pos);
211-
if (i instanceof Instruction.Phi phi) {
212-
if (phi.value().id == phiDef.id) {
213-
insertionPos = pos+1; // After phi
214-
break;
215-
}
216-
}
217-
}
218-
if (insertionPos < 0) {
219-
throw new IllegalStateException();
220-
}
221-
bb.add(insertionPos, newInst);
222-
}
223-
224-
/* Insert a copy from dest to new temp at end of BB, and return temp */
225-
private Register addMoveToTempAtBBEnd(BasicBlock block, Register dest) {
226-
var temp = function.registerPool.newTempReg(dest.name(), dest.type);
227-
var inst = new Instruction.Move(new Operand.RegisterOperand(dest), new Operand.RegisterOperand(temp));
228-
insertAtEnd(block, inst);
229-
return temp;
230-
}
231-
232-
/* If src is the name of a dest in copySet remove the item */
233-
private CopyItem isCycle(List<CopyItem> copySet, Register src) {
234-
for (int i = 0; i < copySet.size(); i++) {
235-
CopyItem copyItem = copySet.get(i);
236-
if (copyItem.dest.id == src.id) {
237-
copySet.remove(i);
238-
return copyItem;
239-
}
240-
}
241-
return null;
242-
}
243-
244-
/* Insert a copy from src to dst at end of BB */
245-
private void addMoveAtBBEnd(BasicBlock block, Register src, Register dest) {
246-
var inst = new Instruction.Move(new Operand.RegisterOperand(src), new Operand.RegisterOperand(dest));
247-
insertAtEnd(block, inst);
248-
// If the copy instruction is followed by a cbr which uses the old var
249-
// then we need to update the cbr instruction
250-
// This is not specified in the Briggs paper but t
251-
var brInst = block.instructions.getLast();
252-
if (brInst instanceof Instruction.ConditionalBranch cbr) {
253-
cbr.replaceUse(src,dest);
254-
}
255-
}
256-
/* Insert a copy from constant src to dst at end of BB */
257-
private void addMoveAtBBEnd(BasicBlock block, Operand.ConstantOperand src, Register dest) {
258-
var inst = new Instruction.Move(src, new Operand.RegisterOperand(dest));
259-
insertAtEnd(block, inst);
260-
}
261-
/* Insert a copy dest to a new temp at phi node defining dest, return temp */
262-
private Register addMoveToTempAfterPhi(BasicBlock block, Register dest) {
263-
var temp = function.registerPool.newTempReg(dest.name(), dest.type);
264-
var inst = new Instruction.Move(new Operand.RegisterOperand(dest), new Operand.RegisterOperand(temp));
265-
insertAfterPhi(block, dest, inst);
266-
return temp;
267-
}
268-
269-
private void initStack() {
270-
stacks = new NameStack[function.registerPool.numRegisters()];
271-
for (int i = 0; i < stacks.length; i++)
272-
stacks[i] = new NameStack();
273-
}
274-
275-
static class NameStack {
276-
List<Register> stack = new ArrayList<>();
277-
void push(Register r) { stack.add(r); }
278-
Register top() { return stack.getLast(); }
279-
void pop() { stack.removeLast(); }
280-
boolean isEmpty() { return stack.isEmpty(); }
10+
if (options.contains(Options.SSA_DESTRUCTION_BOISSINOT_NOCOALESCE))
11+
new ExitSSABoissinotNoCoalesce(function,options);
12+
else
13+
new ExitSSABriggs(function,options);
28114
}
28215
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /