dcc/src/idioms/epilogue_idioms.cpp

149 lines
4.4 KiB
C++

#include "dcc.h"
#include "epilogue_idioms.h"
/*****************************************************************************
* popStkVars - checks for
* [POP DI]
* [POP SI]
* or [POP SI]
* [POP DI]
****************************************************************************/
void EpilogIdiom::popStkVars(iICODE pIcode)
{
// TODO : only process SI-DI DI-SI pairings, no SI-SI, DI-DI like it's now
/* Match [POP DI] */
if (pIcode->ll()->match(iPOP))
{
if ((m_func->flg & DI_REGVAR) && pIcode->ll()->match(rDI))
m_icodes.push_front(pIcode);
else if ((m_func->flg & SI_REGVAR) && pIcode->ll()->match(rSI))
m_icodes.push_front(pIcode);
}
++pIcode;
if(pIcode==m_end)
return;
/* Match [POP SI] */
if (pIcode->ll()->match(iPOP))
{
if ((m_func->flg & SI_REGVAR) && pIcode->ll()->match(rSI))
m_icodes.push_front(pIcode);
else if ((m_func->flg & DI_REGVAR) && pIcode->ll()->match(rDI))
m_icodes.push_front(pIcode);
}
}
/*****************************************************************************
* idiom2 - HLL procedure epilogue; Returns number of instructions matched.
* [POP DI]
* [POP SI]
* MOV SP, BP
* POP BP
* RET(F)
*****************************************************************************/
bool Idiom2::match(iICODE pIcode)
{
iICODE nicode;
if(pIcode==m_func->Icode.begin()) // pIcode->loc_ip == 0
return false;
if ( pIcode->ll()->isLlFlag(I) || (not pIcode->ll()->match(rSP,rBP)) )
return false;
if(distance(pIcode,m_end)<3)
return false;
/* Matched MOV SP, BP */
m_icodes.clear();
m_icodes.push_back(pIcode);
/* Get next icode, skip over holes in the icode array */
nicode = ++iICODE(pIcode);
while (nicode->ll()->isLlFlag(NO_CODE) && (nicode != m_end))
{
nicode++;
}
if(nicode == m_end)
return false;
if (nicode->ll()->match(iPOP,rBP) && ! (nicode->ll()->isLlFlag(I | TARGET | CASE)) )
{
m_icodes.push_back(nicode++); // Matched POP BP
/* Match RET(F) */
if ( nicode != m_end &&
!(nicode->ll()->isLlFlag(I | TARGET | CASE)) &&
(nicode->ll()->match(iRET) || nicode->ll()->match(iRETF))
)
{
m_icodes.push_back(nicode); // Matched RET
advance(pIcode,-2); // move back before our start
popStkVars (pIcode); // and add optional pop di/si to m_icodes
return true;
}
}
return false;
}
int Idiom2::action()
{
for(size_t idx=0; idx<m_icodes.size()-1; ++idx) // don't invalidate last entry
m_icodes[idx]->invalidate();
return 3;
}
/*****************************************************************************
* idiom4 - Pascal calling convention.
* RET(F) immed
* ==> pProc->cbParam = immed
* sets CALL_PASCAL flag
* - Second version: check for optional pop of stack vars
* [POP DI]
* [POP SI]
* POP BP
* RET(F) [immed]
* - Third version: pop stack vars
* [POP DI]
* [POP SI]
* RET(F) [immed]
****************************************************************************/
bool Idiom4::match(iICODE pIcode)
{
m_param_count = 0;
/* Check for [POP DI]
* [POP SI] */
if(distance(m_func->Icode.begin(),pIcode)>=3)
{
iICODE search_at(pIcode);
advance(search_at,-3);
popStkVars(search_at);
}
if(pIcode != m_func->Icode.begin())
{
iICODE prev1 = --iICODE(pIcode);
/* Check for POP BP */
if (prev1->ll()->match(iPOP,rBP) && not prev1->ll()->isLlFlag(I) )
m_icodes.push_back(prev1);
else if(prev1!=m_func->Icode.begin())
{
iICODE search_at(pIcode);
advance(search_at,-2);
popStkVars (search_at);
}
}
/* Check for RET(F) immed */
if (pIcode->ll()->isLlFlag(I) )
{
m_param_count = (int16_t)pIcode->ll()->src.op();
}
}
int Idiom4::action()
{
for(size_t idx=0; idx<m_icodes.size()-1; ++idx) // don't invalidate last entry
m_icodes[idx]->invalidate();
if(m_param_count)
{
m_func->cbParam = (int16_t)m_param_count;
m_func->flg |= CALL_PASCAL;
}
return 1;
}