Refactoring idioms into objects with match/action methods

This commit is contained in:
Artur K 2012-02-26 23:58:06 +01:00
parent bf2d099cd9
commit 11ae65efba
5 changed files with 341 additions and 0 deletions

39
include/epilogue_idioms.h Normal file
View File

@ -0,0 +1,39 @@
#pragma once
#include "idiom.h"
#include "icode.h"
#include <deque>
struct EpilogIdiom : public Idiom
{
protected:
std::deque<iICODE> m_icodes; // deque to push_front optional icodes from popStkVars
void popStkVars (iICODE pIcode);
public:
virtual ~EpilogIdiom() {}
EpilogIdiom(Function *f) : Idiom(f)
{
}
};
struct Idiom2 : public EpilogIdiom
{
virtual ~Idiom2() {}
Idiom2(Function *f) : EpilogIdiom(f)
{
}
uint8_t minimum_match_length() {return 3;}
bool match(iICODE pIcode);
int action();
};
struct Idiom4 : public EpilogIdiom
{
protected:
int m_param_count;
public:
virtual ~Idiom4() {}
Idiom4(Function *f) : EpilogIdiom(f)
{
}
uint8_t minimum_match_length() {return 1;}
bool match(iICODE pIcode);
int action();
};

15
include/idiom.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#include "icode.h"
#include "Procedure.h"
struct Idiom
{
protected:
Function *m_func;
iICODE m_end;
public:
Idiom(Function *f) : m_func(f),m_end(f->Icode.end())
{
}
virtual uint8_t minimum_match_length()=0;
virtual bool match(iICODE at)=0;
};

16
include/idiom1.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include "idiom.h"
struct Idiom1 : public Idiom
{
protected:
std::vector<iICODE> m_icodes;
int m_min_off;
Int checkStkVars (iICODE pIcode);
public:
Idiom1(Function *f) : Idiom(f)
{
}
uint8_t minimum_match_length() {return 1;}
bool match(iICODE picode);
int action();
};

139
src/epilogue_idioms.cpp Normal file
View File

@ -0,0 +1,139 @@
#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->ic.ll.match(iPOP))
{
if ((m_func->flg & DI_REGVAR) && pIcode->ic.ll.match(rDI))
m_icodes.push_front(pIcode);
else if ((m_func->flg & SI_REGVAR) && pIcode->ic.ll.match(rSI))
m_icodes.push_front(pIcode);
}
++pIcode;
if(pIcode==m_end)
return;
/* Match [POP SI] */
if (pIcode->ic.ll.match(iPOP))
{
if ((m_func->flg & SI_REGVAR) && pIcode->ic.ll.match(rSI))
m_icodes.push_front(pIcode);
else if ((m_func->flg & DI_REGVAR) && pIcode->ic.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->ic.ll.flg & I) == I) || not pIcode->ic.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 = pIcode + 1;
while (nicode->ic.ll.flg & NO_CODE && (nicode != m_end))
{
nicode++;
}
if(nicode == m_end)
return false;
if (nicode->ic.ll.match(iPOP,rBP) && ! (nicode->ic.ll.flg & (I | TARGET | CASE)) )
{
m_icodes.push_back(nicode++); // Matched POP BP
/* Match RET(F) */
if ( nicode != m_end &&
!(nicode->ic.ll.flg & (I | TARGET | CASE)) &&
(nicode->ic.ll.match(iRET) || nicode->ic.ll.match(iRETF))
)
{
m_icodes.push_back(nicode); // Matched RET
popStkVars (pIcode-2); // will 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)
popStkVars (pIcode-3);
if(pIcode != m_func->Icode.begin())
{
iICODE prev1=pIcode-1;
/* Check for POP BP */
if (prev1->ic.ll.match(iPOP,rBP) && not prev1->ic.ll.anyFlagSet(I) )
m_icodes.push_back(prev1);
else if(prev1!=m_func->Icode.begin())
popStkVars (pIcode-2);
}
/* Check for RET(F) immed */
if (pIcode->ic.ll.flg & I)
{
m_param_count = (int16)pIcode->ic.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)m_param_count;
m_func->flg |= CALL_PASCAL;
}
return 0;
}

