Mirror of the BLOAT repository
https://www.cs.purdue.edu/homes/hosking/bloat/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
514 lines
15 KiB
514 lines
15 KiB
/**
|
|
* All files in the distribution of BLOAT (Bytecode Level Optimization and
|
|
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
|
|
* Research Foundation of Purdue University. All rights reserved.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
/* Demand-driven Induction Variable Analysis (diva)*/
|
|
package EDU.purdue.cs.bloat.diva;
|
|
|
|
import java.util.*;
|
|
|
|
import EDU.purdue.cs.bloat.cfg.*;
|
|
import EDU.purdue.cs.bloat.ssa.*;
|
|
import EDU.purdue.cs.bloat.tree.*;
|
|
|
|
/**
|
|
* InductionVarAnalyzer traverses a control flow graph and looks for array
|
|
* element swizzle operations inside loops. If possible, these swizzle
|
|
* operations are hoisted out of the loop and are replaced with range swizzle
|
|
* operations. The technique used is Demand-driven Induction Variable Analysis
|
|
* (DIVA).
|
|
* <p>
|
|
* To accomplish its tasks, InductionVarAnalyzer keeps track of a number of
|
|
* induction variables (represented by Swizzler objects) and local variables.
|
|
*
|
|
* @see Swizzler
|
|
* @see LocalExpr
|
|
*/
|
|
public class InductionVarAnalyzer {
|
|
public static boolean DEBUG = false;
|
|
|
|
SSAGraph ssaGraph;
|
|
|
|
FlowGraph CFG; // Control flow graph being operated on
|
|
|
|
HashMap IndStore; // Stores induction variables and
|
|
|
|
// associated swizzlers
|
|
HashMap LocalStore; // Stores local variables
|
|
|
|
Expr ind_var = null; // An induction variable
|
|
|
|
Expr ind_init = null; // Initial value of an induction variable
|
|
|
|
Expr ind_term = null; // Not used???
|
|
|
|
Expr ind_inc = null; // Expression used to increment induction
|
|
|
|
// variable (all uses commented out)
|
|
Expr tgt = null; // Target of the phi statement that defines
|
|
|
|
// an induction var
|
|
|
|
boolean changed = false; // Was the cfg changed?
|
|
|
|
/**
|
|
* Searches the list of induction variables for an induction variable with a
|
|
* given value number.
|
|
*
|
|
* @param vn
|
|
* Value number to search for.
|
|
*
|
|
* @return Swizzler object whose target has the desired value number or
|
|
* null, if value number is not found.
|
|
*/
|
|
public Object get_swizzler(final int vn) {
|
|
final Iterator iter = IndStore.values().iterator();
|
|
|
|
while (iter.hasNext()) {
|
|
final Swizzler swz = (Swizzler) iter.next();
|
|
if ((swz.target().valueNumber() == vn)
|
|
|| (swz.ind_var().valueNumber() == vn)) {
|
|
return swz;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Searchs the stored list of local variables for a local variable with a
|
|
* given value number.
|
|
*
|
|
* @param vn
|
|
* The value number to search for.
|
|
*
|
|
* @return The local variable with the given value number, or null, if not
|
|
* found.
|
|
*/
|
|
public MemExpr get_local(final int vn) {
|
|
final Iterator iter = LocalStore.keySet().iterator();
|
|
|
|
while (iter.hasNext()) {
|
|
final MemExpr le = (MemExpr) iter.next();
|
|
if (le.valueNumber() == vn) {
|
|
return le;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Displays (to System.out) all of the Swizzlers stored in the induction
|
|
* variable store.
|
|
*
|
|
* @see Swizzler
|
|
*/
|
|
public void Display_store() {
|
|
final Iterator iter = IndStore.values().iterator();
|
|
|
|
while (iter.hasNext()) {
|
|
final Swizzler indswz = (Swizzler) iter.next();
|
|
|
|
System.out.println("\nIV: " + indswz.ind_var() + " tgt: "
|
|
+ indswz.target() + "\narray: " + indswz.array()
|
|
+ " init: " + indswz.init_val() + " end: "
|
|
+ indswz.end_val());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Displays the contents of a Swizzler object to System.out.
|
|
*
|
|
* @param indswz
|
|
* The Swizzler to display.
|
|
*/
|
|
public void displaySwizzler(final Swizzler indswz) {
|
|
System.out.println("\nIV: " + indswz.ind_var() + "vn:"
|
|
+ indswz.ind_var().valueNumber() + " tgt: " + indswz.target()
|
|
+ "vn:" + indswz.target().valueNumber() + "\narray: "
|
|
+ indswz.array() + " init: " + indswz.init_val() + " end: "
|
|
+ indswz.end_val());
|
|
}
|
|
|
|
/**
|
|
* Adds a swizzle range statement (SRStmt) to the end of each predacessor
|
|
* block of the block containing the phi statement that defines an induction
|
|
* variable provided that the phi block does not dominate its predacessor.
|
|
* Phew.
|
|
*
|
|
* @param indswz
|
|
* Swizzler representing the induction variable on which the
|
|
* range swizzle statement is added.
|
|
*/
|
|
public void insert_aswrange(final Swizzler indswz) {
|
|
final Iterator iter = CFG.preds(indswz.phi_block()).iterator();
|
|
while (iter.hasNext()) {
|
|
final Block blk = (Block) iter.next();
|
|
if (!indswz.phi_block().dominates(blk)) {
|
|
final SRStmt aswrange = new SRStmt((Expr) indswz.array()
|
|
.clone(), (Expr) indswz.init_val().clone(),
|
|
(Expr) indswz.end_val().clone());
|
|
blk.tree().addStmtBeforeJump(aswrange);
|
|
changed = true;
|
|
if (InductionVarAnalyzer.DEBUG) {
|
|
System.out.println("Inserted ASWR: " + aswrange
|
|
+ "\nin block: " + blk);
|
|
|
|
System.out.println("$$$ can insert aswrange now\n"
|
|
+ "array: " + indswz.array() + "\nIV: "
|
|
+ indswz.ind_var() + "\ninit: " + indswz.init_val()
|
|
+ "\nend: " + indswz.end_val());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* To determine if a phi statement is a mu */
|
|
/* Returns null if not a MU and sets ind_var & ind_init */
|
|
/* to refer to the IV & its initial value otherwise */
|
|
|
|
/**
|
|
* Determines whether or not a phi statement is a mu function. A mu function
|
|
* is a phi function that merges values at loop headers, as opposed to those
|
|
* that occur as a result of forward branching. Mu functions always have two
|
|
* arguments.
|
|
*
|
|
* @param phi
|
|
* phi statement that may be a mu function
|
|
* @param cfg
|
|
* CFG to look through <font color="ff0000">Get rid of this
|
|
* parameter</font>
|
|
*
|
|
* @return The block containing the mu functions external (that is, outside
|
|
* the loop) argument, also known as the external ssalink. If the
|
|
* phi statement is not a mu function, null is returned.
|
|
*/
|
|
public Block isMu(final PhiJoinStmt phi, final FlowGraph cfg) {
|
|
// Does it contain two operands?
|
|
if (phi.numOperands() != 2) {
|
|
return null;
|
|
}
|
|
|
|
// Is it REDUCIBLE?
|
|
if ((cfg.blockType(phi.block()) == Block.IRREDUCIBLE)
|
|
|| (cfg.blockType(phi.block()) == Block.NON_HEADER)) {
|
|
return null;
|
|
}
|
|
|
|
/*
|
|
* Does one of them dominate the phi and the other dominated by the phi?
|
|
*/
|
|
|
|
final Iterator iter = cfg.preds(phi.block()).iterator();
|
|
final Block pred1 = (Block) iter.next();
|
|
final Block pred2 = (Block) iter.next();
|
|
|
|
if (pred1.dominates(phi.block()) && phi.block().dominates(pred2)
|
|
&& (pred1 != phi.block())) {
|
|
if (InductionVarAnalyzer.DEBUG) {
|
|
System.out.println("Extlink = 1 pred1:" + pred1 + " pred2:"
|
|
+ pred2);
|
|
}
|
|
ind_var = phi.operandAt(pred2);
|
|
ind_init = phi.operandAt(pred1);
|
|
return pred1;
|
|
}
|
|
if (pred2.dominates(phi.block()) && phi.block().dominates(pred1)
|
|
&& (pred2 != phi.block())) {
|
|
if (InductionVarAnalyzer.DEBUG) {
|
|
System.out.println("Extlink = 2 pred1:" + pred1 + " pred2:"
|
|
+ pred2);
|
|
}
|
|
ind_var = phi.operandAt(pred1);
|
|
ind_init = phi.operandAt(pred2);
|
|
return pred2;
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
/**
|
|
* Performs DIVA on a CFG public static void transform(FlowGraph cfg) { //
|
|
* Create a new instance to allow multiple threads. InductionVarAnalyzer me =
|
|
* new InductionVarAnalyzer(); me.transform(cfg); }
|
|
*/
|
|
|
|
/**
|
|
* Performs DIVA on a CFG.
|
|
*/
|
|
public void transform(final FlowGraph cfg) {
|
|
ssaGraph = new SSAGraph(cfg);
|
|
CFG = cfg;
|
|
IndStore = new HashMap();
|
|
LocalStore = new HashMap();
|
|
changed = false;
|
|
|
|
if (InductionVarAnalyzer.DEBUG) {
|
|
System.out
|
|
.println("----------Before visitComponents--------------");
|
|
cfg.print(System.out);
|
|
}
|
|
|
|
// Visit each strongly connected component (SCC) in the CFG. SCCs
|
|
// correspond to sequences in the program. Visit each node in the
|
|
// SCC and build the local variable store. Create Swizzlers at
|
|
// PhiStmts, if approproate, and store them in the induction
|
|
// variable store. If it can be determined that an array element
|
|
// swizzle can be hoisted out of a loop, it is hoisted.
|
|
ssaGraph.visitComponents(new ComponentVisitor() {
|
|
public void visitComponent(final List scc) {
|
|
if (InductionVarAnalyzer.DEBUG) {
|
|
System.out.println("SCC =");
|
|
}
|
|
|
|
final Iterator e = scc.iterator();
|
|
|
|
while (e.hasNext()) {
|
|
final Node v = (Node) e.next();
|
|
if (InductionVarAnalyzer.DEBUG) {
|
|
System.out.println(" " + v + "{" + v.key() + "} "
|
|
+ v.getClass());
|
|
}
|
|
|
|
v.visit(new TreeVisitor() {
|
|
public void visitPhiJoinStmt(final PhiJoinStmt phi) {
|
|
if (isMu(phi, CFG) != null) {
|
|
tgt = phi.target();
|
|
if (InductionVarAnalyzer.DEBUG) {
|
|
System.out.println("IV:" + ind_var + " VN:"
|
|
+ ind_var.valueNumber() + "\ninit:"
|
|
+ ind_init + " target: " + tgt
|
|
+ " VN: " + tgt.valueNumber());
|
|
}
|
|
final Swizzler swz = new Swizzler(ind_var, tgt,
|
|
ind_init, phi.block());
|
|
if (InductionVarAnalyzer.DEBUG) {
|
|
System.out
|
|
.println("store swizzler for "
|
|
+ ind_var.def() + " & "
|
|
+ tgt.def());
|
|
displaySwizzler(swz);
|
|
}
|
|
|
|
if (ind_var.def() != null) {
|
|
IndStore.put(ind_var.def(), swz);
|
|
}
|
|
|
|
if (tgt.def() != null) {
|
|
IndStore.put(tgt.def(), swz);
|
|
}
|
|
|
|
if (InductionVarAnalyzer.DEBUG) {
|
|
System.out.println(" Mu: " + phi + "{"
|
|
+ phi.key() + "}");
|
|
}
|
|
} else {
|
|
if (InductionVarAnalyzer.DEBUG) {
|
|
System.out.println("Phi: " + phi + "{"
|
|
+ phi.key() + "}");
|
|
}
|
|
}
|
|
}
|
|
|
|
public void visitLocalExpr(final LocalExpr me) {
|
|
if (me.def() != null) {
|
|
if (LocalStore.get(me.def()) == null) {
|
|
LocalStore.put(me.def(), me);
|
|
}
|
|
}
|
|
if (LocalStore.get(me) == null) {
|
|
LocalStore.put(me, me);
|
|
}
|
|
if (InductionVarAnalyzer.DEBUG) {
|
|
System.out.println("stored ME: " + me
|
|
+ " vn: " + me.valueNumber());
|
|
}
|
|
}
|
|
|
|
public void visitStaticFieldExpr(
|
|
final StaticFieldExpr me) {
|
|
if (me.def() != null) {
|
|
if (LocalStore.get(me.def()) == null) {
|
|
LocalStore.put(me.def(), me);
|
|
}
|
|
}
|
|
if (LocalStore.get(me) == null) {
|
|
LocalStore.put(me, me);
|
|
}
|
|
if (InductionVarAnalyzer.DEBUG) {
|
|
System.out.println("stored ME: " + me
|
|
+ " vn: " + me.valueNumber());
|
|
}
|
|
}
|
|
|
|
public void visitIfCmpStmt(final IfCmpStmt cmp) {
|
|
Swizzler indswz = null;
|
|
boolean set_term = false;
|
|
|
|
if (cmp.left().def() != null) {
|
|
indswz = (Swizzler) IndStore.get(cmp.left()
|
|
.def());
|
|
}
|
|
if (indswz != null) {
|
|
if (InductionVarAnalyzer.DEBUG) {
|
|
displaySwizzler(indswz);
|
|
}
|
|
if (indswz.end_val() == null) {
|
|
indswz.set_end_val(cmp.right());
|
|
set_term = true;
|
|
if (InductionVarAnalyzer.DEBUG) {
|
|
System.out.println("Set end_val of "
|
|
+ indswz.ind_var() + " to "
|
|
+ cmp.right());
|
|
}
|
|
}
|
|
} else {
|
|
if (cmp.right().def() != null) {
|
|
indswz = (Swizzler) IndStore.get(cmp
|
|
.right().def());
|
|
}
|
|
if (indswz != null) {
|
|
if (InductionVarAnalyzer.DEBUG) {
|
|
displaySwizzler(indswz);
|
|
}
|
|
if (indswz.end_val() == null) {
|
|
indswz.set_end_val(cmp.left());
|
|
set_term = true;
|
|
if (InductionVarAnalyzer.DEBUG) {
|
|
System.out
|
|
.println("Set end_val of "
|
|
+ indswz.ind_var()
|
|
+ " to "
|
|
+ cmp.left());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (set_term && (indswz != null)
|
|
&& (indswz.array() != null)) {
|
|
indswz.aswizzle().set_redundant(true);
|
|
insert_aswrange(indswz);
|
|
}
|
|
}
|
|
|
|
public void visitSCStmt(final SCStmt sc) {
|
|
Swizzler indswz;
|
|
MemExpr le = null;
|
|
|
|
if (InductionVarAnalyzer.DEBUG) {
|
|
System.out.println("SC: array= " + sc.array()
|
|
+ " VN:" + sc.array().valueNumber()
|
|
+ "\nindex=" + sc.index() + " VN:"
|
|
+ sc.index().valueNumber());
|
|
}
|
|
|
|
indswz = (Swizzler) get_swizzler(sc.index()
|
|
.valueNumber());
|
|
if (indswz != null) {
|
|
if (InductionVarAnalyzer.DEBUG) {
|
|
displaySwizzler(indswz);
|
|
}
|
|
if (indswz.array() == null) {
|
|
le = get_local(sc.array().valueNumber());
|
|
if ((le == null)
|
|
&& (sc.array().def() != null)) {
|
|
le = get_local(sc.array().def()
|
|
.valueNumber());
|
|
}
|
|
if (le != null) {
|
|
if (InductionVarAnalyzer.DEBUG) {
|
|
System.out.println("Le: " + le);
|
|
}
|
|
indswz.set_array(le);
|
|
indswz.set_aswizzle(sc);
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
if (indswz.end_val() != null) {
|
|
sc.set_redundant(true);
|
|
insert_aswrange(indswz);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* public void visitStoreExpr(StoreExpr ind_store) {
|
|
* if(ind_var != null) {
|
|
* if(ind_var.equalsExpr(ind_store.target())) { if (tgt !=
|
|
* null && ind_store.expr() instanceof ArithExpr){
|
|
* ArithExpr ind_exp = (ArithExpr)ind_store.expr();
|
|
* if(tgt.equalsExpr(ind_exp.left())) ind_inc =
|
|
* ind_exp.right(); else if(tgt.equals(ind_exp.right()))
|
|
* ind_inc = ind_exp.left(); else { ind_inc = null;
|
|
* return; } System.out.println("Ind_inc: "+ind_inc); } } } }
|
|
*/
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
if (InductionVarAnalyzer.DEBUG) {
|
|
System.out.println("------------After visitComponents---------");
|
|
cfg.print(System.out);
|
|
}
|
|
|
|
// If the CFG changed (i.e. if an array range swizzle was added),
|
|
// traverse
|
|
// the graph and remove redundent swizzle statements.
|
|
if (changed) {
|
|
cfg.visit(new TreeVisitor() {
|
|
ListIterator iter;
|
|
|
|
public void visitTree(final Tree tree) {
|
|
iter = tree.stmts().listIterator();
|
|
|
|
while (iter.hasNext()) {
|
|
final Stmt stmt = (Stmt) iter.next();
|
|
stmt.visit(this);
|
|
}
|
|
}
|
|
|
|
public void visitSCStmt(final SCStmt sc) {
|
|
Object dup2stmt;
|
|
if (sc.redundant()) {
|
|
|
|
iter.remove();
|
|
dup2stmt = iter.previous();
|
|
iter.remove();
|
|
if (InductionVarAnalyzer.DEBUG) {
|
|
System.out.println("Removed Redundant ASW: " + sc
|
|
+ "\nand " + dup2stmt);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
if (InductionVarAnalyzer.DEBUG) {
|
|
System.out.println("----------------After cfg.visit--------------");
|
|
cfg.print(System.out);
|
|
}
|
|
}
|
|
}
|
|
|