cc65/src/cc65/coptsize.c

1037 lines
43 KiB
C

/*****************************************************************************/
/* */
/* coptsize.c */
/* */
/* Size optimizations */
/* */
/* */
/* */
/* (C) 2002-2012, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <stdlib.h>
/* common */
#include "cpu.h"
/* cc65 */
#include "codeent.h"
#include "codeinfo.h"
#include "coptsize.h"
#include "reginfo.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Flags for CallDesc */
#define F_NONE 0x0000U /* No extra flags */
#define F_SLOWER 0x0001U /* Function call is slower */
typedef struct CallDesc CallDesc;
struct CallDesc {
const char* LongFunc; /* Long function name */
RegContents Regs; /* Register contents */
unsigned Flags; /* Flags from above */
const char* ShortFunc; /* Short function name */
};
/* Note: The table is sorted. If there is more than one entry with the same
** name, entries are sorted best match first, so when searching linear for
** a match, the first one can be used because it is also the best one (or
** at least none of the following ones are better).
** Note^2: Ptr1 and Tmp1 aren't evaluated, because runtime routines don't
** expect parameters here.
*/
static const CallDesc CallTable [] = {
/* Name A register X register Y register flags replacement */
{
"addeqysp",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"addeq0sp"
},{
"laddeq",
{
/* A X Y SRegLo SRegHi */
1, 0, UNKNOWN_REGVAL, 0, 0,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"laddeq1"
},{
"laddeq",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, 0, 0,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"laddeqa"
},{
"laddeqysp",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"laddeq0sp"
},{
"ldaxidx",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, 1, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"ldaxi"
},{
"ldaxysp",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, 1, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"ldax0sp"
},{
"ldeaxidx",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, 3, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"ldeaxi"
},{
"ldeaxysp",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, 3, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"ldeax0sp"
},{
"leaaxsp",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"leaa0sp"
},{
"lsubeq",
{
/* A X Y SRegLo SRegHi */
1, 0, UNKNOWN_REGVAL, 0, 0,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"lsubeq1"
},{
"lsubeq",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, 0, 0,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"lsubeqa"
},{
"lsubeqysp",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"lsubeq0sp"
},{
"pusha",
{
/* A X Y SRegLo SRegHi */
0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_SLOWER,
"pushc0"
},{
"pusha",
{
/* A X Y SRegLo SRegHi */
1, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_SLOWER,
"pushc1"
},{
"pusha",
{
/* A X Y SRegLo SRegHi */
2, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_SLOWER,
"pushc2"
},{
"pushax",
{
/* A X Y SRegLo SRegHi */
0, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"push0"
},{
"pushax",
{
/* A X Y SRegLo SRegHi */
1, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_SLOWER,
"push1"
},{
"pushax",
{
/* A X Y SRegLo SRegHi */
2, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_SLOWER,
"push2"
},{
"pushax",
{
/* A X Y SRegLo SRegHi */
3, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_SLOWER,
"push3"
},{
"pushax",
{
/* A X Y SRegLo SRegHi */
4, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_SLOWER,
"push4"
},{
"pushax",
{
/* A X Y SRegLo SRegHi */
5, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_SLOWER,
"push5"
},{
"pushax",
{
/* A X Y SRegLo SRegHi */
6, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_SLOWER,
"push6"
},{
"pushax",
{
/* A X Y SRegLo SRegHi */
7, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_SLOWER,
"push7"
},{
"pushax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"pusha0"
},{
"pushax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0xFF, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_SLOWER,
"pushaFF"
},{
"pushaysp",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"pusha0sp"
},{
"pusheax",
{
/* A X Y SRegLo SRegHi */
0, 0, UNKNOWN_REGVAL, 0, 0,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"pushl0"
},{
"pusheax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, 0,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"push0ax"
},{
"pushwidx",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, 1, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"pushw"
},{
"pushwysp",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, 3, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"pushw0sp"
},{
"staxysp",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"stax0sp"
},{
"steaxysp",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"steax0sp"
},{
"subeqysp",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"subeq0sp"
},{
"tosaddax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosadda0"
},{
"tosaddeax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, 0,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosadd0ax"
},{
"tosandax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosanda0"
},{
"tosandeax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, 0,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosand0ax"
},{
"tosdivax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosdiva0"
},{
"tosdiveax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, 0,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosdiv0ax"
},{
"toseqax",
{
/* A X Y SRegLo SRegHi */
0, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"toseq00"
},{
"toseqax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"toseqa0"
},{
"tosgeax",
{
/* A X Y SRegLo SRegHi */
0, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosge00"
},{
"tosgeax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosgea0"
},{
"tosgtax",
{
/* A X Y SRegLo SRegHi */
0, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosgt00"
},{
"tosgtax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosgta0"
},{
"tosicmp",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosicmp0"
},{
"tosleax",
{
/* A X Y SRegLo SRegHi */
0, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosle00"
},{
"tosleax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"toslea0"
},{
"tosltax",
{
/* A X Y SRegLo SRegHi */
0, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"toslt00"
},{
"tosltax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"toslta0"
},{
"tosmodax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosmoda0"
},{
"tosmodeax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, 0,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosmod0ax"
},{
"tosmulax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosmula0"
},{
"tosmuleax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, 0,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosmul0ax"
},{
"tosneax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosnea0"
},{
"tosorax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosora0"
},{
"tosoreax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, 0,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosor0ax"
},{
"tosrsubax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosrsuba0"
},{
"tosrsubeax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, 0,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosrsub0ax"
},{
"tossubax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tossuba0"
},{
"tossubeax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, 0,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tossub0ax"
},{
"tosudivax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosudiva0"
},{
"tosudiveax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, 0,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosudiv0ax"
},{
"tosugeax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosugea0"
},{
"tosugtax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosugta0"
},{
"tosuleax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosulea0"
},{
"tosultax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosulta0"
},{
"tosumodax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosumoda0"
},{
"tosumodeax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, 0,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosumod0ax"
},{
"tosumulax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosumula0"
},{
"tosumuleax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, 0,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosumul0ax"
},{
"tosxorax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosxora0"
},{
"tosxoreax",
{
/* A X Y SRegLo SRegHi */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, 0,
/* Ptr1Lo Ptr1Hi Tmp1 PFlags ZNRegs */
UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_PFVAL_ALL, ZNREG_NONE
},
F_NONE,
"tosxor0ax"
},
};
#define CALL_COUNT (sizeof(CallTable) / sizeof(CallTable[0]))
/*****************************************************************************/
/* Helpers */
/*****************************************************************************/
static const CallDesc* FindCall (const char* Name)
/* Find the function with the given name. Return a pointer to the table entry
** or NULL if the function was not found.
*/
{
/* Do a binary search */
int First = 0;
int Last = CALL_COUNT - 1;
int Found = 0;
while (First <= Last) {
/* Set current to mid of range */
int Current = (Last + First) / 2;
/* Do a compare */
int Result = strcmp (CallTable[Current].LongFunc, Name);
if (Result < 0) {
First = Current + 1;
} else {
Last = Current - 1;
if (Result == 0) {
/* Found. Repeat the procedure until the first of all entries
** with the same name is found.
*/
Found = 1;
}
}
}
/* Return the first entry if found, or NULL otherwise */
return Found? &CallTable[First] : 0;
}
static int RegMatch (short Expected, short Actual)
/* Check for a register match. If Expected has a value, it must be identical
** to Actual.
*/
{
return RegValIsUnknown (Expected) || (Expected == Actual);
}
/*****************************************************************************/
/* Code */
/*****************************************************************************/
unsigned OptSize1 (CodeSeg* S)
/* Do size optimization by calling special subroutines that preload registers.
** This routine does not work standalone, it needs a following register load
** removal pass.
*/
{
CodeEntry* E;
unsigned Changes = 0;
unsigned I;
/* Are we optimizing for size */
int OptForSize = (S->CodeSizeFactor < 100);
/* Walk over the entries */
I = 0;
while (I < CS_GetEntryCount (S)) {
const CallDesc* D;
/* Get next entry */
E = CS_GetEntry (S, I);
/* Check if it's a subroutine call */
if (E->OPC == OP65_JSR && (D = FindCall (E->Arg)) != 0) {
/* Get input register info for this insn */
const RegContents* In = &E->RI->In;
/* FindCall finds the first entry that matches our function name.
** The names are listed in "best match" order, so search for the
** first one, that fulfills our conditions.
*/
while (1) {
/* Check the registers and allow slower code only if
** optimizing for size.
*/
if ((OptForSize || (D->Flags & F_SLOWER) == 0) &&
RegMatch (D->Regs.RegA, In->RegA) &&
RegMatch (D->Regs.RegX, In->RegX) &&
RegMatch (D->Regs.RegY, In->RegY) &&
RegMatch (D->Regs.SRegLo, In->SRegLo) &&
RegMatch (D->Regs.SRegHi, In->SRegHi)) {
/* Ok, match for all conditions */
CodeEntry* X;
X = NewCodeEntry (E->OPC, E->AM, D->ShortFunc, 0, E->LI);
CS_InsertEntry (S, X, I+1);
CS_DelEntry (S, I);
/* Remember that we had changes */
++Changes;
/* Done */
break;
}
/* Next table entry, bail out if next entry not valid */
if (++D >= CallTable + CALL_COUNT ||
strcmp (D->LongFunc, E->Arg) != 0) {
/* End of table or entries reached */
break;
}
}
}
/* Next entry */
++I;
}
/* Return the number of changes made */
return Changes;
}
unsigned OptSize2 (CodeSeg* S)
/* Do size optimization by using shorter code sequences, even if this
** introduces relations between instructions. This step must be one of the
** last steps, because it makes further work much more difficult.
*/
{
unsigned Changes = 0;
unsigned I;
/* Walk over the entries */
I = 0;
while (I < CS_GetEntryCount (S)) {
/* Get next entry */
CodeEntry* E = CS_GetEntry (S, I);
/* Get the input registers */
const RegContents* In = &E->RI->In;
/* Assume we have no replacement */
CodeEntry* X = 0;
/* Check the instruction */
switch (E->OPC) {
case OP65_LDA:
if (CE_IsConstImm (E)) {
short Val = (short) E->Num;
if (Val == In->RegX) {
X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, E->LI);
} else if (Val == In->RegY) {
X = NewCodeEntry (OP65_TYA, AM65_IMP, 0, 0, E->LI);
} else if (RegValIsKnown (In->RegA) && (CPUIsets[CPU] & CPU_ISET_65SC02) != 0) {
if (Val == ((In->RegA - 1) & 0xFF)) {
X = NewCodeEntry (OP65_DEA, AM65_IMP, 0, 0, E->LI);
} else if (Val == ((In->RegA + 1) & 0xFF)) {
X = NewCodeEntry (OP65_INA, AM65_IMP, 0, 0, E->LI);
}
}
}
break;
case OP65_LDX:
if (CE_IsConstImm (E)) {
short Val = (short) E->Num;
if (RegValIsKnown (In->RegX) && Val == ((In->RegX - 1) & 0xFF)) {
X = NewCodeEntry (OP65_DEX, AM65_IMP, 0, 0, E->LI);
} else if (RegValIsKnown (In->RegX) && Val == ((In->RegX + 1) & 0xFF)) {
X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, E->LI);
} else if (Val == In->RegA) {
X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, E->LI);
}
}
break;
case OP65_LDY:
if (CE_IsConstImm (E)) {
short Val = (short) E->Num;
if (RegValIsKnown (In->RegY) && Val == ((In->RegY - 1) & 0xFF)) {
X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, E->LI);
} else if (RegValIsKnown (In->RegY) && Val == ((In->RegY + 1) & 0xFF)) {
X = NewCodeEntry (OP65_INY, AM65_IMP, 0, 0, E->LI);
} else if (Val == In->RegA) {
X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, E->LI);
}
}
break;
default:
/* Avoid gcc warnings */
break;
}
/* Insert the replacement if we have one */
if (X) {
CS_InsertEntry (S, X, I+1);
CS_DelEntry (S, I);
++Changes;
}
/* Next entry */
++I;
}
/* Return the number of changes made */
return Changes;
}