From 5c43d1e04f48c51c743fb3fa66cb00b58ccc0f33 Mon Sep 17 00:00:00 2001 From: acqn Date: Thu, 16 Apr 2020 17:19:16 +0800 Subject: [PATCH] Changed codegen for postfix inc/dec operations by deferring them till sequence points. This usually allows faster & smaller code. Note that deferred operations must still be called at sequence points even if the whole expressions containing them had constant values. --- src/cc65/compile.c | 7 + src/cc65/declare.c | 6 + src/cc65/expr.c | 493 +++++++++++++++++++++++++++++++++++++++----- src/cc65/expr.h | 34 ++- src/cc65/goto.c | 7 + src/cc65/locals.c | 10 + src/cc65/stdfunc.c | 15 ++ src/cc65/stmt.c | 3 + src/cc65/testexpr.c | 9 + 9 files changed, 526 insertions(+), 58 deletions(-) diff --git a/src/cc65/compile.c b/src/cc65/compile.c index ec90e4b2d..d93de96b4 100644 --- a/src/cc65/compile.c +++ b/src/cc65/compile.c @@ -320,6 +320,9 @@ static void Parse (void) } else { /* Parse the function body */ NewFunc (Entry, FuncDef); + + /* Make sure we aren't omitting any work */ + CheckDeferredOpAllDone (); } } @@ -395,6 +398,8 @@ void Compile (const char* FileName) /* DefineNumericMacro ("__STDC__", 1); <- not now */ DefineNumericMacro ("__STDC_HOSTED__", 1); + InitDeferredOps (); + /* Create the base lexical level */ EnterGlobalLevel (); @@ -486,6 +491,8 @@ void Compile (const char* FileName) } } + DoneDeferredOps (); + if (Debug) { PrintMacroStats (stdout); } diff --git a/src/cc65/declare.c b/src/cc65/declare.c index bf27f9c90..08739f333 100644 --- a/src/cc65/declare.c +++ b/src/cc65/declare.c @@ -2302,6 +2302,9 @@ static unsigned ParseScalarInit (Type* T) /* Output the data */ DefineData (&ED); + /* Do this anyways for safety */ + DoDeferred (SQP_KEEP_NONE, &ED); + /* Done */ return SizeOf (T); } @@ -2321,6 +2324,9 @@ static unsigned ParsePointerInit (Type* T) /* Output the data */ DefineData (&ED); + /* Do this anyways for safety */ + DoDeferred (SQP_KEEP_NONE, &ED); + /* Close eventually opening braces */ ClosingCurlyBraces (BraceCount); diff --git a/src/cc65/expr.c b/src/cc65/expr.c index a88710f34..19572944e 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -332,6 +332,264 @@ static void WarnConstCompareResult (const ExprDesc* Expr) +typedef enum { + DOT_INC, + DOT_DEC, +} DeferredOpType; + + +typedef struct { + ExprDesc Expr; + DeferredOpType OpType; +} DeferredOp; + +Collection DeferredOps; + + + +void InitDeferredOps (void) +/* Init the collection for storing deferred ops */ +{ + InitCollection (&DeferredOps); +} + + + +void DoneDeferredOps (void) +/* Deinit the collection for storing deferred ops */ +{ + DoneCollection (&DeferredOps); +} + + + +static void DeferInc (const ExprDesc* Expr) +/* Defer the post-inc and put it in a queue */ +{ + DeferredOp* Op = xmalloc (sizeof (DeferredOp)); + memcpy (&Op->Expr, Expr, sizeof (ExprDesc)); + Op->OpType = DOT_INC; + CollAppend (&DeferredOps, Op); +} + + + +static void DeferDec (const ExprDesc* Expr) +/* Defer the post-dec and put it in a queue */ +{ + DeferredOp* Op = xmalloc (sizeof (DeferredOp)); + memcpy (&Op->Expr, Expr, sizeof (ExprDesc)); + Op->OpType = DOT_DEC; + CollAppend (&DeferredOps, Op); +} + + + +static void DeferredInc (ExprDesc* Expr) +/* Do the deferred post-inc */ +{ + unsigned Flags; + unsigned long Val; + + /* Get the flags */ + Flags = TypeOf (Expr->Type) | GlobalModeFlags (Expr) | CF_FORCECHAR | CF_CONST | CF_NOKEEP; + + /* Get the increment value in bytes */ + Val = IsTypePtr (Expr->Type) ? CheckedSizeOf (Expr->Type + 1) : 1; + + /* Check the location of the data */ + switch (ED_GetLoc (Expr)) { + + case E_LOC_ABS: + /* Absolute: numeric address or const */ + g_addeqstatic (Flags, Expr->IVal, 0, Val); + break; + + case E_LOC_GLOBAL: + /* Global variable */ + g_addeqstatic (Flags, Expr->Name, Expr->IVal, Val); + break; + + case E_LOC_STATIC: + case E_LOC_LITERAL: + /* Static variable or literal in the literal pool */ + g_addeqstatic (Flags, Expr->Name, Expr->IVal, Val); + break; + + case E_LOC_REGISTER: + /* Register variable */ + g_addeqstatic (Flags, Expr->Name, Expr->IVal, Val); + break; + + case E_LOC_STACK: + /* Value on the stack */ + g_addeqlocal (Flags, Expr->IVal, Val); + break; + + case E_LOC_PRIMARY: + /* The primary register */ + g_inc (Flags, Val); + break; + + case E_LOC_EXPR: + /* An expression in the primary register */ + g_addeqind (Flags, Expr->IVal, Val); + break; + + default: + Internal ("Invalid location in DeferredInc(): 0x%04X", ED_GetLoc (Expr)); + } +} + + + +static void DeferredDec (ExprDesc* Expr) +/* Do the deferred post-dec */ +{ + unsigned Flags; + unsigned long Val; + + /* Get the flags */ + Flags = TypeOf (Expr->Type) | GlobalModeFlags (Expr) | CF_FORCECHAR | CF_CONST | CF_NOKEEP; + + /* Get the increment value in bytes */ + Val = IsTypePtr (Expr->Type) ? CheckedSizeOf (Expr->Type + 1) : 1; + + /* Check the location of the data */ + switch (ED_GetLoc (Expr)) { + + case E_LOC_ABS: + /* Absolute: numeric address or const */ + g_subeqstatic (Flags, Expr->IVal, 0, Val); + break; + + case E_LOC_GLOBAL: + /* Global variable */ + g_subeqstatic (Flags, Expr->Name, Expr->IVal, Val); + break; + + case E_LOC_STATIC: + case E_LOC_LITERAL: + /* Static variable or literal in the literal pool */ + g_subeqstatic (Flags, Expr->Name, Expr->IVal, Val); + break; + + case E_LOC_REGISTER: + /* Register variable */ + g_subeqstatic (Flags, Expr->Name, Expr->IVal, Val); + break; + + case E_LOC_STACK: + /* Value on the stack */ + g_subeqlocal (Flags, Expr->IVal, Val); + break; + + case E_LOC_PRIMARY: + /* The primary register */ + g_dec (Flags, Val); + break; + + case E_LOC_EXPR: + /* An expression in the primary register */ + g_subeqind (Flags, Expr->IVal, Val); + break; + + default: + Internal ("Invalid location in DeferredDec(): 0x%04X", ED_GetLoc (Expr)); + } +} + + + +int GetDeferredOpCount (void) +/* Return how many deferred operations are still waiting in the queque */ +{ + return (int)CollCount (&DeferredOps); +} + + + +void CheckDeferredOpAllDone (void) +/* Check if all deferred operations are done at sequence points. +** Die off if check fails. +*/ +{ + if (GetDeferredOpCount () > 0) { + Internal ("Code generation messed up: missing operations past sequence points."); + } +} + + + +void DoDeferred (unsigned Flags, ExprDesc* Expr) +/* Do deferred operations such as post-inc/dec at sequence points */ +{ + int I; + unsigned Size = 0; + int Count = GetDeferredOpCount (); + + /* Nothing to be done */ + if (Count <= 0) { + return; + } + + /* Backup some regs/processor flags around the inc/dec */ + if ((Flags & SQP_KEEP_TEST) != 0 && ED_NeedsTest (Expr)) { + /* Sufficient to add a pair of PHP/PLP for all cases */ + AddCodeLine ("php"); + } + + /* Backup the content of EAX around the inc/dec */ + if ((Flags & SQP_KEEP_EAX) != 0 && ED_NeedsPrimary (Expr)) { + /* Get the size */ + Size = CheckedSizeOf (Expr->Type); + + if (Size < 2) { + AddCodeLine ("pha"); + } else if (Size < 3) { + AddCodeLine ("sta regsave"); + AddCodeLine ("stx regsave+1"); + } else { + AddCodeLine ("jsr saveeax"); + } + } + + for (I = 0; I < Count; ++I) { + DeferredOp* Op = CollAtUnchecked (&DeferredOps, I); + switch (Op->OpType) { + + case DOT_INC: + DeferredInc (&Op->Expr); + break; + + case DOT_DEC: + DeferredDec (&Op->Expr); + break; + } + xfree (&Op->Expr); + } + CollDeleteAll (&DeferredOps); + + /* Restore the content of EAX around the inc/dec */ + if ((Flags & SQP_KEEP_EAX) != 0 && ED_NeedsPrimary (Expr)) { + if (Size < 2) { + AddCodeLine ("pla"); + } else if (Size < 3) { + AddCodeLine ("lda regsave"); + AddCodeLine ("ldx regsave+1"); + } else { + AddCodeLine ("jsr resteax"); + } + } + + /* Restore the regs/processor flags around the inc/dec */ + if ((Flags & SQP_KEEP_TEST) != 0 && ED_NeedsTest (Expr)) { + /* Sufficient to pop the processor flags */ + AddCodeLine ("plp"); + } +} + + static unsigned FunctionParamList (FuncDesc* Func, int IsFastcall, ExprDesc* ED) /* Parse a function parameter list, and pass the arguments to the called ** function. Depending on several criteria, this may be done by just pushing @@ -388,11 +646,17 @@ static unsigned FunctionParamList (FuncDesc* Func, int IsFastcall, ExprDesc* ED) } } + /* The info of the last argument could be needed out of the loop */ + ExprDesc Expr; + ED_Init (&Expr); + Expr.Flags |= ED->Flags & E_MASK_KEEP_SUBEXPR; + /* Parse the actual argument list */ while (CurTok.Tok != TOK_RPAREN) { unsigned Flags; /* Code generator flags, not expression flags */ - ExprDesc Expr; + + /* This way the info of the last parameter won't be cleared */ ED_Init (&Expr); Expr.Flags |= ED->Flags & E_MASK_KEEP_SUBEXPR; @@ -514,6 +778,11 @@ static unsigned FunctionParamList (FuncDesc* Func, int IsFastcall, ExprDesc* ED) Error ("Too few arguments in function call"); } + /* Append deferred inc/dec before the function is called. + ** The last parameter needs to be restored if it is passed with AX/EAX Regs. + */ + DoDeferred (IsFastcall ? SQP_KEEP_EAX : SQP_KEEP_NONE, &Expr); + /* The function returns the size of all arguments pushed onto the stack. ** However, if there are parameters missed (which is an error, and was ** flagged by the compiler), AND a stack frame was preallocated above, @@ -1728,7 +1997,7 @@ static void PreDec (ExprDesc* Expr) static void PostInc (ExprDesc* Expr) /* Handle the postincrement operator */ { - unsigned Flags; + unsigned Flags, Loc; NextToken (); @@ -1746,33 +2015,49 @@ static void PostInc (ExprDesc* Expr) /* Get the data type */ Flags = TypeOf (Expr->Type); + /* We are allowed by the C standard to defer the inc operation until + ** the this expression is used, so that we don't need to save and reload + ** the original value. + */ + /* Emit smaller code if a char variable is at a constant location */ - if ((Flags & CF_CHAR) == CF_CHAR && ED_IsLocConst(Expr)) { + if ((Flags & CF_CHAR) == CF_CHAR && ED_IsLocConst (Expr)) { LoadExpr (CF_NONE, Expr); - AddCodeLine ("inc %s", ED_GetLabelName(Expr, 0)); + AddCodeLine ("inc %s", ED_GetLabelName (Expr, 0)); } else { - /* Push the address if needed */ - PushAddr (Expr); + Loc = ED_GetLoc (Expr); + if (Loc == E_LOC_PRIMARY || Loc == E_LOC_EXPR) { + /* Push the address if needed */ + PushAddr (Expr); - /* Fetch the value and save it (since it's the result of the expression) */ - LoadExpr (CF_NONE, Expr); - g_save (Flags | CF_FORCECHAR); + /* Fetch the value and save it (since it's the result of the expression) */ + LoadExpr (CF_NONE, Expr); + g_save (Flags | CF_FORCECHAR); + + /* If we have a pointer expression, increment by the size of the type */ + if (IsTypePtr (Expr->Type)) { + g_inc (Flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1)); + } else { + g_inc (Flags | CF_CONST | CF_FORCECHAR, 1); + } + + /* Store the result back */ + Store (Expr, 0); + + /* Restore the original value in the primary register */ + g_restore (Flags | CF_FORCECHAR); - /* If we have a pointer expression, increment by the size of the type */ - if (IsTypePtr (Expr->Type)) { - g_inc (Flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1)); } else { - g_inc (Flags | CF_CONST | CF_FORCECHAR, 1); + + /* Fetch the value and use it (since it's the result of the expression) */ + LoadExpr (CF_NONE, Expr); + + /* Defer the increment until the value of this expression is used */; + DeferInc (Expr); } - - /* Store the result back */ - Store (Expr, 0); - - /* Restore the original value in the primary register */ - g_restore (Flags | CF_FORCECHAR); } /* The result is always an expression, no reference */ @@ -1784,7 +2069,7 @@ static void PostInc (ExprDesc* Expr) static void PostDec (ExprDesc* Expr) /* Handle the postdecrement operator */ { - unsigned Flags; + unsigned Flags, Loc; NextToken (); @@ -1803,32 +2088,43 @@ static void PostDec (ExprDesc* Expr) Flags = TypeOf (Expr->Type); /* Emit smaller code if a char variable is at a constant location */ - if ((Flags & CF_CHAR) == CF_CHAR && ED_IsLocConst(Expr)) { + if ((Flags & CF_CHAR) == CF_CHAR && ED_IsLocConst (Expr)) { LoadExpr (CF_NONE, Expr); - AddCodeLine ("dec %s", ED_GetLabelName(Expr, 0)); + AddCodeLine ("dec %s", ED_GetLabelName (Expr, 0)); } else { - /* Push the address if needed */ - PushAddr (Expr); + Loc = ED_GetLoc (Expr); + if (Loc == E_LOC_PRIMARY || Loc == E_LOC_EXPR) { + /* Push the address if needed */ + PushAddr (Expr); - /* Fetch the value and save it (since it's the result of the expression) */ - LoadExpr (CF_NONE, Expr); - g_save (Flags | CF_FORCECHAR); + /* Fetch the value and save it (since it's the result of the expression) */ + LoadExpr (CF_NONE, Expr); + g_save (Flags | CF_FORCECHAR); + + /* If we have a pointer expression, increment by the size of the type */ + if (IsTypePtr (Expr->Type)) { + g_dec (Flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1)); + } else { + g_dec (Flags | CF_CONST | CF_FORCECHAR, 1); + } + + /* Store the result back */ + Store (Expr, 0); + + /* Restore the original value in the primary register */ + g_restore (Flags | CF_FORCECHAR); - /* If we have a pointer expression, increment by the size of the type */ - if (IsTypePtr (Expr->Type)) { - g_dec (Flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1)); } else { - g_dec (Flags | CF_CONST | CF_FORCECHAR, 1); + + /* Fetch the value and save it (since it's the result of the expression) */ + LoadExpr (CF_NONE, Expr); + + /* Defer the decrement until the value of this expression is used */; + DeferDec (Expr); } - - /* Store the result back */ - Store (Expr, 0); - - /* Restore the original value in the primary register */ - g_restore (Flags | CF_FORCECHAR); } /* The result is always an expression, no reference */ @@ -3263,6 +3559,9 @@ static int hieAnd (ExprDesc* Expr, unsigned* TrueLab, int* TrueLabAllocated) /* Load the value */ LoadExpr (CF_FORCECHAR, Expr); + /* Append deferred inc/dec at sequence point */ + DoDeferred (SQP_KEEP_TEST, Expr); + /* Clear the test flag */ ED_RequireNoTest (Expr); @@ -3275,9 +3574,17 @@ static int hieAnd (ExprDesc* Expr, unsigned* TrueLab, int* TrueLabAllocated) /* Generate the jump */ g_falsejump (CF_NONE, FalseLab); - } else if (Expr->IVal == 0 && !ED_IsAddrExpr (Expr)) { - /* Skip remaining */ - Flags |= E_EVAL_UNEVAL; + } else { + /* Constant boolean subexpression could still have deferred inc/dec + ** operations, so just flush their side-effects at this sequence + ** point. + */ + DoDeferred (SQP_KEEP_NONE, Expr); + + if (Expr->IVal == 0 && !ED_IsAddrExpr (Expr)) { + /* Skip remaining */ + Flags |= E_EVAL_UNEVAL; + } } } @@ -3306,6 +3613,9 @@ static int hieAnd (ExprDesc* Expr, unsigned* TrueLab, int* TrueLabAllocated) ED_RequireTest (&Expr2); LoadExpr (CF_FORCECHAR, &Expr2); + /* Append deferred inc/dec at sequence point */ + DoDeferred (SQP_KEEP_TEST, &Expr2); + /* Do short circuit evaluation */ if (CurTok.Tok == TOK_BOOL_AND) { if (HasFalseJump == 0) { @@ -3319,11 +3629,19 @@ static int hieAnd (ExprDesc* Expr, unsigned* TrueLab, int* TrueLabAllocated) /* We need the true label for the last expression */ HasTrueJump = 1; } - } else if (Expr2.IVal == 0 && !ED_IsAddrExpr (&Expr2)) { - /* Skip remaining */ - Flags |= E_EVAL_UNEVAL; - /* The value of the expression will be false */ - ED_MakeConstBool (Expr, 0); + } else { + /* Constant boolean subexpression could still have deferred inc/ + ** dec operations, so just flush their side-effects at this + ** sequence point. + */ + DoDeferred (SQP_KEEP_NONE, &Expr2); + + if (Expr2.IVal == 0 && !ED_IsAddrExpr (&Expr2)) { + /* Skip remaining */ + Flags |= E_EVAL_UNEVAL; + /* The value of the expression will be false */ + ED_MakeConstBool (Expr, 0); + } } } } @@ -3408,6 +3726,9 @@ static void hieOr (ExprDesc *Expr) /* Get first expr */ LoadExpr (CF_FORCECHAR, Expr); + + /* Append deferred inc/dec at sequence point */ + DoDeferred (SQP_KEEP_TEST, Expr); /* Clear the test flag */ ED_RequireNoTest (Expr); @@ -3421,9 +3742,17 @@ static void hieOr (ExprDesc *Expr) /* Jump to TrueLab if true */ g_truejump (CF_NONE, TrueLab); } - } else if (Expr->IVal != 0 || ED_IsAddrExpr (Expr)) { - /* Skip remaining */ - Flags |= E_EVAL_UNEVAL; + } else { + /* Constant boolean subexpression could still have deferred inc/dec + ** operations, so just flush their side-effects at this sequence + ** point. + */ + DoDeferred (SQP_KEEP_NONE, Expr); + + if (Expr->IVal != 0 || ED_IsAddrExpr (Expr)) { + /* Skip remaining */ + Flags |= E_EVAL_UNEVAL; + } } } @@ -3456,17 +3785,28 @@ static void hieOr (ExprDesc *Expr) ED_RequireTest (&Expr2); LoadExpr (CF_FORCECHAR, &Expr2); + /* Append deferred inc/dec at sequence point */ + DoDeferred (SQP_KEEP_TEST, &Expr2); + if (HasTrueJump == 0) { TrueLab = GetLocalLabel(); HasTrueJump = 1; } g_truejump (CF_NONE, TrueLab); } - } else if (Expr2.IVal != 0 || ED_IsAddrExpr (&Expr2)) { - /* Skip remaining */ - Flags |= E_EVAL_UNEVAL; - /* The result is always true */ - ED_MakeConstBool (Expr, 1); + } else { + /* Constant boolean subexpression could still have deferred inc/ + ** dec operations, so just flush their side-effects at this + ** sequence point. + */ + DoDeferred (SQP_KEEP_NONE, &Expr2); + + if (Expr2.IVal != 0 || ED_IsAddrExpr (&Expr2)) { + /* Skip remaining */ + Flags |= E_EVAL_UNEVAL; + /* The result is always true */ + ED_MakeConstBool (Expr, 1); + } } } @@ -3547,11 +3887,22 @@ static void hieQuest (ExprDesc* Expr) /* Condition codes not set, request a test */ ED_RequireTest (Expr); LoadExpr (CF_NONE, Expr); + + /* Append deferred inc/dec at sequence point */ + DoDeferred (SQP_KEEP_TEST, Expr); + FalseLab = GetLocalLabel (); g_falsejump (CF_NONE, FalseLab); - } else if (Expr->IVal == 0) { - /* Remember the current code position */ - GetCodePos (&SkippedBranch); + } else { + /* Constant boolean subexpression could still have deferred inc/dec + ** operations, so just flush their side-effects at this sequence point. + */ + DoDeferred (SQP_KEEP_NONE, Expr); + + if (Expr->IVal == 0) { + /* Remember the current code position */ + GetCodePos (&SkippedBranch); + } } /* Parse second expression. Remember for later if it is a NULL pointer @@ -3563,7 +3914,17 @@ static void hieQuest (ExprDesc* Expr) if (!ConstantCond || !ED_IsConst (&Expr2)) { /* Load it into the primary */ LoadExpr (CF_NONE, &Expr2); + + /* Append deferred inc/dec at sequence point */ + DoDeferred (SQP_KEEP_EXPR, &Expr2); + ED_FinalizeRValLoad (&Expr2); + } else { + /* Constant boolean subexpression could still have deferred inc/ + ** dec operations, so just flush their side-effects at this + ** sequence point. + */ + DoDeferred (SQP_KEEP_NONE, &Expr2); } Expr2.Type = PtrConversion (Expr2.Type); } @@ -3601,7 +3962,17 @@ static void hieQuest (ExprDesc* Expr) if (!ConstantCond || !ED_IsConst (&Expr3)) { /* Load it into the primary */ LoadExpr (CF_NONE, &Expr3); + + /* Append deferred inc/dec at sequence point */ + DoDeferred (SQP_KEEP_EXPR, &Expr3); + ED_FinalizeRValLoad (&Expr3); + } else { + /* Constant boolean subexpression could still have deferred inc/ + ** dec operations, so just flush their side-effects at this + ** sequence point. + */ + DoDeferred (SQP_KEEP_NONE, &Expr3); } Expr3.Type = PtrConversion (Expr3.Type); } @@ -4011,6 +4382,9 @@ void hie0 (ExprDesc *Expr) hie1 (Expr); while (CurTok.Tok == TOK_COMMA) { + /* Append deferred inc/dec at sequence point */ + DoDeferred (SQP_KEEP_NONE, Expr); + /* If the expression didn't generate code or isn't cast to type void, ** emit a warning. */ @@ -4037,7 +4411,9 @@ void hie0 (ExprDesc *Expr) void Expression0 (ExprDesc* Expr) -/* Evaluate an expression via hie0 and put the result into the primary register */ +/* Evaluate an expression via hie0 and put the result into the primary register. +** The expression is completely evaluated and all side effects complete. +*/ { unsigned Flags = Expr->Flags & E_MASK_KEEP_RESULT; @@ -4051,6 +4427,9 @@ void Expression0 (ExprDesc* Expr) if (ED_YetToLoad (Expr)) { LoadExpr (CF_NONE, Expr); } + + /* Append deferred inc/dec at sequence point */ + DoDeferred (SQP_KEEP_EXPR, Expr); } diff --git a/src/cc65/expr.h b/src/cc65/expr.h index 806a376bb..d0a9988af 100644 --- a/src/cc65/expr.h +++ b/src/cc65/expr.h @@ -17,6 +17,19 @@ +/*****************************************************************************/ +/* data */ +/*****************************************************************************/ + + + +#define SQP_KEEP_NONE 0x00 +#define SQP_KEEP_TEST 0x01U +#define SQP_KEEP_EAX 0x02U +#define SQP_KEEP_EXPR 0x03U /* SQP_KEEP_TEST | SQP_KEEP_EAX */ + + + /*****************************************************************************/ /* code */ /*****************************************************************************/ @@ -38,6 +51,23 @@ void PushAddr (const ExprDesc* Expr); ** must be saved if it's not constant, before evaluating the rhs. */ +void InitDeferredOps (void); +/* Init the collection for storing deferred ops */ + +void DoneDeferredOps (void); +/* Deinit the collection for storing deferred ops */ + +int GetDeferredOpCount (void); +/* Return how many deferred operations are still waiting in the queque */ + +void CheckDeferredOpAllDone (void); +/* Check if all deferred operations are done at sequence points. +** Die off if check fails. +*/ + +void DoDeferred (unsigned Flags, ExprDesc* Expr); +/* Do deferred operations such as post-inc/dec at sequence points */ + void Store (ExprDesc* Expr, const Type* StoreType); /* Store the primary register into the location denoted by lval. If StoreType ** is given, use this type when storing instead of lval->Type. If StoreType @@ -52,7 +82,9 @@ int evalexpr (unsigned flags, void (*Func) (ExprDesc*), ExprDesc* Expr); */ void Expression0 (ExprDesc* Expr); -/* Evaluate an expression via hie0 and put the result into the primary register */ +/* Evaluate an expression via hie0 and put the result into the primary register. +** The expression is completely evaluated and all side effects complete. +*/ void BoolExpr (void (*Func) (ExprDesc*), ExprDesc* Expr); /* Will evaluate an expression via the given function. If the result is not diff --git a/src/cc65/goto.c b/src/cc65/goto.c index 06364068f..7d3ff1a6a 100644 --- a/src/cc65/goto.c +++ b/src/cc65/goto.c @@ -105,6 +105,9 @@ void GotoStatement (void) val = (unsigned char)CurTok.IVal; NextToken (); + /* Append deferred inc/dec at sequence point */ + DoDeferred (SQP_KEEP_NONE, &desc); + if (CPUIsets[CPU] & CPU_ISET_65SC02) { AddCodeLine ("ldx #$%02X", val * 2); AddCodeLine ("jmp (.loword(%s),x)", arr->AsmName); @@ -118,6 +121,10 @@ void GotoStatement (void) (idx = FindSym (CurTok.Ident))) { hie10 (&desc); LoadExpr (CF_NONE, &desc); + + /* Append deferred inc/dec at sequence point */ + DoDeferred (SQP_KEEP_EAX, &desc); + AddCodeLine ("asl a"); if (CPUIsets[CPU] & CPU_ISET_65SC02) { diff --git a/src/cc65/locals.c b/src/cc65/locals.c index 81d0cea09..7812acebd 100644 --- a/src/cc65/locals.c +++ b/src/cc65/locals.c @@ -165,6 +165,8 @@ static void ParseRegisterDecl (Declaration* Decl, int Reg) /* Store the value into the variable */ g_putstatic (CF_REGVAR | TypeOf (Sym->Type), Reg, 0); + /* This has to be done at sequence point */ + DoDeferred (SQP_KEEP_NONE, &Expr); } /* Mark the variable as referenced */ @@ -273,6 +275,8 @@ static void ParseAutoDecl (Declaration* Decl) /* Push the value */ g_push (Flags | TypeOf (Sym->Type), Expr.IVal); + /* This has to be done at sequence point */ + DoDeferred (SQP_KEEP_NONE, &Expr); } /* Mark the variable as referenced */ @@ -349,6 +353,9 @@ static void ParseAutoDecl (Declaration* Decl) /* Store the value into the variable */ g_putstatic (CF_STATIC | TypeOf (Sym->Type), DataLabel, 0); + + /* This has to be done at sequence point */ + DoDeferred (SQP_KEEP_NONE, &Expr); } /* Mark the variable as referenced */ @@ -525,6 +532,9 @@ static void ParseOneDecl (const DeclSpec* Spec) } } + + /* Make sure we aren't missing some work */ + CheckDeferredOpAllDone (); } diff --git a/src/cc65/stdfunc.c b/src/cc65/stdfunc.c index 74579212e..c1fb6c735 100644 --- a/src/cc65/stdfunc.c +++ b/src/cc65/stdfunc.c @@ -245,6 +245,9 @@ static void StdFunc_memcpy (FuncDesc* F attribute ((unused)), ExprDesc* Expr) LoadExpr (CF_NONE, &Arg3.Expr); } + /* We still need to append deferred inc/dec before calling into the function */ + DoDeferred (SQP_KEEP_EAX, &Arg3.Expr); + /* Emit the actual function call. This will also cleanup the stack. */ g_call (CF_FIXARGC, Func_memcpy, ParamSize); @@ -594,6 +597,9 @@ static void StdFunc_memset (FuncDesc* F attribute ((unused)), ExprDesc* Expr) LoadExpr (CF_NONE, &Arg3.Expr); } + /* We still need to append deferred inc/dec before calling into the function */ + DoDeferred (SQP_KEEP_EAX, &Arg3.Expr); + /* Emit the actual function call. This will also cleanup the stack. */ g_call (CF_FIXARGC, MemSet? Func_memset : Func__bzero, ParamSize); @@ -808,6 +814,9 @@ static void StdFunc_strcmp (FuncDesc* F attribute ((unused)), ExprDesc* Expr) LoadExpr (CF_NONE, &Arg2.Expr); } + /* We still need to append deferred inc/dec before calling into the function */ + DoDeferred (SQP_KEEP_EAX, &Arg2.Expr); + /* Emit the actual function call. This will also cleanup the stack. */ g_call (CF_FIXARGC, Func_strcmp, ParamSize); @@ -1007,6 +1016,9 @@ static void StdFunc_strcpy (FuncDesc* F attribute ((unused)), ExprDesc* Expr) LoadExpr (CF_NONE, &Arg2.Expr); } + /* We still need to append deferred inc/dec before calling into the function */ + DoDeferred (SQP_KEEP_EAX, &Arg2.Expr); + /* Emit the actual function call. This will also cleanup the stack. */ g_call (CF_FIXARGC, Func_strcpy, ParamSize); @@ -1193,6 +1205,9 @@ static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr) /* Evaluate the parameter */ hie1 (&Arg); + /* We still need to append deferred inc/dec before calling into the function */ + DoDeferred (SQP_KEEP_EAX, &Arg); + /* Check if the argument is an array. If so, remember the element count. ** Otherwise set the element count to undefined. */ diff --git a/src/cc65/stmt.c b/src/cc65/stmt.c index 74b841493..9890c5467 100644 --- a/src/cc65/stmt.c +++ b/src/cc65/stmt.c @@ -352,6 +352,9 @@ static void ReturnStatement (void) LoadExpr (CF_NONE, &Expr); } } + + /* Append deferred inc/dec at sequence point */ + DoDeferred (SQP_KEEP_EAX, &Expr); } } else if (!F_HasVoidReturn (CurrentFunc) && !F_HasOldStyleIntRet (CurrentFunc)) { diff --git a/src/cc65/testexpr.c b/src/cc65/testexpr.c index 80fe4bc3d..eefaeb74a 100644 --- a/src/cc65/testexpr.c +++ b/src/cc65/testexpr.c @@ -66,6 +66,9 @@ unsigned Test (unsigned Label, int Invert) /* Check for a constant expression */ if (ED_IsConstAbs (&Expr)) { + /* Append deferred inc/dec at sequence point */ + DoDeferred (SQP_KEEP_NONE, &Expr); + /* Result is constant, so we know the outcome */ Result = (Expr.IVal != 0); @@ -79,6 +82,9 @@ unsigned Test (unsigned Label, int Invert) } else if (ED_IsAddrExpr (&Expr)) { + /* Append deferred inc/dec at sequence point */ + DoDeferred (SQP_KEEP_NONE, &Expr); + /* Object addresses are non-NULL */ Result = 1; @@ -93,6 +99,9 @@ unsigned Test (unsigned Label, int Invert) /* Load the value into the primary register */ LoadExpr (CF_FORCECHAR, &Expr); + /* Append deferred inc/dec at sequence point */ + DoDeferred (SQP_KEEP_TEST, &Expr); + /* Generate the jump */ if (Invert) { g_truejump (CF_NONE, Label);