/* 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.trans; import java.io.*; import java.util.*; import EDU.purdue.cs.bloat.cfg.*; import EDU.purdue.cs.bloat.editor.*; import EDU.purdue.cs.bloat.ssa.*; import EDU.purdue.cs.bloat.tree.*; /** * <tt>ValueFolding</tt> uses a <tt>ValueFolder</tt> to determine which * nodes in an expression tree can be removed or replaced by common expression * elimination and constant propagation. * * @see ValueFolder */ public class ValueFolding { public static boolean DEBUG = false; SideEffectChecker sideEffects; ValueFolder folder; boolean changed; public static boolean DUMP = false; public static boolean SAVEDUMP = false; PrintWriter vn; PrintWriter dump; /** * Performs value folding (common expression elimination and constant * folding) on a control flow graph. */ int next = 1; public void transform(final FlowGraph cfg) { final File dir = new File("ValueFoldingOutdir"); if (ValueFolding.DUMP) { // System.out.println(" Dumping Value Folding in directory: " + // dir); // try { // cfgFile = new File(dir, "cfg.txt"); // cfg.print(new PrintWriter(new FileWriter(cfgFile), true)); // dotFile = new File(dir, "cfg.dot"); // cfg.printGraph(new PrintWriter(new FileWriter(dotFile), // true)); // vnFile = new File(dir, "value.numbers"); // vn = new PrintWriter(new FileWriter(vnFile), true); // dumpFile = new File(dir, "vn.dump"); // dump = new PrintWriter(new FileWriter(dumpFile), true); // } catch (IOException ex) { // } vn = new PrintWriter(System.out, true); dump = new PrintWriter(System.out, true); } final EditorContext context = cfg.method().declaringClass().context(); sideEffects = new SideEffectChecker(context); folder = new ValueFolder(true, context); final SSAGraph ssaGraph = new SSAGraph(cfg); ssaGraph.visitComponents(new ComponentVisitor() { public void visitComponent(final List scc) { // Maps Nodes in the SCC to their folded value final HashMap map = new HashMap(scc.size() * 2 + 1); boolean changed = true; while (changed) { changed = false; final Iterator iter = scc.iterator(); int x = 0; while (iter.hasNext()) { final Node node = (Node) iter.next(); if (ValueFolding.DUMP) { x++; dump.println("Folding SCC Node " + node + " (" + x + " of " + scc.size() + ")"); } if (fold(map, node)) { changed = true; } } if (ValueFolding.DUMP) { dump.println(""); } if (scc.size() == 1) { break; } } } }); cfg.removeUnreachable(); folder = null; sideEffects = null; // Okay, we've successfully value folded, remove debugging files if (ValueFolding.DUMP && !ValueFolding.SAVEDUMP) { // cfgFile.delete(); // dotFile.delete(); // dumpFile.delete(); // vnFile.delete(); // dir.delete(); } } /** * Builds a mapping between the nodes in a CFG's SCCs and the expressions * they are equivalent to. * * @param map * A mapping between the SCCs of the CFG's SSA Graph * (definitions) and the expressions they are folded to * @param sccNode * A Node in the SCC of the SSA Graph * * @return True, if the value in the mapping was changed. */ boolean fold(final Map map, final Node sccNode) { Node node = (Node) map.get(sccNode); if (ValueFolding.DUMP) { dump .println(" SCC Node " + sccNode + " is mapped to node " + node); } // The SCC node has not been folded yet, fold it to itself if (node == null) { node = sccNode; } if (!node.hasParent()) { return false; } if (ValueFolding.DEBUG) { System.out.println("folding --- " + node + " in " + node.parent()); } if (ValueFolding.DUMP) { dump.println(" Folding " + node + " (" + "VN=" + node.valueNumber() + ") in " + node.parent()); } final int v = node.valueNumber(); if (v == -1) { // Node has not been assigned a value number, can't do anything return false; } folder.values.ensureSize(v + 1); final ConstantExpr oldValue = (ConstantExpr) folder.values.get(v); ConstantExpr value = null; if (ValueFolding.DUMP) { dump.println(" Node " + node + " is mapped to constant " + oldValue); } if (node instanceof ConstantExpr) { // If the node that we're dealing with is already a // ConstantExpr, change it to the mapped value if it is // different. value = (ConstantExpr) node; if ((oldValue == null) || !oldValue.equalsExpr(value)) { // The node was not previously mapped to a constant, or it was // mapped to a different constant. Update the mapping to // relfect the new constant. if (ValueFolding.DEBUG) { System.out.println("changed " + oldValue + " to " + value); } if (ValueFolding.DUMP) { dump.println(" Changed " + oldValue + " to " + value); } folder.values.set(v, value); return true; } // Mapping was already correct, don't do anything. return false; } if ((node instanceof Expr) && (oldValue != null)) { // The node is a non-constant Expr that was mapped to a constant if (node.parent() instanceof PhiCatchStmt) { // Don't fold values inside PhiCatchStmts return false; } sideEffects.reset(); node.visit(sideEffects); if (!sideEffects.hasSideEffects()) { // If the expression does not have side effects, then make a // clone of the value to which it was mapped and map the clone // to the original sccNode (which may or may not be node). // Technically, the mapping did not change. value = (ConstantExpr) oldValue.clone(); node.replaceWith(value); map.put(sccNode, value); return false; } } if (value == null) { // The node is mapped to nothing, Use the ValueFolder to // determine a expression that node can be folded to. folder.node = null; node.visit(folder); if (ValueFolding.DEBUG) { System.out.println("folded " + node + " to " + folder.node); } if (ValueFolding.DUMP) { dump.println(" Using ValueFolder to determine new value"); dump.println(" Folded " + node + " to " + folder.node); } if (folder.node != null) { // Assert.isTrue(folder.node.hasParent(), // "No parent for " + folder.node); map.put(sccNode, folder.node); } if (folder.node instanceof ConstantExpr) { // If the node was folded into a ConstantExpr, then fold it in // the ValueFolder. value = (ConstantExpr) folder.node; folder.values.set(v, value); return true; } } return false; } }