blob: c875f650f1b596fdc3c554286b2081c6b48ccb3b [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, Konstantin M. Anisimov, Igor V. Chebykin
*
*/
#include "IpfLiveAnalyzer.h"
#include "IpfIrPrinter.h"
#include "IpfOpndManager.h"
namespace Jitrino {
namespace IPF {
//========================================================================================//
// QpNode
//========================================================================================//
QpNode::QpNode(QpNode *predNode, QpMask nodeMask) :
predNode(predNode),
compNode(NULL),
nodeMask(nodeMask),
compMask(0),
liveMask(0) {
QpNode *qpNode = predNode;
while (qpNode != NULL) { // iterate through all predecessors of the node
qpNode->orNodeMask(nodeMask); // add bits of this nodeMask in predecessor's nodeMasks
qpNode = qpNode->getPredNode(); // get next predecessor
}
}
//----------------------------------------------------------------------------------------//
// make mask of all predicate spaces interfering with current one. These are all spaces
// except complementing ones
void QpNode::initLiveMask() {
QpNode *qpNode = this;
liveMask = 0;
while (qpNode != NULL) {
QpMask mask = qpNode->getCompMask(); // get nodeMask of complemening to current space
if (mask != MAX_QP_MASK) liveMask |= mask; // if there is complementing space (is not MAX_QP_MASK) - add masks
qpNode = qpNode->getPredNode(); // get next predecessor
} //
liveMask = ~liveMask; // this qpNode interfere with all others except complementing ones
}
//----------------------------------------------------------------------------------------//
// if qpNode has complement node - get its nodeMask (just to speed up "getCompMask" method)
// else - set all ones in compMask
void QpNode::initCompMask() {
if (compNode == NULL) compMask = MAX_QP_MASK;
else compMask = compNode->getNodeMask();
}
//========================================================================================//
// QpTree
//========================================================================================//
QpTree::QpTree(Cfg &cfg) :
cfg(cfg),
mm(cfg.getMM()),
qpMap(mm),
slot(0),
p0(cfg.getOpndManager()->getP0()) {
qpMap.insert( make_pair(p0, new(mm) QpNode(NULL, MAX_QP_MASK)) ); // make root qpNode
}
//----------------------------------------------------------------------------------------//
// build qpMap determining qp->qpNode relations. If qp is defined several times - the tree
// contains several entryes corresponding to the qp.
void QpTree::makeQpTree(InstVector &insts) {
IPF_ASSERT(qpMap.size() == 1);
slot = 1; // init slot (position in mask)
for (InstVector::iterator it=insts.begin(); it!=insts.end(); it++) {
Inst *inst = *it; // iterate insts
if (isDefOnePred(inst)) { // if inst defs one predicate opnd
OpndVector &opnds = inst->getOpnds(); // get opnds of the inst
QpNode *qpNode = findQpNode(opnds[0]); // inst qp is predecessor for predicates defined in the inst
makeQpNode(qpNode, opnds[2]); // make qpNode for the predicate opnd (it is always second one)
continue;
}
if (isDefTwoPreds(inst)) { // if inst defs two predicate opnds
OpndVector &opnds = inst->getOpnds(); // get opnds of the inst
QpNode *qpNode = findQpNode(opnds[0]); // inst qp is predecessor for predicates defined in the inst
QpNode *p1Node = makeQpNode(qpNode, opnds[1]); // make qpNode for first predicate opnd
QpNode *p2Node = makeQpNode(qpNode, opnds[2]); // make qpNode for second predicate opnd
if (isDefComps(inst) == false) continue; // inst does not define mutually complemen predicates - continue
if (p1Node != NULL) p1Node->setCompNode(p2Node); // p2Node complements p1Node
if (p2Node != NULL) p2Node->setCompNode(p1Node); // p1Node complements p2Node
}
}
for (QpMap::iterator it=qpMap.begin(); it!=qpMap.end(); it++) {
QpNode *qpNode = it->second; // iterate all qpNodes in the tree
qpNode->initCompMask(); // set comp mask (to speed up getCompMask)
}
for (QpMap::iterator it=qpMap.begin(); it!=qpMap.end(); it++) {
QpNode *qpNode = it->second; // iterate all qpNodes in the tree
qpNode->initLiveMask(); // set live masks (predicate spaces which do not complement)
}
}
//----------------------------------------------------------------------------------------//
// find qpNode corresponding to "qp" from qpMap. There are can be several nodes
// corresponding to one qp. We should return least recent inserted one
QpNode* QpTree::findQpNode(Opnd *qp) {
QpMap::iterator it = qpMap.upper_bound(qp);
return (--it)->second;
}
//----------------------------------------------------------------------------------------//
// remove qpNode corresponding to "qp" from qpMap. There are can be several nodes
// corresponding to one qp. We should remove least recent inserted one
void QpTree::removeQpNode(Opnd *qp) {
QpMap::iterator it = qpMap.upper_bound(qp); // find in qpMap last node corresponding to "qp"
qpMap.erase(--it); // remove the node from the tree
}
//----------------------------------------------------------------------------------------//
void QpTree::printQpTree() {
QpMap::iterator it = qpMap.upper_bound(p0);
printQpNode(--it, 0);
}
//----------------------------------------------------------------------------------------//
QpNode* QpTree::makeQpNode(QpNode *predNode, Opnd *qp) {
if (qp == p0) return NULL; // node for p0 has been created in constructor
slot <<= 1; // get next empty slot (position in mask)
QpNode *qpNode = new(mm) QpNode(predNode, slot); // create qpNode
qpMap.insert( make_pair(qp, qpNode) ); // insert the qpNode in qpTree
return qpNode;
}
//----------------------------------------------------------------------------------------//
void QpTree::printQpNode(QpMap::iterator nodeIt, uint16 level) {
QpNode *predNode = nodeIt->second;
Opnd *qp = nodeIt->first;
IPF_LOG << " " << IrPrinter::toString(predNode);
for (uint16 i=0; i<level; i++) IPF_LOG << " ";
IPF_LOG << " " << IrPrinter::toString(qp) << endl;
for (QpMap::iterator it=qpMap.begin(); it!=qpMap.end(); it++) {
QpNode *qpNode = it->second;
if (qpNode->getPredNode() != predNode) continue;
printQpNode(it, level+1);
}
}
//----------------------------------------------------------------------------------------//
// return true if the inst defines one pred opnd
bool QpTree::isDefOnePred(Inst *inst) {
switch (inst->getInstCode()) {
case INST_FRCPA :
case INST_FPRCPA :
case INST_FRSQRTA :
case INST_FPRSQRTA : return true;
default : return false;
}
}
//----------------------------------------------------------------------------------------//
// return true if the inst defines two pred opnds
bool QpTree::isDefTwoPreds(Inst *inst) {
switch (inst->getInstCode()) {
case INST_CMP :
case INST_CMP4 :
case INST_FCMP :
case INST_TBIT :
case INST_TNAT :
case INST_FCLASS : return true;
default : return false;
}
}
//----------------------------------------------------------------------------------------//
// return true if the inst defines two mutually complement preds
bool QpTree::isDefComps(Inst *inst) {
InstCode instCode = inst->getInstCode();
if (instCode == INST_FCMP || instCode == INST_FCLASS) return true;
if (instCode == INST_TBIT || instCode == INST_TNAT) return true;
CompVector &comps = inst->getComps();
if (comps.size() < 2) return true;
if (comps[1] == CMPLT_CMP_CTYPE_NONE) return true;
if (comps[1] == CMPLT_CMP_CTYPE_UNC) return true;
return false;
}
//========================================================================================//
// LiveManager
//========================================================================================//
LiveManager::LiveManager(Cfg &cfg) :
cfg(cfg),
qpTree(cfg),
liveSet(cfg.getMM()) {
}
//----------------------------------------------------------------------------------------//
void LiveManager::init(Node *node) {
liveSet.clear(); // clear live set
node->mergeOutLiveSets(liveSet); // all opnds alive in successors are alive in current live set
for (RegOpndSet::iterator it=liveSet.begin(); it!=liveSet.end(); it++) {
RegOpnd *opnd = *it; //
opnd->orQpMask(MAX_QP_MASK); // initially opnds alive in all pred spaces
} //
if (node->getNodeKind() != NODE_BB) return; // if node is not BB - nothing to do
qpTree.makeQpTree(((BbNode *)node)->getInsts()); // make qpTree for current BB
}
//----------------------------------------------------------------------------------------//
// add opnds used in the inst in liveSet. Or modify opnd's qpMask to reflect use under inst's qp
void LiveManager::use(Inst *inst) {
OpndVector &opnds = inst->getOpnds(); // get inst's opnds
RegOpnd *qp = (RegOpnd *)opnds[0]; // fist opnd is instruction qp
QpNode *qpNode = qpTree.findQpNode(qp); // find qpNode corresponding to the qp
if (qp->isWritable()) {
qp->orQpMask(MAX_QP_MASK); // qp is alive in all pred spaces
liveSet.insert(qp);
}
for (uint16 i=inst->getNumDst()+1; i<opnds.size(); i++) {
RegOpnd *opnd = (RegOpnd *)opnds[i];
if (opnd->isWritable() == false) continue;
useOpnd(qpNode, opnd);
liveSet.insert(opnd);
}
}
//----------------------------------------------------------------------------------------//
// remove opnds defined in the inst from liveSet. Or modify opnd's qpMask to reflect def
// under inst's qp
void LiveManager::def(Inst *inst) {
OpndVector &opnds = inst->getOpnds();
RegOpnd *qp = (RegOpnd *)opnds[0]; // fist opnd is instruction qp
QpNode *qpNode = qpTree.findQpNode(qp);
for (uint16 i=1; i<=inst->getNumDst(); i++) {
RegOpnd *opnd = (RegOpnd *)opnds[i];
if (opnd->isWritable() == false) continue;
if (defOpnd(qpNode, opnd) == false) continue;
liveSet.erase(opnd);
}
}
//----------------------------------------------------------------------------------------//
QpMask LiveManager::getLiveMask(RegOpnd *opnd) {
QpNode *qpNode = qpTree.findQpNode(opnd);
return qpNode->getLiveMask();
}
//----------------------------------------------------------------------------------------//
void LiveManager::useOpnd(QpNode *qpNode, RegOpnd *opnd) {
QpMask mask = qpNode->getNodeMask(); // get mask of predicates alive in space of the qpNode
opnd->orQpMask(mask); // add mask to current opnd qpMask
}
//----------------------------------------------------------------------------------------//
bool LiveManager::defOpnd(QpNode *qpNode, RegOpnd *opnd) {
if (opnd->isQp()) qpTree.removeQpNode(opnd); // if we def predicate opnd - remove corresponding qpNode from qpTree
QpMask mask = opnd->getQpMask(); // get mask of pred spaces, the opnd alive in
if (mask == 0) return true; // if mask is zero - opnd is dead
while ((mask & qpNode->getCompMask())==0) { // while opnd is dead in complement predicate space - propagate def up
qpNode = qpNode->getPredNode(); // get predecessor in qpTree
} //
opnd->andQpMask(~(qpNode->getNodeMask())); // null bits corresponding the successors in opnd's qp mask
if (opnd->getQpMask()) return false; // opnd is alive in some predicate spaces
else return true; // opnd is dead
}
} // IPF
} // Jitrino