From 7f05bd797f92564b230346d6cceb97260f0d0353 Mon Sep 17 00:00:00 2001 From: acqn Date: Sun, 21 Feb 2021 16:36:29 +0800 Subject: [PATCH 1/2] Now the compiler tracks code that has no observable effect. --- src/cc65/assignment.c | 12 +++++++ src/cc65/expr.c | 77 +++++++++++++++++++++++++++++++++++++++---- src/cc65/exprdesc.h | 14 ++++++++ src/cc65/loadexpr.c | 4 +++ src/cc65/shiftexpr.c | 3 ++ src/cc65/stdfunc.c | 9 +++++ src/cc65/stmt.c | 11 ++++--- 7 files changed, 119 insertions(+), 11 deletions(-) diff --git a/src/cc65/assignment.c b/src/cc65/assignment.c index e6d1e4526..0a8bc2b21 100644 --- a/src/cc65/assignment.c +++ b/src/cc65/assignment.c @@ -605,6 +605,12 @@ void OpAssign (const GenDesc* Gen, ExprDesc* Expr, const char* Op) /* Normal straight 'op=' */ OpAssignArithmetic (Gen, Expr, Op); } + + /* Expression has had side effects */ + Expr->Flags |= E_SIDE_EFFECTS; + + /* Propagate viral flags */ + ED_PropagateFrom (Expr, &Expr2); } @@ -725,4 +731,10 @@ void OpAddSubAssign (const GenDesc* Gen, ExprDesc *Expr, const char* Op) /* Expression is an rvalue in the primary now */ ED_FinalizeRValLoad (Expr); + + /* Expression has had side effects */ + Expr->Flags |= E_SIDE_EFFECTS; + + /* Propagate viral flags */ + ED_PropagateFrom (Expr, &Expr2); } diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 0275e61a3..621f16c15 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -649,6 +649,9 @@ void DoDeferred (unsigned Flags, ExprDesc* Expr) /* Sufficient to pop the processor flags */ AddCodeLine ("plp"); } + + /* Expression has had side effects */ + Expr->Flags |= E_SIDE_EFFECTS; } @@ -822,6 +825,9 @@ static unsigned FunctionArgList (FuncDesc* Func, int IsFastcall, ExprDesc* ED) } } + /* Propagate viral flags */ + ED_PropagateFrom (ED, &Expr); + /* Check for end of argument list */ if (CurTok.Tok != TOK_COMMA) { break; @@ -1064,6 +1070,9 @@ static void FunctionCall (ExprDesc* Expr) } Expr->Type = ReturnType; + + /* We assume all function calls had side effects */ + Expr->Flags |= E_SIDE_EFFECTS; } @@ -1273,7 +1282,7 @@ static void Primary (ExprDesc* E) case TOK_ASM: /* ASM statement */ AsmStatement (); - E->Flags = E_RTYPE_RVAL | E_EVAL_MAYBE_UNUSED; + E->Flags = E_RTYPE_RVAL | E_EVAL_MAYBE_UNUSED | E_SIDE_EFFECTS; E->Type = type_void; break; @@ -1658,6 +1667,9 @@ static void PreInc (ExprDesc* Expr) /* Result is an expression, no reference */ ED_FinalizeRValLoad (Expr); + + /* Expression has had side effects */ + Expr->Flags |= E_SIDE_EFFECTS; } @@ -1685,6 +1697,9 @@ static void PreDec (ExprDesc* Expr) /* Result is an expression, no reference */ ED_FinalizeRValLoad (Expr); + + /* Expression has had side effects */ + Expr->Flags |= E_SIDE_EFFECTS; } @@ -1721,6 +1736,9 @@ static void PostInc (ExprDesc* Expr) LoadExpr (CF_NONE, Expr); AddCodeLine ("inc %s", ED_GetLabelName (Expr, 0)); + /* Expression has had side effects */ + Expr->Flags |= E_SIDE_EFFECTS; + } else { if (ED_IsLocPrimaryOrExpr (Expr)) { @@ -1728,6 +1746,9 @@ static void PostInc (ExprDesc* Expr) /* Do the increment */ DoInc (Expr, OA_NEED_OLD); + /* Expression has had side effects */ + Expr->Flags |= E_SIDE_EFFECTS; + } else { /* Defer the increment until after the value of this expression is used */ @@ -1771,6 +1792,9 @@ static void PostDec (ExprDesc* Expr) LoadExpr (CF_NONE, Expr); AddCodeLine ("dec %s", ED_GetLabelName (Expr, 0)); + /* Expression has had side effects */ + Expr->Flags |= E_SIDE_EFFECTS; + } else { if (ED_IsLocPrimaryOrExpr (Expr)) { @@ -1778,6 +1802,9 @@ static void PostDec (ExprDesc* Expr) /* Do the decrement */ DoDec (Expr, OA_NEED_OLD); + /* Expression has had side effects */ + Expr->Flags |= E_SIDE_EFFECTS; + } else { /* Defer the decrement until after the value of this expression is used */ @@ -2238,6 +2265,9 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ /* We have an rvalue in the primary now */ ED_FinalizeRValLoad (Expr); } + + /* Propagate viral flags */ + ED_PropagateFrom (Expr, &Expr2); } } @@ -2659,6 +2689,9 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ /* Result type is always boolean */ Done: Expr->Type = type_bool; + + /* Propagate viral flags */ + ED_PropagateFrom (Expr, &Expr2); } } @@ -3075,6 +3108,9 @@ static void parseadd (ExprDesc* Expr, int DoArrayRef) /* Condition code not set */ ED_MarkAsUntested (Expr); + + /* Propagate viral flags */ + ED_PropagateFrom (Expr, &Expr2); } @@ -3352,6 +3388,9 @@ static void parsesub (ExprDesc* Expr) /* Condition code not set */ ED_MarkAsUntested (Expr); + + /* Propagate viral flags */ + ED_PropagateFrom (Expr, &Expr2); } @@ -3603,6 +3642,12 @@ static int hieAnd (ExprDesc* Expr, unsigned* TrueLab, int* TrueLabAllocated) } } } + + /* Propagate viral flags */ + if ((Expr->Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) { + ED_PropagateFrom (Expr, &Expr2); + } + } /* Last expression */ @@ -3768,6 +3813,11 @@ static void hieOr (ExprDesc *Expr) } } + /* Propagate viral flags */ + if ((Expr->Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) { + ED_PropagateFrom (Expr, &Expr2); + } + } /* Convert to bool */ @@ -4059,6 +4109,14 @@ static void hieQuest (ExprDesc* Expr) /* Setup the target expression */ Expr->Type = ResultType; + + /* Propagate viral flags */ + if ((Expr2.Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) { + ED_PropagateFrom (Expr, &Expr2); + } + if ((Expr3.Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) { + ED_PropagateFrom (Expr, &Expr3); + } } } @@ -4140,22 +4198,29 @@ void hie0 (ExprDesc *Expr) ** emit a warning. */ GetCodePos (&End); - if (!ED_MayHaveNoEffect (Expr) && - CodeRangeIsEmpty (&Start, &End) && - IS_Get (&WarnNoEffect) && + if (!ED_MayHaveNoEffect (Expr) && + (CodeRangeIsEmpty (&Start, &End) || + (Expr->Flags & E_SIDE_EFFECTS) == 0) && + IS_Get (&WarnNoEffect) && PrevErrorCount == ErrorCount) { - Warning ("Expression result unused"); + Warning ("Left-hand operand of comma expression has no effect"); } PrevErrorCount = ErrorCount; /* Remember the current code position */ GetCodePos (&Start); + /* Keep viral flags propagated from subexpressions */ + Flags |= Expr->Flags & E_MASK_VIRAL; + /* Reset the expression */ ED_Init (Expr); - Expr->Flags = Flags; + Expr->Flags = Flags & ~E_MASK_VIRAL; NextToken (); hie1 (Expr); + + /* Propagate viral flags */ + Expr->Flags |= Flags & E_MASK_VIRAL; } } diff --git a/src/cc65/exprdesc.h b/src/cc65/exprdesc.h index 13eb36e5e..f1f121cc4 100644 --- a/src/cc65/exprdesc.h +++ b/src/cc65/exprdesc.h @@ -125,6 +125,7 @@ enum { E_LOADED = 0x1000, /* Expression is loaded in primary */ E_CC_SET = 0x2000, /* Condition codes are set */ E_HAVE_MARKS = 0x4000, /* Code marks are valid */ + E_SIDE_EFFECTS = 0x8000, /* Expression has had side effects */ /* Optimization hints */ E_MASK_NEED = 0x030000, @@ -181,6 +182,9 @@ enum { /* Expression result must be known to the compiler and generate no code to load */ E_EVAL_C_CONST = E_EVAL_COMPILER_KNOWN | E_EVAL_NO_CODE, + /* Flags to combine from subexpressions */ + E_MASK_VIRAL = E_SIDE_EFFECTS, + /* Flags to keep in subexpressions of most operations other than ternary */ E_MASK_KEEP_SUBEXPR = E_MASK_EVAL, @@ -467,6 +471,16 @@ INLINE int ED_MayHaveNoEffect (const ExprDesc* Expr) # define ED_MayHaveNoEffect(Expr) (((Expr)->Flags & E_EVAL_MAYBE_UNUSED) == E_EVAL_MAYBE_UNUSED) #endif +#if defined(HAVE_INLINE) +INLINE void ED_PropagateFrom (ExprDesc* Expr, const ExprDesc* SubExpr) +/* Propagate viral flags from subexpression */ +{ + Expr->Flags |= SubExpr->Flags & E_MASK_VIRAL; +} +#else +# define ED_PropagateFrom(Expr, SubExpr) (void)((Expr)->Flags |= (SubExpr)->Flags & E_MASK_VIRAL) +#endif + #if defined(HAVE_INLINE) INLINE int ED_IsLocPrimaryOrExpr (const ExprDesc* Expr) /* Return true if the expression is E_LOC_PRIMARY or E_LOC_EXPR */ diff --git a/src/cc65/loadexpr.c b/src/cc65/loadexpr.c index 4b7f8e279..ccd694e35 100644 --- a/src/cc65/loadexpr.c +++ b/src/cc65/loadexpr.c @@ -277,4 +277,8 @@ void LoadExpr (unsigned Flags, struct ExprDesc* Expr) } } + if (ED_IsLVal (Expr) && IsQualVolatile (Expr->Type)) { + /* Expression has had side effects */ + Expr->Flags |= E_SIDE_EFFECTS; + } } diff --git a/src/cc65/shiftexpr.c b/src/cc65/shiftexpr.c index f7385ace1..eb879a475 100644 --- a/src/cc65/shiftexpr.c +++ b/src/cc65/shiftexpr.c @@ -237,5 +237,8 @@ MakeRVal: /* Set the type of the result */ Expr->Type = ResultType; + + /* Propagate from subexpressions */ + Expr->Flags |= Expr2.Flags & E_MASK_VIRAL; } } diff --git a/src/cc65/stdfunc.c b/src/cc65/stdfunc.c index 37566a455..5ed5ce671 100644 --- a/src/cc65/stdfunc.c +++ b/src/cc65/stdfunc.c @@ -185,6 +185,9 @@ static void ParseArg (ArgDesc* Arg, const Type* Type, ExprDesc* Expr) /* Use the type of the argument for the push */ Arg->Flags |= TypeOf (Arg->Expr.Type); + + /* Propagate from subexpressions */ + Expr->Flags |= Arg->Expr.Flags & E_MASK_VIRAL; } @@ -1365,6 +1368,9 @@ static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr) ExitPoint: /* We expect the closing brace */ ConsumeRParen (); + + /* Propagate from subexpressions */ + Expr->Flags |= Arg.Flags & E_MASK_VIRAL; } @@ -1405,4 +1411,7 @@ void HandleStdFunc (int Index, FuncDesc* F, ExprDesc* lval) /* Call the handler function */ D->Handler (F, lval); + + /* We assume all function calls had side effects */ + lval->Flags |= E_SIDE_EFFECTS; } diff --git a/src/cc65/stmt.c b/src/cc65/stmt.c index 022a8475c..a08197c09 100644 --- a/src/cc65/stmt.c +++ b/src/cc65/stmt.c @@ -613,12 +613,13 @@ static void Statement (int* PendingToken) ** void, emit a warning. */ GetCodePos (&End); - if (!ED_YetToLoad (&Expr) && - !ED_MayHaveNoEffect (&Expr) && - CodeRangeIsEmpty (&Start, &End) && - IS_Get (&WarnNoEffect) && + if (!ED_YetToLoad (&Expr) && + !ED_MayHaveNoEffect (&Expr) && + (CodeRangeIsEmpty (&Start, &End) || + (Expr.Flags & E_SIDE_EFFECTS) == 0) && + IS_Get (&WarnNoEffect) && PrevErrorCount == ErrorCount) { - Warning ("Expression result unused"); + Warning ("Statement has no effect"); } CheckSemi (PendingToken); } From 40b26f406061fc0b05da571da2b6dee3464b2390 Mon Sep 17 00:00:00 2001 From: acqn Date: Mon, 22 Feb 2021 13:47:32 +0800 Subject: [PATCH 2/2] Now the compiler removes code that has no observable effect. --- src/cc65/expr.c | 22 ++++++++++++++-------- src/cc65/stmt.c | 23 ++++++++++++++--------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 621f16c15..d12bc1519 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -4194,19 +4194,25 @@ void hie0 (ExprDesc *Expr) /* 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. + /* If the expression has no observable effect and isn't cast to type + ** void, emit a warning and remove useless code if any. */ GetCodePos (&End); - if (!ED_MayHaveNoEffect (Expr) && - (CodeRangeIsEmpty (&Start, &End) || - (Expr->Flags & E_SIDE_EFFECTS) == 0) && - IS_Get (&WarnNoEffect) && - PrevErrorCount == ErrorCount) { - Warning ("Left-hand operand of comma expression has no effect"); + if (CodeRangeIsEmpty (&Start, &End) || + (Expr->Flags & E_SIDE_EFFECTS) == 0) { + + if (!ED_MayHaveNoEffect (Expr) && + IS_Get (&WarnNoEffect) && + PrevErrorCount == ErrorCount) { + Warning ("Left-hand operand of comma expression has no effect"); + } + + /* Remove code with no effect */ + RemoveCode (&Start); } PrevErrorCount = ErrorCount; + /* Remember the current code position */ GetCodePos (&Start); diff --git a/src/cc65/stmt.c b/src/cc65/stmt.c index a08197c09..7355e88a8 100644 --- a/src/cc65/stmt.c +++ b/src/cc65/stmt.c @@ -609,18 +609,23 @@ static void Statement (int* PendingToken) Expr.Flags |= E_NEED_NONE; Expression0 (&Expr); - /* If the statement didn't generate code, and is not of type - ** void, emit a warning. + /* If the statement has no observable effect and isn't cast to type + ** void, emit a warning and remove useless code if any. */ GetCodePos (&End); - if (!ED_YetToLoad (&Expr) && - !ED_MayHaveNoEffect (&Expr) && - (CodeRangeIsEmpty (&Start, &End) || - (Expr.Flags & E_SIDE_EFFECTS) == 0) && - IS_Get (&WarnNoEffect) && - PrevErrorCount == ErrorCount) { - Warning ("Statement has no effect"); + if (CodeRangeIsEmpty (&Start, &End) || + (Expr.Flags & E_SIDE_EFFECTS) == 0) { + + if (!ED_MayHaveNoEffect (&Expr) && + IS_Get (&WarnNoEffect) && + PrevErrorCount == ErrorCount) { + Warning ("Statement has no effect"); + } + + /* Remove code with no effect */ + RemoveCode (&Start); } + CheckSemi (PendingToken); }