mirror of
https://github.com/cc65/cc65.git
synced 2024-07-31 11:29:16 +00:00
Optimizer bugfixes, polished the line info.
git-svn-id: svn://svn.cc65.org/cc65/trunk@761 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
916a0879d5
commit
034a4b75e5
@ -499,7 +499,7 @@ static unsigned OptSub2 (CodeSeg* S)
|
|||||||
CodeEntry* E = GetCodeEntry (S, I);
|
CodeEntry* E = GetCodeEntry (S, I);
|
||||||
|
|
||||||
/* Check for the sequence */
|
/* Check for the sequence */
|
||||||
if (E->OPC == OPC_LDA &&
|
if (E->OPC == OPC_LDA &&
|
||||||
GetCodeEntries (S, L, I+1, 5) &&
|
GetCodeEntries (S, L, I+1, 5) &&
|
||||||
L[0]->OPC == OPC_SEC &&
|
L[0]->OPC == OPC_SEC &&
|
||||||
!CodeEntryHasLabel (L[0]) &&
|
!CodeEntryHasLabel (L[0]) &&
|
||||||
@ -527,8 +527,15 @@ static unsigned OptSub2 (CodeSeg* S)
|
|||||||
MoveCodeEntry (S, I, I+3);
|
MoveCodeEntry (S, I, I+3);
|
||||||
ReplaceOPC (E, OPC_SBC);
|
ReplaceOPC (E, OPC_SBC);
|
||||||
|
|
||||||
|
/* If the sequence head had a label, move this label back to the
|
||||||
|
* head.
|
||||||
|
*/
|
||||||
|
if (CodeEntryHasLabel (E)) {
|
||||||
|
MoveCodeLabels (S, E, L[0]);
|
||||||
|
}
|
||||||
|
|
||||||
/* Remember, we had changes */
|
/* Remember, we had changes */
|
||||||
++Changes;
|
++Changes;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -765,6 +772,13 @@ static unsigned OptCmp3 (CodeSeg* S)
|
|||||||
ReplaceOPC (L[0], OPC_LDA);
|
ReplaceOPC (L[0], OPC_LDA);
|
||||||
ReplaceOPC (L[1], OPC_CMP);
|
ReplaceOPC (L[1], OPC_CMP);
|
||||||
|
|
||||||
|
/* Beware: If the first LDA instruction had a label, we have
|
||||||
|
* to move this label to the top of the sequence again.
|
||||||
|
*/
|
||||||
|
if (CodeEntryHasLabel (E)) {
|
||||||
|
MoveCodeLabels (S, E, L[0]);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
++Changes;
|
++Changes;
|
||||||
|
@ -296,7 +296,7 @@ void NewFunc (SymEntry* Func)
|
|||||||
HadReturn = 0;
|
HadReturn = 0;
|
||||||
while (CurTok.Tok != TOK_RCURLY) {
|
while (CurTok.Tok != TOK_RCURLY) {
|
||||||
if (CurTok.Tok != TOK_CEOF) {
|
if (CurTok.Tok != TOK_CEOF) {
|
||||||
HadReturn = Statement ();
|
HadReturn = Statement (0);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -46,11 +46,48 @@
|
|||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Forwards */
|
/* Helper functions */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void CheckTok (token_t Tok, const char* Msg, int* PendingToken)
|
||||||
|
/* Helper function for Statement. Will check for Tok and print Msg if not
|
||||||
|
* found. If PendingToken is NULL, it will the skip the token, otherwise
|
||||||
|
* it will store one to PendingToken.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if (CurTok.Tok != Tok) {
|
||||||
|
Error (Msg);
|
||||||
|
} else if (PendingToken) {
|
||||||
|
*PendingToken = 1;
|
||||||
|
} else {
|
||||||
|
NextToken ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void CheckSemi (int* PendingToken)
|
||||||
|
/* Helper function for Statement. Will call CheckTok with the parameters
|
||||||
|
* for a semicolon.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
CheckTok (TOK_SEMI, "`;' expected", PendingToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void SkipPending (int PendingToken)
|
||||||
|
/* Skip the pending token if we have one */
|
||||||
|
{
|
||||||
|
if (PendingToken) {
|
||||||
|
NextToken ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Code */
|
/* Code */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -71,12 +108,13 @@ static int IfStatement (void)
|
|||||||
test (Label1, 0);
|
test (Label1, 0);
|
||||||
|
|
||||||
/* Parse the if body */
|
/* Parse the if body */
|
||||||
GotBreak = Statement ();
|
GotBreak = Statement (0);
|
||||||
|
|
||||||
/* Else clause present? */
|
/* Else clause present? */
|
||||||
if (CurTok.Tok != TOK_ELSE) {
|
if (CurTok.Tok != TOK_ELSE) {
|
||||||
|
|
||||||
g_defcodelabel (Label1);
|
g_defcodelabel (Label1);
|
||||||
|
|
||||||
/* Since there's no else clause, we're not sure, if the a break
|
/* Since there's no else clause, we're not sure, if the a break
|
||||||
* statement is really executed.
|
* statement is really executed.
|
||||||
*/
|
*/
|
||||||
@ -95,7 +133,7 @@ static int IfStatement (void)
|
|||||||
g_defcodelabel (Label1);
|
g_defcodelabel (Label1);
|
||||||
|
|
||||||
/* Total break only if both branches had a break. */
|
/* Total break only if both branches had a break. */
|
||||||
GotBreak &= Statement ();
|
GotBreak &= Statement (0);
|
||||||
|
|
||||||
/* Generate the label for the else clause */
|
/* Generate the label for the else clause */
|
||||||
g_defcodelabel (Label2);
|
g_defcodelabel (Label2);
|
||||||
@ -124,7 +162,7 @@ static void DoStatement (void)
|
|||||||
g_defcodelabel (loop);
|
g_defcodelabel (loop);
|
||||||
|
|
||||||
/* Parse the loop body */
|
/* Parse the loop body */
|
||||||
Statement ();
|
Statement (0);
|
||||||
|
|
||||||
/* Parse the end condition */
|
/* Parse the end condition */
|
||||||
Consume (TOK_WHILE, "`while' expected");
|
Consume (TOK_WHILE, "`while' expected");
|
||||||
@ -143,6 +181,8 @@ static void DoStatement (void)
|
|||||||
static void WhileStatement (void)
|
static void WhileStatement (void)
|
||||||
/* Handle the 'while' statement */
|
/* Handle the 'while' statement */
|
||||||
{
|
{
|
||||||
|
int PendingToken;
|
||||||
|
|
||||||
/* Get the loop control labels */
|
/* Get the loop control labels */
|
||||||
unsigned loop = GetLocalLabel ();
|
unsigned loop = GetLocalLabel ();
|
||||||
unsigned lab = GetLocalLabel ();
|
unsigned lab = GetLocalLabel ();
|
||||||
@ -172,9 +212,10 @@ static void WhileStatement (void)
|
|||||||
NextToken ();
|
NextToken ();
|
||||||
} else {
|
} else {
|
||||||
/* There is code inside the while loop, parse the body */
|
/* There is code inside the while loop, parse the body */
|
||||||
Statement ();
|
Statement (&PendingToken);
|
||||||
g_jump (loop);
|
g_jump (loop);
|
||||||
g_defcodelabel (lab);
|
g_defcodelabel (lab);
|
||||||
|
SkipPending (PendingToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove the loop from the loop stack */
|
/* Remove the loop from the loop stack */
|
||||||
@ -432,7 +473,7 @@ static void CascadeSwitch (struct expent* eval)
|
|||||||
|
|
||||||
/* Parse statements */
|
/* Parse statements */
|
||||||
if (CurTok.Tok != TOK_RCURLY) {
|
if (CurTok.Tok != TOK_RCURLY) {
|
||||||
HaveBreak = Statement ();
|
HaveBreak = Statement (0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -521,7 +562,7 @@ static void TableSwitch (struct expent* eval)
|
|||||||
HaveBreak = 0;
|
HaveBreak = 0;
|
||||||
}
|
}
|
||||||
if (CurTok.Tok != TOK_RCURLY) {
|
if (CurTok.Tok != TOK_RCURLY) {
|
||||||
HaveBreak = Statement ();
|
HaveBreak = Statement (0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -600,6 +641,7 @@ static void ForStatement (void)
|
|||||||
struct expent lval1;
|
struct expent lval1;
|
||||||
struct expent lval2;
|
struct expent lval2;
|
||||||
struct expent lval3;
|
struct expent lval3;
|
||||||
|
int PendingToken;
|
||||||
|
|
||||||
/* Get several local labels needed later */
|
/* Get several local labels needed later */
|
||||||
unsigned TestLabel = GetLocalLabel ();
|
unsigned TestLabel = GetLocalLabel ();
|
||||||
@ -651,10 +693,13 @@ static void ForStatement (void)
|
|||||||
|
|
||||||
/* Loop body */
|
/* Loop body */
|
||||||
g_defcodelabel (lstat);
|
g_defcodelabel (lstat);
|
||||||
Statement ();
|
Statement (&PendingToken);
|
||||||
|
|
||||||
/* Jump back to the increment expression */
|
/* Jump back to the increment expression */
|
||||||
g_jump (IncLabel);
|
g_jump (IncLabel);
|
||||||
|
|
||||||
|
/* Skip a pending token if we have one */
|
||||||
|
SkipPending (PendingToken);
|
||||||
|
|
||||||
/* Declare the break label */
|
/* Declare the break label */
|
||||||
g_defcodelabel (lab);
|
g_defcodelabel (lab);
|
||||||
@ -678,9 +723,6 @@ static int CompoundStatement (void)
|
|||||||
/* Enter a new lexical level */
|
/* Enter a new lexical level */
|
||||||
EnterBlockLevel ();
|
EnterBlockLevel ();
|
||||||
|
|
||||||
/* Skip the rcurly */
|
|
||||||
NextToken ();
|
|
||||||
|
|
||||||
/* Parse local variable declarations if any */
|
/* Parse local variable declarations if any */
|
||||||
DeclareLocals ();
|
DeclareLocals ();
|
||||||
|
|
||||||
@ -688,7 +730,7 @@ static int CompoundStatement (void)
|
|||||||
GotBreak = 0;
|
GotBreak = 0;
|
||||||
while (CurTok.Tok != TOK_RCURLY) {
|
while (CurTok.Tok != TOK_RCURLY) {
|
||||||
if (CurTok.Tok != TOK_CEOF) {
|
if (CurTok.Tok != TOK_CEOF) {
|
||||||
GotBreak = Statement ();
|
GotBreak = Statement (0);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -700,9 +742,6 @@ static int CompoundStatement (void)
|
|||||||
}
|
}
|
||||||
oursp = OldStack;
|
oursp = OldStack;
|
||||||
|
|
||||||
/* Skip the closing brace */
|
|
||||||
ConsumeRCurly ();
|
|
||||||
|
|
||||||
/* Emit references to imports/exports for this block */
|
/* Emit references to imports/exports for this block */
|
||||||
EmitExternals ();
|
EmitExternals ();
|
||||||
|
|
||||||
@ -714,12 +753,23 @@ static int CompoundStatement (void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
int Statement (void)
|
int Statement (int* PendingToken)
|
||||||
/* Statement parser. Returns 1 if the statement does a return/break, returns
|
/* Statement parser. Returns 1 if the statement does a return/break, returns
|
||||||
* 0 otherwise
|
* 0 otherwise. If the PendingToken pointer is not NULL, the function will
|
||||||
|
* not skip the terminating token of the statement (closing brace or
|
||||||
|
* semicolon), but store true if there is a pending token, and false if there
|
||||||
|
* is none. The token is always checked, so there is no need for the caller to
|
||||||
|
* check this token, it must be skipped, however. If the argument pointer is
|
||||||
|
* NULL, the function will skip the token.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
struct expent lval;
|
struct expent lval;
|
||||||
|
int GotBreak;
|
||||||
|
|
||||||
|
/* Assume no pending token */
|
||||||
|
if (PendingToken) {
|
||||||
|
*PendingToken = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check for a label */
|
/* Check for a label */
|
||||||
if (CurTok.Tok == TOK_IDENT && NextTok.Tok == TOK_COLON) {
|
if (CurTok.Tok == TOK_IDENT && NextTok.Tok == TOK_COLON) {
|
||||||
@ -732,7 +782,10 @@ int Statement (void)
|
|||||||
switch (CurTok.Tok) {
|
switch (CurTok.Tok) {
|
||||||
|
|
||||||
case TOK_LCURLY:
|
case TOK_LCURLY:
|
||||||
return CompoundStatement ();
|
NextToken ();
|
||||||
|
GotBreak = CompoundStatement ();
|
||||||
|
CheckTok (TOK_RCURLY, "`{' expected", PendingToken);
|
||||||
|
return GotBreak;
|
||||||
|
|
||||||
case TOK_IF:
|
case TOK_IF:
|
||||||
return IfStatement ();
|
return IfStatement ();
|
||||||
@ -751,17 +804,17 @@ int Statement (void)
|
|||||||
|
|
||||||
case TOK_RETURN:
|
case TOK_RETURN:
|
||||||
ReturnStatement ();
|
ReturnStatement ();
|
||||||
ConsumeSemi ();
|
CheckSemi (PendingToken);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
case TOK_BREAK:
|
case TOK_BREAK:
|
||||||
BreakStatement ();
|
BreakStatement ();
|
||||||
ConsumeSemi ();
|
CheckSemi (PendingToken);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
case TOK_CONTINUE:
|
case TOK_CONTINUE:
|
||||||
ContinueStatement ();
|
ContinueStatement ();
|
||||||
ConsumeSemi ();
|
CheckSemi (PendingToken);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
case TOK_FOR:
|
case TOK_FOR:
|
||||||
@ -770,7 +823,7 @@ int Statement (void)
|
|||||||
|
|
||||||
case TOK_GOTO:
|
case TOK_GOTO:
|
||||||
GotoStatement ();
|
GotoStatement ();
|
||||||
ConsumeSemi ();
|
CheckSemi (PendingToken);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
case TOK_SEMI:
|
case TOK_SEMI:
|
||||||
@ -785,7 +838,7 @@ int Statement (void)
|
|||||||
default:
|
default:
|
||||||
/* Actual statement */
|
/* Actual statement */
|
||||||
expression (&lval);
|
expression (&lval);
|
||||||
ConsumeSemi ();
|
CheckSemi (PendingToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -17,9 +17,14 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
int Statement (void);
|
int Statement (int* PendingToken);
|
||||||
/* Statement parser. Returns 1 if the statement does a return/break, returns
|
/* Statement parser. Returns 1 if the statement does a return/break, returns
|
||||||
* 0 otherwise
|
* 0 otherwise. If the PendingToken pointer is not NULL, the function will
|
||||||
|
* not skip the terminating token of the statement (closing brace or
|
||||||
|
* semicolon), but store true if there is a pending token, and false if there
|
||||||
|
* is none. The token is always checked, so there is no need for the caller to
|
||||||
|
* check this token, it must be skipped, however. If the argument pointer is
|
||||||
|
* NULL, the function will skip the token.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user