406 lines
11 KiB
Java
406 lines
11 KiB
Java
/******************************************************************************
|
|
* Copyright (c) 2002 - 2006 IBM Corporation.
|
|
* All rights reserved. This program and the accompanying materials
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
* which accompanies this distribution, and is available at
|
|
* http://www.eclipse.org/legal/epl-v10.html
|
|
*
|
|
* Contributors:
|
|
* IBM Corporation - initial API and implementation
|
|
*****************************************************************************/
|
|
package com.ibm.wala.cast.ir.ssa;
|
|
|
|
import java.util.Iterator;
|
|
import java.util.LinkedHashSet;
|
|
import java.util.Set;
|
|
|
|
import com.ibm.wala.cfg.IBasicBlock;
|
|
import com.ibm.wala.ssa.IR;
|
|
import com.ibm.wala.ssa.SSACFG;
|
|
import com.ibm.wala.ssa.SSAInstruction;
|
|
import com.ibm.wala.ssa.SSAOptions;
|
|
import com.ibm.wala.ssa.SSAPhiInstruction;
|
|
import com.ibm.wala.ssa.SymbolTable;
|
|
import com.ibm.wala.ssa.SSAOptions.DefaultValues;
|
|
import com.ibm.wala.util.collections.IntStack;
|
|
import com.ibm.wala.util.debug.Assertions;
|
|
import com.ibm.wala.util.graph.DominanceFrontiers;
|
|
import com.ibm.wala.util.graph.Graph;
|
|
|
|
|
|
/**
|
|
* Abstract core of traditional SSA conversion (Cytron et al.).
|
|
*
|
|
* This implementation is abstract in the sense that it is designed
|
|
* to work over the instrutions and CFG of a Domo IR, but it is
|
|
* abstract with respect to several integral portions of the
|
|
* traditional algorithm:
|
|
* <UL>
|
|
* <LI> The notion of uses and defs of a given instruction.
|
|
* <LI> Assignments (<def> := <use>) that are be copy-propagated away
|
|
* <LI> Which values are constants---i.e. have no definition.
|
|
* <LI> Any value numbers to be skipped during SSA construction
|
|
* <LI> Special initialization and exit block processing.
|
|
* </UL>
|
|
*
|
|
* @author Julian dolby (dolby@us.ibm.com)
|
|
*
|
|
*/
|
|
public abstract class AbstractSSAConversion {
|
|
|
|
protected abstract int getNumberOfDefs(SSAInstruction inst);
|
|
|
|
protected abstract int getDef(SSAInstruction inst, int index);
|
|
|
|
protected abstract int getNumberOfUses(SSAInstruction inst);
|
|
|
|
protected abstract int getUse(SSAInstruction inst, int index);
|
|
|
|
|
|
protected abstract boolean isAssignInstruction(SSAInstruction inst);
|
|
|
|
|
|
protected abstract int getMaxValueNumber();
|
|
|
|
protected abstract boolean isLive(SSACFG.BasicBlock Y, int V);
|
|
|
|
protected abstract boolean skip(int vn);
|
|
|
|
protected abstract boolean isConstant(int valueNumber);
|
|
|
|
|
|
protected abstract int getNextNewValueNumber();
|
|
|
|
|
|
protected abstract void initializeVariables();
|
|
|
|
protected abstract void repairExit();
|
|
|
|
|
|
protected abstract void placeNewPhiAt(int value, SSACFG.BasicBlock Y);
|
|
|
|
protected abstract SSAPhiInstruction getPhi(SSACFG.BasicBlock B, int index);
|
|
|
|
protected abstract void setPhi(SSACFG.BasicBlock B, int index, SSAPhiInstruction inst);
|
|
|
|
protected abstract SSAPhiInstruction repairPhiDefs(SSAPhiInstruction phi, int[] newDefs);
|
|
|
|
protected abstract void repairPhiUse(SSACFG.BasicBlock BB, int phiIndex, int rvalIndex, int newRval);
|
|
|
|
|
|
protected abstract void repairInstructionUses(SSAInstruction inst, int index, int[] newUses);
|
|
|
|
protected abstract void repairInstructionDefs(SSAInstruction inst, int index, int[] newDefs, int[] newUses);
|
|
|
|
|
|
protected abstract void pushAssignment(SSAInstruction inst, int index, int newRhs);
|
|
|
|
protected abstract void popAssignment(SSAInstruction inst, int index);
|
|
|
|
|
|
protected final SSACFG CFG;
|
|
protected final DominanceFrontiers<IBasicBlock> DF;
|
|
private final Graph dominatorTree;
|
|
protected final int[] phiCounts;
|
|
protected final SSAInstruction[] instructions;
|
|
private final int flags[];
|
|
protected final SymbolTable symbolTable;
|
|
protected final DefaultValues defaultValues;
|
|
|
|
protected IntStack S[];
|
|
protected int C[];
|
|
protected int valueMap[];
|
|
private Set[] assignmentMap;
|
|
|
|
protected AbstractSSAConversion(IR ir, SSAOptions options) {
|
|
this.CFG = ir.getControlFlowGraph();
|
|
this.DF = new DominanceFrontiers(ir.getControlFlowGraph(), ir.getControlFlowGraph().entry());
|
|
this.dominatorTree = DF.dominatorTree();
|
|
this.flags = new int[2 * ir.getControlFlowGraph().getNumberOfNodes()];
|
|
this.instructions = ir.getInstructions();
|
|
this.phiCounts = new int[CFG.getNumberOfNodes()];
|
|
this.symbolTable = ir.getSymbolTable();
|
|
this.defaultValues = options.getDefaultValues();
|
|
}
|
|
|
|
|
|
//
|
|
// top-level control
|
|
//
|
|
protected void perform() {
|
|
init();
|
|
placePhiNodes();
|
|
renameVariables();
|
|
}
|
|
|
|
|
|
//
|
|
// initialization
|
|
//
|
|
protected void init() {
|
|
this.S = new IntStack[getMaxValueNumber() + 1];
|
|
this.C = new int[getMaxValueNumber() + 1];
|
|
this.valueMap = new int[getMaxValueNumber() + 1];
|
|
makeAssignmentMap();
|
|
}
|
|
|
|
private void makeAssignmentMap() {
|
|
this.assignmentMap = new Set[getMaxValueNumber() + 1];
|
|
for (Iterator BBs = CFG.iterateNodes(); BBs.hasNext();) {
|
|
SSACFG.BasicBlock BB = (SSACFG.BasicBlock) BBs.next();
|
|
if (BB.getFirstInstructionIndex() >= 0) {
|
|
for(Iterator IS = BB.iterateAllInstructions(); IS.hasNext(); ) {
|
|
SSAInstruction inst = (SSAInstruction)IS.next();
|
|
if (inst != null) {
|
|
for (int j = 0; j < getNumberOfDefs(inst); j++) {
|
|
addDefiningBlock(assignmentMap, BB, getDef(inst, j));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void addDefiningBlock(Set[] A, SSACFG.BasicBlock BB, int i) {
|
|
if (! skip(i)) {
|
|
if (A[i] == null) {
|
|
A[i] = new LinkedHashSet(2);
|
|
}
|
|
A[i].add(BB);
|
|
}
|
|
}
|
|
|
|
//
|
|
// place phi nodes phase of traditional algorithm
|
|
//
|
|
protected void placePhiNodes() {
|
|
int IterCount = 0;
|
|
|
|
for (Iterator Xs = CFG.iterateNodes(); Xs.hasNext();) {
|
|
SSACFG.BasicBlock X = (SSACFG.BasicBlock) Xs.next();
|
|
setHasAlready(X, 0);
|
|
setWork(X, 0);
|
|
}
|
|
|
|
Set W = new LinkedHashSet();
|
|
for (int V = 0; V < assignmentMap.length; V++) {
|
|
|
|
// some things (e.g. constants) have no defs at all
|
|
if (assignmentMap[V] == null)
|
|
continue;
|
|
|
|
// ignore values as requested
|
|
if (skip(V))
|
|
continue;
|
|
|
|
IterCount++;
|
|
|
|
for (Iterator XS = assignmentMap[V].iterator(); XS.hasNext();) {
|
|
SSACFG.BasicBlock X = (SSACFG.BasicBlock) XS.next();
|
|
setWork(X, IterCount);
|
|
W.add(X);
|
|
}
|
|
|
|
while (!W.isEmpty()) {
|
|
SSACFG.BasicBlock X = (SSACFG.BasicBlock) W.iterator().next();
|
|
W.remove(X);
|
|
for (Iterator YS = DF.getDominanceFrontier(X); YS.hasNext();) {
|
|
SSACFG.BasicBlock Y = (SSACFG.BasicBlock) YS.next();
|
|
if (getHasAlready(Y) < IterCount) {
|
|
if (isLive(Y, V)) {
|
|
placeNewPhiAt(V, Y);
|
|
phiCounts[Y.getGraphNodeId()]++;
|
|
}
|
|
setHasAlready(Y, IterCount);
|
|
if (getWork(Y) < IterCount) {
|
|
setWork(Y, IterCount);
|
|
W.add(Y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private int getWork(SSACFG.BasicBlock BB) {
|
|
return flags[BB.getGraphNodeId() * 2 + 1];
|
|
}
|
|
|
|
private void setWork(SSACFG.BasicBlock BB, int v) {
|
|
flags[BB.getGraphNodeId() * 2 + 1] = v;
|
|
}
|
|
|
|
private int getHasAlready(SSACFG.BasicBlock BB) {
|
|
return flags[BB.getGraphNodeId() * 2];
|
|
}
|
|
|
|
private void setHasAlready(SSACFG.BasicBlock BB, int v) {
|
|
flags[BB.getGraphNodeId() * 2] = v;
|
|
}
|
|
|
|
|
|
//
|
|
// rename variables phase of traditional algorithm
|
|
//
|
|
private void renameVariables() {
|
|
for (int V = 1; V <= getMaxValueNumber(); V++) {
|
|
if (! skip(V)) {
|
|
C[V] = 0;
|
|
S[V] = new IntStack();
|
|
}
|
|
}
|
|
|
|
initializeVariables();
|
|
|
|
SEARCH((SSACFG.BasicBlock) CFG.entry());
|
|
}
|
|
|
|
private void SEARCH(SSACFG.BasicBlock X) {
|
|
int id = X.getGraphNodeId();
|
|
int Xf = X.getFirstInstructionIndex();
|
|
|
|
// first loop
|
|
for (int i = 0; i < phiCounts[id]; i++) {
|
|
SSAPhiInstruction phi = getPhi(X, i);
|
|
if (! skipRepair(phi, -1)) {
|
|
setPhi(X, i, repairPhiDefs(phi, makeNewDefs(phi)));
|
|
}
|
|
}
|
|
for (int i = Xf; i <= X.getLastInstructionIndex(); i++) {
|
|
SSAInstruction inst = instructions[i];
|
|
if (isAssignInstruction(inst)) {
|
|
int lhs = getDef(inst, 0);
|
|
int rhs = getUse(inst, 0);
|
|
int newRhs = skip(rhs)? rhs: top(rhs);
|
|
S[lhs].push( newRhs );
|
|
|
|
pushAssignment(inst, i, newRhs);
|
|
|
|
} else {
|
|
if (! skipRepair(inst, i)) {
|
|
int[] newUses = makeNewUses(inst);
|
|
repairInstructionUses(inst, i, newUses);
|
|
int[] newDefs = makeNewDefs(inst);
|
|
repairInstructionDefs(inst, i, newDefs, newUses);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (X.isExitBlock()) {
|
|
repairExit();
|
|
}
|
|
|
|
for (Iterator YS = CFG.getSuccNodes(X); YS.hasNext();) {
|
|
SSACFG.BasicBlock Y = (SSACFG.BasicBlock) YS.next();
|
|
int Y_id = Y.getGraphNodeId();
|
|
int j = com.ibm.wala.cast.ir.cfg.Util.whichPred(CFG, Y, X);
|
|
for (int i = 0; i < phiCounts[Y_id]; i++) {
|
|
SSAPhiInstruction phi = getPhi(Y, i);
|
|
int oldUse = getUse(phi, j);
|
|
int newUse = skip(oldUse) ? oldUse: top(oldUse);
|
|
repairPhiUse(Y, i, j, newUse);
|
|
}
|
|
}
|
|
|
|
for (Iterator YS = dominatorTree.getSuccNodes(X); YS.hasNext();) {
|
|
SEARCH((SSACFG.BasicBlock) YS.next());
|
|
}
|
|
|
|
for (int i = 0; i < phiCounts[id]; i++) {
|
|
SSAInstruction A = getPhi(X, i);
|
|
for (int j = 0; j < getNumberOfDefs(A); j++) {
|
|
if (! skip(getDef(A, j))) {
|
|
S[valueMap[getDef(A, j)]].pop();
|
|
}
|
|
}
|
|
}
|
|
for (int i = Xf; i <= X.getLastInstructionIndex(); i++) {
|
|
SSAInstruction A = instructions[i];
|
|
if (isAssignInstruction(A)) {
|
|
S[ getDef(A, 0) ].pop();
|
|
popAssignment(A, i);
|
|
} else if (A != null) {
|
|
for (int j = 0; j < getNumberOfDefs(A); j++) {
|
|
if (! skip(getDef(A, j))) {
|
|
S[valueMap[getDef(A, j)]].pop();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private int[] makeNewUses(SSAInstruction inst) {
|
|
int[] newUses = new int[getNumberOfUses(inst)];
|
|
for (int j = 0; j < getNumberOfUses(inst); j++) {
|
|
newUses[j] =
|
|
skip(getUse(inst, j))? getUse(inst, j): top(getUse(inst, j));
|
|
}
|
|
|
|
return newUses;
|
|
}
|
|
|
|
private int[] makeNewDefs(SSAInstruction inst) {
|
|
int[] newDefs = new int[getNumberOfDefs(inst)];
|
|
|
|
for (int j = 0; j < getNumberOfDefs(inst); j++) {
|
|
if (skip(getDef(inst, j))) {
|
|
newDefs[j] = getDef(inst, j);
|
|
} else {
|
|
int ii = getNextNewValueNumber();
|
|
|
|
if (valueMap.length <= ii) {
|
|
int[] nvm = new int[valueMap.length * 2 + ii + 1];
|
|
System.arraycopy(valueMap, 0, nvm, 0, valueMap.length);
|
|
valueMap = nvm;
|
|
}
|
|
|
|
valueMap[ii] = getDef(inst, j);
|
|
S[getDef(inst, j)].push(ii);
|
|
newDefs[j] = ii;
|
|
}
|
|
}
|
|
|
|
return newDefs;
|
|
}
|
|
|
|
protected boolean skipRepair(SSAInstruction inst, int index) {
|
|
if (inst == null)
|
|
return true;
|
|
for(int i = 0; i < getNumberOfDefs(inst); i++)
|
|
if (! skip(getDef(inst, i))) return false;
|
|
for(int i = 0; i < getNumberOfUses(inst); i++)
|
|
if (! skip(getUse(inst, i))) return false;
|
|
return true;
|
|
}
|
|
|
|
protected void fail(int v) {
|
|
Assertions._assert(
|
|
isConstant(v) || !S[v].isEmpty(),
|
|
"bad stack for " + v + " while SSA converting");
|
|
}
|
|
|
|
protected boolean hasDefaultValue(int valueNumber) {
|
|
return
|
|
(defaultValues != null)
|
|
&&
|
|
(defaultValues.getDefaultValue(symbolTable, valueNumber) != -1);
|
|
}
|
|
|
|
protected int getDefaultValue(int valueNumber) {
|
|
return defaultValues.getDefaultValue(symbolTable, valueNumber);
|
|
}
|
|
|
|
protected int top(int v) {
|
|
if (! (isConstant(v) || !S[v].isEmpty())) {
|
|
if (hasDefaultValue(v)) {
|
|
return getDefaultValue(v);
|
|
} else {
|
|
fail(v);
|
|
}
|
|
}
|
|
|
|
return (isConstant(v)) ? v : S[v].peek();
|
|
}
|
|
|
|
}
|