blob: cff6f9e276e996e6d128559c7d81b83c68559405 [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.
*/
#include "insertpi.h"
#include "walkers.h"
#include "abcdbounds.h"
#include "constantfolder.h"
namespace Jitrino {
static ComparisonModifier
negateComparison(ComparisonModifier mod)
{
switch (mod) {
case Cmp_GT: return Cmp_GTE;
case Cmp_GT_Un: return Cmp_GTE_Un;
case Cmp_GTE: return Cmp_GT;
case Cmp_GTE_Un: return Cmp_GT_Un;
case Cmp_EQ: return Cmp_EQ;
case Cmp_NE_Un: return Cmp_NE_Un;
default:
assert(0); return mod;
}
}
static const char *
printableComparison(ComparisonModifier mod)
{
switch (mod) {
case Cmp_GT: return "Cmp_GT";
case Cmp_GT_Un: return "Cmp_GT_Un";
case Cmp_GTE: return "Cmp_GTE";
case Cmp_GTE_Un: return "Cmp_GTE_Un";
case Cmp_EQ: return "Cmp_EQ";
case Cmp_NE_Un: return "Cmp_NE_Un";
default:
assert(0); return "";
}
}
static Type::Tag
unsignType(Type::Tag typetag)
{
switch (typetag) {
case Type::IntPtr: return Type::UIntPtr;
case Type::Int8: return Type::UInt8;
case Type::Int16: return Type::UInt16;
case Type::Int32: return Type::UInt32;
case Type::Int64: return Type::UInt64;
default:
assert(0); return typetag;
}
}
// a DomWalker, to be applied in pre-order
class InsertPiWalker {
public:
InsertPiWalker(InsertPi* insert_pi) : _insertPi(insert_pi) {};
void applyToDominatorNode(DominatorNode *domNode)
{
_insertPi->insertPiToNode(domNode->getNode());
}
// is called before a node and its children are processed
void enterScope() {};
// is called after node and children are processed
void exitScope() {};
private:
InsertPi* _insertPi;
};
//------------------------------------------------------------------------------
// Add a Pi node in the node if it is after each test
// which tells something about a variable
//
// WARNING: Pi var live ranges may overlap the original var live ranges
// since we don't bother to add Phi nodes and rename subsequent uses of var.
void InsertPi::insertPi()
{
InsertPiWalker insert_pi_walker(this);
// dom-pre-order traversal
DomTreeWalk<true, InsertPiWalker>(_domTree, insert_pi_walker, _mm);
renamePiVariables();
if (Log::isEnabled()) {
Log::out() << "IR after Pi insertion" << std::endl;
FlowGraph::printHIR(Log::out(), _irManager.getFlowGraph(),
_irManager.getMethodDesc());
FlowGraph::printDotFile(_irManager.getFlowGraph(),
_irManager.getMethodDesc(), "withpi");
}
}
//------------------------------------------------------------------------------
// add Pi in the node iff after a test which tells something about the var
void InsertPi::insertPiToNode(Node* block)
{
Edge *dom_edge = 0;
// see if there is a predecessor block idom such that
// (1) idom dominates this one
// (2) this block dominates all other predecessors
// (3) idom has multiple out-edges
// (4) idom has only 1 edge to this node
// (1a) if a predecessor dominates it must be idom
Node *idom = _domTree.getIdom(block);
// (3) must exist and have multiple out-edges
if ((idom == NULL) || (idom->hasOnlyOneSuccEdge())) {
return;
}
if (Log::isEnabled()) {
Log::out() << "Checking block " << (int)block->getId() << " with idom "
<< (int) idom->getId() << std::endl;
}
if (block->hasOnlyOnePredEdge()) {
// must be from idom -- (1b)
// satisfies (2) trivially
dom_edge = *(block->getInEdges().begin());
} else {
// check (1b) and (2)
const Edges &inedges = block->getInEdges();
typedef Edges::const_iterator EdgeIter;
EdgeIter e_last = inedges.end();
for (EdgeIter e_iter = inedges.begin(); e_iter != e_last; e_iter++) {
Edge *in_edge = *e_iter;
Node *pred_block = in_edge->getSourceNode();
if (pred_block == idom) {
// (1b) found idom
if (dom_edge) {
// failed (4): idom found on more than one incoming edge
return;
}
dom_edge = in_edge;
} else if (! _domTree.dominates(block, pred_block)) {
// failed (2)
return;
}
}
}
if (dom_edge) {
Edge *in_edge = dom_edge;
Node *pred_block = idom;
if (Log::isEnabled()) {
Log::out() << "Checking branch for " << (int)block->getId()
<< " with idom "
<< (int) idom->getId() << std::endl;
}
if (!pred_block->hasOnlyOneSuccEdge()) {
Edge::Kind kind = in_edge->getKind();
switch (kind) {
case Edge::Kind_True:
case Edge::Kind_False:
{
Inst* branchi1 = (Inst*)pred_block->getLastInst();
assert(branchi1 != NULL);
BranchInst* branchi = branchi1->asBranchInst();
if (branchi && branchi->isConditionalBranch()) {
insertPiForBranch(block, branchi, kind);
} else {
return;
}
}
break;
case Edge::Kind_Dispatch:
return;
case Edge::Kind_Unconditional:
// Previous block must have a PEI
// since it had multiple out-edges.
// This is the unexceptional condition.
{
Inst* lasti = (Inst*)pred_block->getLastInst();
assert(lasti != NULL);
insertPiForUnexceptionalPEI(block, lasti);
}
// We could look for a bounds check in predecessor.
// But: since now all useful PEIs have explicit results,
// they imply a Pi-like action.
break;
case Edge::Kind_Catch:
break;
default:
break;
}
}
}
}
//------------------------------------------------------------------------------
void InsertPi::insertPiForUnexceptionalPEI(Node *block, Inst *lasti)
{
switch (lasti->getOpcode()) {
case Op_TauCheckBounds:
{
// the number of newarray elements must be >= 0.
assert(lasti->getNumSrcOperands() == 2);
Opnd *idxOp = lasti->getSrc(1);
Opnd *boundsOp = lasti->getSrc(0);
if (Log::isEnabled()) {
Log::out() << "Adding info about CheckBounds instruction ";
lasti->print(Log::out());
Log::out() << std::endl;
}
Type::Tag typetag = idxOp->getType()->tag;
PiBound lb(typetag, int64(0));
PiBound ub(typetag, 1, VarBound(boundsOp),int64(-1));
PiCondition bounds0(lb, ub);
Opnd *tauOpnd = lasti->getDst(); // use the checkbounds tau
insertPiForOpndAndAliases(block, idxOp, bounds0, tauOpnd);
PiBound idxBound(typetag, 1, VarBound(idxOp), int64(1));
PiCondition bounds1(idxBound, PiBound(typetag, false));
insertPiForOpndAndAliases(block, boundsOp, bounds1, tauOpnd);
}
break;
case Op_NewArray:
{
// the number of newarray elements must be in [0, MAXINT32]
assert(lasti->getNumSrcOperands() == 1);
Opnd *numElemOpnd = lasti->getSrc(0);
if (Log::isEnabled()) {
Log::out() << "Adding info about NewArray instruction ";
lasti->print(Log::out());
Log::out() << std::endl;
}
Opnd *tauOpnd = getBlockTauEdge(block); // need to use a TauEdge
PiCondition bounds0(PiBound(numElemOpnd->getType()->tag,
int64(0)),
PiBound(numElemOpnd->getType()->tag,
int64(0x7fffffff)));
insertPiForOpndAndAliases(block, numElemOpnd, bounds0, tauOpnd);
}
break;
case Op_NewMultiArray:
{
// the number of newarray dimensions must be >= 1.
U_32 numOpnds = lasti->getNumSrcOperands();
assert(numOpnds >= 1);
StlSet<Opnd *> done(_mm);
if (Log::isEnabled()) {
Log::out() << "Adding info about NewMultiArray instruction ";
lasti->print(Log::out());
Log::out() << std::endl;
}
Opnd *tauOpnd = 0;
// the number of newarray elements must be in [0, MAXINT32]
for (U_32 opndNum = 0; opndNum < numOpnds; opndNum++) {
Opnd *thisOpnd = lasti->getSrc(opndNum);
if (!done.has(thisOpnd)) {
done.insert(thisOpnd);
PiCondition bounds0(PiBound(thisOpnd->getType()->tag,
int64(0)),
PiBound(thisOpnd->getType()->tag,
int64(0x7fffffff)));
if ( !tauOpnd ) {
tauOpnd = getBlockTauEdge(block); // must use a tauEdge
}
insertPiForOpndAndAliases(block, thisOpnd, bounds0, tauOpnd);
}
}
}
break;
default:
break;
}
}
//------------------------------------------------------------------------------
SsaTmpOpnd* InsertPi::getBlockTauEdge(Node *block) {
if ((_lastTauEdgeBlock == block) && _blockTauEdge) return _blockTauEdge;
Inst *firstInst = (Inst*)block->getFirstInst();
Inst *inst = firstInst->getNextInst();
for (; inst != NULL; inst = inst->getNextInst()) {
if (inst->getOpcode() == Op_TauEdge) {
_blockTauEdge = inst->getDst()->asSsaTmpOpnd();
assert(_blockTauEdge);
_lastTauEdgeBlock = block;
return _blockTauEdge;
}
}
for (inst = firstInst->getNextInst(); inst != NULL; inst = inst->getNextInst()) {
if ((inst->getOpcode() != Op_Phi) && (inst->getOpcode() != Op_TauPoint)) {
break; // insert before inst.
}
}
// no non-phis, insert before inst;
TypeManager &tm = _irManager.getTypeManager();
SsaTmpOpnd *tauOpnd = _irManager.getOpndManager().createSsaTmpOpnd(tm.getTauType());
Inst* tauEdge = _irManager.getInstFactory().makeTauEdge(tauOpnd);
if(Log::isEnabled()) {
Log::out() << "Inserting tauEdge inst ";
tauEdge->print(Log::out());
if (inst!=NULL) {
Log::out() << " before inst ";
inst->print(Log::out());
}
Log::out() << std::endl;
}
if (inst != NULL) {
tauEdge->insertBefore(inst);
} else {
block->appendInst(tauEdge);
}
_blockTauEdge = tauOpnd;
_lastTauEdgeBlock = block;
return tauOpnd;
}
//------------------------------------------------------------------------------
// Insert Pi Nodes for any variables occurring in the branch test
//
// Since we're examining the test anyway, let's figure out the conditions
// here, too, so we don't have to duplicate any code. Note that this
// condition may already be in terms of Pi variables from the predecessor
// block, since
// -- predecessor dominates this block
// -- we are traversing blocks in a dominator-tree preorder
// so we must have already visited the predecessor.
//
// We also must add the new Pi variable to our map.
//
void InsertPi::insertPiForBranch(Node* block,
BranchInst* branchi,
Edge::Kind kind) // True or False only
{
Type::Tag instTypeTag = branchi->getType();
if (!Type::isInteger(instTypeTag))
return;
ComparisonModifier mod = branchi->getComparisonModifier();
if (branchi->getNumSrcOperands() == 1) {
Opnd *op0 = branchi->getSrc(0);
PiCondition zeroBounds(PiBound(instTypeTag, (int64)0),
PiBound(instTypeTag, (int64)0));
switch (mod) {
case Cmp_Zero:
insertPiForComparison(block,
Cmp_EQ,
zeroBounds,
op0,
false,
// negate if false edge
(kind == Edge::Kind_False));
break;
case Cmp_NonZero:
insertPiForComparison(block,
Cmp_EQ, // use EQ
zeroBounds,
op0,
false,
// but negate if true edge
(kind == Edge::Kind_True));
break;
default:
break;
}
} else {
Opnd *op0 = branchi->getSrc(0);
Opnd *op1 = branchi->getSrc(1);
assert(branchi->getNumSrcOperands() == 2);
PiCondition bounds0(op0->getType()->tag, op0);
PiCondition bounds1(op1->getType()->tag, op1);
if (!bounds0.isUnknown()) {
insertPiForComparison(block,
mod,
bounds0,
op1,
false,
// negate for false edge
(kind == Edge::Kind_False));
}
if (!bounds1.isUnknown()) {
insertPiForComparison(block,
mod,
bounds1,
op0,
true,
// negate for false edge
(kind == Edge::Kind_False));
}
}
}
//------------------------------------------------------------------------------
void InsertPi::insertPiForComparison(Node* block,
ComparisonModifier mod,
const PiCondition &bounds,
Opnd* op,
bool swap_operands,
bool negate_comparison)
{
if (Log::isEnabled()) {
Log::out() << "insertPiForComparison(..., ";
Log::out() << printableComparison(mod);
Log::out() << ", ";
bounds.print(Log::out());
Log::out() << ", ";
op->print(Log::out());
Log::out() << ", ";
Log::out() << (swap_operands ? "true" : "false");
Log::out() << ", ";
Log::out() << (negate_comparison ? "true" : "false");
Log::out() << ")" << std::endl;
// Print last inst from all prev blocks.
Edges::const_iterator it = block->getInEdges().begin(),
end = block->getInEdges().end();
for(; it != end; ++it) {
Edge* edge = (*it);
Log::out() << "pred inst---> ";
((Inst*)edge->getSourceNode()->getLastInst())->print(Log::out());
Log::out() << std::endl;
}
}
PiCondition bounds0 = bounds;
// add a Pi node for immediate value.
if (negate_comparison) {
mod = negateComparison(mod);
swap_operands = !swap_operands;
if (Log::isEnabled()) {
Log::out() << "insertPiForComparison: negating comparison to " ;
Log::out() << printableComparison(mod);
Log::out() << std::endl;
}
}
switch (mod) {
case Cmp_EQ:
if (!negate_comparison)
insertPiForOpndAndAliases(block, op, bounds0, NULL);
else {
if (Log::isEnabled()) {
Log::out() << "insertPiForComparison: cannot represent ! Cmp_EQ" << std::endl;
}
}
// we can't represent the other case
break;
case Cmp_NE_Un:
if (negate_comparison)
insertPiForOpndAndAliases(block, op, bounds0, NULL);
else {
if (Log::isEnabled()) {
Log::out() << "insertPiForComparison: cannot represent Cmp_NE_Un" << std::endl;
}
}
// we can't represent the other case
break;
case Cmp_GT_Un:
if (swap_operands) { // op > bounds, only a lower bound on op
Type::Tag optag = op->getType()->tag;
if (!Type::isUnsignedInteger(optag)) {
// 1 is a lower bound on int op
PiCondition oneBounds(PiBound(optag, (int64)1),
PiBound(optag, (int64)1));
PiCondition oneLowerBound(oneBounds.only_lower_bound());
insertPiForOpndAndAliases(block, op, oneLowerBound, NULL);
} else {
// we can be more precise for an unsigned op
bounds0 = bounds0.cast(unsignType(bounds0.getType()));
PiCondition bounds1a(bounds0.only_lower_bound());
PiCondition bounds1(bounds1a.add((int64)1));
if (! bounds1.getLb().isUnknown())
insertPiForOpndAndAliases(block, op, bounds1, NULL);
else {
if (Log::isEnabled()) {
Log::out() << "insertPiForComparison(1): bounds1 LB is Unknown;\n\tbounds is ";
bounds.print(Log::out());
Log::out() << "\n\tbounds0 is ";
bounds0.print(Log::out());
Log::out() << "\n\tbounds1a is ";
bounds1a.print(Log::out());
Log::out() << "\n\tbounds1 is ";
bounds1.print(Log::out());
Log::out() << std::endl;
}
}
}
} else { // bounds > op, only an upper bound on op
Type::Tag optag = op->getType()->tag;
if (Type::isUnsignedInteger(optag)) {
// for an unsigned upper bound, we're ok
bounds0 = bounds0.cast(unsignType(bounds0.getType()));
PiCondition bounds1(bounds0.only_upper_bound().add((int64)-1));
if (! bounds1.getUb().isUnknown())
insertPiForOpndAndAliases(block, op, bounds1, NULL);
else {
if (Log::isEnabled()) {
Log::out() << "insertPiForComparison(2): bounds1 LB is Unknown;\n\tbounds is ";
bounds.print(Log::out());
Log::out() << "\n\tbounds0 is ";
bounds0.print(Log::out());
Log::out() << "\n\tbounds1 is ";
bounds1.print(Log::out());
Log::out() << std::endl;
}
}
} else {
// otherwise, we know nothing unless bound is a small constant
PiCondition bounds1(bounds0.only_upper_bound().add((int64)-1));
if (bounds0.getUb().isConstant()) {
int64 ubConst = bounds1.getUb().getConst();
if (((optag == Type::Int32) &&
((ubConst&0xffffffff) <= 0x7ffffff) &&
((ubConst&0xffffffff) >= 0)) ||
((optag == Type::Int64) &&
((ubConst <= 0x7ffffff) &&
(ubConst >= 0)))) {
insertPiForOpndAndAliases(block, op, bounds1, NULL);
} else {
if (Log::isEnabled()) {
Log::out() << "insertPiForComparison(2): bounds1 LB is Unknown;\n\tbounds is ";
bounds.print(Log::out());
Log::out() << "\n\tbounds0 is ";
bounds0.print(Log::out());
Log::out() << "\n\tbounds1 is ";
bounds1.print(Log::out());
Log::out() << std::endl;
}
}
}
}
}
break;
case Cmp_GT:
if (swap_operands) { // op > bounds, only a lower bound on op
PiCondition bounds1a(bounds0.only_lower_bound());
PiCondition bounds1(bounds1a.add((int64)1));
if (! bounds1.getLb().isUnknown())
insertPiForOpndAndAliases(block, op, bounds1, NULL);
else {
if (Log::isEnabled()) {
Log::out() << "insertPiForComparison(1): bounds1 LB is Unknown;\n\tbounds is ";
bounds.print(Log::out());
Log::out() << "\n\tbounds0 is ";
bounds0.print(Log::out());
Log::out() << "\n\tbounds1a is ";
bounds1a.print(Log::out());
Log::out() << "\n\tbounds1 is ";
bounds1.print(Log::out());
Log::out() << std::endl;
}
}
} else { // bounds > op, only an upper bound on op
PiCondition bounds1(bounds0.only_upper_bound().add((int64)-1));
if (! bounds1.getUb().isUnknown())
insertPiForOpndAndAliases(block, op, bounds1, NULL);
else {
if (Log::isEnabled()) {
Log::out() << "insertPiForComparison(2): bounds1 LB is Unknown;\n\tbounds is ";
bounds.print(Log::out());
Log::out() << "\n\tbounds0 is ";
bounds0.print(Log::out());
Log::out() << "\n\tbounds1 is ";
bounds1.print(Log::out());
Log::out() << std::endl;
}
}
}
break;
case Cmp_GTE_Un:
if (swap_operands) { // op >= bounds, only lower bound on op
Type::Tag optag = op->getType()->tag;
if (!Type::isUnsignedInteger(optag)) {
// 0 is a lower bound on an int op
PiCondition zeroBounds(PiBound(optag, (int64)0),
PiBound(optag, (int64)0));
PiCondition zeroLowerBound(zeroBounds.only_lower_bound());
insertPiForOpndAndAliases(block, op, zeroLowerBound, NULL);
} else {
// we can be more precise for an unsigned op lb
bounds0 = bounds0.cast(unsignType(bounds0.getType()));
if (! bounds0.getLb().isUnknown()) {
insertPiForOpndAndAliases(block, op,
bounds0.only_lower_bound(), NULL);
} else {
if (Log::isEnabled()) {
Log::out() << "insertPiForComparison(3): bounds0 LB is Unknown;\n\tbounds is ";
bounds.print(Log::out());
Log::out() << "\n\tbounds0 is ";
bounds0.print(Log::out());
Log::out() << std::endl;
}
}
}
} else { // bounds >= op, only upper bound on op
Type::Tag optag = op->getType()->tag;
if (Type::isUnsignedInteger(optag)) {
// unsigned ub on unsigned op
bounds0 = bounds0.cast(unsignType(bounds0.getType()));
if (! bounds0.getUb().isUnknown())
insertPiForOpndAndAliases(block, op,
bounds0.only_upper_bound(), NULL);
else {
if (Log::isEnabled()) {
Log::out() << "insertPiForComparison(4): bounds0 UB is Unknown;\n\tbounds is ";
bounds.print(Log::out());
Log::out() << "\n\tbounds0 is ";
bounds0.print(Log::out());
Log::out() << std::endl;
}
}
} else {
// otherwise, we know nothing unless bound is a small constant
if (bounds0.getUb().isConstant()) {
int64 ubConst = bounds0.getUb().getConst();
if (((optag == Type::Int32) &&
((ubConst&0xffffffff) <= 0x7ffffff) &&
((ubConst&0xffffffff) >= 0)) ||
((optag == Type::Int64) &&
((ubConst <= 0x7ffffff) &&
(ubConst >= 0)))) {
insertPiForOpndAndAliases(block, op, bounds0, NULL);
} else {
if (Log::isEnabled()) {
Log::out() << "insertPiForComparison(2): bounds0 LB is Unknown;\n\tbounds is ";
bounds.print(Log::out());
Log::out() << "\n\tbounds0 is ";
bounds0.print(Log::out());
Log::out() << std::endl;
}
}
}
}
}
break;
case Cmp_GTE:
if (swap_operands) { // op >= bounds, only lower bound on op
if (! bounds0.getLb().isUnknown()) {
insertPiForOpndAndAliases(block, op,
bounds0.only_lower_bound(), NULL);
} else {
if (Log::isEnabled()) {
Log::out() << "insertPiForComparison(3): bounds0 LB is Unknown;\n\tbounds is ";
bounds.print(Log::out());
Log::out() << "\n\tbounds0 is ";
bounds0.print(Log::out());
Log::out() << std::endl;
}
}
} else { // bounds >= op, only upper bound on op
if (! bounds0.getUb().isUnknown())
insertPiForOpndAndAliases(block, op,
bounds0.only_upper_bound(), NULL);
else {
if (Log::isEnabled()) {
Log::out() << "insertPiForComparison(4): bounds0 UB is Unknown;\n\tbounds is ";
bounds.print(Log::out());
Log::out() << "\n\tbounds0 is ";
bounds0.print(Log::out());
Log::out() << std::endl;
}
}
}
break;
case Cmp_Zero:
case Cmp_NonZero:
case Cmp_Mask:
assert(0);
break;
default:
assert(false);
break;
}
}
//------------------------------------------------------------------------------
void InsertPi::insertPiForOpnd(Node *block,
Opnd *org,
const PiCondition &cond,
Opnd *tauOpnd)
{
if (ConstantFolder::isConstant(org)) {
if (Log::isEnabled()) {
Log::out() << "Skipping Pi Node for opnd ";
org->print(Log::out());
Log::out() << " under condition ";
cond.print(Log::out());
Log::out() << " since it is constant" << std::endl;
}
} else {
PiOpnd *piOpnd = _irManager.getOpndManager().createPiOpnd(org);
Inst *headInst = (Inst*)block->getFirstInst();
PiCondition *condPtr = new (_irManager.getMemoryManager()) PiCondition(cond);
if (tauOpnd == 0)
tauOpnd = getBlockTauEdge(block);
Inst *newInst = _irManager.getInstFactory().makeTauPi(piOpnd, org, tauOpnd, condPtr);
Inst *place = headInst->getNextInst();
while (place != NULL) {
Opcode opc = place->getOpcode();
if ((opc != Op_Phi) && (opc != Op_TauPoint) && (opc != Op_TauEdge))
break;
place = place->getNextInst();
}
if (Log::isEnabled()) {
Log::out() << "Inserting Pi Node for opnd ";
org->print(Log::out());
Log::out() << " under condition ";
cond.print(Log::out());
if (place!=NULL) {
Log::out() << " just before inst ";
place->print(Log::out());
}
Log::out() << std::endl;
}
if (place != NULL) {
newInst->insertBefore(place);
} else {
block->appendInst(newInst);
}
}
}
//------------------------------------------------------------------------------
// dereferencing through Pis, 0 if not constant.
Opnd* InsertPi::getConstantOpnd(Opnd *opnd)
{
return ConstantFolder::isConstant(opnd) ? opnd : NULL;
}
//------------------------------------------------------------------------------
bool InsertPi::getAliases(Opnd *opnd, AbcdAliases *aliases, int64 addend)
{
Inst *inst = opnd->getInst();
switch (inst->getOpcode()) {
case Op_TauPi:
return getAliases(inst->getSrc(0), aliases, addend);
case Op_Add:
{
Opnd *op0 = inst->getSrc(0);
Opnd *op1 = inst->getSrc(1);
Opnd *constOpnd0 = getConstantOpnd(op0);
Opnd *constOpnd1 = getConstantOpnd(op1);
if ((constOpnd0 || constOpnd1) &&
(inst->getType() == Type::Int32)) {
// I assume we've done folding first
assert(!(constOpnd0 && constOpnd1));
if (constOpnd1) {
// swap the operands;
constOpnd0 = constOpnd1;
op1 = op0;
}
// now constOpnd0 should be constant
// op1 is the non-constant operand
Inst *inst0 = constOpnd0->getInst();
assert(inst0);
ConstInst *cinst0 = inst0->asConstInst();
assert(cinst0);
ConstInst::ConstValue cv = cinst0->getValue();
I_32 c = cv.i4;
int64 sumc = c + addend;
if (add_overflowed<int64>(sumc, c, addend)) {
return false;
} else {
VarBound vb(op1);
aliases->theSet.insert(PiBound(inst->getType(), 1, vb, sumc));
getAliases(op1, aliases, sumc);
return true;
}
}
}
break;
case Op_Sub:
{
Opnd *constOpnd = getConstantOpnd(inst->getSrc(1));
if (constOpnd && (inst->getType() == Type::Int32)) {
Opnd *op1 = constOpnd;
Inst *inst1 = op1->getInst();
assert(inst1);
ConstInst *cinst1 = inst1->asConstInst();
assert(cinst1);
ConstInst::ConstValue cv = cinst1->getValue();
int64 c = cv.i4;
int64 negc = -c;
int64 subres = addend + negc;
if (neg_overflowed<int64>(negc, c) ||
add_overflowed<int64>(subres, addend, negc)) {
return false;
} else {
VarBound vb(op1);
aliases->theSet.insert(PiBound(inst->getType(), 1, vb, subres));
getAliases(op1, aliases, subres);
return true;
}
}
}
break;
case Op_Copy:
assert(0); // do copy propagation first
break;
case Op_TauCheckZero:
return false;
default:
break;
}
return false;
}
//------------------------------------------------------------------------------
// checks for aliases of opnd, inserts them.
void InsertPi::insertPiForOpndAndAliases(Node *block,
Opnd *org,
const PiCondition &cond,
Opnd *tauOpnd)
{
const PiBound &lb = cond.getLb();
const PiBound &ub = cond.getUb();
if (_useAliases) {
if (Log::isEnabled()) {
Log::out() << "Inserting Pi Node for opnd ";
org->print(Log::out());
Log::out() << " and its aliases";
Log::out() << " under condition ";
cond.print(Log::out());
Log::out() << std::endl;
}
AbcdAliases aliases(_mm);
// check for aliases
insertPiForOpnd(block, org, cond, tauOpnd);
if (getAliases(org, &aliases, 0)) {
if (Log::isEnabled()) {
Log::out() << "Has aliases ";
AbcdAliasesSet::iterator iter = aliases.theSet.begin();
AbcdAliasesSet::iterator end = aliases.theSet.end();
for ( ; iter != end; iter++) {
PiBound alias = *iter;
alias.print(Log::out());
Log::out() << " ";
}
Log::out() << std::endl;
}
AbcdAliasesSet::iterator iter = aliases.theSet.begin();
AbcdAliasesSet::iterator end = aliases.theSet.end();
for ( ; iter != end; iter++) {
PiBound alias = *iter;
PiBound inverted = alias.invert(org); // org - c
// plug-in lb and ub into inverted, yields bounds:
// [ lb - c, ub - c ]
PiCondition renamedCondition(PiBound(inverted, org, lb),
PiBound(inverted, org, ub));
insertPiForOpnd(block, alias.getVar().the_var,
renamedCondition, tauOpnd);
}
}
} else {
insertPiForOpnd(block, org, cond, tauOpnd);
}
}
//------------------------------------------------------------------------------
// a DomWalker, to be applied forwards/preorder
class RenamePiWalker {
public:
RenamePiWalker(InsertPi *insert_pi,
MemoryManager &localMM,
SparseOpndMap* &piMap0,
int sizeEstimate0) :
_insertPi(insert_pi),
localMemManager(localMM),
_piMap(piMap0),
sizeEstimate(sizeEstimate0)
{}
void applyToDominatorNode(DominatorNode *domNode)
{
_insertPi->renamePiVariablesInNode(domNode->getNode());
}
void enterScope()
{
if (!_piMap) _piMap =
new (localMemManager) SparseOpndMap(sizeEstimate,
localMemManager, 1, 4, 7);
_piMap->enter_scope();
}
void exitScope()
{
_piMap->exit_scope();
}
private:
InsertPi* _insertPi;
MemoryManager &localMemManager;
SparseOpndMap* &_piMap;
int sizeEstimate;
};
//------------------------------------------------------------------------------
void InsertPi::renamePiVariables()
{
MethodDesc &methodDesc= _irManager.getMethodDesc();
U_32 byteCodeSize = methodDesc.getByteCodeSize();
MemoryManager localMemManager("Abcd::renamePiNodes");
RenamePiWalker theWalker(this, localMemManager, _piMap, byteCodeSize);
DomTreeWalk<true, RenamePiWalker>(_domTree, theWalker, localMemManager);
}
//------------------------------------------------------------------------------
void InsertPi::renamePiVariablesInNode(Node *block)
{
// For each variable use in the block, check for a Pi version in
// the piTable. Since we are visiting in preorder over dominator
// tree dominator order, any found version will dominate this node.
// Phase 0: remap just Pi inst source operands.
Inst* headInst = (Inst*)block->getFirstInst();
for (Inst* inst = headInst->getNextInst(); inst != NULL; inst = inst->getNextInst()) {
if (inst->getOpcode() == Op_TauPi) {
// Replace Pi source operands with renames from the map.
Opnd *dstOpnd = inst->getDst();
assert(dstOpnd->isPiOpnd());
Opnd *srcOpnd = inst->getSrc(0);
if (_useAliases) {
if (srcOpnd->isSsaVarOpnd()) {
srcOpnd = srcOpnd->asSsaVarOpnd()->getVar();
}
}
// Find the end of the operand replace chain.
// The most constrained operand is being used, the more
// opportunities we have for optimization.
Opnd *replaceOpnd = _piMap->lookupTillEnd(srcOpnd);
if (replaceOpnd) {
// Disallow remapping source operand of Pi Nodes to their
// destination operands.
if (Log::isEnabled()) {
Log::out() << "remapping src in Pi: ";
inst->print(Log::out());
Log::out() << ", replaceOpnd: ";
replaceOpnd->print(Log::out());
}
if (dstOpnd->getId() != replaceOpnd->getId()) {
inst->setSrc(0, replaceOpnd);
srcOpnd = replaceOpnd;
if (Log::isEnabled()) {
Log::out() << "... done" << std::endl;
}
} else {
if (Log::isEnabled()) {
Log::out() << "... defines this opnd, cannot remap" << std::endl;
}
}
}
// We now replaced the source. Add any Pi node destination to the map.
_piMap->insert(srcOpnd, dstOpnd);
if (Log::isEnabled()) {
Log::out() << "adding remap for Pi of ";
srcOpnd->print(Log::out());
Log::out() << " to ";
inst->getDst()->print(Log::out());
Log::out() << std::endl;
}
}
}
// Phase 1: add Pi remappings, remap source operands of other instructions
// and pi conditions.
for (Inst* inst = headInst->getNextInst(); inst != NULL; inst = inst->getNextInst()) {
// Remap source operands if they match a Pi definition.
U_32 numOpnds = inst->getNumSrcOperands();
for (U_32 i=0; i<numOpnds; i++) {
Opnd *opnd = inst->getSrc(i);
while (opnd->isPiOpnd()) {
opnd = opnd->asPiOpnd()->getOrg();
}
// Transitively look up for deepest Pi renamings of this operand.
// The most constrained operand is being used, the more
// opportunities we have for optimization.
Opnd *foundOpnd = _piMap->lookupTillEnd(opnd);
if (foundOpnd) {
// Remap the source operand except for Pi instruction and for
// array argument for chkbounds instruction. The latter is
// because (a) we do not need any facts provided by pi renaming
// for this operand, (b) we should limit array operand renaming
// to be able to search the proof path by exact array operand
// id.
if (inst->getOpcode() != Op_TauPi &&
(inst->getOpcode() != Op_TauCheckBounds || i != 0)) {
inst->setSrc(i, foundOpnd);
}
}
}
// Remap variables appearing in the condition of the Pi node.
if (inst->getOpcode() == Op_TauPi) {
TauPiInst *thePiInst = inst->asTauPiInst();
assert(thePiInst);
if (Log::isEnabled()) {
Log::out() << "remapping condition in ";
inst->print(Log::out());
Log::out() << std::endl;
}
PiCondition *cond = thePiInst->cond;
if (Log::isEnabled()) {
Log::out() << " original condition is ";
cond->print(Log::out());
Log::out() << std::endl;
}
Opnd *lbRemap = cond->getLb().getVar().the_var;
if (lbRemap) {
if (Log::isEnabled()) {
Log::out() << " has lbRemap=";
lbRemap->print(Log::out());
Log::out() << std::endl;
}
if (lbRemap->isPiOpnd())
lbRemap = lbRemap->asPiOpnd()->getOrg();
Opnd *lbRemapTo = _piMap->lookupTillEnd(lbRemap);
if (lbRemapTo) {
if (Log::isEnabled()) {
Log::out() << "adding remap of lbRemap=";
lbRemap->print(Log::out());
Log::out() << " to lbRemapTo=";
lbRemapTo->print(Log::out());
Log::out() << " to condition ";
cond->print(Log::out());
}
PiCondition remapped(*cond, lbRemap, lbRemapTo);
if (Log::isEnabled()) {
Log::out() << " YIELDS1 ";
remapped.print(Log::out());
}
*cond = remapped;
if (Log::isEnabled()) {
Log::out() << " YIELDS ";
cond->print(Log::out());
Log::out() << std::endl;
}
}
}
Opnd *ubRemap = cond->getUb().getVar().the_var;
if (ubRemap && (lbRemap != ubRemap)) {
if (Log::isEnabled()) {
Log::out() << " has ubRemap=";
ubRemap->print(Log::out());
Log::out() << std::endl;
}
if (ubRemap->isPiOpnd())
ubRemap = ubRemap->asPiOpnd()->getOrg();
Opnd *ubRemapTo = _piMap->lookupTillEnd(ubRemap);
if (ubRemapTo) {
if (Log::isEnabled()) {
Log::out() << "adding remap of ubRemap=";
ubRemap->print(Log::out());
Log::out() << " to ubRemapTo=";
ubRemapTo->print(Log::out());
Log::out() << " to condition ";
cond->print(Log::out());
}
PiCondition remapped(*cond, ubRemap, ubRemapTo);
if (Log::isEnabled()) {
Log::out() << " YIELDS1 ";
remapped.print(Log::out());
}
*cond = remapped;
if (Log::isEnabled()) {
Log::out() << " YIELDS ";
cond->print(Log::out());
Log::out() << std::endl;
}
}
}
}
}
}
//------------------------------------------------------------------------------
// a ScopedDomNodeInstWalker, forward/preorder
class RemovePiWalker {
public:
RemovePiWalker(InsertPi* ins) : _insertPi(ins), block(0) // forward
{}
void startNode(DominatorNode *domNode) { block = domNode->getNode(); };
void applyToInst(Inst *i) { _insertPi->removePiOnInst(block, i); }
void finishNode(DominatorNode *domNode) {}
void enterScope() {}
void exitScope() {}
private:
InsertPi* _insertPi;
Node* block;
};
//------------------------------------------------------------------------------
void InsertPi::removePi()
{
RemovePiWalker removePiWalker(this);
typedef ScopedDomNodeInst2DomWalker<true, RemovePiWalker>
RemovePiDomWalker;
RemovePiDomWalker removePiDomWalker(removePiWalker);
DomTreeWalk<true, RemovePiDomWalker>(_domTree, removePiDomWalker, _mm);
}
//------------------------------------------------------------------------------
void InsertPi::removePiOnInst(Node* block, Inst *inst)
{
if ( inst->getOpcode() == Op_TauPi ) {
inst->unlink();
}else{
// replace Pi operands with original ones
U_32 num_opnds = inst->getNumSrcOperands();
for (U_32 i = 0; i < num_opnds; i++) {
Opnd* pi_opnd = inst->getSrc(i);
while ( pi_opnd->isPiOpnd() ) {
pi_opnd = pi_opnd->asPiOpnd()->getOrg();
}
inst->setSrc(i, pi_opnd);
}
}
}
//------------------------------------------------------------------------------
} //namespace Jitrino