X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fassignment.c;h=662128c84821d3bafacaafe8667f516ad2a0869f;hb=6b3e515573e5165aefaff9e59ac42f3567e6ab25;hp=af414ff50e76e2902c7b4c40e567a462125271c9;hpb=45d4771584d7f28097f3fbb0a3ce1743c418685f;p=cc65 diff --git a/src/cc65/assignment.c b/src/cc65/assignment.c index af414ff50..662128c84 100644 --- a/src/cc65/assignment.c +++ b/src/cc65/assignment.c @@ -34,6 +34,7 @@ /* cc65 */ +#include "asmcode.h" #include "assignment.h" #include "codegen.h" #include "datatype.h" @@ -160,6 +161,9 @@ void Assignment (ExprDesc* Expr) } else if (ED_IsBitField (Expr)) { + CodeMark AndPos; + CodeMark PushPos; + unsigned Mask; unsigned Flags; @@ -182,30 +186,57 @@ void Assignment (ExprDesc* Expr) /* Mask unwanted bits */ Mask = (0x0001U << Expr->BitWidth) - 1U; + GetCodePos (&AndPos); g_and (Flags | CF_CONST, ~(Mask << Expr->BitOffs)); /* Push it on stack */ + GetCodePos (&PushPos); g_push (Flags, 0); /* Read the expression on the right side of the '=' */ - hie1 (&Expr2); + MarkedExprWithCheck (hie1, &Expr2); - /* Do type conversion if necessary. Beware: Do not use char type + /* Do type conversion if necessary. Beware: Do not use char type * here! */ TypeConversion (&Expr2, ltype); - /* If necessary, load the value into the primary register */ - LoadExpr (CF_NONE, &Expr2); + /* Special treatment if the value is constant. */ + /* Beware: Expr2 may contain side effects, so there must not be + * code generated for Expr2. + */ + if (ED_IsConstAbsInt (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) { + + /* Get the value and apply the mask */ + unsigned Val = (unsigned) (Expr2.IVal & Mask); - /* Apply the mask */ - g_and (Flags | CF_CONST, Mask); + /* Since we will do the OR with a constant, we can remove the push */ + RemoveCode (&PushPos); - /* Shift it into the right position */ - g_asl (Flags | CF_CONST, Expr->BitOffs); + /* If the value is equal to the mask now, all bits are one, and we + * can remove the mask operation from above. + */ + if (Val == Mask) { + RemoveCode (&AndPos); + } - /* Or both values */ - g_or (Flags, 0); + /* Generate the or operation */ + g_or (Flags | CF_CONST, Val << Expr->BitOffs); + + } else { + + /* If necessary, load the value into the primary register */ + LoadExpr (CF_NONE, &Expr2); + + /* Apply the mask */ + g_and (Flags | CF_CONST, Mask); + + /* Shift it into the right position */ + g_asl (Flags | CF_CONST, Expr->BitOffs); + + /* Or both values */ + g_or (Flags, 0); + } /* Generate a store instruction */ Store (Expr, 0);