132
src/idiom1.cpp Normal file
View File

@ -0,0 +1,132 @@
#include "idiom1.h"
#include "dcc.h"
/*****************************************************************************
* idiom1 - HLL procedure prologue; Returns number of instructions matched.
* PUSH BP ==> ENTER immed, 0
* MOV BP, SP and sets PROC_HLL flag
* [SUB SP, immed]
* [PUSH SI]
* [PUSH DI]
* - Second version: Push stack variables and then save BP
* PUSH BP
* PUSH SI
* [PUSH DI]
* MOV BP, SP
* - Third version: Stack variables
* [PUSH SI]
* [PUSH DI]
****************************************************************************/
/*****************************************************************************
/* checkStkVars - Checks for PUSH SI
* [PUSH DI]
* or PUSH DI
* [PUSH SI]
* In which case, the stack variable flags are set
****************************************************************************/
Int Idiom1::checkStkVars (iICODE pIcode)
{
/* Look for PUSH SI */
int si_matched=0;
int di_matched=0;
if(pIcode==m_end)
return 0;
if (pIcode->ic.ll.match(iPUSH,rSI))
{
si_matched = 1;
++pIcode;
if ((pIcode != m_end) && pIcode->ic.ll.match(iPUSH,rDI)) // Look for PUSH DI
di_matched = 1;
}
else if (pIcode->ic.ll.match(iPUSH,rDI))
{
di_matched = 1;
++pIcode;
if ((pIcode != m_end) && pIcode->ic.ll.match(iPUSH,rSI)) // Look for PUSH SI
si_matched = 1;
}
m_func->flg |= (si_matched ? SI_REGVAR : 0) | (di_matched ? DI_REGVAR : 0);
return si_matched+di_matched;
}
bool Idiom1::match(iICODE picode)
{
uint8_t type = 0; /* type of variable: 1 = reg-var, 2 = local */
byte regi; /* register of the MOV */
if(picode==m_end)
return false;
Int n;
m_icodes.clear();
m_min_off = 0;
/* PUSH BP as first instruction of procedure */
if ( !(picode->ic.ll.flg & I) && picode->ic.ll.src.regi == rBP)
{
m_icodes.push_back( picode++ ); // insert iPUSH
if(picode==m_end)
return false;
/* MOV BP, SP as next instruction */
if ( !picode->ic.ll.anyFlagSet(I | TARGET | CASE) && picode->ic.ll.match(iMOV ,rBP,rSP) )
{
m_icodes.push_back( picode++ ); // insert iMOV
if(picode==m_end)
return false;
m_min_off = 2;
/* Look for SUB SP, immed */
if (
picode->ic.ll.anyFlagSet(I | TARGET | CASE) && picode->ic.ll.match(iSUB,rSP)
)
{
m_icodes.push_back( picode++ ); // insert iSUB
int n = checkStkVars (picode); // find iPUSH si [iPUSH di]
for(int i=0; i<n; ++i)
m_icodes.push_back(picode++); // insert
}
}
/* PUSH SI
* [PUSH DI]
* MOV BP, SP */
else
{
int n = checkStkVars (picode);
if (n > 0)
{
for(int i=0; i<n; ++i)
m_icodes.push_back(picode++);
if(picode == m_end)
return false;
/* Look for MOV BP, SP */
if ( picode != m_end &&
!picode->ic.ll.anyFlagSet(I | TARGET | CASE) &&
picode->ic.ll.match(iMOV,rBP,rSP))
{
m_icodes.push_back(picode);
m_min_off = 2 + (n * 2);
}
else
return false; // Cristina: check this please!
}
else
return false; // Cristina: check this please!
}
}
else // push di [push si] / push si [push di]
{
n = checkStkVars (picode);
for(int i=0; i<n; ++i)
m_icodes.push_back(picode++);
}
return !m_icodes.empty();
}
int Idiom1::action()
{
for(iICODE ic : m_icodes)
{
ic->invalidate();
}
m_func->flg |= PROC_IS_HLL;
if(0!=m_min_off)
m_func->args.m_minOff = m_min_off;
return m_icodes.size();
}