dcc/src/idioms.cpp
nemerle d6249916e1 More logic operator replacements.
Use Qt string classes.
2016-04-25 15:51:58 +02:00

283 lines
8.4 KiB
C++

/*****************************************************************************
* dcc project machine idiom recognition
* (C) Cristina Cifuentes
****************************************************************************/
//#include <llvm/Config/llvm-config.h>
//#if( (LLVM_VERSION_MAJOR==3 ) and (LLVM_VERSION_MINOR>3) )
//#include <llvm/IR/PatternMatch.h>
//#else
//#include <llvm/Support/PatternMatch.h>
//#endif
#include "idiom.h"
#include "idiom1.h"
#include "epilogue_idioms.h"
#include "call_idioms.h"
#include "mov_idioms.h"
#include "xor_idioms.h"
#include "neg_idioms.h"
#include "shift_idioms.h"
#include "arith_idioms.h"
#include "dcc.h"
#include "msvc_fixes.h"
#include <boost/iterator/filter_iterator.hpp>
#include <cstring>
#include <deque>
/*****************************************************************************
* JmpInst - Returns true if opcode is a conditional or unconditional jump
****************************************************************************/
bool LLInst::isJmpInst()
{
switch (getOpcode())
{
case iJMP: case iJMPF: case iJCXZ:
case iLOOP: case iLOOPE:case iLOOPNE:
case iJB: case iJBE: case iJAE: case iJA:
case iJL: case iJLE: case iJGE: case iJG:
case iJE: case iJNE: case iJS: case iJNS:
case iJO: case iJNO: case iJP: case iJNP:
return true;
}
return false;
}
/*****************************************************************************
* findIdioms - translates LOW_LEVEL icode idioms into HIGH_LEVEL icodes.
****************************************************************************/
void Function::findIdioms()
{
// int ip; /* Index to current icode */
iICODE pEnd, pIcode; /* Pointers to end of BB and current icodes */
int16_t delta;
pIcode = Icode.begin();
pEnd = Icode.end();
Idiom1 i01(this);
Idiom2 i02(this);
Idiom3 i03(this);
Idiom4 i04(this);
Idiom13 i13(this);
Idiom14 i14(this);
Idiom17 i17(this);
// xor idioms
Idiom21 i21(this);
Idiom7 i07(this);
// or idioms
Idiom10 i10(this);
// neg idiom
Idiom11 i11(this);
Idiom16 i16(this);
// shift idioms
Idiom8 i08(this);
Idiom12 i12(this);
Idiom15 i15(this);
Idiom9 i09(this);
//arithmetic idioms
Idiom5 i05(this);
Idiom6 i06(this);
Idiom18 i18(this);
Idiom19 i19(this);
Idiom20 i20(this);
struct is_valid
{
bool operator()(ICODE &z) { return z.valid();}
};
typedef boost::filter_iterator<is_valid,iICODE> ifICODE;
while (pIcode != pEnd)
{
switch (pIcode->ll()->getOpcode())
{
case iDEC: case iINC:
if (i18.match(pIcode))
advance(pIcode,i18.action());
else if (i19.match(pIcode))
advance(pIcode,i19.action());
else if (i20.match(pIcode))
advance(pIcode,i20.action());
else
pIcode++;
break;
case iPUSH:
{
/* Idiom 1 */
//TODO: add other push idioms.
advance(pIcode,i01(pIcode));
break;
}
case iMOV:
{
if (i02.match(pIcode)) /* Idiom 2 */
advance(pIcode,i02.action());
else if (i14.match(pIcode)) /* Idiom 14 */
advance(pIcode,i14.action());
else if (i13.match(pIcode)) /* Idiom 13 */
advance(pIcode,i13.action());
else
pIcode++;
break;
}
case iCALL: case iCALLF:
/* Check for library functions that return a long register.
* Propagate this result */
if (pIcode->ll()->src().proc.proc != nullptr)
if ((pIcode->ll()->src().proc.proc->flg & PROC_ISLIB) and
(pIcode->ll()->src().proc.proc->flg & PROC_IS_FUNC))
{
if ((pIcode->ll()->src().proc.proc->retVal.type==TYPE_LONG_SIGN)
or (pIcode->ll()->src().proc.proc->retVal.type == TYPE_LONG_UNSIGN))
localId.newLongReg(TYPE_LONG_SIGN, LONGID_TYPE(rDX,rAX), pIcode/*ip*/);
}
/* Check for idioms */
if (i03.match(pIcode)) /* idiom 3 */
advance(pIcode,i03.action());
else if (i17.match(pIcode)) /* idiom 17 */
advance(pIcode,i17.action());
else
pIcode++;
break;
case iRET: /* Idiom 4 */
case iRETF:
advance(pIcode,i04(pIcode));
break;
case iADD: /* Idiom 5 */
advance(pIcode,i05(pIcode));
break;
case iSAR: /* Idiom 8 */
advance(pIcode,i08(pIcode));
break;
case iSHL:
if (i15.match(pIcode)) /* idiom 15 */
advance(pIcode,i15.action());
else if (i12.match(pIcode)) /* idiom 12 */
advance(pIcode,i12.action());
else
pIcode++;
break;
case iSHR: /* Idiom 9 */
advance(pIcode,i09(pIcode));
break;
case iSUB: /* Idiom 6 */
advance(pIcode,i06(pIcode));
break;
case iOR: /* Idiom 10 */
advance(pIcode,i10(pIcode));
break;
case iNEG: /* Idiom 11 */
if (i11.match(pIcode))
advance(pIcode,i11.action());
else if (i16.match(pIcode))
advance(pIcode,i16.action());
else
pIcode++;
break;
case iNOP:
(pIcode++)->invalidate();
break;
case iENTER: /* ENTER is equivalent to init PUSH bp */
if (pIcode == Icode.begin()) //ip == 0
{
flg |= (PROC_HLL | PROC_IS_HLL);
}
pIcode++;
break;
case iXOR: /* Idiom 7 */
if (i21.match(pIcode))
advance(pIcode,i21.action());
else if (i07.match(pIcode))
advance(pIcode,i07.action());
else
++pIcode;
break;
default:
pIcode++;
}
}
/* Check if number of parameter bytes match their calling convention */
if ((flg & PROC_HLL) and (not args.empty()))
{
args.m_minOff += (flg & PROC_FAR ? 4 : 2);
delta = args.maxOff - args.m_minOff;
if (cbParam != delta)
{
cbParam = delta;
callingConv(CConv::UNKNOWN);
}
}
}
/* Sets up the TARGET flag for jump target addresses, and
* binds jump target addresses to icode offsets. */
void Function::bindIcodeOff()
{
iICODE pIcode; /* ptr icode array */
if (Icode.empty()) /* No Icode */
return;
pIcode = Icode.begin();
/* Flag all jump targets for BB construction and disassembly stage 2 */
for(ICODE &c : Icode) // TODO: use filtered here
{
LLInst *ll=c.ll();
if (ll->testFlags(I) and ll->isJmpInst())
{
iICODE loc=Icode.labelSrch(ll->src().getImm2());
if (loc!=Icode.end())
loc->ll()->setFlags(TARGET);
}
}
/* Finally bind jump targets to Icode offsets. Jumps for which no label
* is found (no code at dest. of jump) are simply left unlinked and
* flagged as going nowhere. */
//for (pIcode = Icode.begin(); pIcode!= Icode.end(); pIcode++)
for(ICODE &icode : Icode)
{
LLInst *ll=icode.ll();
if (not ll->isJmpInst())
continue;
if (ll->testFlags(I) )
{
uint32_t found;
if (not Icode.labelSrch(ll->src().getImm2(), found))
ll->setFlags( NO_LABEL );
else
ll->replaceSrc(LLOperand::CreateImm2(found));
}
else if (ll->testFlags(SWITCH) )
{
/* for case table */
for (uint32_t &p : ll->caseTbl2)
Icode.labelSrch(p, p); // for each entry in caseTable replace it with target insn Idx
}
}
}
/** Performs idioms analysis, and propagates long operands, if any */
void Function::lowLevelAnalysis ()
{
findIdioms(); // Idiom analysis - sets up some flags and creates some HIGH_LEVEL icodes
propLong(); // Propagate HIGH_LEVEL idiom information for long operands
}