/* This file is part of the db4o object database http://www.db4o.com Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com db4o is free software; you can redistribute it and/or modify it under the terms of version 3 of the GNU General Public License as published by the Free Software Foundation. db4o is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. */ package EDU.purdue.cs.bloat.ssa; import java.util.*; import EDU.purdue.cs.bloat.cfg.*; import EDU.purdue.cs.bloat.tree.*; import EDU.purdue.cs.bloat.util.*; /** * <tt>SSAConstructionInfo</tt> contains information needed to convert a CFG * into SSA form. Each variable (VarExpr) has an SSAConstructionInfo associated * with it. Each <tt>SSAConstructionInfo</tt> keeps track of information such * as the <tt>PhiStmt</tt>s that define copies of the variable, the * <tt>Block</tt>s in which the variable is defined, and the occurrences * (uses) of the variable in both phi and non-phi statements. Note that no * <tt>PhiStmt</tt> is really inserted into a basic block. We just keep track * of the mapping. It should also be noted that once a phi statement for a given * variable is "inserted" into a block, no other phi statement for that variable * is inserted. Thus, the order of insertion determines the precedence of the * phi statements: <tt>PhiReturnStmt</tt> > <tt>PhiCatchStmt</tt> > * <tt>PhiJoinStmt</tt>. * * <p> * * Additionally, <tt>SSAConstruction</tt> has methods to insert various * flavors of <tt>PhiStmt</tt>s whose targets are the variable associated * with the <tt>SSAConstruction</tt> into <tt>Block</tt>s. * * @see SSA * @see PhiStmt * @see PhiCatchStmt * @see PhiJoinStmt * @see PhiReturnStmt */ public class SSAConstructionInfo { FlowGraph cfg; // The cfg we're converting into SSA form VarExpr prototype; // The variable we're converting into SSA form LinkedList[] reals; // The real (non-phi) occurrences associated // with a given node (block) LinkedList allReals; // All the real occurrences of the variable PhiStmt[] phis; // Phi statement associated with a given block Set defBlocks; // Blocks in which variable is defined /** * Constructor. * * @param cfg * The control flow graph that is being converted to SSA form. * @param expr * A variable in the CFG on which SSA analysis is being done. */ public SSAConstructionInfo(final FlowGraph cfg, final VarExpr expr) { this.cfg = cfg; prototype = (VarExpr) expr.clone(); prototype.setDef(null); reals = new LinkedList[cfg.size()]; allReals = new LinkedList(); defBlocks = new HashSet(); phis = new PhiStmt[cfg.size()]; } /** * Returns the program variable associated with this * <tt>SSAConstructionInfo</tt>. */ public VarExpr prototype() { return prototype; } /** * Makes note of a <tt>Block</tt> in which the variable is defined by a * <tt>PhiStmt</tt>. */ public void addDefBlock(final Block block) { defBlocks.add(block); } /** * Returns the phi statement for the variable represented by this * SSAConstructionInfo at a given block in the CFG. */ public PhiStmt phiAtBlock(final Block block) { return phis[cfg.preOrderIndex(block)]; } /** * Removes the phi statement for this variable at a given block. */ public void removePhiAtBlock(final Block block) { final PhiStmt phi = phis[cfg.preOrderIndex(block)]; if (phi != null) { if (SSA.DEBUG) { System.out.println(" removing " + phi + " at " + block); } phi.cleanup(); phis[cfg.preOrderIndex(block)] = null; } } /** * Adds a <tt>PhiJoinStmt</tt> for the variable represented by this * <tt>SSAConstructionInfo</tt> to a given <tt>Block</tt>. */ public void addPhi(final Block block) { if (phis[cfg.preOrderIndex(block)] != null) { return; } final VarExpr target = (VarExpr) prototype.clone(); final PhiJoinStmt phi = new PhiJoinStmt(target, block); phis[cfg.preOrderIndex(block)] = phi; if (SSA.DEBUG) { System.out.println(" place " + phi + " in " + block); } } /** * Adds a <tt>PhiReturnStmt</tt> to all of the <tt>Block</tt>s that are * executed upon returning from a given <tt>Subroutine</tt>. * * @see PhiReturnStmt * @see Subroutine#paths */ public void addRetPhis(final Subroutine sub) { final Iterator paths = sub.paths().iterator(); while (paths.hasNext()) { final Block[] path = (Block[]) paths.next(); addRetPhi(sub, path[1]); } } /** * Inserts a <tt>PhiCatchStmt</tt> (whose target is the variable * represented by this <tt>SSAConstructionInfo</tt>) into a given * <tt>Block</tt>. * * @see PhiCatchStmt */ public void addCatchPhi(final Block block) { if (phis[cfg.preOrderIndex(block)] != null) { return; } if (prototype instanceof LocalExpr) { final LocalExpr target = (LocalExpr) prototype.clone(); final PhiCatchStmt phi = new PhiCatchStmt(target); phis[cfg.preOrderIndex(block)] = phi; if (SSA.DEBUG) { System.out.println(" place " + phi + " in " + block); } } } /** * Adds a <tt>PhiReturnStmt</tt> associated with a given * <tt>Subroutine</tt>. The <tt>PhiReturnStmt</tt> is placed in a given * block. * * @see PhiReturnStmt */ private void addRetPhi(final Subroutine sub, final Block block) { if (phis[cfg.preOrderIndex(block)] != null) { return; } final VarExpr target = (VarExpr) prototype.clone(); final PhiReturnStmt phi = new PhiReturnStmt(target, sub); phis[cfg.preOrderIndex(block)] = phi; if (SSA.DEBUG) { System.out.println(" place " + phi + " in " + block); } } /** * Notes a real occurrence (that is, a use that is not an operand to a phi * statement) of the variable represented by this * <tt>SSAConstructionInfo</tt>. * * @see PhiStmt */ public void addReal(final VarExpr real) { if (real.stmt() instanceof PhiStmt) { return; } final Block block = real.block(); if (real.isDef()) { defBlocks.add(block); } Assert.isTrue(block != null, real + " not in a " + block); LinkedList l = reals[cfg.preOrderIndex(block)]; if (l == null) { l = new LinkedList(); reals[cfg.preOrderIndex(block)] = l; } l.add(real); allReals.add(real); } /** * Returns all of the real occurrences of this variable. */ public Collection reals() { return allReals; } /** * Returns all of the real occurrences of this variable in a given block. */ public Collection realsAtBlock(final Block block) { LinkedList l = reals[cfg.preOrderIndex(block)]; if (l == null) { l = new LinkedList(); reals[cfg.preOrderIndex(block)] = l; } return l; } /** * Returns the Blocks containing a definition of the variable represented by * this SSAConstruction info. */ public Collection defBlocks() { return defBlocks; } }