Added new code hints for use at the end of a function
git-svn-id: svn://svn.cc65.org/cc65/trunk@552 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
a05a5e5c38
commit
c8171988a2
4 changed files with 99 additions and 62 deletions
|
@ -485,6 +485,12 @@ void g_leave (int flags, int val)
|
|||
int k;
|
||||
char buf [40];
|
||||
|
||||
/* CF_REG is set if we're returning a value from the function */
|
||||
if ((flags & CF_REG) == 0) {
|
||||
AddCodeHint ("x:-");
|
||||
AddCodeHint ("a:-");
|
||||
}
|
||||
|
||||
/* How many bytes of locals do we have to drop? */
|
||||
k = -oursp;
|
||||
|
||||
|
@ -499,8 +505,10 @@ void g_leave (int flags, int val)
|
|||
/* Drop stackframe or leave with rts */
|
||||
k += funcargs;
|
||||
if (k == 0) {
|
||||
AddCodeHint ("y:-"); /* Y register no longer used */
|
||||
AddCodeLine ("\trts");
|
||||
} else if (k <= 8) {
|
||||
AddCodeHint ("y:-"); /* Y register no longer used */
|
||||
AddCodeLine ("\tjmp\tincsp%d", k);
|
||||
} else {
|
||||
CheckLocalOffs (k);
|
||||
|
@ -515,7 +523,10 @@ void g_leave (int flags, int val)
|
|||
/* We've a stack frame to drop */
|
||||
ldyconst (k);
|
||||
strcat (buf, "y");
|
||||
}
|
||||
} else {
|
||||
/* Y register no longer used */
|
||||
AddCodeHint ("y:-");
|
||||
}
|
||||
if (flags & CF_CONST) {
|
||||
if ((flags & CF_TYPE) != CF_LONG) {
|
||||
/* Constant int sized value given for return code */
|
||||
|
|
|
@ -198,6 +198,7 @@ void NewFunc (SymEntry* Func)
|
|||
/* Parse argument declarations and function body. */
|
||||
{
|
||||
int isbrk;
|
||||
unsigned Flags;
|
||||
|
||||
/* Get the function descriptor from the function entry */
|
||||
FuncDesc* D = DecodePtr (Func->Type+1);
|
||||
|
@ -251,7 +252,9 @@ void NewFunc (SymEntry* Func)
|
|||
}
|
||||
#endif
|
||||
RestoreRegVars (0);
|
||||
g_leave (CF_NONE, 0);
|
||||
|
||||
Flags = HasVoidReturn (CurrentFunc)? CF_NONE : CF_REG;
|
||||
g_leave (Flags, 0);
|
||||
}
|
||||
|
||||
/* Dump literal data created by the function */
|
||||
|
|
|
@ -461,7 +461,7 @@ static void FreeLines (Line* Start, Line* End)
|
|||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Line Collections */
|
||||
/* Line Collections */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
@ -536,6 +536,14 @@ static int IsLocalLabel (const Line* L)
|
|||
|
||||
|
||||
|
||||
static int IsExtLabel (const Line* L)
|
||||
/* Return true if the line is an external label line */
|
||||
{
|
||||
return (L->Line [0] == '_');
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int IsLabel (const Line* L)
|
||||
/* Return true if the line is a label line */
|
||||
{
|
||||
|
@ -1136,13 +1144,15 @@ static unsigned RVUInt2 (Line* L,
|
|||
L = GetTargetLine (L->Line+5);
|
||||
}
|
||||
|
||||
/* Get the next instruction line */
|
||||
L = NextInstruction (L);
|
||||
/* Get the next line, skip local labels */
|
||||
do {
|
||||
L = NextCodeSegLine (L);
|
||||
} while (L && (IsLocalLabel (L) || L->Line[0] == '\0'));
|
||||
|
||||
/* Bail out if we're done */
|
||||
if (L == 0 || IsLabel (L)) {
|
||||
/* Something is wrong */
|
||||
return REG_ALL;
|
||||
if (L == 0 || IsExtLabel (L)) {
|
||||
/* End of function reached */
|
||||
goto ExitPoint;
|
||||
}
|
||||
|
||||
/* Check if we had this line already. If so, bail out, if not,
|
||||
|
@ -1154,56 +1164,69 @@ static unsigned RVUInt2 (Line* L,
|
|||
|
||||
} while (LineMatch (L, "\tjmp\tL") || LineMatch (L, "\tbra\tL"));
|
||||
|
||||
/* Special handling of code hints */
|
||||
if (IsHintLine (L)) {
|
||||
|
||||
if (IsHint (L, "a:-") && (Used & REG_A) == 0) {
|
||||
Unused |= REG_A;
|
||||
} else if (IsHint (L, "x:-") && (Used & REG_X) == 0) {
|
||||
Unused |= REG_X;
|
||||
} else if (IsHint (L, "y:-") && (Used & REG_Y) == 0) {
|
||||
Unused |= REG_Y;
|
||||
}
|
||||
|
||||
/* Special handling for branches */
|
||||
if (LineMatchX (L, ShortBranches) >= 0 ||
|
||||
} else if (LineMatchX (L, ShortBranches) >= 0 ||
|
||||
LineMatchX (L, LongBranches) >= 0) {
|
||||
const char* Target = L->Line+5;
|
||||
if (Target[0] == 'L') {
|
||||
/* Jump to local label. Check the register usage starting at
|
||||
* the branch target and at the code following the branch.
|
||||
* All registers that are unused in both execution flows are
|
||||
* returned as unused.
|
||||
*/
|
||||
unsigned U1, U2;
|
||||
/* Jump to local label. Check the register usage starting at
|
||||
* the branch target and at the code following the branch.
|
||||
* All registers that are unused in both execution flows are
|
||||
* returned as unused.
|
||||
*/
|
||||
unsigned U1, U2;
|
||||
U2 = RVUInt1 (GetTargetLine (Target), LC, Used, Unused);
|
||||
U1 = RVUInt1 (L, LC, Used, Unused);
|
||||
return U1 | U2; /* Used in any of the branches */
|
||||
U1 = RVUInt1 (L, LC, Used, Unused);
|
||||
return U1 | U2; /* Used in any of the branches */
|
||||
}
|
||||
} else {
|
||||
|
||||
/* Search for the instruction in this line */
|
||||
I = FindCmd (L);
|
||||
|
||||
/* If we don't find it, assume all other registers are used */
|
||||
if (I < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Evaluate the use flags, check for addressing modes */
|
||||
R = CmdDesc[I].Use;
|
||||
if (IsXAddrMode (L)) {
|
||||
R |= REG_X;
|
||||
} else if (IsYAddrMode (L)) {
|
||||
R |= REG_Y;
|
||||
}
|
||||
if (R) {
|
||||
/* Remove registers that were already new loaded */
|
||||
R &= ~Unused;
|
||||
|
||||
/* Remember the remaining registers */
|
||||
Used |= R;
|
||||
}
|
||||
|
||||
/* Evaluate the load flags */
|
||||
R = CmdDesc[I].Load;
|
||||
if (R) {
|
||||
/* Remove registers that were already used */
|
||||
R &= ~Used;
|
||||
|
||||
/* Remember the remaining registers */
|
||||
Unused |= R;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Search for the instruction in this line */
|
||||
I = FindCmd (L);
|
||||
|
||||
/* If we don't find it, assume all other registers are */
|
||||
if (I < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Evaluate the use flags, check for addressing modes */
|
||||
R = CmdDesc[I].Use;
|
||||
if (IsXAddrMode (L)) {
|
||||
R |= REG_X;
|
||||
} else if (IsYAddrMode (L)) {
|
||||
R |= REG_Y;
|
||||
}
|
||||
if (R) {
|
||||
/* Remove registers that were already new loaded */
|
||||
R &= ~Unused;
|
||||
|
||||
/* Remember the remaining registers */
|
||||
Used |= R;
|
||||
}
|
||||
|
||||
/* Evaluate the load flags */
|
||||
R = CmdDesc[I].Load;
|
||||
if (R) {
|
||||
/* Remove registers that were already used */
|
||||
R &= ~Used;
|
||||
|
||||
/* Remember the remaining registers */
|
||||
Unused |= R;
|
||||
}
|
||||
|
||||
/* If we know about all registers, bail out */
|
||||
if ((Used | Unused) == REG_ALL) {
|
||||
break;
|
||||
|
|
|
@ -166,7 +166,7 @@ static void doreturn (void)
|
|||
/* Handle 'return' statement here */
|
||||
{
|
||||
struct expent lval;
|
||||
unsigned etype = 0; /* Type of return expression */
|
||||
unsigned Flags = 0; /* Code generator flags */
|
||||
int HaveVal = 0; /* Do we have a return value in ax? */
|
||||
|
||||
|
||||
|
@ -177,21 +177,21 @@ static void doreturn (void)
|
|||
}
|
||||
if (evalexpr (CF_NONE, hie0, &lval) == 0) {
|
||||
/* Constant value */
|
||||
etype = CF_CONST;
|
||||
Flags = CF_CONST;
|
||||
} else {
|
||||
/* Value in the primary register */
|
||||
HaveVal = 1;
|
||||
}
|
||||
/* Value in the primary register */
|
||||
HaveVal = 1;
|
||||
}
|
||||
|
||||
/* Convert the return value to the type of the function result */
|
||||
if (!HasVoidReturn (CurrentFunc)) {
|
||||
etype |= assignadjust (GetReturnType (CurrentFunc), &lval) & ~CF_CONST;
|
||||
}
|
||||
/* Convert the return value to the type of the function result */
|
||||
if (!HasVoidReturn (CurrentFunc)) {
|
||||
Flags |= (assignadjust (GetReturnType (CurrentFunc), &lval) & ~CF_CONST) | CF_REG;
|
||||
}
|
||||
} else if (!HasVoidReturn (CurrentFunc)) {
|
||||
Error ("Function `%s' must return a value", GetFuncName (CurrentFunc));
|
||||
Error ("Function `%s' must return a value", GetFuncName (CurrentFunc));
|
||||
}
|
||||
RestoreRegVars (HaveVal);
|
||||
g_leave (etype, lval.e_const);
|
||||
g_leave (Flags, lval.e_const);
|
||||
}
|
||||
|
||||
|
||||
|
@ -396,7 +396,7 @@ static void cascadeswitch (struct expent* eval)
|
|||
CodeLab = GetLabel ();
|
||||
}
|
||||
g_jump (CodeLab);
|
||||
}
|
||||
}
|
||||
|
||||
/* Remember that we had a default label */
|
||||
HaveDefault = 1;
|
||||
|
|
Loading…
Add table
Reference in a new issue