Index: build/custom/msvc_2003/jitrino/jitrino.vcproj
===================================================================
--- build/custom/msvc_2003/jitrino/jitrino.vcproj (revision 638284)
+++ build/custom/msvc_2003/jitrino/jitrino.vcproj (working copy)
@@ -170,6 +170,12 @@
RelativePath="..\..\..\..\vm\jitrino\src\optimizer\CSEHash.h">
+
+
+
+
+
+
getNode()); }
static void printInsts(std::ostream& cout, Node* node, uint32 indent);
- static void printDotFile(ControlFlowGraph& cfg, MethodDesc& methodDesc,const char *suffix);
+ static void printDotFile(ControlFlowGraph& cfg, MethodDesc& methodDesc,const char *suffix, PrintDotFile* dotPrinter = NULL);
private:
static Node* duplicateNode(IRManager& irm, Node *source, Node *before, OpndRenameTable *renameTable);
@@ -125,6 +125,20 @@
virtual uint32 getKeyHashCode(Node* key) const { return ((uint32)(((POINTER_SIZE_INT)key) >> sizeof(void*))); }
};
+class HIRDotPrinter : public PrintDotFile {
+public:
+ HIRDotPrinter(ControlFlowGraph& _fg) : fg(_fg), loopTree(NULL), dom(NULL){}
+ virtual void printDotBody();
+ virtual void printDotNode(Node* node);
+ virtual void printDotNodeOtherInfo(Node* node) {}
+ virtual void printDotEdge(Edge* edge);
+private:
+ ControlFlowGraph& fg;
+ LoopTree* loopTree;
+ DominatorTree* dom;
+};
+
+
} //namespace Jitrino
#endif // _FLOWGRAPH_
Index: vm/jitrino/src/optimizer/Opnd.h
===================================================================
--- vm/jitrino/src/optimizer/Opnd.h (revision 638284)
+++ vm/jitrino/src/optimizer/Opnd.h (working copy)
@@ -277,15 +277,6 @@
// from the general set of types to the legal set of types for opnds.
//
Type* getOpndTypeFromLdType(Type* ldType);
- //
- // Change DefUse so that it does not depend on the Opnd::id
- // Use a hashtable instead.
- //
- int getUniqueId(Opnd *op) {
- int id = op->getId();
- if (op->isVarOpnd()) id += (nextSsaOpndId-1);
- return id;
- }
static Opnd* getNullOpnd() {return &_nullOpnd;}
VarOpnd* getVarOpnds() {return varOpnds;}
uint32 getNumVarOpnds() {return nextVarId;}
Index: vm/jitrino/src/optimizer/LiveVarAnalyzer.cpp
===================================================================
--- vm/jitrino/src/optimizer/LiveVarAnalyzer.cpp (revision 0)
+++ vm/jitrino/src/optimizer/LiveVarAnalyzer.cpp (revision 0)
@@ -0,0 +1,293 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @author Pavel A. Ozhdikhin
+ */
+
+#include "optpass.h"
+#include "irmanager.h"
+#include "ControlFlowGraph.h"
+#include "FlowGraph.h"
+#include "BitSet.h"
+#include "PrintDotFile.h"
+#include "Stl.h"
+
+namespace Jitrino {
+
+DEFINE_SESSION_ACTION(LivenessAnalysisPass, liveness, "HIR Operand Liveness Analysis")
+
+// Liveness analysis pass.
+// Calculates HIR operand liveness info at the entry of every CFG node.
+// Prints liveness info into the dot file if dot printing is enabled.
+// Validates liveness in the debug mode with the assertion that there
+// are no live operands at CFG entry.
+// Add "liveness" pass into the optimizer path to use. For example:
+// -XX:jit.SD1_OPT.path.optimizer=liveness,ssa,simplify,...
+//
+// Does not work on SSA form!
+// Currently does not support obtaining the list of live operand objects at CFG node.
+// To support the feature we need a single index for SSA and Var opnds and keeping
+// the list of operands indexed by its id in the OpndManager.
+class LiveVarAnalyzer : public HIRDotPrinter {
+public:
+ LiveVarAnalyzer(MemoryManager& mm, IRManager & irm, SessionAction* sa)
+ : _memManager(mm), _irManager(irm),
+ _opndManager(irm.getOpndManager()),
+ _sa(sa),
+ _flowgraph(irm.getFlowGraph()),
+ _numSsaOpnds(_opndManager.getNumSsaOpnds() - 1),
+ _numOpnds(_numSsaOpnds + _opndManager.getNumVarOpnds()),
+ _numNodes(_flowgraph.getMaxNodeId()),
+ _completedNodes(mm, _numNodes),
+ _currLive(NULL), _livenessIsComputed(false),
+ HIRDotPrinter(irm.getFlowGraph()) {
+ _liveAtNodeEntry = new(_memManager) BitSet*[_numNodes];
+ }
+
+ // Compute liveness of global operands and variables
+ void computeLiveness();
+
+ void computeLiveAtNodeExit(Node* node, BitSet& live);
+
+ // Get bit set of live variables at the node entry
+ BitSet& getLiveAtNodeEntry(Node *node);
+
+ // Print liveness information
+ void printLive(std::ostream& os);
+ void printLiveAtNode(Node* node, std::ostream& os);
+ void printDotNodeOtherInfo(Node* node);
+private:
+ void processInst(Inst* inst, BitSet& live);
+ void processNode(Node* node);
+
+ // Setting dead/live bits
+ inline void markOpndDead(Opnd* opnd, BitSet& live) {
+ // if (opnd->isGlobal())
+ live.setBit(getUniqueOpndId(opnd), false);
+ }
+ inline void markOpndLive(Opnd* opnd, BitSet& live) {
+ // if (opnd->isGlobal())
+ live.setBit(getUniqueOpndId(opnd), true);
+ }
+
+ uint32 getUniqueOpndId(Opnd *op) {
+ int id = op->getId();
+ // Make sure unique ID fits into 32-bit
+ assert((id & 0xFFFF) >= 0);
+ if (op->isVarOpnd()) id += _numSsaOpnds;
+ assert(id >= 0);
+ return id;
+ }
+
+ // Memory manager for internal structures
+ MemoryManager& _memManager;
+ // IRManager
+ IRManager& _irManager;
+ // Flow Graph analyzed for liveness
+ ControlFlowGraph& _flowgraph;
+ // Operand manager
+ OpndManager& _opndManager;
+ // Array of bit sets of variables live at each node entry
+ BitSet** _liveAtNodeEntry;
+ // Number of SSA operands
+ uint32 _numSsaOpnds;
+ // Overall number of operands
+ const uint32 _numOpnds;
+ // Number of CFG nodes
+ const uint32 _numNodes;
+ // Just a flag
+ bool _livenessChanged;
+ // Bit set of nodes where liveness is already known
+ BitSet _completedNodes;
+ // Temporary storage for liveness info at the node exit. Move to locals???
+ BitSet* _currLive;
+ // Flag to know that liveness info is up to date
+ bool _livenessIsComputed;
+ // Parental optimization pass
+ SessionAction* _sa;
+};
+
+void LivenessAnalysisPass::_run(IRManager& irm) {
+ MemoryManager mm("LivenessAnalysisPass::_run");
+ LiveVarAnalyzer lva(mm, irm, this);
+ lva.computeLiveness();
+ // Log liveness info
+ if (Log::isLogEnabled(LogStream::DOTDUMP)) {
+ printDotFile(irm, getId(), getTagName(), "hir", &lva);
+ }
+}
+
+// Compute liveness of operands and variables
+void LiveVarAnalyzer::computeLiveness() {
+
+ // Initialize array of bit sets for node entry liveness
+ for (uint32 i = 0; i < _numNodes; i++) {
+ _liveAtNodeEntry[i] = NULL;
+ }
+
+ // Create array of nodes. Write nodes in order optimal for
+ // data flow analysis.
+ StlVector nodes(_memManager);
+ _flowgraph.getNodesPostOrder(nodes);
+
+ // Data flow analysis
+ do {
+ _livenessChanged = false;
+ _completedNodes.clear();
+ for (StlVector::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) {
+ Node* node = *it;
+ assert(node);
+ if (!_completedNodes.getBit(node->getId()))
+ processNode(node);
+ }
+ } while (_livenessChanged);
+ _livenessIsComputed = true;
+
+ // Make sure there are no live opnds at CFG entry
+ assert(getLiveAtNodeEntry(_flowgraph.getEntryNode()).isEmpty());
+}
+
+
+// Process node, i.e., update liveness at node entry
+void LiveVarAnalyzer::processNode(Node* node) {
+
+ // Mark node as completed
+ uint32 nodeId = node->getId();
+ _completedNodes.setBit(nodeId, true);
+
+ // Compute liveness at the node exit
+ if (_currLive == NULL) {
+ _currLive = new (_memManager) BitSet(_memManager, _numOpnds);
+ }
+ computeLiveAtNodeExit(node, *_currLive);
+
+ // Process node's content
+ // Iterate backward through the instruction list
+ for (Inst* inst = (Inst*) node->getLastInst(); inst!=NULL; inst = inst->getPrevInst()) {
+ processInst(inst, *_currLive);
+ }
+
+ // Decide whether node liveness has changed
+ bool nodeLivenessChanged = false;
+ if (_liveAtNodeEntry[nodeId] == NULL)
+ nodeLivenessChanged = !_currLive->isEmpty();
+ else
+ nodeLivenessChanged = !_currLive->isEqual(*_liveAtNodeEntry[nodeId]);
+
+ // Swap currLive and node's live set
+ if (_liveAtNodeEntry[nodeId] == NULL || nodeLivenessChanged) {
+ // Update node's liveness
+ BitSet* tmp = _currLive;
+ _currLive = _liveAtNodeEntry[nodeId];
+ _liveAtNodeEntry[nodeId] = tmp;
+ }
+
+ // Mark node's predecessors as not completed
+ if (nodeLivenessChanged) {
+ _livenessChanged = true;
+ // Mark node's predecessors as not completed
+ const Edges& inEdges = node->getInEdges();
+ for(Edges::const_iterator eiter = inEdges.begin(); eiter != inEdges.end(); ++eiter) {
+ Edge* edge = *eiter;
+ assert(edge);
+ Node* srcNode = edge->getSourceNode();
+ _completedNodes.setBit(srcNode->getId(), false);
+ }
+ }
+}
+
+
+// Compute liveness at node exit
+void LiveVarAnalyzer::computeLiveAtNodeExit(Node* node, BitSet& live) {
+ assert(live.getSetSize() == _numOpnds);
+ uint32 numInputs = 0;
+
+ const Edges& outEdges = node->getOutEdges();
+ for (Edges::const_iterator eiter = outEdges.begin(), end = outEdges.end(); eiter!=end; ++eiter) {
+ Edge* edge = *eiter;
+ assert(edge);
+ Node* targetNode = edge->getTargetNode();
+ BitSet* succLive = _liveAtNodeEntry[targetNode->getId()];
+ if (succLive != NULL) {
+ if (numInputs == 0)
+ live.copyFrom(*succLive);
+ else
+ live.unionWith(*succLive);
+ numInputs++;
+ }
+ }
+ if (numInputs == 0)
+ live.clear();
+}
+
+// Process instruction,
+// i.e., given liveness after instruction compute liveness before instruction
+void LiveVarAnalyzer::processInst(Inst *inst, BitSet& live) {
+
+ // Mark destination as dead
+ markOpndDead(inst->getDst(), live);
+
+ // Mark live variables
+ uint32 numSrcs = inst->getNumSrcOperands();
+ for (uint32 i = 0; i < numSrcs; i++) {
+ markOpndLive(inst->getSrc(i), live);
+ }
+}
+
+// Get bit set of live variables at the node entry
+BitSet& LiveVarAnalyzer::getLiveAtNodeEntry(Node *node) {
+ assert(_livenessIsComputed);
+ assert(_liveAtNodeEntry[node->getId()] != NULL);
+ return *(_liveAtNodeEntry[node->getId()]);
+}
+
+/*======================================================================*/
+// Print liveness information
+//
+void LiveVarAnalyzer::printLive(std::ostream& os) {
+ const Nodes& nodes = _flowgraph.getNodes();
+ for(Nodes::const_iterator niter = nodes.begin(); niter != nodes.end(); ++niter) {
+ Node* node = *niter;
+ os << "Operands live at entry to ";
+ FlowGraph::printLabel(os, node);
+ os << ":\t";
+ printLiveAtNode(node, os);
+ os << std::endl;
+ }
+}
+
+void LiveVarAnalyzer::printLiveAtNode(Node* node, std::ostream& os) {
+ BitSet& live = getLiveAtNodeEntry(node);
+ for (uint32 i = 0; i < live.getSetSize(); i++) {
+ if (live.getBit(i)) {
+ if (i <= _numSsaOpnds) os << "t" << i;
+ else os << "v" << i - _numSsaOpnds;
+ os << " ";
+ }
+ }
+}
+
+void LiveVarAnalyzer::printDotNodeOtherInfo(Node* node) {
+ std::ostream& out = *os;
+ out << "\\l|\\" << std::endl;
+ out << "live: ";
+ printLiveAtNode(node, out);
+}
+
+} //namespace Jitrino
+
Index: vm/jitrino/src/optimizer/FlowGraph.cpp
===================================================================
--- vm/jitrino/src/optimizer/FlowGraph.cpp (revision 638284)
+++ vm/jitrino/src/optimizer/FlowGraph.cpp (working copy)
@@ -1207,21 +1207,13 @@
}
}
-class HIRDotPrinter : public PrintDotFile {
-public:
- HIRDotPrinter(ControlFlowGraph& _fg) : fg(_fg), loopTree(NULL), dom(NULL){}
- void printDotBody();
- void printDotNode(Node* node);
- void printDotEdge(Edge* edge);
-private:
- ControlFlowGraph& fg;
- LoopTree* loopTree;
- DominatorTree* dom;
-};
-
-void FlowGraph::printDotFile(ControlFlowGraph& fg, MethodDesc& methodDesc,const char *suffix) {
- HIRDotPrinter printer(fg);
- printer.printDotFile(methodDesc, suffix);
+void FlowGraph::printDotFile(ControlFlowGraph& fg, MethodDesc& methodDesc,const char *suffix, PrintDotFile* dotPrinter) {
+ if (dotPrinter) {
+ dotPrinter->printDotFile(methodDesc, suffix);
+ } else {
+ HIRDotPrinter printer(fg);
+ printer.printDotFile(methodDesc, suffix);
+ }
}
void HIRDotPrinter::printDotBody() {
@@ -1279,6 +1271,8 @@
out << ") ";
}
+ printDotNodeOtherInfo(node);
+
if (!node->isEmpty()) {
out << "\\l|\\" << std::endl;
Inst* first = (Inst*)node->getFirstInst();
Index: vm/jitrino/src/optimizer/optpass.h
===================================================================
--- vm/jitrino/src/optimizer/optpass.h (revision 638284)
+++ vm/jitrino/src/optimizer/optpass.h (working copy)
@@ -27,6 +27,7 @@
#include "CompilationContext.h"
#include "PMFAction.h"
+#include "PrintDotFile.h"
#include
@@ -49,6 +50,11 @@
virtual const char* getTagName() = 0;
//
+ // Sequential id of the pass
+ //
+ const unsigned getId() { return id; }
+
+ //
// Run the pass.
//
void run();
@@ -69,8 +75,8 @@
static void smoothProfile(IRManager& irm);
static void printHIR(IRManager& irm);
- static void printDotFile(IRManager& irm, int id, const char* name, const char* suffix);
- static void printDotFile(IRManager& irm, const char* suffix);
+ static void printDotFile(IRManager& irm, int id, const char* name, const char* suffix, PrintDotFile* dotPrinter = NULL);
+ static void printDotFile(IRManager& irm, const char* suffix, PrintDotFile* dotPrinter = NULL);
static const char* indent(IRManager& irm);
protected:
Index: vm/jitrino/src/optimizer/optpass.cpp
===================================================================
--- vm/jitrino/src/optimizer/optpass.cpp (revision 638284)
+++ vm/jitrino/src/optimizer/optpass.cpp (working copy)
@@ -199,16 +199,16 @@
}
void
-OptPass::printDotFile(IRManager& irm, int id, const char* name, const char* suffix) {
+OptPass::printDotFile(IRManager& irm, int id, const char* name, const char* suffix, PrintDotFile* dotPrinter) {
char temp[128];
snprintf(temp, sizeof(temp), "%.2i.%s.%s", id, name, suffix);
- printDotFile(irm, temp);
+ printDotFile(irm, temp, dotPrinter);
}
void
-OptPass::printDotFile(IRManager& irm, const char* name) {
+OptPass::printDotFile(IRManager& irm, const char* name, PrintDotFile* dotPrinter) {
ControlFlowGraph& flowGraph = irm.getFlowGraph();
- FlowGraph::printDotFile(flowGraph, irm.getMethodDesc(), name);
+ FlowGraph::printDotFile(flowGraph, irm.getMethodDesc(), name, dotPrinter);
}
const char*