/* */
/* */
/* */
-/* (C) 2001-2006, Ullrich von Bassewitz */
-/* Römerstraße 52 */
+/* (C) 2001-2009, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
*/
typedef struct FuncInfo FuncInfo;
struct FuncInfo {
- const char* Name; /* Function name */
- unsigned short Use; /* Register usage */
- unsigned short Chg; /* Changed/destroyed registers */
+ const char* Name; /* Function name */
+ unsigned short Use; /* Register usage */
+ unsigned short Chg; /* Changed/destroyed registers */
};
+/* Note for the shift functions: Shifts are done modulo 32, so all shift
+ * routines are marked to use only the A register. The remainder is ignored
+ * anyway.
+ */
static const FuncInfo FuncInfoTable[] = {
{ "addeq0sp", REG_AX, REG_AXY },
{ "addeqysp", REG_AXY, REG_AXY },
{ "aslax2", REG_AX, REG_AX | REG_TMP1 },
{ "aslax3", REG_AX, REG_AX | REG_TMP1 },
{ "aslax4", REG_AX, REG_AX | REG_TMP1 },
+ { "asleax1", REG_EAX, REG_EAX | REG_TMP1 },
+ { "asleax2", REG_EAX, REG_EAX | REG_TMP1 },
+ { "asleax3", REG_EAX, REG_EAX | REG_TMP1 },
+ { "asleax4", REG_EAX, REG_EAXY | REG_TMP1 },
+ { "asrax1", REG_AX, REG_AX | REG_TMP1 },
+ { "asrax2", REG_AX, REG_AX | REG_TMP1 },
+ { "asrax3", REG_AX, REG_AX | REG_TMP1 },
+ { "asrax4", REG_AX, REG_AX | REG_TMP1 },
+ { "asreax1", REG_EAX, REG_EAX | REG_TMP1 },
+ { "asreax2", REG_EAX, REG_EAX | REG_TMP1 },
+ { "asreax3", REG_EAX, REG_EAX | REG_TMP1 },
+ { "asreax4", REG_EAX, REG_EAXY | REG_TMP1 },
{ "bnega", REG_A, REG_AX },
{ "bnegax", REG_AX, REG_AX },
{ "bnegeax", REG_EAX, REG_EAX },
{ "boolge", REG_NONE, REG_AX },
{ "boolgt", REG_NONE, REG_AX },
{ "boolle", REG_NONE, REG_AX },
- { "boollt", REG_NONE, REG_AX },
+ { "boollt", REG_NONE, REG_AX },
{ "boolne", REG_NONE, REG_AX },
{ "booluge", REG_NONE, REG_AX },
{ "boolugt", REG_NONE, REG_AX },
{ "boolule", REG_NONE, REG_AX },
{ "boolult", REG_NONE, REG_AX },
+ { "callax", REG_AX, REG_ALL },
{ "complax", REG_AX, REG_AX },
{ "decax1", REG_AX, REG_AX },
{ "decax2", REG_AX, REG_AX },
{ "decsp6", REG_NONE, REG_A },
{ "decsp7", REG_NONE, REG_A },
{ "decsp8", REG_NONE, REG_A },
- { "incax1", REG_AX, REG_AX },
- { "incax2", REG_AX, REG_AX },
- { "incax3", REG_AX, REG_AX },
- { "incax4", REG_AX, REG_AX },
- { "incax5", REG_AX, REG_AX },
- { "incax6", REG_AX, REG_AX },
- { "incax7", REG_AX, REG_AX },
- { "incax8", REG_AX, REG_AX },
+ { "incax1", REG_AX, REG_AX },
+ { "incax2", REG_AX, REG_AX },
+ { "incax3", REG_AX, REG_AXY | REG_TMP1 },
+ { "incax4", REG_AX, REG_AXY | REG_TMP1 },
+ { "incax5", REG_AX, REG_AXY | REG_TMP1 },
+ { "incax6", REG_AX, REG_AXY | REG_TMP1 },
+ { "incax7", REG_AX, REG_AXY | REG_TMP1 },
+ { "incax8", REG_AX, REG_AXY | REG_TMP1 },
+ { "incaxy", REG_AXY, REG_AXY | REG_TMP1 },
{ "incsp1", REG_NONE, REG_NONE },
{ "incsp2", REG_NONE, REG_Y },
{ "incsp3", REG_NONE, REG_Y },
{ "ldeaxi", REG_AX, REG_EAXY | REG_PTR1 },
{ "ldeaxidx", REG_AXY, REG_EAXY | REG_PTR1 },
{ "ldeaxysp", REG_Y, REG_EAXY },
- { "leaasp", REG_A, REG_AX },
+ { "leaa0sp", REG_A, REG_AX },
+ { "leaaxsp", REG_AX, REG_AX },
{ "lsubeq", REG_EAXY|REG_PTR1_LO, REG_EAXY | REG_PTR1_HI },
{ "lsubeq0sp", REG_EAX, REG_EAXY },
{ "lsubeq1", REG_Y | REG_PTR1_LO, REG_EAXY | REG_PTR1_HI },
{ "lsubeqa", REG_AY | REG_PTR1_LO, REG_EAXY | REG_PTR1_HI },
{ "lsubeqysp", REG_EAXY, REG_EAXY },
+ { "mulax10", REG_AX, REG_AX | REG_PTR1 },
+ { "mulax3", REG_AX, REG_AX | REG_PTR1 },
+ { "mulax5", REG_AX, REG_AX | REG_PTR1 },
+ { "mulax6", REG_AX, REG_AX | REG_PTR1 },
+ { "mulax7", REG_AX, REG_AX | REG_PTR1 },
+ { "mulax9", REG_AX, REG_AX | REG_PTR1 },
{ "negax", REG_AX, REG_AX },
{ "push0", REG_NONE, REG_AXY },
+ { "push0ax", REG_AX, REG_Y | REG_SREG },
{ "push1", REG_NONE, REG_AXY },
{ "push2", REG_NONE, REG_AXY },
{ "push3", REG_NONE, REG_AXY },
{ "pusha", REG_A, REG_Y },
{ "pusha0", REG_A, REG_XY },
{ "pusha0sp", REG_NONE, REG_AY },
- { "pushax", REG_AX, REG_Y },
+ { "pushaFF", REG_A, REG_Y },
+ { "pushax", REG_AX, REG_Y },
{ "pushaysp", REG_Y, REG_AY },
{ "pushc0", REG_NONE, REG_A | REG_Y },
{ "pushc1", REG_NONE, REG_A | REG_Y },
{ "regswap", REG_AXY, REG_AXY | REG_TMP1 },
{ "regswap1", REG_XY, REG_A },
{ "regswap2", REG_XY, REG_A | REG_Y },
+ { "return0", REG_NONE, REG_AX },
+ { "return1", REG_NONE, REG_AX },
{ "shlax1", REG_AX, REG_AX | REG_TMP1 },
{ "shlax2", REG_AX, REG_AX | REG_TMP1 },
{ "shlax3", REG_AX, REG_AX | REG_TMP1 },
{ "shlax4", REG_AX, REG_AX | REG_TMP1 },
+ { "shleax1", REG_EAX, REG_EAX | REG_TMP1 },
+ { "shleax2", REG_EAX, REG_EAX | REG_TMP1 },
+ { "shleax3", REG_EAX, REG_EAX | REG_TMP1 },
+ { "shleax4", REG_EAX, REG_EAXY | REG_TMP1 },
{ "shrax1", REG_AX, REG_AX | REG_TMP1 },
{ "shrax2", REG_AX, REG_AX | REG_TMP1 },
{ "shrax3", REG_AX, REG_AX | REG_TMP1 },
{ "shrax4", REG_AX, REG_AX | REG_TMP1 },
- { "shreax1", REG_EAX, REG_AX | REG_TMP1 },
- { "shreax2", REG_EAX, REG_AX | REG_TMP1 },
- { "shreax3", REG_EAX, REG_AX | REG_TMP1 },
- { "shreax4", REG_EAX, REG_AX | REG_TMP1 },
+ { "shreax1", REG_EAX, REG_EAX | REG_TMP1 },
+ { "shreax2", REG_EAX, REG_EAX | REG_TMP1 },
+ { "shreax3", REG_EAX, REG_EAX | REG_TMP1 },
+ { "shreax4", REG_EAX, REG_EAXY | REG_TMP1 },
{ "staspidx", REG_A | REG_Y, REG_Y | REG_TMP1 | REG_PTR1 },
{ "stax0sp", REG_AX, REG_Y },
{ "staxspidx", REG_AXY, REG_TMP1 | REG_PTR1 },
{ "steaxysp", REG_EAXY, REG_Y },
{ "subeq0sp", REG_AX, REG_AXY },
{ "subeqysp", REG_AXY, REG_AXY },
+ { "tosadd0ax", REG_AX, REG_EAXY | REG_TMP1 },
{ "tosadda0", REG_A, REG_AXY },
{ "tosaddax", REG_AX, REG_AXY },
+ { "tosaddeax", REG_EAX, REG_EAXY | REG_TMP1 },
+ { "tosand0ax", REG_AX, REG_EAX | REG_TMP1 },
{ "tosanda0", REG_A, REG_AXY },
{ "tosandax", REG_AX, REG_AXY },
+ { "tosandeax", REG_EAX, REG_EAX | REG_TMP1 },
{ "tosaslax", REG_A, REG_AXY | REG_TMP1 },
- { "tosasleax", REG_A, REG_EAXY | REG_TMP1 },
+ { "tosasleax", REG_A, REG_EAXY | REG_TMP1 },
{ "tosasrax", REG_A, REG_AXY | REG_TMP1 },
- { "tosasreax", REG_A, REG_EAXY | REG_TMP1 },
- { "tosdiva0", REG_AY, REG_ALL },
- { "tosdivax", REG_AXY, REG_ALL },
- { "tosdiveax", REG_EAXY, REG_ALL },
+ { "tosasreax", REG_A, REG_EAXY | REG_TMP1 },
+ { "tosdiv0ax", REG_AX, REG_ALL },
+ { "tosdiva0", REG_A, REG_ALL },
+ { "tosdivax", REG_AX, REG_ALL },
+ { "tosdiveax", REG_EAX, REG_ALL },
+ { "toseq00", REG_NONE, REG_AXY | REG_SREG },
+ { "toseqa0", REG_A, REG_AXY | REG_SREG },
+ { "toseqax", REG_AX, REG_AXY | REG_SREG },
{ "toseqeax", REG_EAX, REG_AXY | REG_PTR1 },
+ { "tosge00", REG_NONE, REG_AXY | REG_SREG },
+ { "tosgea0", REG_A, REG_AXY | REG_SREG },
+ { "tosgeax", REG_AX, REG_AXY | REG_SREG },
{ "tosgeeax", REG_EAX, REG_AXY | REG_PTR1 },
+ { "tosgt00", REG_NONE, REG_AXY | REG_SREG },
+ { "tosgta0", REG_A, REG_AXY | REG_SREG },
+ { "tosgtax", REG_AX, REG_AXY | REG_SREG },
{ "tosgteax", REG_EAX, REG_AXY | REG_PTR1 },
{ "tosicmp", REG_AX, REG_AXY | REG_SREG },
+ { "tosicmp0", REG_A, REG_AXY | REG_SREG },
{ "toslcmp", REG_EAX, REG_A | REG_Y | REG_PTR1 },
+ { "tosle00", REG_NONE, REG_AXY | REG_SREG },
+ { "toslea0", REG_A, REG_AXY | REG_SREG },
+ { "tosleax", REG_AX, REG_AXY | REG_SREG },
{ "tosleeax", REG_EAX, REG_AXY | REG_PTR1 },
+ { "toslt00", REG_NONE, REG_AXY | REG_SREG },
+ { "toslta0", REG_A, REG_AXY | REG_SREG },
+ { "tosltax", REG_AX, REG_AXY | REG_SREG },
{ "toslteax", REG_EAX, REG_AXY | REG_PTR1 },
- { "tosmula0", REG_AX, REG_ALL },
+ { "tosmod0ax", REG_AX, REG_ALL },
+ { "tosmodeax", REG_EAX, REG_ALL },
+ { "tosmul0ax", REG_AX, REG_ALL },
+ { "tosmula0", REG_A, REG_ALL },
{ "tosmulax", REG_AX, REG_ALL },
{ "tosmuleax", REG_EAX, REG_ALL },
+ { "tosne00", REG_NONE, REG_AXY | REG_SREG },
+ { "tosnea0", REG_A, REG_AXY | REG_SREG },
+ { "tosneax", REG_AX, REG_AXY | REG_SREG },
{ "tosneeax", REG_EAX, REG_AXY | REG_PTR1 },
+ { "tosor0ax", REG_AX, REG_EAX | REG_TMP1 },
+ { "tosora0", REG_A, REG_AXY | REG_TMP1 },
+ { "tosorax", REG_AX, REG_AXY | REG_TMP1 },
+ { "tosoreax", REG_EAX, REG_EAX | REG_TMP1 },
+ { "tosrsub0ax", REG_AX, REG_EAX | REG_TMP1 },
+ { "tosrsuba0", REG_A, REG_AX | REG_TMP1 },
+ { "tosrsubax", REG_AX, REG_AX | REG_TMP1 },
+ { "tosrsubeax", REG_EAX, REG_EAX | REG_TMP1 },
{ "tosshlax", REG_A, REG_AXY | REG_TMP1 },
{ "tosshleax", REG_A, REG_EAXY | REG_TMP1 },
{ "tosshrax", REG_A, REG_AXY | REG_TMP1 },
{ "tosshreax", REG_A, REG_EAXY | REG_TMP1 },
+ { "tossub0ax", REG_AX, REG_EAXY },
{ "tossuba0", REG_A, REG_AXY },
{ "tossubax", REG_AX, REG_AXY },
{ "tossubeax", REG_EAX, REG_EAXY },
+ { "tosudiv0ax", REG_AX, REG_ALL & ~REG_SAVE },
+ { "tosudiva0", REG_A, REG_EAXY | REG_PTR1 }, /* also ptr4 */
+ { "tosudivax", REG_AX, REG_EAXY | REG_PTR1 }, /* also ptr4 */
+ { "tosudiveax", REG_EAX, REG_ALL & ~REG_SAVE },
+ { "tosuge00", REG_NONE, REG_AXY | REG_SREG },
+ { "tosugea0", REG_A, REG_AXY | REG_SREG },
+ { "tosugeax", REG_AX, REG_AXY | REG_SREG },
{ "tosugeeax", REG_EAX, REG_AXY | REG_PTR1 },
+ { "tosugt00", REG_NONE, REG_AXY | REG_SREG },
+ { "tosugta0", REG_A, REG_AXY | REG_SREG },
+ { "tosugtax", REG_AX, REG_AXY | REG_SREG },
{ "tosugteax", REG_EAX, REG_AXY | REG_PTR1 },
+ { "tosule00", REG_NONE, REG_AXY | REG_SREG },
+ { "tosulea0", REG_A, REG_AXY | REG_SREG },
+ { "tosuleax", REG_AX, REG_AXY | REG_SREG },
{ "tosuleeax", REG_EAX, REG_AXY | REG_PTR1 },
+ { "tosult00", REG_NONE, REG_AXY | REG_SREG },
+ { "tosulta0", REG_A, REG_AXY | REG_SREG },
+ { "tosultax", REG_AX, REG_AXY | REG_SREG },
{ "tosulteax", REG_EAX, REG_AXY | REG_PTR1 },
- { "tosumula0", REG_AX, REG_ALL },
+ { "tosumod0ax", REG_AX, REG_ALL & ~REG_SAVE },
+ { "tosumoda0", REG_A, REG_EAXY | REG_PTR1 }, /* also ptr4 */
+ { "tosumodax", REG_AX, REG_EAXY | REG_PTR1 }, /* also ptr4 */
+ { "tosumodeax", REG_EAX, REG_ALL & ~REG_SAVE },
+ { "tosumul0ax", REG_AX, REG_ALL },
+ { "tosumula0", REG_A, REG_ALL },
{ "tosumulax", REG_AX, REG_ALL },
{ "tosumuleax", REG_EAX, REG_ALL },
+ { "tosxor0ax", REG_AX, REG_EAX | REG_TMP1 },
+ { "tosxora0", REG_A, REG_AX | REG_TMP1 },
+ { "tosxorax", REG_AX, REG_AX | REG_TMP1 },
+ { "tosxoreax", REG_EAX, REG_EAX | REG_TMP1 },
{ "tsteax", REG_EAX, REG_Y },
{ "utsteax", REG_EAX, REG_Y },
};
/* Did we find it in the top level table? */
if (E && IsTypeFunc (E->Type)) {
+ FuncDesc* D = E->V.F.Func;
+
/* A function may use the A or A/X registers if it is a fastcall
* function. If it is not a fastcall function but a variadic one,
* it will use the Y register (the parameter size is passed here).
* In all other cases, no registers are used. However, we assume
* that any function will destroy all registers.
*/
- FuncDesc* D = E->V.F.Func;
- if ((D->Flags & FD_FASTCALL) != 0 && D->ParamCount > 0) {
+ if (IsQualFastcall (E->Type) && D->ParamCount > 0) {
/* Will use registers depending on the last param */
unsigned LastParamSize = CheckedSizeOf (D->LastParam->Type);
if (LastParamSize == 1) {
* use and change all registers.
*/
if (Debug) {
- fprintf (stderr, "No info about internal function `%s'", Name);
+ fprintf (stderr, "No info about internal function `%s'\n", Name);
}
*Use = REG_ALL;
*Chg = REG_ALL;