blob: 529906175f4de3722e369c1d501ca327c87e3f46 [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, Vyacheslav P. Shakin
*/
#include <stdlib.h>
#include "CodeGenerator_arch.h"
#include "Ia32CodeSelector.h"
#include "Ia32CFG.h"
#include "Ia32InstCodeSelector.h"
#include "EMInterface.h"
#include "XTimer.h"
namespace Jitrino
{
namespace Ia32{
CountTime selectionTimer("ia32::selector::selection");
CountTime blockMergingTimer("ia32::selector::blockMerging");
CountTime fixNodeInfoTimer("ia32::selector::fixNodeInfo");
//_______________________________________________________________________________________________________________
// FP conversion internal helpers (temp solution to be optimized)
//========================================================================================================
// class CfgCodeSelector
//========================================================================================================
//_______________________________________________________________________________________________
/** Construct CFG builder */
CfgCodeSelector::CfgCodeSelector(::Jitrino::SessionAction* sa,
CompilationInterface& compIntfc,
MethodCodeSelector& methodCodeSel,
MemoryManager& codeSelectorMM,
U_32 nNodes,
IRManager& irM
)
: numNodes(nNodes), nextNodeId(0), compilationInterface(compIntfc), methodCodeSelector(methodCodeSel),
irMemManager(irM.getMemoryManager()),
codeSelectorMemManager(codeSelectorMM), irManager(irM),
hasDispatchNodes(false), currBlock(NULL), returnOperand(0)
{
nextNodeId = 0;
nodes = new (codeSelectorMemManager) Node*[numNodes];
U_32 i;
for (i = 0; i < numNodes; i++)
nodes[i] = NULL;
InstCodeSelector::onCFGInit(irManager);
flags.useInternalHelpersForInteger2FloatConv = sa->getBoolArg("useInternalHelpersForInteger2FloatConv", false);
flags.slowLdString = sa->getBoolArg("SlowLdString", false);
}
//_______________________________________________________________________________________________
/** Create an exception handling (dispatching) node */
U_32 CfgCodeSelector::genDispatchNode(U_32 numInEdges,U_32 numOutEdges, const StlVector<MethodDesc*>& inlineEndMarkers, double cnt)
{
assert(nextNodeId < numNodes);
U_32 nodeId = nextNodeId++;
Node* node = irManager.getFlowGraph()->createDispatchNode();
node->setExecCount(cnt);
nodes[nodeId] = node;
hasDispatchNodes = true;
for (StlVector<MethodDesc*>::const_iterator it = inlineEndMarkers.begin(), end = inlineEndMarkers.end(); it!=end; ++it) {
MethodDesc* desc = *it;
node->appendInst(irManager.newMethodEndPseudoInst(desc));
}
return nodeId;
}
//_______________________________________________________________________________________________
/** Create a basic block */
U_32 CfgCodeSelector::genBlock(U_32 numInEdges,
U_32 numOutEdges,
BlockKind blockKind,
BlockCodeSelector& codeSelector,
double cnt)
{
assert(nextNodeId < numNodes);
U_32 nodeId = nextNodeId++;
Node* bb = irManager.getFlowGraph()->createBlockNode();
bb->setExecCount(cnt);
nodes[nodeId] = bb;
InstCodeSelector instCodeSelector(compilationInterface, *this, irManager, bb);
currBlock = bb;
{
codeSelector.genCode(instCodeSelector);
}
currBlock = NULL;
// Set prolog or epilogue node
switch (blockKind) {
case Prolog:
{
// Copy execution count into IA32 CFG prolog node and
// create an edge from IA32 CFG prolog node to optimizer's prolog node
Node* prolog = irManager.getFlowGraph()->getEntryNode();
prolog->setExecCount(cnt);
irManager.getFlowGraph()->addEdge(prolog, bb, 1.0);
break;
}
case Epilog:
{
assert(bb->isEmpty());
break;
}
case InnerBlock:
break; // nothing to do
}
if (instCodeSelector.endsWithSwitch()) {
// Generate an additional node that contains switch dispatch
U_32 numTargets = instCodeSelector.getSwitchNumTargets();
Opnd * switchSrc = instCodeSelector.getSwitchSrc();
genSwitchBlock(bb, numTargets, switchSrc);
}
return nodeId;
}
//_______________________________________________________________________________________________
/**
Create unwind node.
This is a temporary node that exists only during code selection.
We create it using code selector memory manager and insert it into its own CFG.
*/
U_32 CfgCodeSelector::genUnwindNode(U_32 numInEdges,
U_32 numOutEdges,
double cnt)
{
assert(nextNodeId < numNodes);
U_32 nodeId = nextNodeId++;
ControlFlowGraph* fg = irManager.getFlowGraph();
Node* unwindNode = fg->createDispatchNode();
fg->setUnwindNode(unwindNode);
unwindNode->setExecCount(cnt);
nodes[nodeId] = unwindNode;
return nodeId;
}
//_______________________________________________________________________________________________
/** Create exit node */
U_32 CfgCodeSelector::genExitNode(U_32 numInEdges, double cnt)
{
assert(nextNodeId < numNodes);
U_32 nodeId = nextNodeId++;
ControlFlowGraph* fg = irManager.getFlowGraph();
Node* exitNode = fg->createExitNode();
exitNode->setExecCount(cnt);
fg->setExitNode(exitNode);
nodes[nodeId] = exitNode;
return nodeId;
}
//_______________________________________________________________________________________________
/** Create a block for a switch statement */
void CfgCodeSelector::genSwitchBlock(Node *originalBlock,
U_32 numTargets,
Opnd * switchSrc)
{
Node *bb = irManager.getFlowGraph()->createBlockNode();
bb->setExecCount(originalBlock->getExecCount());
InstCodeSelector instSelector(compilationInterface, *this, irManager, bb);
{
instSelector.genSwitchDispatch(numTargets,switchSrc);
}
// Create an edge from the original block to bb
genFalseEdge(originalBlock, bb, 1.0);
}
//_______________________________________________________________________________________________
/** Create true edge (i.e., edge that corresponds to a taken conditional branch) */
void CfgCodeSelector::genTrueEdge(U_32 tailNodeId,U_32 headNodeId, double prob)
{
Node* tailNode= nodes[tailNodeId];
Node * headNode = nodes[headNodeId];
genTrueEdge(tailNode, headNode, prob);
}
void CfgCodeSelector::genTrueEdge(Node* tailNode, Node* headNode, double prob) {
assert(tailNode->isBlockNode() && headNode->isBlockNode());
Inst* inst = (Inst*)tailNode->getLastInst();
assert(inst!=NULL && inst->hasKind(Inst::Kind_BranchInst));
BranchInst* br = (BranchInst*)inst;
br->setTrueTarget(headNode);
irManager.getFlowGraph()->addEdge(tailNode, headNode, prob);
}
//_______________________________________________________________________________________________
/** Create false edge (i.e., edge that corresponds to a fallthrough after untaken conditional branch) */
void CfgCodeSelector::genFalseEdge(U_32 tailNodeId,U_32 headNodeId, double prob)
{
Node* tailNode = nodes[tailNodeId];
Node* headNode = nodes[headNodeId];
genFalseEdge(tailNode, headNode, prob);
}
void CfgCodeSelector::genFalseEdge(Node* tailNode,Node* headNode, double prob) {
assert(tailNode->isBlockNode() && headNode->isBlockNode());
Inst* inst = (Inst*)tailNode->getLastInst();
assert(inst!=NULL && inst->hasKind(Inst::Kind_BranchInst));
BranchInst* br = (BranchInst*)inst;
br->setFalseTarget(headNode);
irManager.getFlowGraph()->addEdge(tailNode, headNode, prob);
}
//_______________________________________________________________________________________________
/** Create unconditional edge (i.e., edge that corresponds to fallthrough) */
void CfgCodeSelector::genUnconditionalEdge(U_32 tailNodeId,U_32 headNodeId, double prob)
{
Node * tailNode = nodes[tailNodeId];
Node * headNode = nodes[headNodeId];
assert(tailNode->isBlockNode());
assert(headNode->isBlockNode() || headNode == irManager.getFlowGraph()->getExitNode());
Inst* lastInst = (Inst*)tailNode->getLastInst();
if (lastInst!=NULL && lastInst->hasKind(Inst::Kind_BranchInst)) {
BranchInst* br = (BranchInst*)lastInst;
assert(br->getTrueTarget() != NULL);
assert(br->getFalseTarget() == NULL);
br->setFalseTarget(headNode);
}
irManager.getFlowGraph()->addEdge(tailNode, headNode, prob);
}
//_______________________________________________________________________________________________
/** Create switch edges */
void CfgCodeSelector::genSwitchEdges(U_32 tailNodeId, U_32 numTargets,
U_32 *targets, double *probs,
U_32 defaultTarget)
{
//
// Switch structure:
//
// origBlock switchBlock
// =========== Fallthrough =============
// .... =======> .......
// if (switchVar >= numTargets) swTarget= jmp [switchVar + swTableBase]
// jmp defaultTarget
//
Node * origBlock = nodes[tailNodeId];
const Edges& outEdges=origBlock->getOutEdges();
assert(outEdges.size() == 1);
Node * switchBlock= outEdges.front()->getTargetNode();
assert(switchBlock->isBlockNode());
assert(((Inst*)switchBlock->getLastInst())->hasKind(Inst::Kind_SwitchInst));
SwitchInst * swInst = (SwitchInst *)switchBlock->getLastInst();
double defaultEdgeProb = 1.0;
defaultEdgeProb = 1.0;
for (U_32 i = 0; i < numTargets; i++) {
U_32 targetId = targets[i];
if ( targetId == defaultTarget) {
defaultEdgeProb = probs[i];
break;
}
if (std::find(targets, targets+i, targetId)!=targets+i) {
continue; //repeated target
}
if (probs[i] < 0) {
defaultEdgeProb = 0;
break;
}
defaultEdgeProb -= 1.0/(numTargets+1);
}
genTrueEdge(tailNodeId, defaultTarget, defaultEdgeProb);
// Fix probability of fallthrough edge
if (defaultEdgeProb!=0) {
origBlock->getOutEdges().front()->setEdgeProb(1.0 - defaultEdgeProb);
}
// Generate edges from switchBlock to switch targets
for (U_32 i = 0; i < numTargets; i++) {
Node * targetNode = nodes[targets[i]];
// Avoid generating duplicate edges. Jump table however needs all entries
if (! switchBlock->isConnectedTo(true, targetNode)) {
irManager.getFlowGraph()->addEdge(switchBlock, targetNode, probs[i]);
}
swInst->setTarget(i, targetNode);
}
}
//_______________________________________________________________________________________________
/** Create an edge to the exception dispatch node or unwind node */
void CfgCodeSelector::genExceptionEdge(U_32 tailNodeId, U_32 headNodeId, double prob)
{
Node * headNode = nodes[headNodeId];
Node * tailNode = nodes[tailNodeId];
assert(headNode->isDispatchNode() || headNode->isExitNode());
irManager.getFlowGraph()->addEdge(tailNode, headNode, prob);
}
//_______________________________________________________________________________________________
/** Create catch edge */
void CfgCodeSelector::genCatchEdge(U_32 tailNodeId,
U_32 headNodeId,
U_32 priority,
Type* exceptionType,
double prob)
{
Node * headNode = nodes[headNodeId];
Node * tailNode = nodes[tailNodeId];
assert(tailNode->isDispatchNode());
assert(headNode->isBlockNode());
CatchEdge* edge = (CatchEdge*)irManager.getFlowGraph()->addEdge(tailNode, headNode, prob);
edge->setType(exceptionType);
edge->setPriority(priority);
}
//_______________________________________________________________________________________________
/** Cfg code selector is notified that method contains calls */
void CfgCodeSelector::methodHasCalls(bool nonExceptionCall)
{
irManager.setHasCalls();
if (nonExceptionCall)
irManager.setHasNonExceptionCalls();
}
///////////////////////////////////////////////////////////////////////////////////
//
// class VarGenerator
//
///////////////////////////////////////////////////////////////////////////////////
//_______________________________________________________________________________________________
U_32 VarGenerator::defVar(Type* varType, bool isAddressTaken, bool isPinned)
{
Opnd * opnd=irManager.newOpnd(varType);
return opnd->getId();
}
//_______________________________________________________________________________________________
void VarGenerator::setManagedPointerBase(U_32 managedPtrVarNum, U_32 baseVarNum)
{
}
///////////////////////////////////////////////////////////////////////////////////
//
// class MethodCodeSelector
//
///////////////////////////////////////////////////////////////////////////////////
//_______________________________________________________________________________________________
/** Generate variable operands */
void MethodCodeSelector::genVars(U_32 numVars, VarCodeSelector& varCodeSelector)
{
numVarOpnds = numVars;
VarGenerator varCodeSelectorCallback(irManager,*this);
varCodeSelector.genCode(varCodeSelectorCallback);
}
//_______________________________________________________________________________________________
/** Update register usage */
void MethodCodeSelector::updateRegUsage()
{
}
//_______________________________________________________________________________________________
/** Set persistent ids, and others for nodes that exist only in the code generator CFG */
void CfgCodeSelector::fixNodeInfo()
{
MemoryManager tmpMM("Ia32CS:fixNodeInfoMM");
ControlFlowGraph* fg = irManager.getFlowGraph();
Nodes nodes(tmpMM);
fg->getNodes(nodes); //copy nodes -> loop creates new ones, so we can't use reference to cfg->getNodes()
for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) {
Node* node = *it;
// connect throw nodes added during inst code selection to corresponding dispatch or unwind nodes
if (node->isBlockNode()){
Inst * lastInst = (Inst*)node->getLastInst();
if (lastInst) {
Inst * prevInst = lastInst->getPrevInst();
if(prevInst && prevInst->getKind() == Inst::Kind_BranchInst) {
Edge * ftEdge = node->getFalseEdge();
Edge * dbEdge = node->getTrueEdge();
assert(ftEdge && dbEdge);
Node* newBB = fg->createBlockNode();
Node* nextFT = ftEdge->getTargetNode();
Node* nextDB = dbEdge->getTargetNode();
fg->removeEdge(ftEdge);
fg->removeEdge(dbEdge);
newBB->appendInst(irManager.newBranchInst(lastInst->getMnemonic(), nextDB, nextFT));
lastInst->unlink();
//now fix prev branch successors
BranchInst* prevBranch = (BranchInst*)prevInst;
assert(prevBranch->getTrueTarget() == NULL && prevBranch->getFalseTarget() == NULL);
prevBranch->setTrueTarget(lastInst->getMnemonic() == Mnemonic_JZ? nextFT : nextDB);
prevBranch->setFalseTarget(newBB);
fg->addEdge(node, lastInst->getMnemonic() == Mnemonic_JZ? nextFT : nextDB, 0);
fg->addEdge(node, newBB, 0);
fg->addEdge(newBB, nextDB, 0);
fg->addEdge(newBB, nextFT, 0);
}
}
if (node->getOutDegree() == 0){ // throw node
assert(node->getInDegree()==1);
Node* bbIn = node->getInEdges().front()->getSourceNode();
assert(bbIn!=NULL);
Node * target=bbIn->getExceptionEdgeTarget();
assert(target!=NULL);
fg->addEdge(node, target, 1.0);
}
// fixup empty catch blocks otherwise respective catchEdges will be lost
// There is no [catchBlock]-->[catchHandler] edge. Catch block will be removed
// as an empty one and exception handling will be incorrect
if (node->isCatchBlock() && node->isEmpty()) {
assert(node->getInDegree()==1);
Edge* catchEdge = node->getInEdges().front();
assert(catchEdge->getSourceNode()->isDispatchNode());
assert(node->getOutDegree()==1);
Node* succ = node->getUnconditionalEdgeTarget();
while( succ->isEmpty() && (succ->getOutDegree() == 1) ) {
succ = succ->getUnconditionalEdgeTarget();
}
assert(succ && ((Inst*)succ->getFirstInst())->hasKind(Inst::Kind_CatchPseudoInst));
fg->replaceEdgeTarget(catchEdge,succ,true/*keepOldBody*/);
}
}
}
}
//_______________________________________________________________________________________________
/** Generate heap base initialization */
void MethodCodeSelector::genHeapBase()
{
}
//_______________________________________________________________________________________________
/** Generate control flow graph */
MethodCodeSelector::MethodCodeSelector(
::Jitrino::SessionAction* _sa,
CompilationInterface& compIntfc,
MemoryManager& irMM,
MemoryManager& codeSelectorMM,
IRManager& irM)
: sa(_sa), compilationInterface(compIntfc),
irMemManager(irMM), codeSelectorMemManager(codeSelectorMM),
irManager(irM),
methodDesc(NULL),
edgeProfile(NULL)
{
ProfilingInterface* pi = irManager.getProfilingInterface();
if (pi!=NULL && pi->isProfilingEnabled(ProfileType_Edge, JITProfilingRole_GEN)) {
edgeProfile = pi->getEdgeMethodProfile(irMM, irM.getMethodDesc(), JITProfilingRole_GEN);
}
}
void MethodCodeSelector::genCFG(U_32 numNodes, CFGCodeSelector& codeSelector,
bool useEdgeProfile)
{
ControlFlowGraph* fg = irManager.getFlowGraph();
fg->setEdgeProfile(useEdgeProfile);
CfgCodeSelector cfgCodeSelector(sa, compilationInterface, *this,
codeSelectorMemManager,numNodes, irManager);
{
AutoTimer tm(selectionTimer);
if( NULL == irManager.getEntryPointInst() ) {
irManager.newEntryPointPseudoInst( irManager.getDefaultManagedCallingConvention() );
}
codeSelector.genCode(cfgCodeSelector);
}
{
AutoTimer tm(fixNodeInfoTimer);
irManager.expandSystemExceptions(0);
cfgCodeSelector.fixNodeInfo();
}
{
AutoTimer tm(blockMergingTimer);
fg->purgeEmptyNodes(false, true);
fg->mergeAdjacentNodes(true, false);
fg->purgeUnreachableNodes();
}
}
//_______________________________________________________________________________________________
}; // namespace Ia32
};