blob: 8d6c92f85c175c84c61070727370916951ba1422 [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 Nikolay A. Sidelnikov
*/
#include "Ia32IRManager.h"
#include "Ia32Printer.h"
#include "Interval.h"
namespace Jitrino
{
namespace Ia32{
#define FPU_FLAG_C0 0x100
#define FPU_FLAG_C2 0x400
#define FPU_FLAG_C3 0x4000
#define FPU_FLAGS (FPU_FLAG_C0 | FPU_FLAG_C2 |FPU_FLAG_C3)
#define ROUND_FLAG 0xC00
//========================================================================================
//========================================================================================
/**
I586InstsExpansion translates SSE2 instructions and newer to the corresponding SSE and x87 instructions
and SETcc and CMOVcc instructions to branches
*/
class I586InstsExpansion : public SessionAction {
void runImpl();
void lowerToX87();
void lowerToSSE();
U_32 getNeedInfo()const{ return 0; }
U_32 getSideEffects()const{ return hasSideEffects ? SideEffect_InvalidatesLivenessInfo: 0; }
bool isIRDumpEnabled(){ return hasSideEffects;}
bool hasSideEffects;
public:
I586InstsExpansion() : hasSideEffects(false){}
};
static ActionFactory<I586InstsExpansion> _i586("i586");
//NOTE: today the following methods contains info only for mnemonics used in CG.
//TODO: update them to have all mnemonics from Architecture Manual or add this info to Encoder
static bool isSSE2OrNewer(Mnemonic mn) {
switch (mn) {
case Mnemonic_MOVAPD:
return true;
default:
return false;
}
}
//return true if instruction is SSE or newer
static bool isSSEOrNewer(Mnemonic mn) {
switch (mn) {
case Mnemonic_ADDSS:
case Mnemonic_ADDSD:
case Mnemonic_SUBSS:
case Mnemonic_SUBSD:
case Mnemonic_MULSS:
case Mnemonic_MULSD:
case Mnemonic_DIVSS:
case Mnemonic_DIVSD:
case Mnemonic_XORPD:
case Mnemonic_XORPS:
case Mnemonic_PXOR:
case Mnemonic_MOVQ:
case Mnemonic_MOVD:
case Mnemonic_MOVSD:
case Mnemonic_MOVSS:
case Mnemonic_UCOMISD:
case Mnemonic_UCOMISS:
case Mnemonic_CVTTSS2SI:
case Mnemonic_CVTTSD2SI:
case Mnemonic_CVTSI2SS:
case Mnemonic_CVTSI2SD:
return true;
default:
return isSSE2OrNewer(mn);
}
}
static void mapToX87(Mnemonic mn, Mnemonic &fMnem1, Mnemonic &fMnem2) {
switch (mn) {
case Mnemonic_ADDSS:
case Mnemonic_ADDSD:
fMnem1 = Mnemonic_FADDP;
fMnem2 = Mnemonic_FADD;
return;
case Mnemonic_SUBSS:
case Mnemonic_SUBSD:
fMnem1 = Mnemonic_FSUBP;
fMnem2 = Mnemonic_FSUB;
return;
case Mnemonic_MULSS:
case Mnemonic_MULSD:
fMnem1 = Mnemonic_FMULP;
fMnem2 = Mnemonic_FMUL;
return;
case Mnemonic_DIVSS:
case Mnemonic_DIVSD:
fMnem1 = Mnemonic_FDIVP;
fMnem2 = Mnemonic_FDIV;
return;
default:
return;
}
}
enum FPUMode {
FPUMode_X87 = 1,
FPUMode_SSE = 2,
FPUMode_SSE2 = 3
};
void I586InstsExpansion::runImpl() {
FPUMode mode = CPUID::isSSE2Supported() ? FPUMode_SSE2 : FPUMode_SSE;
const char* modeStr = getArg("mode");
if (modeStr!=NULL && !strcmp(modeStr, "sse")) {
mode = FPUMode_SSE;
} else if (modeStr!=NULL && !strcmp(modeStr, "x87")) {
mode = FPUMode_X87;
}
if (Log::isEnabled()) {
Log::out()<<"has sse2:" << CPUID::isSSE2Supported() << " mode:"<<(int)mode<<std::endl;
}
switch(mode) {
case FPUMode_X87:
lowerToX87();
return;
case FPUMode_SSE:
lowerToSSE();
return;
case FPUMode_SSE2:
//do nothing;
break;
default: assert(0);
}
}
void I586InstsExpansion::lowerToSSE() {
const Nodes& nodes = irManager->getFlowGraph()->getNodes();
for (Nodes::const_iterator cit = nodes.begin(); cit != nodes.end(); ++cit) {
Node* node = *cit;
if (!node->isBlockNode()) {
continue;
}
for(Inst * inst = (Inst *)node->getFirstInst(); inst != NULL; ) {
Mnemonic mn = inst->getMnemonic();
if (!isSSE2OrNewer(mn)) {
continue;
}
//Mode is not implemented for a SSE2 and newer systems.
//Must never hit for SSE-only hardware.
assert(0);
}
}
}
void I586InstsExpansion::lowerToX87() {
//check if to use FPU mode. Otherwise SSE1 insts will be allowed
irManager->updateLivenessInfo();
hasSideEffects = true;
//create stack memory operands for storing values of XMM registers
StlMap<unsigned, Opnd *> xmmMemOp32Map(irManager->getMemoryManager());
StlMap<unsigned, Opnd *> xmmMemOp64Map(irManager->getMemoryManager());
for (unsigned i = 0; i< 16; i++) {
xmmMemOp32Map[i] = NULL;
xmmMemOp64Map[i] = NULL;
}
StlMap<unsigned, Opnd *> * xmmMemOpsPtr = &xmmMemOp64Map;
//create FP registers operands with corresponding size
Opnd * fp0Op32 = irManager->newOpnd(irManager->getTypeManager().getSingleType(), RegName_FP0S);
fp0Op32->assignRegName(RegName_FP0S);
Opnd * fp0Op64 = irManager->newOpnd(irManager->getTypeManager().getDoubleType(), RegName_FP0D);
fp0Op64->assignRegName(RegName_FP0D);
Opnd * fp1Op32 = irManager->newOpnd(irManager->getTypeManager().getSingleType(), RegName_FP1S);
fp1Op32->assignRegName(RegName_FP1S);
Opnd * fp1Op64 = irManager->newOpnd(irManager->getTypeManager().getDoubleType(), RegName_FP1D);
fp1Op64->assignRegName(RegName_FP1D);
const Nodes& nodes = irManager->getFlowGraph()->getNodes();
for (Nodes::const_iterator cit = nodes.begin(); cit != nodes.end(); ++cit) {
Node* node = *cit;
if (!node->isBlockNode()) {
continue;
}
for(Inst * inst = (Inst *)node->getFirstInst(); inst != NULL; ) {
Inst * tmpInst = inst->getNextInst();
Mnemonic mn = inst->getMnemonic();
Mnemonic fMnem1 = Mnemonic_NULL, fMnem2 = Mnemonic_NULL;
if (!isSSEOrNewer(mn)) {
//check all other instruction for XMM registers operands
Inst::Opnds xmms(inst, Inst::OpndRole_Explicit|Inst::OpndRole_UseDef);
for (Inst::Opnds::iterator it = xmms.begin(); it != xmms.end(); it = xmms.next(it)) {
Opnd * op = inst->getOpnd(it);
if (op->isPlacedIn(OpndKind_XMMReg)) {
std::string str = std::string("SSE instruction found: ") + Encoder::getMnemonicString(mn);
Jitrino::crash(str.c_str());
}
}
inst = tmpInst;
continue;
}
mapToX87(mn, fMnem1, fMnem2);
Opnd * fp0;
Opnd * fp1;
//number of registers in instruction
unsigned regNum1 = 0;
//XMM-suspected operands
Inst::Opnds xmms(inst, Inst::OpndRole_Explicit|Inst::OpndRole_UseDef);
Opnd * op1 = inst->getOpnd(xmms.begin());
Opnd * op2 = inst->getOpnd(xmms.begin()+1);
//choose operands size
if (op2->getSize() == OpndSize_64) {
fp0 = fp0Op64;
fp1 = fp1Op64;
xmmMemOpsPtr = &xmmMemOp64Map;
} else {
fp0 = fp0Op32;
fp1 = fp1Op32;
xmmMemOpsPtr = &xmmMemOp32Map;
}
switch (mn) {
case Mnemonic_XORPD:
case Mnemonic_XORPS:
case Mnemonic_PXOR:
{
//Packed XOR is used only for loading of zero into a XMM register
//replace: XORPD xmm2, xmm2 -> FLDZ fp0
// FSTP [xmm2_Mem]
if (op1 == op2) {
RegName reg = op1->getRegName();
unsigned regNum = (unsigned)reg & 0xF;
//create memory operand for the XMM register if it doesn't exist
if (!(*xmmMemOpsPtr)[regNum] || (*xmmMemOpsPtr)[regNum]->getSize() != op1->getSize()) {
Opnd* opnd = irManager->newMemOpnd(fp0->getType(), MemOpndKind_StackAutoLayout, irManager->getRegOpnd(STACK_REG), 0);
opnd->setMemOpndAlignment(Opnd::MemOpndAlignment_16);
(*xmmMemOpsPtr)[regNum] = opnd;
}
//load zero
node->prependInst(irManager->newInst(Mnemonic_FLDZ, fp0),inst);
//store zero and pop FPU stack
node->prependInst(irManager->newInst(Mnemonic_FSTP, (*xmmMemOpsPtr)[regNum], fp0), inst);
} else {
assert(0);
}
break;
}
case Mnemonic_ADDSS:
case Mnemonic_ADDSD:
case Mnemonic_SUBSS:
case Mnemonic_SUBSD:
case Mnemonic_MULSS:
case Mnemonic_MULSD:
case Mnemonic_DIVSS:
case Mnemonic_DIVSD:
{
//replace: ADDSS xmm1, xmm2 (op2) -> FLD fp0, [xmm1_Mem]
// FLD fp0, [xmm2_Mem] ;also move previous fp0 value to fp1)
// FADDP fp0, fp1 (FADD fp0, op2)
// FSTP [xmm1_Mem]
//push first operand on stack
if (op1->isPlacedIn(OpndKind_XMMReg)) {
RegName reg1 = op1->getRegName();
regNum1 = (unsigned)reg1 & 0xF;
assert((*xmmMemOpsPtr)[regNum1]);
node->prependInst(irManager->newInst(Mnemonic_FLD, fp0, (*xmmMemOpsPtr)[regNum1]),inst);
} else {
assert(0);
}
//push second operand on FPU stack if it is an XMM register
if (op2->isPlacedIn(OpndKind_XMMReg)) {
RegName reg2 = op2->getRegName();
unsigned regNum2 = (unsigned)reg2 & 0xF;
assert((*xmmMemOpsPtr)[regNum2]);
node->prependInst(irManager->newInst(Mnemonic_FLD, fp0, (*xmmMemOpsPtr)[regNum2]),inst);
//do the operation and pop FPU stack
node->prependInst(irManager->newInst(fMnem1, fp0, fp1),inst);
} else {
//do the operation
node->prependInst(irManager->newInst(fMnem2, fp0, op2),inst);
}
//store result and pop FPU stack
node->prependInst(irManager->newInst(Mnemonic_FSTP, (*xmmMemOpsPtr)[regNum1], fp0),inst);
break;
}
case Mnemonic_MOVQ:
case Mnemonic_MOVD:
case Mnemonic_MOVSD:
case Mnemonic_MOVSS:
{
if (op1->isPlacedIn(OpndKind_XMMReg)) {
RegName reg1 = op1->getRegName();
regNum1 = (unsigned)reg1 & 0xF;
//create memory operand for the destination XMM register if it doesn't exist
if (!(*xmmMemOpsPtr)[regNum1] || (*xmmMemOpsPtr)[regNum1]->getSize() != op1->getSize()) {
(*xmmMemOpsPtr)[regNum1] = irManager->newMemOpnd(fp0->getType(), MemOpndKind_StackAutoLayout, irManager->getRegOpnd(STACK_REG), 0);
}
//store value to XMM-memory slot and pop FPU stack
node->appendInst(irManager->newInst(Mnemonic_FSTP, (*xmmMemOpsPtr)[regNum1], fp0),inst);
} else {
//store value to memory and pop FPU stack
node->appendInst(irManager->newInst(Mnemonic_FSTP, op1, fp0),inst);
}
if (op2->isPlacedIn(OpndKind_XMMReg)) {
RegName reg2 = op2->getRegName();
unsigned regNum2 = (unsigned)reg2 & 0xF;
assert((*xmmMemOpsPtr)[regNum2]);
//load value from XMM-memory slot onto FPU stack
node->prependInst(irManager->newInst(Mnemonic_FLD, fp0, (*xmmMemOpsPtr)[regNum2]),inst);
} else {
//load value from memory onto FPU stack
node->prependInst(irManager->newInst(Mnemonic_FLD, fp0, op2),inst);
}
break;
}
case Mnemonic_CVTTSS2SI:
case Mnemonic_CVTTSD2SI:
{
//replace: CVTTSS2SI ebx, xmm2 -> FNSTCW [fpucw]
// FNSTCW [tmpcw]
// OR [fpucw], ROUND_FLAG
// FLDCW [fpucw]
// FLD fp0, [xmm2_Mem]
// FISTP [cMemOp], fp0
// MOV ebx, [cMemOp]
// FLDCW [tmpcw]
//set rounding mode to "round to zero" before operation and and restore old value after operation
Opnd * fpucw = irManager->newMemOpnd(irManager->getTypeManager().getInt16Type(),
MemOpndKind_StackAutoLayout, irManager->getRegOpnd(STACK_REG), 0);
Opnd * tmpcw = irManager->newMemOpnd(irManager->getTypeManager().getInt16Type(),
MemOpndKind_StackAutoLayout, irManager->getRegOpnd(STACK_REG), 0);
node->prependInst(irManager->newInst(Mnemonic_FNSTCW, fpucw),inst);
node->prependInst(irManager->newInst(Mnemonic_FNSTCW, tmpcw),inst);
node->prependInst(irManager->newInst(Mnemonic_OR, fpucw, irManager->newImmOpnd(fpucw->getType(), ROUND_FLAG)),inst);
node->prependInst(irManager->newInst(Mnemonic_FLDCW, fpucw),inst);
node->appendInst(irManager->newInst(Mnemonic_FLDCW, tmpcw),inst);
//create the memory slot
Opnd * cMemOp = irManager->newMemOpnd(op1->getType(), MemOpndKind_StackAutoLayout, irManager->getRegOpnd(STACK_REG), 0);
//move result from the memory slot to destination
node->appendInst(irManager->newInst(Mnemonic_MOV, op1, cMemOp),inst);
//store the value with truncation to the memory slot and pop FPU stack
node->appendInst(irManager->newInst(Mnemonic_FISTP, cMemOp, fp0),inst);
if (op2->isPlacedIn(OpndKind_XMMReg)) {
RegName reg2 = op2->getRegName();
unsigned regNum2 = (unsigned)reg2 & 0xF;
assert((*xmmMemOpsPtr)[regNum2]);
//load value from XMM-memory slot onto FPU stack
node->prependInst(irManager->newInst(Mnemonic_FLD, fp0, (*xmmMemOpsPtr)[regNum2]),inst);
} else {
//load value from memory onto FPU stack
node->prependInst(irManager->newInst(Mnemonic_FLD, fp0, op2),inst);
}
break;
}
case Mnemonic_UCOMISD:
case Mnemonic_UCOMISS:
{
//replace: UCOMISD xmm0, xmm2 -> PUSH eax
// JP L1 FLD fp0, [xmm2_Mem]
// JNA L2 FLD fp0, [xmm0_Mem]
// FUCOMPP fp0, fp1
// FNSTSW eax
// MOV [cMemOp], eax
// POP eax
// AND [cMemOp], FPU_FLAGS
// CMP [cMemOp], FPU_FLAGS
// JZ L1
// AND [cMemOp], FPU_FLAGS
// CMP [cMemOp], 0
// JNZ L2
Inst * nextInst = inst->getNextInst();
//find conditional instruction
for (; nextInst != NULL ; nextInst = nextInst->getNextInst()) {
Mnemonic bm = getBaseConditionMnemonic(nextInst->getMnemonic());
if (bm != Mnemonic_Null)
break;
}
assert(nextInst);
//save and restore EAX register
Opnd * eax = irManager->getRegOpnd(RegName_EAX);
node->prependInst(irManager->newInst(Mnemonic_PUSH, eax),inst);
node->appendInst(irManager->newInst(Mnemonic_POP, eax),inst);
//generate x87 comparison
if (op2->isPlacedIn(OpndKind_XMMReg)) {
RegName reg2 = op2->getRegName();
unsigned regNum2 = (unsigned)reg2 & 0xF;
assert((*xmmMemOpsPtr)[regNum2]);
node->prependInst(irManager->newInst(Mnemonic_FLD, fp0, (*xmmMemOpsPtr)[regNum2]),inst);
} else {
node->prependInst(irManager->newInst(Mnemonic_FLD, fp0, op2),inst);
}
if (op1->isPlacedIn(OpndKind_XMMReg)) {
RegName reg1 = op1->getRegName();
regNum1 = (unsigned)reg1 & 0xF;
assert((*xmmMemOpsPtr)[regNum1]);
node->prependInst(irManager->newInst(Mnemonic_FLD, fp0, (*xmmMemOpsPtr)[regNum1]),inst);
} else {
assert(0);
}
node->prependInst(irManager->newInst(Mnemonic_FUCOMPP, fp0, fp1),inst);
node->prependInst(irManager->newInst(Mnemonic_FNSTSW, eax),inst);
//save result from eax to memory
Opnd * cMemOp = irManager->newMemOpnd(eax->getType(), MemOpndKind_StackAutoLayout, irManager->getRegOpnd(STACK_REG), 0);
node->appendInst(irManager->newInst(Mnemonic_MOV, cMemOp, eax),inst);
Inst * parityInst = NULL;
Node * trueTarget, * falseTarget;
if (nextInst->getKind() == Inst::Kind_BranchInst) {
Mnemonic mn = nextInst->getMnemonic();
//if the instruction is a check for NaN
if (mn == Mnemonic_JP || mn == Mnemonic_JNP) {
parityInst = nextInst;
trueTarget = ((BranchInst *)parityInst)->getTrueTarget();
falseTarget = ((BranchInst *)parityInst)->getFalseTarget();
//if NaN then all FPU flags are set
node->prependInst(irManager->newInst(Mnemonic_AND, cMemOp, irManager->newImmOpnd(cMemOp->getType(),FPU_FLAGS)),nextInst);
node->prependInst(irManager->newInst(Mnemonic_CMP, cMemOp, irManager->newImmOpnd(cMemOp->getType(),FPU_FLAGS)),nextInst);
if (mn == Mnemonic_JP) {
node->prependInst(irManager->newBranchInst(Mnemonic_JZ, trueTarget, falseTarget),nextInst);
nextInst = (Inst *)falseTarget->getLastInst();
} else {
node->prependInst(irManager->newBranchInst(Mnemonic_JNZ, trueTarget, falseTarget),nextInst);
nextInst = (Inst *)trueTarget->getLastInst();
}
parityInst->unlink();
mn = nextInst->getMnemonic();
}
trueTarget = ((BranchInst *)nextInst)->getTrueTarget();
falseTarget = ((BranchInst *)nextInst)->getFalseTarget();
Node * nextNode = nextInst->getNode();
//check particular flags and do the corresponding conditional jump
if (mn == Mnemonic_JA || mn == Mnemonic_JNA) {
nextNode->prependInst(irManager->newInst(Mnemonic_AND, cMemOp, irManager->newImmOpnd(cMemOp->getType(),FPU_FLAGS)),nextInst);
nextNode->prependInst(irManager->newInst(Mnemonic_CMP, cMemOp, irManager->newImmOpnd(cMemOp->getType(),0)),nextInst);
nextNode->prependInst(irManager->newBranchInst(mn==Mnemonic_JA ? Mnemonic_JZ : Mnemonic_JNZ, trueTarget, falseTarget),nextInst);
} else if (mn == Mnemonic_JAE || mn == Mnemonic_JNAE) {
nextNode->prependInst(irManager->newInst(Mnemonic_AND, cMemOp, irManager->newImmOpnd(cMemOp->getType(),FPU_FLAG_C0)),nextInst);
nextNode->prependInst(irManager->newBranchInst(mn==Mnemonic_JAE? Mnemonic_JZ : Mnemonic_JNZ, trueTarget, falseTarget),nextInst);
} else if (mn == Mnemonic_JE || mn == Mnemonic_JNE) {
nextNode->prependInst(irManager->newInst(Mnemonic_AND, cMemOp, irManager->newImmOpnd(cMemOp->getType(),FPU_FLAG_C3)),nextInst);
nextNode->prependInst(irManager->newBranchInst(mn==Mnemonic_JE? Mnemonic_JNZ : Mnemonic_JZ, trueTarget, falseTarget),nextInst);
}
nextInst->unlink();
} else {
nextInst = nextInst->getNextInst();
Mnemonic mn = nextInst->getMnemonic();
Inst::Opnds sopnds(nextInst, Inst::OpndRole_Explicit|Inst::OpndRole_UseDef);
Inst::Opnds::iterator oit = sopnds.begin();
Opnd * sop = inst->getOpnd(oit);
//check particular flags and do the corresponding conditional set
if (mn == Mnemonic_SETA || mn == Mnemonic_SETNA) {
node->prependInst(irManager->newInst(Mnemonic_CMP, cMemOp, irManager->newImmOpnd(cMemOp->getType(),0)),nextInst);
node->prependInst(irManager->newInst(mn==Mnemonic_SETA ? Mnemonic_SETZ : Mnemonic_SETNZ, sop),nextInst);
} else if (mn == Mnemonic_SETAE || mn == Mnemonic_SETNAE) {
node->prependInst(irManager->newInst(Mnemonic_AND, cMemOp, irManager->newImmOpnd(cMemOp->getType(),FPU_FLAGS)),nextInst);
node->prependInst(irManager->newInst(Mnemonic_CMP, cMemOp, irManager->newImmOpnd(cMemOp->getType(),FPU_FLAG_C0)),nextInst);
node->prependInst(irManager->newInst(mn==Mnemonic_SETAE? Mnemonic_SETNZ : Mnemonic_SETZ, sop),nextInst);
} else if (mn == Mnemonic_SETE || mn == Mnemonic_SETNE) {
node->prependInst(irManager->newInst(Mnemonic_AND, cMemOp, irManager->newImmOpnd(cMemOp->getType(),FPU_FLAGS)),nextInst);
node->prependInst(irManager->newInst(Mnemonic_CMP, cMemOp, irManager->newImmOpnd(cMemOp->getType(),FPU_FLAGS)),nextInst);
node->prependInst(irManager->newInst(mn==Mnemonic_SETE? Mnemonic_SETZ : Mnemonic_SETNZ, sop),nextInst);
}
parityInst = nextInst->getNextInst();
nextInst->unlink();
if (parityInst) {
nextInst = parityInst;
mn = parityInst->getMnemonic();
//if the instruction is a check for NaN
if (mn == Mnemonic_CMOVP || mn == Mnemonic_CMOVNP) {
node->prependInst(irManager->newInst(Mnemonic_AND, cMemOp, irManager->newImmOpnd(cMemOp->getType(),FPU_FLAGS)),nextInst);
node->prependInst(irManager->newInst(Mnemonic_CMP, cMemOp, irManager->newImmOpnd(cMemOp->getType(),FPU_FLAGS)),nextInst);
Opnd * cop0 = NULL;
Opnd * cop1 = NULL;
Inst::Opnds copnds(nextInst, Inst::OpndRole_Explicit|Inst::OpndRole_UseDef);
Inst::Opnds::iterator oit = copnds.begin();
cop0 = inst->getOpnd(oit);
cop1 = inst->getOpnd(copnds.next(oit));
if (mn ==Mnemonic_CMOVP) {
node->prependInst(irManager->newInst((Mnemonic_CMOVNZ), cop0, cop1),nextInst);
nextInst = nextInst->getNextInst();
} else {
node->prependInst(irManager->newInst((Mnemonic_CMOVZ), cop0, cop1),nextInst);
}
nextInst->unlink();
}
}
}
break;
}
default:
{
assert(0);
break;
}
}
inst->unlink();
inst = (Inst * )node->getFirstInst();
}
}
StlVector<Inst *> cmovs(irManager->getMemoryManager());
StlVector<Inst *> sets(irManager->getMemoryManager());
for (Nodes::const_iterator cit = nodes.begin(); cit != nodes.end(); ++cit) {
Node* node = *cit;
if (!node->isBlockNode()) {
continue;
}
for(Inst * inst = (Inst *)node->getFirstInst(); inst != NULL; inst = inst->getNextInst()) {
Mnemonic mn = inst->getMnemonic();
Mnemonic bm = getBaseConditionMnemonic(mn);
if(bm == Mnemonic_CMOVcc) {
cmovs.push_back(inst);
} else if (bm == Mnemonic_SETcc) {
sets.push_back(inst);
}
}
}
for(unsigned i = 0 ; i<cmovs.size(); i++) {
//replace: CMOVcc op1, op2 -> Jcc L1
// JMP L2
// L1: MOV op1, op2
// L2: ...
Inst * inst = cmovs[i];
Mnemonic mn = inst->getMnemonic();
Mnemonic bm = getBaseConditionMnemonic(mn);
Inst::Opnds opnds(inst, Inst::OpndRole_Explicit|Inst::OpndRole_UseDef);
Opnd * op1 = inst->getOpnd(opnds.begin());
Opnd * op2 = inst->getOpnd(opnds.begin()+1);
ControlFlowGraph* subCFG = irManager->createSubCFG(true, false);
Node* bbJmp = subCFG->getEntryNode();
Node* bbTrue = subCFG->createBlockNode();
Node* bbRet = subCFG->getReturnNode();
Inst * jmp = irManager->newBranchInst((Mnemonic)(Mnemonic_Jcc+(mn-bm)),bbTrue, bbRet);
bbJmp->appendInst(jmp);
Inst * trueMov = irManager->newInst(Mnemonic_MOV, op1, op2);
bbTrue->appendInst(trueMov);
subCFG->addEdge(bbJmp, bbTrue, 0.5);
subCFG->addEdge(bbJmp, bbRet, 0.5);
subCFG->addEdge(bbTrue, bbRet, 1);
irManager->getFlowGraph()->spliceFlowGraphInline(inst, *subCFG);
inst->unlink();
}
for(unsigned i = 0 ; i<sets.size(); i++) {
//replace: SETcc op1 -> Jcc L1
// MOV op1, 0
// JMP L2
// L1: MOV op1, 1
// L2: ...
Inst * inst = sets[i];
Mnemonic mn = inst->getMnemonic();
Mnemonic bm = getBaseConditionMnemonic(mn);
Inst::Opnds opnds(inst, Inst::OpndRole_Explicit|Inst::OpndRole_UseDef);
Opnd * op1 = inst->getOpnd(opnds.begin());
ControlFlowGraph* subCFG = irManager->createSubCFG(true, false);
Node* bbJmp = subCFG->getEntryNode();
Node* bbTrue = subCFG->createBlockNode();
Node* bbFalse = subCFG->createBlockNode();
Node* bbRet = subCFG->getReturnNode();
Inst * jmp = irManager->newBranchInst((Mnemonic)(Mnemonic_Jcc+(mn-bm)),bbTrue, bbFalse);
bbJmp->appendInst(jmp);
Inst * trueMov = irManager->newInst(Mnemonic_MOV, op1, irManager->newImmOpnd(op1->getType(), 1));
bbTrue->appendInst(trueMov);
Inst * falseMov = irManager->newInst(Mnemonic_MOV, op1, irManager->newImmOpnd(op1->getType(), 0));
bbFalse->appendInst(falseMov);
subCFG->addEdge(bbJmp, bbTrue, 0.5);
subCFG->addEdge(bbJmp, bbFalse, 0.5);
subCFG->addEdge(bbTrue, bbRet, 1);
subCFG->addEdge(bbFalse, bbRet, 1);
irManager->getFlowGraph()->spliceFlowGraphInline(inst, *subCFG);
inst->unlink();
}
irManager->getFlowGraph()->purgeEmptyNodes();
irManager->getFlowGraph()->purgeUnreachableNodes();
irManager->fixEdgeProfile();
}
}}; //namespace Ia32