blob: 454173116f553ea6a1de6be189a3d81b63c4453c [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 "CodeGenIntfc.h"
#include "IpfEmitter.h"
#include "IpfOpndManager.h"
#include "IpfIrPrinter.h"
#include "IpfVerifier.h"
#include <iomanip>
namespace Jitrino {
namespace IPF {
//============================================================================//
const BundleDescription Bundle::BundleDesc[TEMPLATES_COUNT] = {
{ IT_SLOT0(IT_M) | IT_SLOT1(IT_I) | IT_SLOT2(IT_I), 0x0, 0x00 },
{ IT_SLOT0(IT_M) | IT_SLOT1(IT_I) | IT_SLOT2(IT_I), 0x4, 0x01 },
{ IT_SLOT0(IT_M) | IT_SLOT1(IT_I) | IT_SLOT2(IT_I), 0x2, 0x02 },
{ IT_SLOT0(IT_M) | IT_SLOT1(IT_I) | IT_SLOT2(IT_I), 0x6, 0x03 },
{ IT_SLOT0(IT_M) | IT_SLOT1(IT_L) | IT_SLOT2(IT_X), 0x0, 0x04 },
{ IT_SLOT0(IT_M) | IT_SLOT1(IT_L) | IT_SLOT2(IT_X), 0x4, 0x05 },
{ IT_SLOT0(IT_M) | IT_SLOT1(IT_M) | IT_SLOT2(IT_I), 0x0, 0x08 },
{ IT_SLOT0(IT_M) | IT_SLOT1(IT_M) | IT_SLOT2(IT_I), 0x4, 0x09 },
{ IT_SLOT0(IT_M) | IT_SLOT1(IT_M) | IT_SLOT2(IT_I), 0x1, 0x0a },
{ IT_SLOT0(IT_M) | IT_SLOT1(IT_M) | IT_SLOT2(IT_I), 0x5, 0x0b },
{ IT_SLOT0(IT_M) | IT_SLOT1(IT_F) | IT_SLOT2(IT_I), 0x0, 0x0c },
{ IT_SLOT0(IT_M) | IT_SLOT1(IT_F) | IT_SLOT2(IT_I), 0x4, 0x0d },
{ IT_SLOT0(IT_M) | IT_SLOT1(IT_M) | IT_SLOT2(IT_F), 0x0, 0x0e },
{ IT_SLOT0(IT_M) | IT_SLOT1(IT_M) | IT_SLOT2(IT_F), 0x4, 0x0f },
{ IT_SLOT0(IT_M) | IT_SLOT1(IT_I) | IT_SLOT2(IT_B), 0x0, 0x10 },
{ IT_SLOT0(IT_M) | IT_SLOT1(IT_I) | IT_SLOT2(IT_B), 0x4, 0x11 },
{ IT_SLOT0(IT_M) | IT_SLOT1(IT_B) | IT_SLOT2(IT_B), 0x0, 0x12 },
{ IT_SLOT0(IT_M) | IT_SLOT1(IT_B) | IT_SLOT2(IT_B), 0x4, 0x13 },
{ IT_SLOT0(IT_B) | IT_SLOT1(IT_B) | IT_SLOT2(IT_B), 0x0, 0x16 },
{ IT_SLOT0(IT_B) | IT_SLOT1(IT_B) | IT_SLOT2(IT_B), 0x4, 0x17 },
{ IT_SLOT0(IT_M) | IT_SLOT1(IT_M) | IT_SLOT2(IT_B), 0x0, 0x18 },
{ IT_SLOT0(IT_M) | IT_SLOT1(IT_M) | IT_SLOT2(IT_B), 0x4, 0x19 },
{ IT_SLOT0(IT_M) | IT_SLOT1(IT_F) | IT_SLOT2(IT_B), 0x0, 0x1c },
{ IT_SLOT0(IT_M) | IT_SLOT1(IT_F) | IT_SLOT2(IT_B), 0x4, 0x1d }
};
//============================================================================//
const char Emitter::Itanium2_DualIssueBundles[30][30] = {
{1, 1, 1, 1, 0, 0, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1}, // MII, 0x00
{1, 1, 1, 1, 0, 0, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1}, // MII, 0x01
{1, 1, 1, 1, 0, 0, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1}, // MII, 0x02
{1, 1, 1, 1, 0, 0, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1}, // MII, 0x03
{1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1}, // MLX, 0x04
{1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1}, // MLX, 0x05
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1}, // MMI, 0x08
{1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1}, // MMI, 0x09
{1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1}, // MMI, 0x0a
{1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1}, // MMI, 0x0b
{1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1}, // MFI, 0x0c
{1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1}, // MFI, 0x0d
{1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1}, // MMF, 0x0e
{1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1}, // MMF, 0x0f
{1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 0, 0, 1, 1, -1, -1, 1, 1}, // MIB, 0x10
{1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 0, 0, 1, 1, -1, -1, 1, 1}, // MIB, 0x11
{0, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0}, // MBB, 0x12
{0, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0}, // MBB, 0x13
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0}, // BBB, 0x16
{0, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0}, // BBB, 0x17
{1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 0, 0, 1, 1, -1, -1, 1, 1}, // MMB, 0x18
{1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 0, 0, 1, 1, -1, -1, 1, 1}, // MMB, 0x19
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 0, 0, 1, 1, -1, -1, 1, 1}, // MFB, 0x1c
{1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 0, 0, 1, 1, -1, -1, 1, 1} // MFB, 0x1d
};
//============================================================================//
void Emitter::checkForDualIssueBundles() {
EmitterBb *bb;
Bundle *bundle1, *bundle2;
U_32 tmpl1, tmpl2;
bool header_printed = false;
for (int bbindex=0 ; bbindex<(int)bbs->size() ; bbindex++) {
bb = bbs->at(bbindex);
BundleVector & bundles = *(bb->bundles);
for (int bi=0, bii=bundles.size()-1 ; bi<bii ; ) {
bundle1 = bundles[bi];
bundle2 = bundles[bi+1];
tmpl1 = bundle1->getTmpl();
tmpl2 = bundle2->getTmpl();
if (!bundle1->hasStop() && Itanium2_DualIssueBundles[tmpl1][tmpl2]==0) {
if (!header_printed) {
header_printed = true;
clog << "CHECK_DUAL_ISSUE: Method:"
<< " bundles=" << codesize/IPF_BUNDLE_SIZE
<< "; SIG="
<< compilationinterface.getMethodToCompile()->getParentType()->getName()
<< "." << compilationinterface.getMethodToCompile()->getName()
<< compilationinterface.getMethodToCompile()->getSignatureString()
<< "\n";
}
clog << "CHECK_DUAL_ISSUE: bbindex=" << bbindex
<< ", node_id=" << bb->node->getId()
<< "; bi=" << bi
<< "; tmpl1=0x" << hex << tmpl1
<< "; tmpl2=0x" << tmpl2 << dec
<< "\n";
bi += 1;
continue;
} else if (Itanium2_DualIssueBundles[tmpl1][tmpl2] == -1) {
if (!header_printed) {
header_printed = true;
clog << "Method:"
<< " bundles=" << codesize/IPF_BUNDLE_SIZE
<< "; SIG="
<< compilationinterface.getMethodToCompile()->getParentType()->getName()
<< "." << compilationinterface.getMethodToCompile()->getName()
<< compilationinterface.getMethodToCompile()->getSignatureString()
<< "\n";
}
clog << "BAD templates: " << tmpl1 << ", " << tmpl2
<< "\n";
}
if (bundle2->hasStop()) {
bi += 1;
continue;
} else {
bi += 2;
continue;
}
}
}
}
//============================================================================//
Bundle::Bundle(Cfg& cfg, U_32 itmp, Inst *i0, Inst *i1, Inst *i2) {
indxtmpl = itmp; // !!! THis is not template, but index in Bundle::BundleDesc[] !!!
MemoryManager& mm = cfg.getMM();
OpndManager* opndManager = cfg.getOpndManager();
// slot 0
if( i0==NULL ) {
slot[0] = new(mm) Inst(mm, INST_NOP, PR(0), IMM(INST_BREAKPOINT_IMM_VALUE));
} else {
slot[0] = i0;
}
// slot 1
if( i1==NULL ) {
slot[1] = new(mm) Inst(mm, INST_NOP, PR(0), IMM(INST_BREAKPOINT_IMM_VALUE));
} else {
slot[1] = i1;
}
// slot 2
if( i2==NULL ) {
slot[2] = new(mm) Inst(mm, INST_NOP, PR(0), IMM(INST_BREAKPOINT_IMM_VALUE));
} else {
slot[2] = i2;
}
}
//============================================================================//
void Bundle::emitBundleGeneral(void *whereToEmit) {
uint64 * p = (uint64 *)whereToEmit;
uint64 s;
p[0] = 0;
p[1] = 0;
p[0] = getTmpl();
s = getSlotBits(0);
p[0] |= s << 5;
s = getSlotBits(1);
p[0] |= s << 46;
p[1] = s >> 18;
s = getSlotBits(2);
p[1] |= s << 23;
}
void Bundle::emitBundleBranch(void *whereToEmit, int * bundletarget) {
uint64 * p = (uint64 *)whereToEmit;
uint64 s;
U_32 itmp = getTmpl();
p[0] = 0;
p[1] = 0;
p[0] = itmp;
if (itmp==0x16 || itmp==0x17) {
s = getSlotBitsBranch(0, bundletarget[0]);
} else {
s = getSlotBits(0);
}
p[0] |= s << 5;
if (itmp>=0x12 && itmp<=0x17) {
s = getSlotBitsBranch(1, bundletarget[1]);
} else {
s = getSlotBits(1);
}
p[0] |= s << 46;
p[1] = s >> 18;
if (itmp>=0x10) {
s = getSlotBitsBranch(2, bundletarget[2]);
} else {
s = getSlotBits(2);
}
p[1] |= s << 23;
}
void Bundle::emitBundleExtended(void *whereToEmit) {
uint64 * p = (uint64 *)whereToEmit;
uint64 s;
uint64 s12[2];
p[0] = 0;
p[1] = 0;
p[0] = getTmpl();
s = getSlotBits(0);
p[0] |= s << 5;
getSlotBitsExtended(s12, whereToEmit);
p[0] |= s12[0] << 46;
p[1] = s12[0] >> 18;
p[1] |= s12[1] << 23;
}
uint64 Bundle::getSlotBits(int slotindex) {
return Encoder::getInstBits(Emitter::getExecUnitType(indxtmpl, slotindex)
, slot[slotindex]);
}
uint64 Bundle::getSlotBitsBranch(int slotindex, int target) {
return Encoder::getInstBitsBranch(Emitter::getExecUnitType(indxtmpl, slotindex)
, slot[slotindex], target);
}
uint64 * Bundle::getSlotBitsExtended(uint64 *slots12, void *whereToEmit) {
return Encoder::getInstBitsExtended(slot[1], slots12, whereToEmit);
}
//============================================================================//
void Bundle::print() {
Inst * inst = getSlot(0);
U_32 tmpl = getTmpl();
IPF_LOG << "(" << tmpl << ")\n";
IPF_LOG << IrPrinter::toString(inst);
IPF_LOG << ( tmpl==0x0A || tmpl==0x0B ? " ;;" : "")
<< "\n";
inst = getSlot(1);
IPF_LOG << IrPrinter::toString(inst);
IPF_LOG << ( tmpl==0x02 || tmpl==0x03 ? " ;;" : "")
<< "\n";
inst = getSlot(2);
IPF_LOG << IrPrinter::toString(inst);
IPF_LOG << ( tmpl%2==1 ? " ;;" : "")
<< "\n";
}
//============================================================================//
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#ifndef _REENTRANT
#define _REENTRANT
#endif
#include <signal.h>
#include <errno.h>
#include <ucontext.h>
void sighandler(int sn, siginfo_t *si, void *_sc) {
struct sigaction signal_action;
struct ucontext * signal_ucontext;
int saved_errno = errno;
if (sn==SIGILL && si->si_code==ILL_BREAK && si->si_imm==INST_BREAKPOINT_IMM_VALUE) {
signal_ucontext = (struct ucontext *)_sc;
if ( (signal_ucontext->_u._mc.sc_ip & 0x03)==2 ) {
signal_ucontext->_u._mc.sc_ip = (signal_ucontext->_u._mc.sc_ip & ~0x03) + 0x10;
} else {
signal_ucontext->_u._mc.sc_ip++;
}
//printf("-- sighandler() for signal %d, si_code %d, si_imm %x\n", sn, si->si_code, si->si_imm);
signal_action.sa_flags = SA_SIGINFO;
signal_action.sa_sigaction = sighandler;
if (sigaction(SIGILL, &signal_action, NULL)) {
printf("Sigaction returned error = %d\n", errno);
}
}
errno = saved_errno;
return;
}
//============================================================================//
EmitterBb::EmitterBb(Cfg & cfg, CompilationInterface & compilationinterface
, BbNode * node_, bool _break4cafe, bool _nop4cafe) :
node(node_),
insts(node->getInsts())
{
MemoryManager& mm=cfg.getMM();
OpndManager * opndManager = cfg.getOpndManager();
Opnd * p0 = opndManager->getP0();
isize=insts.size();
stops=new(mm) vectorbool(isize);
wregs=new(mm) vectorregs(isize);
rregs=new(mm) vectorregs(isize);
bundles=new(mm) BundleVector(cfg);
consts=new(mm) vectorconst;
bsize=0;
if (!_break4cafe) {
if (_nop4cafe) {
bundles->addBundle(0x01
, new(mm) Inst(mm, INST_NOP, p0, IMM(INST_BREAKPOINT_IMM_VALUE))
, new(mm) Inst(mm, INST_NOP, p0, IMM(INST_BREAKPOINT_IMM_VALUE))
, new(mm) Inst(mm, INST_NOP, p0, IMM(INST_BREAKPOINT_IMM_VALUE)));
}
} else {
struct sigaction signal_action;
signal_action.sa_flags = SA_SIGINFO;
signal_action.sa_sigaction = sighandler;
if (sigaction(SIGILL, &signal_action, NULL)) {
printf("Sigaction returned error = %d\n", errno);
}
bundles->addBundle(0x01
, new(mm) Inst(mm, INST_NOP, p0, IMM(INST_BREAKPOINT_IMM_VALUE))
, new(mm) Inst(mm, INST_BREAK, p0, IMM(INST_BREAKPOINT_IMM_VALUE))
, new(mm) Inst(mm, INST_NOP, p0, IMM(INST_BREAKPOINT_IMM_VALUE)));
}
};
//============================================================================//
Emitter::Emitter(Cfg & cfg_, CompilationInterface & compilationinterface_, bool _break4cafe) :
mm(cfg_.getMM()),
cfg(cfg_),
compilationinterface(compilationinterface_)
{
removeUselessInst(cfg, compilationinterface);
removeIgnoreTypeInst(cfg, compilationinterface);
(new(mm) IpfVerifier(cfg, compilationinterface))->verifyMethod();
bbs = new(mm) vectorbb;
BbNode * node = (BbNode *)cfg.getEnterNode();
EmitterBb * bbdesc;
bool break4cafe = _break4cafe;
bool nop4cafe = false;
do {
bbdesc = new(mm) EmitterBb(cfg, compilationinterface, node, break4cafe, nop4cafe);
bbs->push_back(bbdesc);
break4cafe = false;
nop4cafe = false;
} while( (node = node->getLayoutSucc()) != NULL );
};
//============================================================================//
int Emitter::removeUselessInst(Cfg & cfg, CompilationInterface & compilationinterface) {
BbNode * node = (BbNode *)cfg.getEnterNode();
int methoduseless = 0;
int methodafter = 0;
do {
InstVector &insts = node->getInsts();
int i;
for( i=0 ; i < (int)insts.size() ; ) {
Inst *inst = insts[i];
InstCode icode = inst->getInstCode();
OpndVector &opnds = inst->getOpnds();
if (icode==INST_MOV) {
if (inst->getNumOpnd()==3) {
if (((opnds[1]->isGReg() && opnds[2]->isGReg()) || (opnds[1]->isFReg() && opnds[2]->isFReg()))
&& opnds[1]->getValue()==opnds[2]->getValue()) {
IPF_LOG << "USELESS: " << IrPrinter::toString(inst) << "\n";
insts.erase(insts.begin() + i);
methoduseless++;
continue;
}
}
}
if (icode==INST_ADD || icode==INST_ADDS || icode==INST_ADDL) {
if (inst->getNumOpnd()==4) {
if (opnds[2]->getValue()==0
&& opnds[1]->getValue()==opnds[3]->getValue()) {
IPF_LOG << "USELESS: " << IrPrinter::toString(inst) << "\n";
insts.erase(insts.begin() + i);
methoduseless++;
continue;
}
}
}
i++;
}
methodafter += i;
} while( (node = node->getLayoutSucc()) != NULL );
/* statistical data */
if (0 && (methoduseless > 0)) {
static int alluseless = 0;
static int allafter = 0;
alluseless += methoduseless;
allafter += methodafter;
if (methoduseless > 0) {
IPF_LOG << "USELESS: method: " << methoduseless
<< "(" << (((float)methoduseless)/(methoduseless + methodafter))*100 << "%) instructions\n";
IPF_LOG << "USELESS: all: " << alluseless
<< "(" << (((float)alluseless)/(alluseless + allafter))*100 << "%) instructions\n";
}
}
if (methoduseless > 0) {
IPF_LOG << "USELESS: removed " << methoduseless
<< "(" << (((float)methoduseless)/(methoduseless + methodafter) * 100) << "%) instructions\n";
}
return methoduseless;
}
//============================================================================//
int Emitter::removeIgnoreTypeInst(Cfg & cfg, CompilationInterface & compilationinterface) {
BbNode * node = (BbNode *)cfg.getEnterNode();
int ignoredcc = 0, i = 0;
do {
InstVector &insts = node->getInsts();
for( i=0 ; i < (int)insts.size() ; ) {
Inst *inst = insts[i];
if (Encoder::isIgnoreInst(inst)) {
IPF_LOG << "IGNORED: " << IrPrinter::toString(inst) << "\n";
insts.erase(insts.begin() + i);
continue;
}
i++;
}
} while( (node = node->getLayoutSucc()) != NULL );
if (ignoredcc>0 && i>0) {
IPF_LOG << "IGNORED: removed " << ignoredcc
<< "(" << (((float)ignoredcc)/(ignoredcc + i) * 100) << "%) instructions\n";
}
return ignoredcc;
}
//============================================================================//
InstructionType Emitter::getExecUnitType(int templateindex, int slotindex) {
return (InstructionType)((Bundle::BundleDesc[templateindex].slots >> (slotindex * 8)) & 0xFF);
}
//============================================================================//
void Emitter::getTmpl(int bbindex, BundleDescription & tmp, Inst *i0, Inst *i1, Inst *i2, bool s0, bool s1, bool s2) {
if(i0!=NULL) {
tmp.slots = IT_SLOT0(Encoder::getInstType(i0));
} else {
tmp.slots = IT_SLOT0(IT_ANY);
}
tmp.stops = (s0 ? 1 : 0);
if(i1!=NULL) {
tmp.slots |= IT_SLOT1(Encoder::getInstType(i1));
} else {
tmp.slots |= IT_SLOT1(IT_ANY);
}
tmp.stops |= (s1 ? 2 : 0);
if( i2!=NULL ) {
tmp.slots |= IT_SLOT2(Encoder::getInstType(i2));
} else {
tmp.slots |= IT_SLOT2(IT_ANY);
}
tmp.stops |= (s2 ? 4 : 0);
}
int Emitter::findTmpl(const BundleDescription & tmp) {
for( int j=0 ; j<TEMPLATES_COUNT ; j++ ) {
if( (Bundle::BundleDesc[j].slots & tmp.slots)==Bundle::BundleDesc[j].slots
&& (Bundle::BundleDesc[j].stops == tmp.stops) ) {
return j;
}
}
return -1;
}
//============================================================================//
void Emitter::getWriteDpndBitset(Inst * inst, RegistersBitset * regs)
{
OpndVector & opnds = inst->getOpnds();
if(opnds.size() <= 1) return;
U_32 dstcount=inst->getNumDst();
Opnd *opnd;
for( U_32 i=0 ; i<dstcount ; i++ ) {
opnd = opnds[i+1];
switch (opnd->getOpndKind()) {
case OPND_G_REG:
regs->GR.set(opnd->getValue());
break;
case OPND_F_REG:
regs->FR.set(opnd->getValue());
break;
case OPND_P_REG:
regs->PR.set(opnd->getValue());
break;
case OPND_B_REG:
regs->BR.set(opnd->getValue());
break;
default:
break;
}
}
}
//============================================================================//
void Emitter::getReadDpndBitset(Inst * inst, RegistersBitset * regs)
{
OpndVector & opnds = inst->getOpnds();
if(opnds.size() <= 1) return;
U_32 dstcount=inst->getNumDst();
U_32 opndcount=inst->getNumOpnd();
Opnd *opnd;
for( U_32 i=1+dstcount ; i<opndcount ; i++ ) {
opnd = opnds[i];
switch (opnd->getOpndKind()) {
case OPND_G_REG:
regs->GR.set(opnd->getValue());
break;
case OPND_F_REG:
regs->FR.set(opnd->getValue());
break;
case OPND_P_REG:
regs->PR.set(opnd->getValue());
break;
case OPND_B_REG:
regs->BR.set(opnd->getValue());
break;
default:
break;
}
}
int p=opnds[0]->getValue();
if( p ) {
regs->PR.set(p);
}
}
//============================================================================//
bool Emitter::tricking(InstVector & insts, MemoryManager& mm, Cfg& cfg) {
RegistersBitset * regs;
Inst *inst;
for( int i=0 ; i < (int)insts.size() ; i++ ) {
inst = insts[i];
// regs masks
regs = new(mm) RegistersBitset();
getWriteDpndBitset(inst, regs);
if (regs->GR.test(33)) {
OpndManager * opndManager = cfg.getOpndManager();
insts.insert(insts.begin() + i
, new(mm) Inst(mm, INST_BREAK, opndManager->getP0(), opndManager->newImm(INST_BREAKPOINT_IMM_VALUE)));
i++;
}
}
return true;
}
//============================================================================//
bool Emitter::parsing() {
bool ret = true;
datasize = 0;
for (int bbindex=0, bbssize=(int)bbs->size() ; bbindex<bbssize ; bbindex++) {
ret &= parsing(bbindex);
}
return ret;
}
bool Emitter::parsing(int bbindex) {
EmitterBb * bb = bbs->at(bbindex);
InstVector & insts = bb->insts;
vectorregs * wr = bb->wregs;
vectorregs * rr = bb->rregs;
Inst *inst;
RegistersBitset * regs;
U_32 dstcount;
U_32 opndcount;
Opnd * opnd;
vectorconst * consts = bb->consts;
Constant * constant;
for( int i=0 ; i < (int)insts.size() ; i++ ) {
inst = insts[i];
InstCode instCode = inst->getInstCode();
OpndVector & opnds = inst->getOpnds();
if (instCode==INST_BR13 || instCode==INST_BRL13) {
instCode = (instCode == INST_BR13 ? INST_BR : INST_BRL);
}
// if inst is branch and target is DATA_NODE_REF
// set istarget flag for target bb
if (instCode==INST_BR || instCode==INST_BRL) {
int is13 = (instCode==INST_BRL13 || instCode==INST_BR13 ? 1 : 0); // must be 1 or 0
opnd = opnds[is13 + 1];
if (opnd->getDataKind() == DATA_NODE_REF) {
int targetind = getBbNodeIndex(((NodeRef*) opnd)->getNode());
bbs->at(targetind)->istarget=true;
}
}
// regs masks
regs = new(mm) RegistersBitset();
getWriteDpndBitset(inst, regs);
wr->at(i) = regs;
regs = new(mm) RegistersBitset();
getReadDpndBitset(inst, regs);
rr->at(i) = regs;
// constants
dstcount=inst->getNumDst();
opndcount=inst->getNumOpnd();
for( U_32 j=1 ; j<opndcount ; j++ ) {
opnd = opnds[j];
if (opnd->isImm()) {
if ( opnd->getDataKind() == DATA_CONST_REF) {
constant = ((ConstantRef *)opnd)->getConstant();
consts->push_back(opnd);
datasize += constant->getSize();
} else if ( opnd->getDataKind() == DATA_SWITCH_REF) {
constant = ((ConstantRef *)opnd)->getConstant();
consts->push_back(opnd);
datasize += ((SwitchConstant *)constant)->getSize();
}
}
}
}
return true;
}
//============================================================================//
bool Emitter::stopping() {
bool ret = true;
for (int bbindex=0 ; bbindex<(int)bbs->size() ; bbindex++) {
ret &= stopping(bbindex);
}
return ret;
}
bool Emitter::stopping(int bbindex) {
EmitterBb * bb = bbs->at(bbindex);
InstVector & insts = bb->insts;
long sizebb = insts.size();
if (sizebb==0) return true;
vectorbool * stops = bb->stops;
vectorregs * wr = bb->wregs;
vectorregs * rr = bb->rregs;
Inst *inst1, *inst2;
InstCode icode1, icode2;
RegistersBitset * regs1w, * regs2w, * regs2r;
long start, stop, hardstop;
for( start=0, stop=sizebb ; start < (sizebb - 1) ; ) {
hardstop = -1;
for (long i = start; i < (stop-1) ; i++) {
inst1 = insts[i];
icode1 = inst1->getInstCode();
if (icode1==INST_BRL || icode1==INST_BRL13) {
hardstop=i;
break;
} else if (icode1 == INST_ALLOC) {
if (i>0) stops->at(i-1) = true;
}
if (Encoder::isIgnoreInst(inst1)) continue;
if (icode1 >= INST_ST_FIRST && icode1 <= INST_ST_LAST) continue;
regs1w = wr->at(i);
if(!regs1w->any()) continue;
for (long j = i + 1; j < stop; j++) {
inst2 = insts[j];
icode2 = inst2->getInstCode();
if (icode2 == INST_ALLOC) {
if (j>0) stops->at(j-1) = true;
}
if (Encoder::isIgnoreInst(inst2)) continue;
regs2w = wr->at(j);
regs2r = rr->at(j);
if(!regs2w->any() && !regs2r->any()) continue;
if (Encoder::isBranchInst(inst2)) {
if( (Encoder::getInstType(icode1) & IT_F)
&& (regs1w->PR & (regs2w->PR | regs2r->PR)).any() ) {
stop=j;
break;
}
continue;
}
if( (regs1w->GR & (regs2w->GR | regs2r->GR)).any()
|| (regs1w->FR & (regs2w->FR | regs2r->FR)).any()
|| (regs1w->PR & (regs2w->PR | regs2r->PR)).any()
|| (regs1w->BR & (regs2w->BR | regs2r->BR)).any() ) {
stop=j;
break;
}
}
}
if (hardstop>=0) {
stops->at(hardstop) = true;
start=hardstop+1;
stop=sizebb;
} else if( stop==sizebb ) {
start++;
} else {
stops->at(stop-1) = true;
start=stop;
stop=sizebb;
}
}
stops->at(stops->size()-1) = true;
return true;
}
//============================================================================//
bool Emitter::bundling() {
EmitterBb * bb;
char * off=0;
bool ret = true;
for (int bbindex=0 ; bbindex<(int)bbs->size() ; bbindex++) {
ret &= bundling(bbindex);
bb = bbs->at(bbindex);
bb->bsize = bb->bundles->size();
bb->codeoff = off;
bb->codesize = bb->bsize * IPF_BUNDLE_SIZE;
// align bb if istarget==true
if (false && bb->istarget) { // switch off aligning
uint16 bytes4align = (bb->codesize % IPF_CODE_ALIGNMENT) == 0
? 0
: IPF_CODE_ALIGNMENT - (bb->codesize % IPF_CODE_ALIGNMENT);
if (bytes4align>0 && (bytes4align%IPF_BUNDLE_SIZE)==0) {
bb->codesize += bytes4align;
uint16 bundles4align = bytes4align/IPF_BUNDLE_SIZE;
OpndManager * opndManager = cfg.getOpndManager();
Opnd * p0 = opndManager->getP0();
for (uint16 i=0 ; i<bundles4align ; i++) {
bb->bundles->addBundle(0x00
, new(mm) Inst(mm, INST_NOP, p0, IMM(INST_BREAKPOINT_IMM_VALUE))
, new(mm) Inst(mm, INST_NOP, p0, IMM(INST_BREAKPOINT_IMM_VALUE))
, new(mm) Inst(mm, INST_NOP, p0, IMM(INST_BREAKPOINT_IMM_VALUE)));
}
}
}
off = (char *)off + bb->codesize;
}
codesize = (long)((char *)off);
return ret;
}
bool Emitter::bundling(int bbindex) {
EmitterBb * bb = bbs->at(bbindex);
InstVector & insts = bb->insts;
long sizebb = insts.size();
if (sizebb==0) return true;
vectorbool * stops = bb->stops;
BundleVector * bundles = bb->bundles;
BundleDescription tmp = {0,0,0};
int iTmpl=-1;
Inst *inst0=NULL, *inst1=NULL, *inst2=NULL, *inst3=NULL;
bool stop0=false, stop1=false, stop2=false, stop3=false;
bool stop0_f=false, stop1_f=false, stop2_f=false, stop3_f=false; // inst is first in group
bool stop0_l=false, stop1_l=false, stop2_l=false; // inst is last in group
int it0=0, it1=0, it2=0, it3=0; // insts type
long i0, i1, i2, i3;
for ( i0=0 ; i0 < sizebb ; ) {
inst0=Encoder::resolvePseudo(cfg, insts[i0]);
if (Encoder::isIgnoreInst(inst0)) { i0++; continue; }
stop0=stops->at(i0);
for ( i1=i0+1 ; i1<sizebb ; ) {
inst1=Encoder::resolvePseudo(cfg, insts[i1]);
if (Encoder::isIgnoreInst(inst1)) { i1++; continue; }
stop1=stops->at(i1);
break;
}
if ( i1 >= sizebb ) { inst1=NULL; }
for ( i2=i1+1 ; i2<sizebb ; ) {
inst2=Encoder::resolvePseudo(cfg, insts[i2]);
if (Encoder::isIgnoreInst(inst2)) { i2++; continue; }
stop2=stops->at(i2);
break;
}
if ( i2 >= sizebb ) { inst2=NULL; }
for ( i3=i2+1 ; i3<sizebb ; ) {
inst3=Encoder::resolvePseudo(cfg, insts[i3]);
if (Encoder::isIgnoreInst(inst3)) { i3++; continue; }
stop3=stops->at(i3);
break;
}
if ( i3 >= sizebb ) { inst3=NULL; }
it0 = Encoder::getInstType(inst0);
it1 = Encoder::getInstType(inst1);
it2 = Encoder::getInstType(inst2);
it3 = Encoder::getInstType(inst3);
stop0_l = (it0 & IT_GL)==IT_GL;
stop1_l = (it1 & IT_GL)==IT_GL;
stop2_l = (it2 & IT_GL)==IT_GL;
stop0_f = (it0 & IT_GF)==IT_GF;
stop1_f = (it1 & IT_GF)==IT_GF;
stop2_f = (it2 & IT_GF)==IT_GF;
stop3_f = (it3 & IT_GF)==IT_GF;
/*********************************************
* Special case for br.call
* br.ret will return to next bundle, so
* all instructions after br.call must be nop
*********************************************/
if (inst0->getInstCode()==INST_BR || inst0->getInstCode()==INST_BR13) {
CompVector & cmpls0 = inst0->getComps();
if (cmpls0.size()>0 && cmpls0[0]==CMPLT_BTYPE_CALL) {
inst1=NULL;
inst2=NULL;
}
} else if (inst1!=NULL && (inst1->getInstCode()==INST_BR || inst1->getInstCode()==INST_BR13)) {
CompVector & cmpls1 = inst1->getComps();
if (cmpls1.size()>0 && cmpls1[0]==CMPLT_BTYPE_CALL) {
inst2=NULL;
}
}
/*********************************************
* Special case for inst0==LX type (brl,...)
*********************************************/
if ( Encoder::getInstType(inst0->getInstCode()) & IT_L ) {
inst1=NULL;
inst2=NULL;
getTmpl(bbindex, tmp, NULL, inst0, NULL
, false, false, stop0 || stop0_l || stop1_f);
iTmpl=findTmpl(tmp);
if( iTmpl>=0 ) {
bundles->addBundle(iTmpl, NULL, inst0, NULL);
i0 += 1;
continue;
}
IPF_ERR << "BUNDLING ERROR: CAN'T FIND TEMPLATE !\n";
IPF_ERR << "BUNDLING ERROR: " << IrPrinter::toString(inst0) << "\n";
IPF_ASSERT(0);
}
/********************************
* Special case for inst1==LX type (brl,...)
********************************/
if (inst1!=NULL && (Encoder::getInstType(inst1->getInstCode()) & IT_L)) {
inst2=NULL;
getTmpl(bbindex, tmp, inst0, inst1, NULL
, stop0 || stop0_l || stop1_f, false, stop1 || stop1_l || stop2_f);
iTmpl=findTmpl(tmp);
if( iTmpl>=0 ) {
bundles->addBundle(iTmpl, inst0, inst1, NULL);
i0 = i1 + 1;
continue;
}
inst1=NULL;
}
/********************************
* inst1!=NULL && inst2!=NULL
********************************/
if (inst1!=NULL && inst2!=NULL) {
getTmpl(bbindex, tmp, inst0, inst1, inst2
, stop0 || stop0_l || stop1_f, stop1 || stop1_l || stop2_f, stop2 || stop2_l || stop3_f);
iTmpl=findTmpl(tmp);
if( iTmpl>=0 ) {
bundles->addBundle(iTmpl, inst0, inst1, inst2);
i0 = i2 + 1;
continue;
}
}
/********************************
* inst2==NULL && inst1!=LX type (brl,...)
********************************/
if (inst1!=NULL) {
getTmpl(bbindex, tmp, inst0, inst1, NULL
, stop0 || stop0_l || stop1_f, stop1 || stop1_l || stop2_f, false);
iTmpl=findTmpl(tmp);
if( iTmpl>=0 ) {
bundles->addBundle(iTmpl, inst0, inst1, NULL);
i0 = i1 + 1;
continue;
}
getTmpl(bbindex, tmp, inst0, inst1, NULL
, stop0 || stop0_l || stop1_f, false, stop1 || stop1_l || stop2_f);
iTmpl=findTmpl(tmp);
if( iTmpl>=0 ) {
bundles->addBundle(iTmpl, inst0, inst1, NULL);
i0 = i1 + 1;
continue;
}
getTmpl(bbindex, tmp, inst0, NULL, inst1
, stop0 || stop0_l || stop1_f, false, stop1 || stop1_l || stop2_f);
iTmpl=findTmpl(tmp);
if( iTmpl>=0 ) {
bundles->addBundle(iTmpl, inst0, NULL, inst1);
i0 = i1 + 1;
continue;
}
getTmpl(bbindex, tmp, inst0, NULL, inst1
, false, stop0 || stop0_l || stop1_f, stop1 || stop1_l || stop2_f);
iTmpl=findTmpl(tmp);
if( iTmpl>=0 ) {
bundles->addBundle(iTmpl, inst0, NULL, inst1);
i0 = i1 + 1;
continue;
}
getTmpl(bbindex, tmp, NULL, inst0, inst1
, false, stop0 || stop0_l || stop1_f, stop1 || stop1_l || stop2_f);
iTmpl=findTmpl(tmp);
if( iTmpl>=0 ) {
bundles->addBundle(iTmpl, NULL,inst0, inst1);
i0 = i1 + 1;
continue;
}
}
/********************************
* inst1==NULL
********************************/
getTmpl(bbindex, tmp, inst0, NULL, NULL
, stop0 || stop0_l || stop1_f, false, false);
iTmpl=findTmpl(tmp);
if( iTmpl>=0 ) {
bundles->addBundle(iTmpl, inst0, NULL, NULL);
i0 += 1;
continue;
}
getTmpl(bbindex, tmp, inst0, NULL, NULL
, false, stop0 || stop0_l || stop1_f, false);
iTmpl=findTmpl(tmp);
if( iTmpl>=0 ) {
bundles->addBundle(iTmpl, inst0, NULL, NULL);
i0 += 1;
continue;
}
getTmpl(bbindex, tmp, inst0, NULL, NULL
, false, false, stop0 || stop0_l || stop1_f);
iTmpl=findTmpl(tmp);
if( iTmpl>=0 ) {
bundles->addBundle(iTmpl, inst0, NULL, NULL);
i0 += 1;
continue;
}
getTmpl(bbindex, tmp, NULL, inst0, NULL
, false, stop0 || stop0_l || stop1_f, false);
iTmpl=findTmpl(tmp);
if( iTmpl>=0 ) {
bundles->addBundle(iTmpl, NULL, inst0, NULL);
i0 += 1;
continue;
}
getTmpl(bbindex, tmp, NULL, inst0, NULL
, false, false, stop0 || stop0_l || stop1_f);
iTmpl=findTmpl(tmp);
if( iTmpl>=0 ) {
bundles->addBundle(iTmpl, NULL, inst0, NULL);
i0 += 1;
continue;
}
getTmpl(bbindex, tmp, NULL, NULL, inst0
, false, false, stop0 || stop0_l || stop1_f);
iTmpl=findTmpl(tmp);
if( iTmpl>=0 ) {
bundles->addBundle(iTmpl, NULL, NULL, inst0);
i0 += 1;
continue;
}
IPF_ERR << "ERROR: CAN'T FIND TEMPLATE !!!\n";
IPF_ASSERT(0);
i0++;
}
return true;
}
//============================================================================//
bool Emitter::emitData() {
if (datasize==0) return true;
bool ret = true;
EmitterBb * bb;
char * p;
Opnd * opnd;
dataoff = (char *)compilationinterface.allocateDataBlock(datasize
, L2_CACHE_LINE_SIZE);
assert(dataoff != NULL);
if ( dataoff == NULL ) return false;
p = dataoff;
for (int bbindex=0 ; bbindex<(int)bbs->size() ; bbindex++) {
bb = bbs->at(bbindex);
for ( int i=0, ii=bb->consts->size() ; i < ii ; i++ ) {
opnd = bb->consts->at(i);
if (opnd->isImm()) {
if ( opnd->getDataKind() == DATA_CONST_REF) {
Constant * c;
c = ((ConstantRef *)opnd)->getConstant();
switch (c->getDataKind()) {
case DATA_I64:
*((int64 *)p) = ((Int64Constant *)c)->getValue();
c->setAddress(p);
p += sizeof(int64);
break;
case DATA_S:
*((float *)p) = ((FloatConstant *)c)->getValue();
c->setAddress(p);
p += sizeof(float);
break;
case DATA_D:
*((double *)p) = ((DoubleConstant *)c)->getValue();
c->setAddress(p);
p += sizeof(double);
break;
default:
IPF_ERR << "DATA UNKNOWN\n";
break;
}
} else if ( opnd->getDataKind() == DATA_SWITCH_REF) {
SwitchConstant * c;
c = (SwitchConstant *)((ConstantRef *)opnd)->getConstant();
*((uint64 *)p) = (uint64)opnd; // need to fill with actual
// values of node's addresses
// after code emitting!
c->setAddress(p);
p += c->getSize();
}
} else {
IPF_LOG << "DATA UNKNOWN\n";
assert(0);
}
}
}
return ret;
}
//============================================================================//
bool Emitter::fixSwitchTables() {
if ( datasize==0 ) return true;
if ( dataoff == NULL ) return true;
bool ret = true;
EmitterBb * bb;
void * p;
Opnd * opnd;
SwitchConstant * c;
Node * node;
Edge * edge;
for (int bbindex=0 ; bbindex<(int)bbs->size() ; bbindex++) {
bb = bbs->at(bbindex);
for ( int i=0, ii=bb->consts->size() ; i < ii ; i++ ) {
opnd = bb->consts->at(i);
if (opnd->isImm() && opnd->getDataKind()==DATA_SWITCH_REF) {
c = (SwitchConstant *)((ConstantRef *)opnd)->getConstant();
p = c->getAddress();
for (int j=0, jj=c->getChoiceCount() ; j<jj ; j++) {
edge = c->getEdge(j);
node = edge->getTarget();
*((uint64 *)p) = (uint64)(codeoff + (int64)getBbNodeOff((BbNode *)node));
p = (uint64 *)p +1;
}
}
}
}
return ret;
}
//============================================================================//
bool Emitter::emitCode() {
EmitterBb *bb;
BundleVector * bundles;
Bundle * bundle;
int target[3];
char *bboff = 0;
char *off = 0;
Inst *inst;
codeoff = (char *)compilationinterface.allocateCodeBlock(
codesize, IPF_CODE_ALIGNMENT, CodeBlockHeatDefault, 0, false);
assert(codeoff != NULL);
IPF_LOG << endl;
if ( codeoff ) {
off=codeoff;
for (int bbindex=0 ; bbindex<(int)bbs->size() ; bbindex++) {
bb = bbs->at(bbindex);
// sa
bb->node->setAddress((uint64)off);
bboff = off;
bundles = bb->bundles;
for(int i=0, ii=(int)bundles->size() ; i<ii ; i++ ) {
bundle = bundles->at(i);
for (U_32 si=0 ; si < IPF_SLOTS_COUNT ; si++) {
inst = bundle->getSlot(si);
inst->setAddr((U_32)(off - bboff) + si);
}
if ( isBranchBundle(bundle, codeoff, off, target) ) {
// bundle contains B type inst
bundle->emitBundleBranch(off, target);
} else if ( isExtendedBundle(bundle) ) {
// bundle contains L+X type inst
bundle->emitBundleExtended(off);
inst = bundle->getSlot(1);
InstCode icode = inst->getInstCode();
unsigned int is13 = (icode==INST_BRL13 ? 1 : 0); // must be 1 or 0
if ((icode==INST_BRL || icode==INST_BRL13)
&& (inst->getComps())[0]==CMPLT_BTYPE_CALL
&& (inst->getOpnds()[is13 + 2])->getDataKind()==DATA_METHOD_REF) {
if (((((uint64)off) | (((uint64)0x4cafe) << 32)) & ~((uint64)0x4cafe << 32))==(uint64)off) {
registerDirectCall(inst, ((uint64)off) | (((uint64)0x4cafe) << 32));
} else {
IPF_ERR << "\n";
assert(0);
}
}
} else {
bundle->emitBundleGeneral(off);
}
off = off + IPF_BUNDLE_SIZE;
}
}
IPF_LOG << "END code emitting: "
<< compilationinterface.getMethodToCompile()->getParentType()->getName()
<< "." << compilationinterface.getMethodToCompile()->getName()
<< compilationinterface.getMethodToCompile()->getSignatureString()
<< endl;
return true;
}
return false;
}
bool Emitter::isBranchBundle(Bundle * bundle, char * baseoff, char * bundleoff, int * branchtargets) {
bool ret = false;
if ( bundle->getTmpl() > 15 ) {
Inst * inst;
Opnd * opnd;
InstCode icode;
unsigned int is13; // must be 1 or 0
for (int i=0 ; i<IPF_SLOTS_COUNT ; i++ ) {
branchtargets[i] = 0;
inst = bundle->getSlot(i);
if(Encoder::isBranchInst(inst)) {
icode = inst->getInstCode();
is13 = (icode==INST_BRL13 || icode==INST_BR13 ? 1 : 0); // must be 1 or 0
ret = true;
opnd = inst->getOpnd(is13 + 1);
if (opnd->getDataKind() == DATA_NODE_REF) {
branchtargets[i] = (long)getBbNodeOff(((NodeRef*) opnd)->getNode()) - (long)(bundleoff - baseoff);
}
}
}
}
return ret;
}
char * Emitter::getBbNodeOff(BbNode * node) {
for (int i=0 ; i<(int)bbs->size() ; i++) {
if (bbs->at(i)->node == node) {
return bbs->at(i)->codeoff;
}
}
return (char *)-1;
}
int Emitter::getBbNodeIndex(BbNode * node) {
for (int i=0 ; i<(int)bbs->size() ; i++) {
if (bbs->at(i)->node == node) {
return i;
}
}
return -1;
}
bool Emitter::emit() {
bool ret = true;
// 0 pass: parsing insts
// - clear ignored insts
// - define registers read/write masks
// - create vector of constants
// - create vector of brunches
ret &= parsing();
if (!ret) { IPF_ERR << "Bad results for parsing\n"; return ret; }
// 1 pass: emit data
ret &= emitData();
if (!ret) { IPF_ERR << "Bad results for emitData\n"; return ret; }
// 2 pass: define stops
ret &= stopping();
if (!ret) { IPF_ERR << "Bad results for stopping\n"; return ret; }
// 3 pass: bundling instructions (also saving indexes of bundles with branch insts)
ret &= bundling();
if (!ret) { IPF_ERR << "Bad results for bundling\n"; return ret; }
// 4 pass: emits bundles
ret &= emitCode();
if (!ret) { IPF_ERR << "Bad results for emitCode\n"; return ret; }
// 5 pass: fix switch tables
ret &= fixSwitchTables();
if (!ret) { IPF_ERR << "Bad results for fixSwitchTables\n"; return ret; }
// checkForDualIssueBundles();
if (LOG_ON) {
printInsts(" Result of stopping() ");
printBundles(" Result of bundling() ");
printCodeBlock(" Result of emitting() ");
printDisasm(" Result of emitting(disasm) ");
}
return ret;
}
void Emitter::printBundles(char * cap) {
if (LOG_ON) {
IPF_LOG << "-----------" << cap << "-----------------------------\n";
for (int i=0 ; i<(int)bbs->size() ; i++) {
printBundles(i);
}
IPF_LOG << "\n";
}
}
void Emitter::printBundles(int bbindex) {
BundleVector * bundles = bbs->at(bbindex)->bundles;
Bundle * bndl;
IPF_LOG << ".L" << bbs->at(bbindex)->node->getId()
<< " (0x" << hex << bbs->at(bbindex)->node->getAddress() << dec << ")\n";
for (long i = 0, ii=bundles->size() ; i < ii ; i++) {
bndl = bundles->at(i);
if( bndl==NULL ) {
IPF_LOG << i;
IPF_LOG << " \tNULL\n"
<< " \tNULL\n"
<< " \tNULL\n";
IPF_LOG << "\n";
} else {
IPF_LOG << i;
bndl->print();
IPF_LOG << "\n";
}
}
}
void Emitter::printInsts(char *cap) {
IPF_LOG << "\n-----------" << cap << "-----------------------------\n";
for (int i=0 ; i<(int)bbs->size() ; i++) {
printInsts(i);
}
IPF_LOG << "\n";
}
void Emitter::printInsts(int bbindex) {
InstVector & insts = bbs->at(bbindex)->insts;
vectorbool * stops = bbs->at(bbindex)->stops;
Inst *inst;
IPF_LOG << ".L" << bbs->at(bbindex)->node->getId() << "\n";
for (U_32 i = 0, ii=insts.size() ; i < ii ; i++) {
inst = insts[i];
if( inst==NULL ) {
IPF_LOG << IrPrinter::toString(inst);
} else {
IPF_LOG << IrPrinter::toString(inst);
IPF_LOG << (stops->at(i) ? " ;;" : "");
}
IPF_LOG << "\n";
}
}
void Emitter::printCodeBlock(char * cap) {
char printbuf[256];
char * off = codeoff;
uint64 * p, tmpl, i0, i1, i2;
IPF_LOG << "\n-----------" << cap << "-----------------------------\n";
sprintf(printbuf, "%-11.11s %-11.11s %-11.11s %-8.8s\n", "slot2", "slot1", "slot0", "template");
IPF_LOG << printbuf;
for(int i=0 ; i<codesize; i += IPF_BUNDLE_SIZE) {
p = (uint64 *)off;
tmpl = p[0] & 0x1F;
i0 = (p[0] & 0x3FFFFFFFFFE0) >> 5;
i1 = (((p[0] & ~0x1F) & ~0x3FFFFFFFFFE0) >> 46) | ((p[1] & 0x7FFFFF) << 18);
i2 = (p[1] & ~0x7FFFFF) >> 23;
sprintf(printbuf, "%11.11llx %11.11llx %11.11llx %2.2x \n", i2, i1, i0, (unsigned)tmpl);
IPF_LOG << printbuf;
off += IPF_BUNDLE_SIZE;
}
IPF_LOG << "---------------------------------------------------\n";
}
void Emitter::registerDirectCall(Inst * inst, uint64 data)
{
InstCode icode = inst->getInstCode();
unsigned int is13 = (icode==INST_BRL13 ? 1 : 0); // must be 1 or 0
assert((icode==INST_BRL || icode==INST_BRL13)
&& (inst->getComps())[0]==CMPLT_BTYPE_CALL);
Opnd * target = (inst->getOpnds())[is13 + 2];
assert(target->isImm() && target->getDataKind()==DATA_METHOD_REF);
MethodDesc * method = ((MethodRef *)target)->getMethod();
compilationinterface.setNotifyWhenMethodIsRecompiled(method, (void *)data);
if (LOG_ON) {
IPF_LOG << "Registered call to " << method->getParentType()->getName()
<< "." << method->getName()
<< " : data=0x" << hex << data << dec
<< " for recompiled method event" << endl;
}
}
#include <dlfcn.h>
#include <libgen.h>
void Emitter::printDisasm(char * cap) {
static bool load_done = false;
static unsigned (*disasm)(const char *, char *, unsigned) = NULL;
if (!load_done) {
char buf[PATH_MAX+1];
// Resolve full path to module
string sz("");
int len = 0;
len = readlink("/proc/self/exe", buf, sizeof(buf)-1);
if (len < 0) {
buf[0]='.';
buf[1]='/';
buf[2]='\0';
} else {
buf[len] = 0;
}
char * slash = strrchr(buf, '/');
if (slash) {
*(slash) = '\0';
}
sz.append(buf);
sz.append("/libdisasm.so");
std::cout << "Loading `" << sz << "'...";
char * path = strdup(sz.c_str());
void * handle = dlopen(path, RTLD_NOW);
free(path);
disasm = (unsigned (*)(const char *, char *, unsigned))
(handle == NULL ? NULL : dlsym(handle, "disasm"));
load_done = true;
if (disasm==NULL) {
std::cout << "CAN'T LOAD" << std::endl;
return;
} else {
std::cout << "OK" << std::endl;
}
}
if (disasm==NULL) {
return;
}
string str("");
char buf[100];
char * off = codeoff;
for (unsigned i=0 ; i<codesize ; off=codeoff+i) {
unsigned l = disasm((const char*)off, buf, sizeof(buf)-1);
for (int bbindex=0 ; bbindex<(int)bbs->size() ; bbindex++) {
EmitterBb *bb = bbs->at(bbindex);
char * bboff = (char *)bb->node->getAddress();
if (bboff==off) {
char bbid[64];
sprintf(bbid, "%i (%p)", (int)bb->node->getId(), bboff);
str.append("\n.L");
str.append(bbid);
break;
}
}
if (buf[0]=='[') {
str.append("\n");
buf[5] = '\0';
str.append(buf);
str.append("\n ");
str.append(buf + 6);
str.append("\n");
} else {
str.append(buf);
str.append("\n");
}
i += l;
}
IPF_LOG << endl << "-----------" << cap << "-----------------------" << endl;
IPF_LOG << str;
}
} // IPF
} // Jitrino