dcc/src/idioms/arith_idioms.cpp
2017-02-13 12:11:29 +01:00

334 lines
11 KiB
C++

#include "arith_idioms.h"
#include "dcc.h"
#include "msvc_fixes.h"
#include <QtCore/QDebug>
using namespace std;
/*****************************************************************************
* idiom5 - Long addition.
* ADD reg/stackOff, reg/stackOff
* ADC reg/stackOff, reg/stackOff
* Eg: ADD ax, [bp-4]
* ADC dx, [bp-2]
* => dx:ax = dx:ax + [bp-2]:[bp-4]
* Found in Borland Turbo C code.
* Commonly used idiom for long addition.
****************************************************************************/
bool Idiom5::match(iICODE pIcode)
{
if(distance(pIcode,m_end)<2)
return false;
m_icodes[0]=pIcode++;
m_icodes[1]=pIcode++;
if (m_icodes[1]->ll()->match(iADC))
return true;
return false;
}
int Idiom5::action()
{
AstIdent *rhs,*lhs;
Expr *expr;
lhs = AstIdent::Long (&m_func->localId, DST, m_icodes[0], LOW_FIRST, m_icodes[0], USE_DEF, *m_icodes[1]->ll());
rhs = AstIdent::Long (&m_func->localId, SRC, m_icodes[0], LOW_FIRST, m_icodes[0], eUSE, *m_icodes[1]->ll());
expr = new BinaryOperator(ADD,lhs, rhs);
m_icodes[0]->setAsgn(lhs, expr);
m_icodes[1]->invalidate();
return 2;
}
/*****************************************************************************
* idiom6 - Long substraction.
* SUB reg/stackOff, reg/stackOff
* SBB reg/stackOff, reg/stackOff
* Eg: SUB ax, [bp-4]
* SBB dx, [bp-2]
* => dx:ax = dx:ax - [bp-2]:[bp-4]
* Found in Borland Turbo C code.
* Commonly used idiom for long substraction.
****************************************************************************/
bool Idiom6::match(iICODE pIcode)
{
if(distance(pIcode,m_end)<2)
return false;
m_icodes[0]=pIcode++;
m_icodes[1]=pIcode++;
if (m_icodes[1]->ll()->match(iSBB))
return true;
return false;
}
int Idiom6::action()
{
AstIdent *rhs,*lhs;
Expr *expr;
lhs = AstIdent::Long (&m_func->localId, DST, m_icodes[0], LOW_FIRST, m_icodes[0], USE_DEF, *m_icodes[1]->ll());
rhs = AstIdent::Long (&m_func->localId, SRC, m_icodes[0], LOW_FIRST, m_icodes[0], eUSE, *m_icodes[1]->ll());
expr = new BinaryOperator(SUB,lhs, rhs);
m_icodes[0]->setAsgn(lhs, expr);
m_icodes[1]->invalidate();
return 2;
}
/*****************************************************************************
* idiom 18: Post-increment or post-decrement in a conditional jump
* Used
* 0 MOV reg, var (including register variables)
* 1 INC var or DEC var <------------------------- input point
* 2 CMP var, Y
* 3 JX label
* => HLI_JCOND (var++ X Y)
* Eg: MOV ax, si
* INC si
* CMP ax, 8
* JL labX
* => HLI_JCOND (si++ < 8)
* Found in Borland Turbo C. Intrinsic to C languages.
****************************************************************************/
bool Idiom18::match(iICODE picode)
{
if(picode==m_func->Icode.begin())
return false;
if(std::distance(picode,m_end)<3)
return false;
--picode; //
for(int i=0; i<4; ++i)
m_icodes[i] =picode++;
m_idiom_type=-1;
m_is_dec = m_icodes[1]->ll()->match(iDEC);
uint8_t regi; /* register of the MOV */
if(not m_icodes[0]->ll()->matchWithRegDst(iMOV) )
return false;
regi = m_icodes[0]->ll()->m_dst.regi;
if( not ( m_icodes[2]->ll()->match(iCMP,regi) and
m_icodes[3]->ll()->conditionalJump() ) )
return false;
// Simple matching finished, select apropriate matcher based on dst type
/* Get variable */
if (m_icodes[1]->ll()->m_dst.regi == 0) /* global variable */
{
/* not supported yet */
m_idiom_type = 0;
}
else if ( m_icodes[1]->ll()->m_dst.isReg() ) /* register */
{
m_idiom_type = 1;
// if ((m_icodes[1]->ll()->dst.regi == rSI) and (m_func->flg & SI_REGVAR))
// m_idiom_type = 1;
// else if ((m_icodes[1]->ll()->dst.regi == rDI) and (m_func->flg & DI_REGVAR))
// m_idiom_type = 1;
}
else if (m_icodes[1]->ll()->m_dst.off) /* local variable */
m_idiom_type = 2;
else /* indexed */
{
m_idiom_type=3;
/* not supported yet */
ICODE &ic(*picode);
const Function *my_proc(ic.getParent()->getParent());
qWarning() << "Unsupported idiom18 type at"<< QString::number(ic.loc_ip,16)
<< "in"<< my_proc->name <<':'<< QString::number(my_proc->procEntry,16) << "- indexed";
}
switch(m_idiom_type)
{
case 0: // global
printf("Unsupported idiom18 type at %x : global variable\n",picode->loc_ip);
break;
case 1: /* register variable */
/* Check previous instruction for a MOV */
if ( m_icodes[0]->ll()->src().regi == m_icodes[1]->ll()->m_dst.regi)
{
return true;
}
break;
case 2: /* local */
if (m_icodes[0]->ll()->src().off == m_icodes[1]->ll()->m_dst.off)
{
return true;
}
break;
case 3: // indexed
printf("Untested idiom18 type: indexed\n");
if ((m_icodes[0]->ll()->src() == m_icodes[1]->ll()->m_dst))
{
return true;
}
break;
}
return false;
}
int Idiom18::action() // action length
{
Expr *rhs,*lhs;/* Pointers to left and right hand side exps */
Expr *expr;
lhs = AstIdent::id (*m_icodes[0]->ll(), SRC, m_func, m_icodes[1], *m_icodes[1], eUSE);
lhs = UnaryOperator::Create(m_is_dec ? POST_DEC : POST_INC, lhs);
rhs = AstIdent::id (*m_icodes[2]->ll(), SRC, m_func, m_icodes[1], *m_icodes[3], eUSE);
expr = new BinaryOperator(condOpJCond[m_icodes[3]->ll()->getOpcode() - iJB],lhs, rhs);
m_icodes[3]->setJCond(expr);
m_icodes[0]->invalidate();
m_icodes[1]->invalidate();
m_icodes[2]->invalidate();
return 3;
}
/*****************************************************************************
* idiom 19: pre-increment or pre-decrement in conditional jump, comparing against 0.
* [INC | DEC] var (including register vars)
* JX lab JX lab
* => HLI_JCOND (++var X 0) or HLI_JCOND (--var X 0)
* Eg: INC [bp+4]
* JG lab2
* => HLI_JCOND (++[bp+4] > 0)
* Found in Borland Turbo C. Intrinsic to C language.
****************************************************************************/
bool Idiom19::match(iICODE picode)
{
if(std::distance(picode,m_end)<2)
return false;
ICODE &ic(*picode);
int type;
for(int i=0; i<2; ++i)
m_icodes[i] =picode++;
m_is_dec = m_icodes[0]->ll()->match(iDEC);
if ( not m_icodes[1]->ll()->conditionalJump() )
return false;
if (m_icodes[0]->ll()->m_dst.regi == 0) /* global variable */
/* not supported yet */ ;
else if ( m_icodes[0]->ll()->m_dst.isReg() ) /* register */
{
// if (((picode->ll()->dst.regi == rSI) and (pproc->flg & SI_REGVAR)) or
// ((picode->ll()->dst.regi == rDI) and (pproc->flg & DI_REGVAR)))
return true;
}
else if (m_icodes[0]->ll()->m_dst.off) /* stack variable */
{
return true;
}
else /* indexed */
{
fprintf(stderr,"idiom19 : Untested type [indexed]\n");
return true;
/* not supported yet */
}
return false;
}
int Idiom19::action()
{
Expr *lhs,*expr;
lhs = AstIdent::id (*m_icodes[0]->ll(), DST, m_func, m_icodes[0], *m_icodes[1], eUSE);
lhs = UnaryOperator::Create(m_is_dec ? PRE_DEC : PRE_INC, lhs);
expr = new BinaryOperator(condOpJCond[m_icodes[1]->ll()->getOpcode() - iJB],lhs, new Constant(0, 2));
m_icodes[1]->setJCond(expr);
m_icodes[0]->invalidate();
return 2;
}
/*****************************************************************************
* idiom20: Pre increment/decrement in conditional expression (compares
* against a register, variable or constant different than 0).
* INC var or DEC var (including register vars)
* MOV reg, var MOV reg, var
* CMP reg, Y CMP reg, Y
* JX lab JX lab
* => HLI_JCOND (++var X Y) or HLI_JCOND (--var X Y)
* Eg: INC si (si is a register variable)
* MOV ax, si
* CMP ax, 2
* JL lab4
* => HLI_JCOND (++si < 2)
* Found in Turbo C. Intrinsic to C language.
****************************************************************************/
bool Idiom20::match(iICODE picode)
{
uint8_t type = 0; /* type of variable: 1 = reg-var, 2 = local */
uint8_t regi; /* register of the MOV */
if(std::distance(picode,m_end)<4)
return false;
for(int i=0; i<4; ++i)
m_icodes[i] =picode++;
/* Check second instruction for a MOV */
if( not m_icodes[1]->ll()->matchWithRegDst(iMOV) )
return false;
m_is_dec = m_icodes[0]->ll()->match(iDEC) ? PRE_DEC : PRE_INC;
const LLOperand &ll_dest(m_icodes[0]->ll()->m_dst);
/* Get variable */
if (ll_dest.regi == 0) /* global variable */
{
/* not supported yet */ ;
}
else if ( ll_dest.isReg() ) /* register */
{
type = 1;
// if ((ll_dest.regi == rSI) and (m_func->flg & SI_REGVAR))
// type = 1;
// else if ((ll_dest.regi == rDI) and (m_func->flg & DI_REGVAR))
// type = 1;
}
else if (ll_dest.off) /* local variable */
type = 2;
else /* indexed */
{
printf("idiom20 : Untested type [indexed]\n");
type = 3;
/* not supported yet */ ;
}
regi = m_icodes[1]->ll()->m_dst.regi;
const LLOperand &mov_src(m_icodes[1]->ll()->src());
if (m_icodes[2]->ll()->match(iCMP,(eReg)regi) and m_icodes[3]->ll()->conditionalJump())
{
switch(type)
{
case 1: /* register variable */
if ((mov_src.regi == ll_dest.regi))
{
return true;
}
break;
case 2: // local
if ((mov_src.off == ll_dest.off))
{
return true;
}
break;
case 3:
fprintf(stderr,"Test 3 ");
if ((mov_src == ll_dest))
{
return true;
}
break;
}
}
return false;
}
int Idiom20::action()
{
Expr *lhs,*rhs,*expr;
lhs = AstIdent::id (*m_icodes[1]->ll(), SRC, m_func, m_icodes[0], *m_icodes[0], eUSE);
lhs = UnaryOperator::Create(m_is_dec, lhs);
rhs = AstIdent::id (*m_icodes[2]->ll(), SRC, m_func, m_icodes[0], *m_icodes[3], eUSE);
expr = new BinaryOperator(condOpJCond[m_icodes[3]->ll()->getOpcode() - iJB],lhs, rhs);
m_icodes[3]->setJCond(expr);
for(int i=0; i<3; ++i)
m_icodes[i]->invalidate();
return 4;
}