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:
@@ -485,6 +485,12 @@ void g_leave (int flags, int val)
|
|||||||
int k;
|
int k;
|
||||||
char buf [40];
|
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? */
|
/* How many bytes of locals do we have to drop? */
|
||||||
k = -oursp;
|
k = -oursp;
|
||||||
|
|
||||||
@@ -499,8 +505,10 @@ void g_leave (int flags, int val)
|
|||||||
/* Drop stackframe or leave with rts */
|
/* Drop stackframe or leave with rts */
|
||||||
k += funcargs;
|
k += funcargs;
|
||||||
if (k == 0) {
|
if (k == 0) {
|
||||||
|
AddCodeHint ("y:-"); /* Y register no longer used */
|
||||||
AddCodeLine ("\trts");
|
AddCodeLine ("\trts");
|
||||||
} else if (k <= 8) {
|
} else if (k <= 8) {
|
||||||
|
AddCodeHint ("y:-"); /* Y register no longer used */
|
||||||
AddCodeLine ("\tjmp\tincsp%d", k);
|
AddCodeLine ("\tjmp\tincsp%d", k);
|
||||||
} else {
|
} else {
|
||||||
CheckLocalOffs (k);
|
CheckLocalOffs (k);
|
||||||
@@ -515,7 +523,10 @@ void g_leave (int flags, int val)
|
|||||||
/* We've a stack frame to drop */
|
/* We've a stack frame to drop */
|
||||||
ldyconst (k);
|
ldyconst (k);
|
||||||
strcat (buf, "y");
|
strcat (buf, "y");
|
||||||
}
|
} else {
|
||||||
|
/* Y register no longer used */
|
||||||
|
AddCodeHint ("y:-");
|
||||||
|
}
|
||||||
if (flags & CF_CONST) {
|
if (flags & CF_CONST) {
|
||||||
if ((flags & CF_TYPE) != CF_LONG) {
|
if ((flags & CF_TYPE) != CF_LONG) {
|
||||||
/* Constant int sized value given for return code */
|
/* Constant int sized value given for return code */
|
||||||
|
|||||||
@@ -198,6 +198,7 @@ void NewFunc (SymEntry* Func)
|
|||||||
/* Parse argument declarations and function body. */
|
/* Parse argument declarations and function body. */
|
||||||
{
|
{
|
||||||
int isbrk;
|
int isbrk;
|
||||||
|
unsigned Flags;
|
||||||
|
|
||||||
/* Get the function descriptor from the function entry */
|
/* Get the function descriptor from the function entry */
|
||||||
FuncDesc* D = DecodePtr (Func->Type+1);
|
FuncDesc* D = DecodePtr (Func->Type+1);
|
||||||
@@ -251,7 +252,9 @@ void NewFunc (SymEntry* Func)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
RestoreRegVars (0);
|
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 */
|
/* 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)
|
static int IsLabel (const Line* L)
|
||||||
/* Return true if the line is a label line */
|
/* Return true if the line is a label line */
|
||||||
{
|
{
|
||||||
@@ -1136,13 +1144,15 @@ static unsigned RVUInt2 (Line* L,
|
|||||||
L = GetTargetLine (L->Line+5);
|
L = GetTargetLine (L->Line+5);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the next instruction line */
|
/* Get the next line, skip local labels */
|
||||||
L = NextInstruction (L);
|
do {
|
||||||
|
L = NextCodeSegLine (L);
|
||||||
|
} while (L && (IsLocalLabel (L) || L->Line[0] == '\0'));
|
||||||
|
|
||||||
/* Bail out if we're done */
|
/* Bail out if we're done */
|
||||||
if (L == 0 || IsLabel (L)) {
|
if (L == 0 || IsExtLabel (L)) {
|
||||||
/* Something is wrong */
|
/* End of function reached */
|
||||||
return REG_ALL;
|
goto ExitPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if we had this line already. If so, bail out, if not,
|
/* 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"));
|
} 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 */
|
/* Special handling for branches */
|
||||||
if (LineMatchX (L, ShortBranches) >= 0 ||
|
} else if (LineMatchX (L, ShortBranches) >= 0 ||
|
||||||
LineMatchX (L, LongBranches) >= 0) {
|
LineMatchX (L, LongBranches) >= 0) {
|
||||||
const char* Target = L->Line+5;
|
const char* Target = L->Line+5;
|
||||||
if (Target[0] == 'L') {
|
if (Target[0] == 'L') {
|
||||||
/* Jump to local label. Check the register usage starting at
|
/* Jump to local label. Check the register usage starting at
|
||||||
* the branch target and at the code following the branch.
|
* the branch target and at the code following the branch.
|
||||||
* All registers that are unused in both execution flows are
|
* All registers that are unused in both execution flows are
|
||||||
* returned as unused.
|
* returned as unused.
|
||||||
*/
|
*/
|
||||||
unsigned U1, U2;
|
unsigned U1, U2;
|
||||||
U2 = RVUInt1 (GetTargetLine (Target), LC, Used, Unused);
|
U2 = RVUInt1 (GetTargetLine (Target), LC, Used, Unused);
|
||||||
U1 = RVUInt1 (L, LC, Used, Unused);
|
U1 = RVUInt1 (L, LC, Used, Unused);
|
||||||
return U1 | U2; /* Used in any of the branches */
|
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 we know about all registers, bail out */
|
||||||
if ((Used | Unused) == REG_ALL) {
|
if ((Used | Unused) == REG_ALL) {
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ static void doreturn (void)
|
|||||||
/* Handle 'return' statement here */
|
/* Handle 'return' statement here */
|
||||||
{
|
{
|
||||||
struct expent lval;
|
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? */
|
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) {
|
if (evalexpr (CF_NONE, hie0, &lval) == 0) {
|
||||||
/* Constant value */
|
/* Constant value */
|
||||||
etype = CF_CONST;
|
Flags = CF_CONST;
|
||||||
} else {
|
} else {
|
||||||
/* Value in the primary register */
|
/* Value in the primary register */
|
||||||
HaveVal = 1;
|
HaveVal = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert the return value to the type of the function result */
|
/* Convert the return value to the type of the function result */
|
||||||
if (!HasVoidReturn (CurrentFunc)) {
|
if (!HasVoidReturn (CurrentFunc)) {
|
||||||
etype |= assignadjust (GetReturnType (CurrentFunc), &lval) & ~CF_CONST;
|
Flags |= (assignadjust (GetReturnType (CurrentFunc), &lval) & ~CF_CONST) | CF_REG;
|
||||||
}
|
}
|
||||||
} else if (!HasVoidReturn (CurrentFunc)) {
|
} else if (!HasVoidReturn (CurrentFunc)) {
|
||||||
Error ("Function `%s' must return a value", GetFuncName (CurrentFunc));
|
Error ("Function `%s' must return a value", GetFuncName (CurrentFunc));
|
||||||
}
|
}
|
||||||
RestoreRegVars (HaveVal);
|
RestoreRegVars (HaveVal);
|
||||||
g_leave (etype, lval.e_const);
|
g_leave (Flags, lval.e_const);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user