blob: be64fd8c12f044b48fac3e68dbbee9ac7e2f3be8 [file] [log] [blame]
/*
* 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 Intel, Pavel A. Ozhdikhin
*
*/
#include <assert.h>
#include <iostream>
#include <algorithm>
#include "Stl.h"
#include "Log.h"
#include "open/types.h"
#include "Inst.h"
#include "irmanager.h"
#include "Dominator.h"
#include "Loop.h"
#include "globalcodemotion.h"
#include "CSEHash.h"
#include "Opcode.h"
#include "constantfolder.h"
#include "walkers.h"
#include "optimizer.h"
#include "hashvaluenumberer.h"
#include "aliasanalyzer.h"
#include "memoryopt.h"
#include "FlowGraph.h"
#include "optpass.h"
namespace Jitrino {
static void printLabel(std::ostream& os, DominatorNode* dNode) {
FlowGraph::printLabel(os, dNode->getNode());
}
DEFINE_SESSION_ACTION(GlobalCodeMotionPass, gcm, "Global Code Motion")
void GlobalCodeMotionPass::_run(IRManager& irm) {
OptPass::splitCriticalEdges(irm);
OptPass::computeDominatorsAndLoops(irm);
MemoryManager& memoryManager = irm.getNestedMemoryManager();
DominatorTree* dominatorTree = irm.getDominatorTree();
LoopTree* loopTree = irm.getLoopTree();
assert(dominatorTree->isValid() && loopTree->isValid());
GlobalCodeMotion gcm(irm, memoryManager, *dominatorTree, loopTree);
gcm.runPass();
}
DEFINE_SESSION_ACTION(GlobalValueNumberingPass, gvn, "Global Value Numbering")
void GlobalValueNumberingPass::_run(IRManager& irm) {
OptPass::computeDominatorsAndLoops(irm);
DominatorTree* dominatorTree = irm.getDominatorTree();
assert(dominatorTree && dominatorTree->isValid());
LoopTree* loopTree = irm.getLoopTree();
assert(loopTree && loopTree->isValid());
MemoryManager& memoryManager = irm.getNestedMemoryManager();
ControlFlowGraph& flowGraph = irm.getFlowGraph();
DomFrontier frontier(memoryManager,*dominatorTree,&flowGraph);
TypeAliasAnalyzer aliasAnalyzer;
MemoryOpt mopt(irm, memoryManager, *dominatorTree,
frontier, loopTree, &aliasAnalyzer);
mopt.runPass();
HashValueNumberer valueNumberer(irm, *dominatorTree);
valueNumberer.doGlobalValueNumbering(&mopt);
}
GlobalCodeMotion::GlobalCodeMotion(IRManager &irManager0,
MemoryManager& memManager,
DominatorTree& dom0,
LoopTree *loopTree0)
: irManager(irManager0),
fg(irManager0.getFlowGraph()),
methodDesc(irManager0.getMethodDesc()),
mm(memManager),
dominators(dom0),
loopTree(loopTree0),
flags(*irManager.getOptimizerFlags().gcmFlags),
earliest(memManager),
latest(memManager),
visited(memManager),
uses(memManager)
{
}
GlobalCodeMotion::~GlobalCodeMotion()
{
}
void
GlobalCodeMotion::readFlags(Action* argSource, GcmFlags* flags) {
IAction::HPipeline p = NULL; //default pipeline for argSource
flags->dry_run = argSource->getBoolArg(p, "gcm.dry_run", false);
flags->sink_stvars = argSource->getBoolArg(p, "gcm.sink_stvars", false);
flags->min_cut = argSource->getBoolArg(p, "gcm.min_cut", false);
flags->sink_constants = argSource->getBoolArg(p, "gcm.sink_constants", false);
}
void GlobalCodeMotion::showFlags(std::ostream& os) {
os << " global code motion flags:"<<std::endl;
os << " gcm.dry_run[={on|OFF}] - don't really move anything" << std::endl;
os << " gcm.sink_stvars[={on|OFF}] - raise ldvar, sink stvar to Phi nodes" << std::endl;
os << " gcm.min_cut[={on|OFF}] - duplicate placement on mincut between def and uses" << std::endl;
os << " gcm.sink_constants[={ON|off}] - sink constants after placement" << std::endl;
}
void GlobalCodeMotion::runPass() {
if (flags.dry_run && !flags.sink_constants) return;
if (Log::isEnabled()) {
Log::out() << "IR before GCM pass" << std::endl;
FlowGraph::printHIR(Log::out(), irManager.getFlowGraph(), methodDesc);
FlowGraph::printDotFile(irManager.getFlowGraph(), methodDesc, "beforegcm");
dominators.printDotFile(methodDesc, "beforegcm.dom");
dominators.printIndentedTree(Log::out(), "beforegcm.dom");
loopTree->printDotFile(methodDesc, "beforegcm.loop");
}
if (!flags.dry_run) {
// schedule instructions early
scheduleAllEarly();
// now earliest[i] = domNode for earliest placement.
clearVisited();
scheduleAllLate();
}
// sink loads of constants, since IPF back-end doesn't re-materialize
if (flags.sink_constants)
sinkAllConstants();
// patch up SSA form in case live ranges overlap now
// for now, we don't move Phis, Ldvars, or Stvars, so Ssa form is unaffected
// fixSsaForm();
if (Log::isEnabled() ) {
Log::out() << "IR after GCM pass" << std::endl;
FlowGraph::printHIR(Log::out(),irManager.getFlowGraph(), methodDesc);
FlowGraph::printDotFile( irManager.getFlowGraph(), methodDesc, "aftergcm");
dominators.printDotFile(methodDesc, "aftergcm.dom");
}
}
// EARLY SCHEDULING
// a DomNodeInstWalker, forwards/preorder
class GcmScheduleEarlyWalker {
GlobalCodeMotion *thePass;
Node *block;
DominatorNode *domNode;
public:
void startNode(DominatorNode *domNode0) {
domNode = domNode0;
block = domNode->getNode();
if (Log::isEnabled() ) {
Log::out() << "Begin early scheduling of block ";
FlowGraph::print(Log::out(), block);
Log::out() << std::endl;
}
};
void applyToInst(Inst *i) { thePass->scheduleEarly(domNode, i); };
void finishNode(DominatorNode *domNode) {
Node *block1 = domNode->getNode();
if( !(block == block1) ) assert(0);
if (Log::isEnabled() ) {
Log::out() << "Done early scheduling of block ";
FlowGraph::print(Log::out(), block);
Log::out() << std::endl;
}
};
GcmScheduleEarlyWalker(GlobalCodeMotion *thePass0)
: thePass(thePass0), block(0), domNode(0)
{
};
};
void GlobalCodeMotion::scheduleAllEarly()
{
GcmScheduleEarlyWalker scheduleEarlyWalker(this);
// adapt the DomNodeInstWalker to a forwards DomWalker
typedef DomNodeInst2DomWalker<true, GcmScheduleEarlyWalker> EarlyDomInstWalker;
EarlyDomInstWalker domInstWalker(scheduleEarlyWalker);
// do the walk, pre-order
DomTreeWalk<true, EarlyDomInstWalker>(dominators, domInstWalker, mm);
}
// since it will usually visit in the right order, we used dominator tree order
// BUT: since GVN may leave instructions out of place, we can't count on
// operands having been visited before the instruction.
// THOUGH: we guarantee the head of each cycle (when placed legally) will
// be a Phi function, and thus pinned. This means that for non-Phi instrs,
// we can just place all operands first, then this instruction.
// For Phi instructions, we must just leave them in place (pinned) and leave
// the operands for later visiting.
// domNode should be 0 or i's DominatorNode, if we happen to know it.
void GlobalCodeMotion::scheduleEarly(DominatorNode *domNode, Inst *i)
{
if (i->isLabel()) return;
if (alreadyVisited(i)) {
/* if (Log::isEnabled() ) {
Log::out() << "= Inst is already scheduled early: "; i->print(Log::out());
Log::out() << std::endl;
}
*/
return;
}
Node *cfgNode = i->getNode();
if (domNode==NULL) {
domNode = dominators.getDominatorNode(cfgNode);
}
bool pinned = isPinned(i);
markAsVisited(i);
if (Log::isEnabled() ) {
Log::out() << "< Beginning early scheduling of " << (pinned?"":"not");
Log::out() << " pinned inst "; i->print(Log::out());
Log::out() << std::endl;
}
if (pinned) { // leave it here
// We place operands before placing instruction, to get ordering right
// in the block; in normal code, operands should appear first and
// have been already placed, but after GVN we don't have that guarantee.
if (i->getOpcode() != Op_Phi) { // phi operands must also be pinned, skip them.
if (Log::isEnabled() ) {
Log::out() << " Inst is not a Phi, processing operands" << std::endl;
}
// for others, record uses in this instruction
U_32 numSrcs = i->getNumSrcOperands();
for (U_32 srcNum=0; srcNum < numSrcs; ++srcNum) {
Opnd *srcOpnd = i->getSrc(srcNum);
Inst *srcInst = srcOpnd->getInst();
scheduleEarly(0, srcInst);
if (Log::isEnabled() ) {
Log::out() << " Recording that "; srcInst->print(Log::out());
Log::out() << " is used by "; i->print(Log::out());
Log::out() << std::endl;
}
UsesMap::iterator it = uses.find(srcInst);
UsesSet* theSet = NULL;
if (it == uses.end()) {
theSet = new (mm) UsesSet(mm);
it = uses.insert(::std::make_pair(srcInst, theSet)).first;
}
theSet = it->second;
theSet->insert(i);
}
}
// now place instruction
earliest[i] = domNode;
if (i->getOperation().canThrow()) {
// as a special case, mark it as being in the normal successor node;
// this will cause dependent instructions to be placed correctly.
Node *peiNode = earliest[i]->getNode();
const Edges &outedges = peiNode->getOutEdges();
typedef Edges::const_iterator EdgeIter;
EdgeIter eLast = outedges.end();
DominatorNode *newDom = 0;
for (EdgeIter eIter = outedges.begin(); eIter != eLast; eIter++) {
Edge *outEdge = *eIter;
Edge::Kind kind = outEdge->getKind();
if (kind != Edge::Kind_Dispatch) {
Node *succBlock = outEdge->getTargetNode();
newDom = dominators.getDominatorNode(succBlock);
break;
}
}
if (newDom) {
earliest[i] = newDom;
}
}
} else {
// not pinned, figure out earliest placement
DominatorNode *currentEarliest = dominators.getDominatorRoot();
DominatorNode *srcInstEarliest = NULL;
U_32 numSrcs = i->getNumSrcOperands();
for (U_32 srcNum=0; srcNum < numSrcs; ++srcNum) {
Opnd *srcOpnd = i->getSrc(srcNum);
Inst *srcInst = srcOpnd->getInst();
scheduleEarly(0, srcInst);
srcInstEarliest = earliest[srcInst];
// Note that both currentEarliest and srcInstEarliest dominate this instruction.
// Thus one of them must dominate the other.
// The dominated one is the earliest place we can put this.
if (currentEarliest->isAncestorOf(srcInstEarliest)) {
// must move currentEarliest down to have srcOpnd available
currentEarliest = srcInstEarliest;
}
if (Log::isEnabled() ) {
Log::out() << " Inst uses "; srcInst->print(Log::out());
Log::out() << ", which has early placement in "; FlowGraph::printLabel(Log::out(), srcInstEarliest);
Log::out() << std::endl;
}
// record the use while we're iterating.
UsesMap::iterator it = uses.find(srcInst);
UsesSet* theSet = NULL;
if (it == uses.end()) {
theSet = new (mm) UsesSet(mm);
it = uses.insert(::std::make_pair(srcInst, theSet)).first;
}
theSet = it->second;
theSet->insert(i);
}
srcInstEarliest = currentEarliest; // now is the latest placement of src insts
// moving above catch inst may cause problems in code emitter
// check that we do not cross catch boundaries
// find earliest intermediate basic block, starting from the block containing i
DominatorNode *instEarliest = domNode;
for (currentEarliest = domNode; ; currentEarliest = currentEarliest->getParent()) {
if(currentEarliest==0){
break;
}
Node *candidateNode = currentEarliest->getNode();
if (Log::isEnabled() ) {
Log::out() << " trying node "; FlowGraph::printLabel(Log::out(), candidateNode);
}
// intermediate basic blocks with catch labels are
// inappropriate to place instructions in
if (candidateNode->isDispatchNode()) {
if (Log::isEnabled() ) {
Log::out() << " ... isDispatchNode"; Log::out() << std::endl;
}
break;
}
LabelInst *first = (LabelInst*)(candidateNode->getFirstInst());
Inst* next=first->getNextInst();
if ((next !=NULL) && (next->getOpcode() == Op_Catch)) {
if (Log::isEnabled() ) {
Log::out() << " ... getOpcode() == Op_Catch"; Log::out() << std::endl;
}
instEarliest=currentEarliest;
break;
}
if (first->isCatchLabel()) {
if (Log::isEnabled() ) {
Log::out() << " ... isCatchLabel"; Log::out() << std::endl;
}
break;
}
if (Log::isEnabled() ) {
Log::out() << " ... OK"; Log::out() << std::endl;
}
instEarliest=currentEarliest;
if (currentEarliest==srcInstEarliest) {
break;
}
} // end for
earliest[i] = instEarliest;
}
if (Log::isEnabled() ) {
Log::out() << "> Done earliest placement of "; i->print(Log::out());
Log::out() << " is in block "; FlowGraph::printLabel(Log::out(), earliest[i]);
Log::out() << std::endl;
}
}
// LATE SCHEDULING
// a domNodeInstWalker, backwards/postorder
class GcmScheduleLateWalker {
GlobalCodeMotion *thePass;
Node *block;
DominatorNode *domNode;
public:
void startNode(DominatorNode *domNode0) {
domNode = domNode0;
block = domNode->getNode();
if (Log::isEnabled() ) {
Log::out() << "Begin late scheduling of block ";
FlowGraph::print(Log::out(), block);
Log::out() << std::endl;
}
};
void applyToInst(Inst *i) { thePass->scheduleLate(domNode, 0, i); };
void finishNode(DominatorNode *domNode) {
Node *block1 = domNode->getNode();
if( !(block == block1) ) assert(0);;
if (Log::isEnabled() ) {
Log::out() << "Done late scheduling of block ";
FlowGraph::print(Log::out(), block);
Log::out() << std::endl;
}
};
GcmScheduleLateWalker(GlobalCodeMotion *thePass0)
: thePass(thePass0), block(0), domNode(0)
{
};
};
void GlobalCodeMotion::scheduleAllLate()
{
GcmScheduleLateWalker scheduleLateWalker(this);
// adapt the DomNodeInstWalker to a forwards DomWalker
typedef DomNodeInst2DomWalker<false, GcmScheduleLateWalker> LateDomInstWalker;
LateDomInstWalker domInstWalker(scheduleLateWalker);
DomTreeWalk<false, LateDomInstWalker>(dominators, domInstWalker, mm);
}
// Note that we are visiting instructions in a block in reverse order.
// It is safe to modify anything below the current instruction.
// as long as no using* instruction precedes this instruction in the same block, we
// are safe in recursively placing use.
// basei, if non-0, is the instruction where we are current iterating, and domNode is
// its node. If i is where we are iterating, then domNode is its node and basei is 0.
void GlobalCodeMotion::scheduleLate(DominatorNode *domNode, Inst *basei, Inst *i)
{
if (i->isLabel()) return;
if (alreadyVisited(i)) return;
if (domNode==NULL) {
domNode = dominators.getDominatorNode(i->getNode());
}
markAsVisited(i);
if (Log::isEnabled() ) {
Log::out() << "< Beginning late scheduling of inst ";
i->print(Log::out());
Log::out() << std::endl;
}
bool pinned = isPinned(i);
// figure out where to put it, first scheduling users along the way
// schedule users
DominatorNode *lca = 0;
UsesMap::iterator it = uses.find(i);
UsesSet* users = NULL;
if (it == uses.end()) {
users = new (mm) UsesSet(mm);
it = uses.insert(::std::make_pair(i, users)).first;
}
users = it->second;
UsesSet::iterator uiter = users->begin();
UsesSet::iterator uend = users->end();
for ( ; uiter != uend; ++uiter) {
Inst *useri = *uiter;
// schedule use
scheduleLate(domNode, basei, useri);
if (Log::isEnabled() ) {
Log::out() << "Inst "; i->print(Log::out());
Log::out() << " is used by inst "; useri->print(Log::out());
Log::out() << " which is in "; FlowGraph::printLabel(Log::out(), latest[useri]);
Log::out() << std::endl;
}
if (pinned) continue;
DominatorNode *usingBlock = latest[useri];
lca = leastCommonAncestor(lca, usingBlock);
while (lca->getNode()->isDispatchNode()) {
lca = lca->getParent(); // code can't be placed in dispatch nodes
}
}
if (pinned) {
// if following instruction is not already scheduled,
// then we are scheduling this pinned instruction as a use of some
// other instruction. Before scheduling it, we must schedule any
// following pinned instruction.
Inst *nextInst = i->getNextInst();
while ((nextInst!=NULL) && !alreadyVisited(nextInst)) {
if (isPinned(nextInst)) {
if (Log::isEnabled() ) {
Log::out() << "Pinned Inst "; i->print(Log::out());
Log::out() << " is followed by unscheduled pinned inst ";
nextInst->print(Log::out());
Log::out() << std::endl;
}
scheduleLate(domNode, basei, nextInst);
// scheduling nextInst should result in scheduling
// any following pinned inst, so break out of loop.
break;
} else {
if (Log::isEnabled() ) {
Log::out() << "Pinned Inst "; i->print(Log::out());
Log::out() << " is followed by unscheduled unpinned inst ";
nextInst->print(Log::out());
Log::out() << std::endl;
}
nextInst = nextInst->getNextInst();
}
}
if (Log::isEnabled() ) {
Log::out() << "Inst is pinned, left in place: "; i->print(Log::out());
Log::out() << std::endl;
}
latest[i] = dominators.getDominatorNode(i->getNode()); // leave it here.
} else if (lca == 0) {
// if LCA==0, then there are no uses; i is dead.
if (Log::isEnabled() ) {
Log::out() << "Inst has no uses, left in place: "; i->print(Log::out());
Log::out() << std::endl;
}
latest[i] = dominators.getDominatorNode(i->getNode()); // leave it here.
} else {
// now LCA is leastCommonAncestor of all uses
if (i->isLdVar()) {
// moving ldVar late is dangerous: can jump over stVar for the same var
if (domNode->isAncestorOf(lca)) {
lca=domNode;
}
}
Node* lcaNode = lca->getNode();
DominatorNode *best = lca;
Node* bestNode = best->getNode();
DominatorNode *earliestBlock = earliest[i];
// code can't be placed in dispatch nodes:
assert(!earliestBlock->getNode()->isDispatchNode());
if (Log::isEnabled() ) {
Log::out() << " LCA is "; FlowGraph::printLabel(Log::out(), lca);
Log::out() << ", best is "; printLabel(Log::out(), best);
Log::out() << " earliestBlock is "; printLabel(Log::out(), earliestBlock);
Log::out() << std::endl;
}
while (lca != earliestBlock) {
lca = lca->getParent(); // go up dom tree
lcaNode = lca->getNode();
assert(lca && lcaNode);
if (lcaNode->isDispatchNode()) {
continue; // code can't be placed in dispatch nodes
}
if (Log::isEnabled() ) {
Log::out() << " LCA is "; printLabel(Log::out(), lca); Log::out() << " with depth " << (int)loopTree->getLoopDepth(lcaNode);
Log::out() << ", best is "; printLabel(Log::out(), best);
Log::out() << " with depth " << (int)loopTree->getLoopDepth(bestNode);
Log::out() << std::endl;
}
if (loopTree->getLoopDepth(lcaNode) < loopTree->getLoopDepth(bestNode)) {
// find deepest block at shallowest nest
best = lca;
bestNode = lcaNode;
if (Log::isEnabled() ) {
Log::out() << " LCA replaces best" << std::endl;
}
}
};
if (Log::isEnabled() ) {
Log::out() << " Finally, best is "; printLabel(Log::out(), best);
Log::out() << std::endl;
}
latest[i] = best;
}
if (Log::isEnabled() ) {
Log::out() << " Placing inst "; i->print(Log::out());
Log::out() << " in block "; printLabel(Log::out(), latest[i]);
Log::out() << std::endl;
}
// now, to actually move the instruction:
// we always move instructions at the start of the block.
// this looks confusing if we are inserting into the same block
// we are iterating over: we may see the instruction again, but
// this is safe since the instruction is already marked as placed.
// we do this even for pinned instructions; they will be visited in
// reverse order, so they will be replaced in the block starting at
// the top, so we are ok.
Node *node = latest[i]->getNode();
Inst* headInst = (Inst*)node->getFirstInst();
assert(headInst->isLabel());
i->unlink();
if (i->getOperation().mustEndBlock()) {
// but an instruction which must be at the end must stay there.
// this includes branches.
if (Log::isEnabled()) {
Log::out() << "> Placing inst before headinst ";
headInst->print(Log::out());
Log::out() << std::endl;
}
node->appendInst(i);
} else {
if (Log::isEnabled()) {
Log::out() << "> Placing inst after headinst ";
headInst->print(Log::out());
Log::out() << std::endl;
}
node->prependInst(i);
}
}
DominatorNode *GlobalCodeMotion::leastCommonAncestor(DominatorNode *a, DominatorNode *b)
{
if (a == 0) return b;
assert(b != 0);
while (a != b) {
if (dominators.isAncestor(a, b)) {
b = a;
} else if (dominators.isAncestor(b, a)) {
a = b;
} else {
a = a->getParent();
b = b->getParent();
}
}
return a;
}
// a NodeInstWalker, forwards/preorder
class GcmSinkConstantsWalker {
GlobalCodeMotion *thePass;
Node *block;
public:
void startNode(Node *cfgNode0) {
block = cfgNode0;
if (Log::isEnabled()) {
Log::out() << "Begin sinking constants in block";
FlowGraph::print(Log::out(), block);
Log::out() << std::endl;
}
};
void applyToInst(Inst *i) { thePass->sinkConstants(i); };
void finishNode(Node *cfgNode0) {
if (Log::isEnabled() ) {
Log::out() << "Done sinking constants in block";
FlowGraph::print(Log::out(), block);
Log::out() << std::endl;
}
};
GcmSinkConstantsWalker(GlobalCodeMotion *thePass0)
: thePass(thePass0), block(0)
{
};
};
void GlobalCodeMotion::sinkAllConstants()
{
GcmSinkConstantsWalker gcmSinkConstantsWalker(this);
// adapt the NodeInstWalker to a NodeWalker
typedef NodeInst2NodeWalker<true, GcmSinkConstantsWalker>
SinkConstantsNodeWalker;
SinkConstantsNodeWalker sinkConstantsNodeWalker(gcmSinkConstantsWalker);
// do the walk, postorder
NodeWalk<SinkConstantsNodeWalker>(fg, sinkConstantsNodeWalker);
}
void GlobalCodeMotion::sinkConstants(Inst *inst)
{
for (U_32 i = 0; i < inst->getNumSrcOperands(); i++) {
Opnd *opnd = inst->getSrc(i);
Inst *opndInst = opnd->getInst();
if (opndInst->isConst()) {
ConstInst* cinst = opndInst->asConstInst();
ConstInst::ConstValue cv = cinst->getValue();
InstFactory &ifactory = irManager.getInstFactory();
OpndManager &opndManager = irManager.getOpndManager();
Opnd *newOp = opndManager.createSsaTmpOpnd(opnd->getType());
Inst *newInst = ifactory.makeLdConst(newOp, cv);
newInst->insertBefore(inst);
}
}
}
// MISC STUFF
bool GlobalCodeMotion::isPinned(Inst *i)
{
Opcode opcode = i->getOpcode();
// be explicit about SSA ops
// if ((opcode == Op_LdVar) || (opcode == Op_StVar) || (opcode == Op_Phi))
if ((opcode == Op_StVar) || (opcode == Op_Phi))
return true;
if (i->getOperation().isMovable()) {
return false;
}
const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags();
if (0 && optimizerFlags.cse_final) {
switch (i->getOpcode()) {
case Op_TauLdInd:
{
Inst *srcInst = i->getSrc(0)->getInst();
if ((srcInst->getOpcode() == Op_LdFieldAddr) ||
(srcInst->getOpcode() == Op_LdStaticAddr)) {
FieldAccessInst *faInst = srcInst->asFieldAccessInst();
FieldDesc *fd = faInst->getFieldDesc();
if (fd->isInitOnly()) {
return false;
}
}
}
break;
case Op_LdStatic:
{
FieldAccessInst *inst = i->asFieldAccessInst();
assert(inst);
FieldDesc* fd = inst->getFieldDesc();
if (fd->isInitOnly())
return false;
}
break;
case Op_TauLdField:
{
FieldAccessInst *inst = i->asFieldAccessInst();
assert(inst);
FieldDesc* fd = inst->getFieldDesc();
if (fd->isInitOnly())
return false;
}
break;
default:
break;
};
}
return true;
}
void GlobalCodeMotion::markAsVisited(Inst *i)
{
visited.insert(i);
}
bool GlobalCodeMotion::alreadyVisited(Inst *i)
{
VisitedSet::const_iterator it = visited.find(i);
return (it != visited.end());
}
void GlobalCodeMotion::clearVisited()
{
visited.clear();
}
} //namespace Jitrino