blob: 23b50ebae862d770c9f9fc3190bae40fa188cae4 [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 Sergey L. Ivashin
*/
#include "Ia32RegAllocCheck.h"
#include "Log.h"
#include "XTimer.h"
namespace Jitrino
{
namespace Ia32
{
using ::std::endl;
using ::std::ostream;
//========================================================================================
// utility routines
//========================================================================================
static ostream& operator << (ostream& os, const Inst& x)
{
return os << "I#" << x.getId();
}
static ostream& operator << (ostream& os, const Opnd& x)
{
return os << "O#" << x.getFirstId();
}
static ostream& operator << (ostream& os, RegName x)
{
return os << getRegNameString(x);
}
//========================================================================================
// class RegAllocCheck
//========================================================================================
bool RegAllocCheck::run (bool checkloc)
{
static CountTime regAllocCheckTimer("ia32::regAllocCheck");
AutoTimer tm(regAllocCheckTimer);
opandcount = irm.getOpndCount();
errors = 0;
headprinted = false;
if (checkloc)
checkLocations();
const Nodes& nodes = irm.getFlowGraph()->getNodes();
for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) {
Node* node = *it;
if (node->isBlockNode())
{
bblock = node;
checkLiveness();
checkConstraints();
}
}
if (errors != 0)
header() << endl << "ERRORS DETECTED: " << errors << endl;
else if (Log::isEnabled())
header() << endl << "No errors detected" << endl;
return errors == 0;
}
const size_t MaxRegs = IRMaxRegNamesSameKind*IRMaxRegKinds;
static RegName regName (int x)
{
U_32 k = x / IRMaxRegNamesSameKind;
return getRegName((OpndKind)k, Constraint::getDefaultSize(k), x % IRMaxRegNamesSameKind);
}
static size_t regIdx (const Opnd* opnd)
{
RegName rn;
if ((rn = opnd->getRegName()) == RegName_Null)
return MaxRegs;
size_t x = getRegIndex(rn),
k = getRegKind(rn);
assert(x < IRMaxRegNamesSameKind && k < IRMaxRegKinds);
return k*IRMaxRegNamesSameKind + x;
}
void RegAllocCheck::checkLiveness ()
{
lastbb = 0;
BitSet lives(mm, (U_32)opandcount);
irm.getLiveAtExit(bblock, lives);
Opnd* regdefs[MaxRegs],
* reguses[MaxRegs],
* regnxts[MaxRegs];
size_t ridx;
for (ridx = 0; ridx != MaxRegs; ++ridx)
regdefs[ridx] = 0,
reguses[ridx] = 0,
regnxts[ridx] = 0;
Opnd* opnd;
BitSet::IterB ls(lives);
for (int i = ls.getNext(); i != -1; i = ls.getNext())
{
opnd = irm.getOpnd(i);
if ((ridx = regIdx(opnd)) < MaxRegs)
{
if (regnxts[ridx] == 0)
regnxts[ridx] = opnd;
else
if (regnxts[ridx] != opnd)
{
error() << "at end of block," << regName((int)ridx)
<< " assigned to " << *regnxts[ridx] << " and " << *opnd << endl;
}
}
}
// iterate over instructions towards the top of the block
for (Inst* inst = (Inst*)bblock->getLastInst(); inst != 0; inst = inst->getPrevInst())
{
const U_32 props = inst->getProperties();
// In general, operands can be stored in arbitrary order
Inst::Opnds opnds(inst, Inst::OpndRole_All);
for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)){
opnd = opnds.getOpnd(it);
if ((ridx = regIdx(opnd)) < MaxRegs)
{
const U_32 roles = inst->getOpndRoles(it);
if ((roles & Inst::OpndRole_Def) != 0)
{
if (regdefs[ridx] == 0)
regdefs[ridx] = opnd;
else
if (regdefs[ridx] != opnd)
{
error() << " Invalid definitions at " << *inst << " " << regName((int)ridx)
<< " of " << *regdefs[ridx] << " or " << *opnd << endl;
}
}
if ((roles & Inst::OpndRole_Use) != 0)
{
if (reguses[ridx] == 0)
reguses[ridx] = opnd;
else
if (reguses[ridx] != opnd)
{
error() << " Invalid usages at " << *inst << " " << regName((int)ridx)
<< " of " << *reguses[ridx] << " or " << *opnd << endl;
}
}
}
}
for (ridx = 0; ridx != MaxRegs; ++ridx)
{
if (regdefs[ridx] != 0)
{
// conditional definitions are ignored
if ((props & Inst::Properties_Conditional) == 0)
{
if (regdefs[ridx] != regnxts[ridx]) {
if (regnxts[ridx] != 0)
{
error() << " " << *inst << " " << regName((int)ridx)
<< " invalid usage of " << *regnxts[ridx]
<< " instead of " << *regdefs[ridx] << endl;
}
else
{
// dead def
}
}
regnxts[ridx] = 0; // this register can used in the instruction
}
}
else if (reguses[ridx] != 0)
{
if (reguses[ridx] != regnxts[ridx] && regnxts[ridx] != 0)
{
error() << " " << *inst << " " << regName((int)ridx)
<< " invalid usage of " << *reguses[ridx]
<< " or " << *regnxts[ridx] << endl;
}
regnxts[ridx] = reguses[ridx];
}
// clear for next instruction to be processed
regdefs[ridx] = 0;
reguses[ridx] = 0;
}
}
}
void RegAllocCheck::checkLocations ()
{
for (size_t i = 0; i != opandcount; ++i)
{
Opnd* opnd = irm.getOpnd((U_32)i);
if (!opnd->hasAssignedPhysicalLocation())
{
header() << "Not assigned opand " << *opnd << endl;
errors++;
}
}
}
void RegAllocCheck::checkConstraints ()
{
lastbb = 0;
for (const Inst* inst = (Inst*)bblock->getFirstInst(); inst != 0; inst = inst->getNextInst())
{
Opnd* opnd;
Inst::Opnds opnds(inst, Inst::OpndRole_AllDefs);
U_32 mask = 0;
for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it))
{
opnd = opnds.getOpnd(it);
Constraint cloc = opnd->getConstraint(Opnd::ConstraintKind_Location);
mask |= 1<<it;
Constraint c = ((Inst *)inst)->getConstraint(it, mask, cloc.getSize());
if (!cloc.isNull())
if (c.getSize() == cloc.getSize() && !c.contains(cloc))
error() << "Constraint error " << *inst << " " << *opnd << endl;
}
}
}
ostream& RegAllocCheck::error ()
{
if (lastbb != bblock)
{
lastbb = bblock;
header() << "BasicBlock " << bblock->getId()
<< "[" << ((Inst*)bblock->getFirstInst())->getId() << " .. "
<< ((Inst*)bblock->getLastInst())->getId() << "]"
<< endl ;
}
errors++;
return Log::out();
}
ostream& RegAllocCheck::header ()
{
if (!headprinted)
{
headprinted = true;
MethodDesc& md=irm.getMethodDesc();
Log::out() << endl << "RegAllocCheck for "
<< md.getParentType()->getName()
<< "." << md.getName() << "(" << md.getSignatureString() << ")"
<< endl;
}
return Log::out();
}
} //namespace Ia32
} //namespace Jitrino