From 21084895230d137db87f8a4febac8a9359e8e548 Mon Sep 17 00:00:00 2001 From: acqn Date: Wed, 15 Jul 2020 20:22:28 +0800 Subject: [PATCH] Fix for Issue #1075 and #1077. --- src/cc65/assignment.c | 6 +- src/cc65/codegen.c | 5 + src/cc65/codegen.h | 7 +- src/cc65/declare.c | 9 +- src/cc65/expr.c | 231 +++++++++++++++++++------------------ src/cc65/exprdesc.c | 196 ++++++++++++++++++++++++++----- src/cc65/exprdesc.h | 263 ++++++++++++++++++++++++++++++++---------- src/cc65/loadexpr.c | 80 ++++++++----- src/cc65/locals.c | 2 +- src/cc65/shiftexpr.c | 10 +- src/cc65/stdfunc.c | 30 ++--- src/cc65/typeconv.c | 19 ++- 12 files changed, 598 insertions(+), 260 deletions(-) diff --git a/src/cc65/assignment.c b/src/cc65/assignment.c index f0607ac58..8e42a338f 100644 --- a/src/cc65/assignment.c +++ b/src/cc65/assignment.c @@ -98,7 +98,7 @@ void Assignment (ExprDesc* Expr) if (UseReg) { PushAddr (Expr); } else { - ED_MakeRVal (Expr); + ED_MarkExprAsRVal (Expr); LoadExpr (CF_NONE, Expr); g_push (CF_PTR | CF_UNSIGNED, 0); } @@ -127,7 +127,7 @@ void Assignment (ExprDesc* Expr) } else { /* We will use memcpy. Push the address of the rhs */ - ED_MakeRVal (&Expr2); + ED_MarkExprAsRVal (&Expr2); LoadExpr (CF_NONE, &Expr2); /* Push the address (or whatever is in ax in case of errors) */ @@ -264,5 +264,5 @@ void Assignment (ExprDesc* Expr) } /* Value is still in primary and not an lvalue */ - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); } diff --git a/src/cc65/codegen.c b/src/cc65/codegen.c index 920d8fe90..7af329b91 100644 --- a/src/cc65/codegen.c +++ b/src/cc65/codegen.c @@ -100,6 +100,11 @@ static const char* GetLabelName (unsigned Flags, uintptr_t Label, long Offs) /* Create the correct label name */ switch (Flags & CF_ADDRMASK) { + case CF_IMM: + /* Immediate constant values */ + xsprintf (Buf, sizeof (Buf), "$%04X", (unsigned)((Offs) & 0xFFFF)); + break; + case CF_STATIC: /* Static memory cell */ if (Offs) { diff --git a/src/cc65/codegen.h b/src/cc65/codegen.h index 6f61b33a6..af539df8b 100644 --- a/src/cc65/codegen.h +++ b/src/cc65/codegen.h @@ -81,11 +81,12 @@ #define CF_TEST 0x0080 /* Test value */ #define CF_FIXARGC 0x0100 /* Function has fixed arg count */ #define CF_FORCECHAR 0x0200 /* Handle chars as chars, not ints */ -#define CF_REG 0x0800 /* Value is in primary register */ /* Type of static address */ -#define CF_ADDRMASK 0xF000 /* Type of address */ -#define CF_STATIC 0x0000 /* Static local */ +#define CF_ADDRMASK 0xFC00 /* Type of address */ +#define CF_IMM 0x0000 /* Value is pure rvalue and has no address */ +#define CF_REG 0x0400 /* Value is in primary register */ +#define CF_STATIC 0x0800 /* Static local */ #define CF_EXTERNAL 0x1000 /* Static external */ #define CF_ABSOLUTE 0x2000 /* Numeric absolute address */ #define CF_LOCAL 0x4000 /* Auto variable */ diff --git a/src/cc65/declare.c b/src/cc65/declare.c index 58baaf769..5827eb6dc 100644 --- a/src/cc65/declare.c +++ b/src/cc65/declare.c @@ -1773,9 +1773,14 @@ static void DefineData (ExprDesc* Expr) { switch (ED_GetLoc (Expr)) { + case E_LOC_NONE: + /* Immediate numeric value with no storage */ + g_defdata (CF_IMM | TypeOf (Expr->Type) | CF_CONST, Expr->IVal, 0); + break; + case E_LOC_ABS: - /* Absolute: numeric address or const */ - g_defdata (TypeOf (Expr->Type) | CF_CONST, Expr->IVal, 0); + /* Absolute numeric address */ + g_defdata (CF_ABSOLUTE | TypeOf(Expr->Type) | CF_CONST, Expr->IVal, 0); break; case E_LOC_GLOBAL: diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 84f11189e..38a52e744 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -83,6 +83,7 @@ static unsigned GlobalModeFlags (const ExprDesc* Expr) /* Return the addressing mode flags for the given expression */ { switch (ED_GetLoc (Expr)) { + case E_LOC_NONE: return CF_IMM; case E_LOC_ABS: return CF_ABSOLUTE; case E_LOC_GLOBAL: return CF_EXTERNAL; case E_LOC_STATIC: return CF_STATIC; @@ -183,7 +184,7 @@ static unsigned typeadjust (ExprDesc* lhs, ExprDesc* rhs, int NoPush) /* Generate type adjustment code if needed */ ltype = TypeOf (lhst); - if (ED_IsLocAbs (lhs)) { + if (ED_IsLocNone (lhs)) { ltype |= CF_CONST; } if (NoPush) { @@ -191,7 +192,7 @@ static unsigned typeadjust (ExprDesc* lhs, ExprDesc* rhs, int NoPush) ltype |= CF_REG; } rtype = TypeOf (rhst); - if (ED_IsLocAbs (rhs)) { + if (ED_IsLocNone (rhs)) { rtype |= CF_CONST; } flags = g_typeadjust (ltype, rtype); @@ -506,7 +507,7 @@ static void FunctionCall (ExprDesc* Expr) ** the pointer into the primary and mark it as an expression. */ LoadExpr (CF_NONE, Expr); - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); /* Remember the code position */ GetCodePos (&Mark); @@ -646,7 +647,7 @@ static void FunctionCall (ExprDesc* Expr) } /* The function result is an rvalue in the primary register */ - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); Expr->Type = GetFuncReturn (Expr->Type); } @@ -663,7 +664,7 @@ static void Primary (ExprDesc* E) /* Character and integer constants. */ if (CurTok.Tok == TOK_ICONST || CurTok.Tok == TOK_CCONST) { E->IVal = CurTok.IVal; - E->Flags = E_LOC_ABS | E_RTYPE_RVAL; + E->Flags = E_LOC_NONE | E_RTYPE_RVAL; E->Type = CurTok.Type; NextToken (); return; @@ -672,7 +673,7 @@ static void Primary (ExprDesc* E) /* Floating point constant */ if (CurTok.Tok == TOK_FCONST) { E->FVal = CurTok.FVal; - E->Flags = E_LOC_ABS | E_RTYPE_RVAL; + E->Flags = E_LOC_NONE | E_RTYPE_RVAL; E->Type = CurTok.Type; NextToken (); return; @@ -716,7 +717,7 @@ static void Primary (ExprDesc* E) NextToken (); Entry = AddLabelSym (CurTok.Ident, SC_REF | SC_GOTO_IND); /* output its label */ - E->Flags = E_RTYPE_RVAL | E_LOC_STATIC; + E->Flags = E_RTYPE_RVAL | E_LOC_STATIC | E_ADDRESS_OF; E->Name = Entry->V.L.Label; E->Type = PointerTo (type_void); NextToken (); @@ -756,7 +757,7 @@ static void Primary (ExprDesc* E) /* Check for legal symbol types */ if ((Sym->Flags & SC_CONST) == SC_CONST) { /* Enum or some other numeric constant */ - E->Flags = E_LOC_ABS | E_RTYPE_RVAL; + E->Flags = E_LOC_NONE | E_RTYPE_RVAL; E->IVal = Sym->V.ConstVal; } else if ((Sym->Flags & SC_FUNC) == SC_FUNC) { /* Function */ @@ -797,12 +798,12 @@ static void Primary (ExprDesc* E) /* We've made all variables lvalues above. However, this is ** not always correct: An array is actually the address of its - ** first element, which is a rvalue, and a function is a + ** first element, which is an rvalue, and a function is an ** rvalue, too, because we cannot store anything in a function. ** So fix the flags depending on the type. */ if (IsTypeArray (E->Type) || IsTypeFunc (E->Type)) { - ED_MakeRVal (E); + ED_AddrExpr (E); } } else { @@ -845,7 +846,7 @@ static void Primary (ExprDesc* E) /* String literal */ E->LVal = UseLiteral (CurTok.SVal); E->Type = GetCharArrayType (GetLiteralSize (CurTok.SVal)); - E->Flags = E_LOC_LITERAL | E_RTYPE_RVAL; + E->Flags = E_LOC_LITERAL | E_RTYPE_RVAL | E_ADDRESS_OF; E->IVal = 0; E->Name = GetLiteralLabel (CurTok.SVal); NextToken (); @@ -854,7 +855,7 @@ static void Primary (ExprDesc* E) case TOK_ASM: /* ASM statement */ AsmStatement (); - E->Flags = E_LOC_EXPR | E_RTYPE_RVAL; + E->Flags = E_RTYPE_RVAL; E->Type = type_void; break; @@ -912,12 +913,11 @@ static void ArrayRef (ExprDesc* Expr) /* We can apply a special treatment for arrays that have a const base ** address. This is true for most arrays and will produce a lot better - ** code. Check if this is a const base address. + ** code. Check if this is a "quasi-const base" address. */ - ConstBaseAddr = ED_IsRVal (Expr) && - (ED_IsLocConst (Expr) || ED_IsLocStack (Expr)); + ConstBaseAddr = ED_IsRVal (Expr) && ED_IsLocQuasiConst (Expr); - /* If we have a constant base, we delay the address fetch */ + /* If we have a quasi-const base address, we delay the address fetch */ GetCodePos (&Mark1); if (!ConstBaseAddr) { /* Get a pointer to the array into the primary */ @@ -984,7 +984,7 @@ static void ArrayRef (ExprDesc* Expr) /* If the subscript is a bit-field, load it and make it an rvalue */ if (ED_IsBitField (&Subscript)) { LoadExpr (CF_NONE, &Subscript); - ED_MakeRValExpr (&Subscript); + ED_FinalizeRValLoad (&Subscript); } /* Check if the subscript is constant absolute value */ @@ -1015,25 +1015,21 @@ static void ArrayRef (ExprDesc* Expr) ** already in Expr. If the base address was a constant, we can even ** remove the code that loaded the address into the primary. */ - if (IsTypeArray (Expr->Type)) { - - /* Adjust the offset */ - Expr->IVal += Subscript.IVal; - - } else { - + if (!IsTypeArray (Expr->Type)) { + /* It's a pointer, so we do have to load it into the primary ** first (if it's not already there). */ - if (ConstBaseAddr || ED_IsLVal (Expr)) { + if (!ConstBaseAddr && ED_IsLVal (Expr)) { LoadExpr (CF_NONE, Expr); - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); } - - /* Use the offset */ - Expr->IVal = Subscript.IVal; } + /* Adjust the offset */ + Expr->IVal += Subscript.IVal; + + } else { /* Scale the rhs value according to the element type */ @@ -1106,7 +1102,7 @@ static void ArrayRef (ExprDesc* Expr) ** subscript was not scaled, that is, if this was a byte array ** or pointer. */ - if ((ED_IsLocConst (&Subscript) || ED_IsLocStack (&Subscript)) && + if (ED_IsLocQuasiConst (&Subscript) && CheckedSizeOf (ElementType) == SIZEOF_CHAR) { unsigned Flags; @@ -1131,12 +1127,13 @@ static void ArrayRef (ExprDesc* Expr) } } else { - if (ED_IsLocAbs (Expr)) { + if (ED_IsLocNone (Expr) || + (ED_IsLocAbs (Expr) && ED_IsAddrExpr (Expr))) { /* Constant numeric address. Just add it */ g_inc (CF_INT, Expr->IVal); } else if (ED_IsLocStack (Expr)) { /* Base address is a local variable address */ - if (IsTypeArray (Expr->Type)) { + if (ED_IsAddrExpr (Expr)) { g_addaddr_local (CF_INT, Expr->IVal); } else { g_addlocal (CF_PTR, Expr->IVal); @@ -1144,7 +1141,7 @@ static void ArrayRef (ExprDesc* Expr) } else { /* Base address is a static variable address */ unsigned Flags = CF_INT | GlobalModeFlags (Expr); - if (ED_IsRVal (Expr)) { + if (ED_IsAddrExpr (Expr)) { /* Add the address of the location */ g_addaddr_static (Flags, Expr->Name, Expr->IVal); } else { @@ -1153,27 +1150,27 @@ static void ArrayRef (ExprDesc* Expr) } } } - - } - /* The result is an expression in the primary */ - ED_MakeRValExpr (Expr); + /* The pointer is an rvalue in the primary */ + ED_FinalizeRValLoad (Expr); } - /* Result is of element type */ + /* The result is usually an lvalue expression of element type referenced in + ** the primary, unless it's an array which is a rare case. We can just + ** assume the usual case first, and change it later if necessary. + */ + ED_IndExpr (Expr); Expr->Type = ElementType; - /* An array element is actually a variable. So the rules for variables - ** with respect to the reference type apply: If it's an array, it is - ** a rvalue, otherwise it's an lvalue. (A function would also be a rvalue, - ** but an array cannot contain functions). + /* An array element is actually a variable. So the rules for variables with + ** respect to the reference type apply: If it's an array, it is virtually + ** an rvalue address, otherwise it's an lvalue reference. (A function would + ** also be an rvalue address, but an array cannot contain functions). */ if (IsTypeArray (Expr->Type)) { - ED_MakeRVal (Expr); - } else { - ED_MakeLVal (Expr); + ED_AddrExpr (Expr); } /* Consume the closing bracket */ @@ -1210,16 +1207,26 @@ static void StructRef (ExprDesc* Expr) return; } - /* If we have a struct pointer that is an lvalue and not already in the - ** primary, load it now. - */ - if (ED_IsLVal (Expr) && IsTypePtr (Expr->Type)) { + if (IsTypePtr (Expr->Type)) { + /* If we have a struct pointer that is an lvalue and not already in the + ** primary, load its content now. + */ + if (!ED_IsConst (Expr)) { + /* Load into the primary */ + LoadExpr (CF_NONE, Expr); - /* Load into the primary */ + /* Clear the offset */ + Expr->IVal = 0; + } + + /* Dereference the expression */ + ED_IndExpr (Expr); + + } else if (!ED_IsLocQuasiConst (Expr) && !ED_IsLocPrimaryOrExpr (Expr)) { + /* Load the base address into the primary (and use it as a reference + ** later) if it's not quasi-const or in the primary already. + */ LoadExpr (CF_NONE, Expr); - - /* Make it an lvalue expression */ - ED_MakeLValExpr (Expr); } /* The type is the type of the field plus any qualifiers from the struct */ @@ -1235,8 +1242,8 @@ static void StructRef (ExprDesc* Expr) FinalType->C |= Q; } - /* A struct is usually an lvalue. If not, it is a struct in the primary - ** register. + /* A struct is usually an lvalue. If not, it is a struct referenced in the + ** primary register, which is likely to be returned from a function. */ if (ED_IsRVal (Expr) && ED_IsLocExpr (Expr) && !IsTypePtr (Expr->Type)) { @@ -1289,13 +1296,12 @@ static void StructRef (ExprDesc* Expr) /* An struct member is actually a variable. So the rules for variables ** with respect to the reference type apply: If it's an array, it is - ** a rvalue, otherwise it's an lvalue. (A function would also be a rvalue, - ** but a struct field cannot be a function). + ** virtually an rvalue address, otherwise it's an lvalue reference. (A + ** function would also be an rvalue address, but a struct field cannot + ** contain functions). */ if (IsTypeArray (Expr->Type)) { - ED_MakeRVal (Expr); - } else { - ED_MakeLVal (Expr); + ED_AddrExpr (Expr); } /* Make the expression a bit field if necessary */ @@ -1391,7 +1397,7 @@ void Store (ExprDesc* Expr, const Type* StoreType) switch (ED_GetLoc (Expr)) { case E_LOC_ABS: - /* Absolute: numeric address or const */ + /* Absolute numeric addressed variable */ g_putstatic (Flags, Expr->IVal, 0); break; @@ -1421,10 +1427,14 @@ void Store (ExprDesc* Expr, const Type* StoreType) break; case E_LOC_EXPR: - /* An expression in the primary register */ + /* An expression referenced in the primary register */ g_putind (Flags, Expr->IVal); break; + case E_LOC_NONE: + /* We may get here as a result of previous compiler errors */ + break; + default: Internal ("Invalid location in Store(): 0x%04X", ED_GetLoc (Expr)); } @@ -1466,7 +1476,7 @@ static void PreInc (ExprDesc* Expr) switch (ED_GetLoc (Expr)) { case E_LOC_ABS: - /* Absolute: numeric address or const */ + /* Absolute numeric addressed variable */ g_addeqstatic (Flags, Expr->IVal, 0, Val); break; @@ -1497,7 +1507,7 @@ static void PreInc (ExprDesc* Expr) break; case E_LOC_EXPR: - /* An expression in the primary register */ + /* An expression referenced in the primary register */ g_addeqind (Flags, Expr->IVal, Val); break; @@ -1506,7 +1516,7 @@ static void PreInc (ExprDesc* Expr) } /* Result is an expression, no reference */ - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); } @@ -1542,7 +1552,7 @@ static void PreDec (ExprDesc* Expr) switch (ED_GetLoc (Expr)) { case E_LOC_ABS: - /* Absolute: numeric address or const */ + /* Absolute numeric addressed variable */ g_subeqstatic (Flags, Expr->IVal, 0, Val); break; @@ -1582,7 +1592,7 @@ static void PreDec (ExprDesc* Expr) } /* Result is an expression, no reference */ - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); } @@ -1638,7 +1648,7 @@ static void PostInc (ExprDesc* Expr) } /* The result is always an expression, no reference */ - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); } @@ -1694,7 +1704,7 @@ static void PostDec (ExprDesc* Expr) } /* The result is always an expression, no reference */ - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); } @@ -1741,8 +1751,8 @@ static void UnaryOp (ExprDesc* Expr) default: Internal ("Unexpected token: %d", Tok); } - /* The result is a rvalue in the primary */ - ED_MakeRValExpr (Expr); + /* The result is an rvalue in the primary */ + ED_FinalizeRValLoad (Expr); } } @@ -1776,7 +1786,7 @@ void hie10 (ExprDesc* Expr) Expr->IVal = !Expr->IVal; } else { g_bneg (TypeOf (Expr->Type)); - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); ED_TestDone (Expr); /* bneg will set cc */ } break; @@ -1784,13 +1794,14 @@ void hie10 (ExprDesc* Expr) case TOK_STAR: NextToken (); ExprWithCheck (hie10, Expr); - if (ED_IsLVal (Expr) || !(ED_IsLocConst (Expr) || ED_IsLocStack (Expr))) { - /* Not a const, load it into the primary and make it a + if (ED_IsLVal (Expr) || !ED_IsLocQuasiConst (Expr)) { + /* Not a const, load the pointer into the primary and make it a ** calculated value. */ LoadExpr (CF_NONE, Expr); - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); } + /* If the expression is already a pointer to function, the ** additional dereferencing operator must be ignored. A function ** itself is represented as "pointer to function", so any number @@ -1799,7 +1810,7 @@ void hie10 (ExprDesc* Expr) */ if (IsTypeFuncPtr (Expr->Type) || IsTypeFunc (Expr->Type)) { /* Expression not storable */ - ED_MakeRVal (Expr); + ED_MarkExprAsRVal (Expr); } else { if (IsClassPtr (Expr->Type)) { Expr->Type = Indirect (Expr->Type); @@ -1810,8 +1821,8 @@ void hie10 (ExprDesc* Expr) ** address -- it already is the location of the first element. */ if (!IsTypeArray (Expr->Type)) { - /* The * operator yields an lvalue */ - ED_MakeLVal (Expr); + /* The * operator yields an lvalue reference */ + ED_IndExpr (Expr); } } break; @@ -1831,8 +1842,8 @@ void hie10 (ExprDesc* Expr) Expr->Flags &= ~E_BITFIELD; } Expr->Type = PointerTo (Expr->Type); - /* The & operator yields an rvalue */ - ED_MakeRVal (Expr); + /* The & operator yields an rvalue address */ + ED_AddrExpr (Expr); } break; @@ -2067,8 +2078,8 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ /* Generate code */ Gen->Func (type, Expr->IVal); - /* We have a rvalue in the primary now */ - ED_MakeRValExpr (Expr); + /* We have an rvalue in the primary now */ + ED_FinalizeRValLoad (Expr); } else { @@ -2100,8 +2111,8 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ /* Generate code */ Gen->Func (type, Expr2.IVal); - /* We have a rvalue in the primary now */ - ED_MakeRValExpr (Expr); + /* We have an rvalue in the primary now */ + ED_FinalizeRValLoad (Expr); } } } @@ -2441,7 +2452,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ GenFunc (flags, Expr2.IVal); /* The result is an rvalue in the primary */ - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); } /* Result type is always int */ @@ -2534,7 +2545,7 @@ static void parseadd (ExprDesc* Expr) rhst = Expr2.Type; /* Setup flags */ - if (ED_IsLocAbs (Expr)) { + if (ED_IsLocNone (Expr)) { /* A numerical constant */ flags |= CF_CONST; } else { @@ -2549,7 +2560,7 @@ static void parseadd (ExprDesc* Expr) /* Operate on pointers, result type is a pointer */ flags |= CF_PTR; /* Generate the code for the add */ - if (ED_GetLoc (Expr) == E_LOC_ABS) { + if (ED_GetLoc (Expr) == E_LOC_NONE) { /* Numeric constant */ g_inc (flags, Expr->IVal); } else { @@ -2569,7 +2580,7 @@ static void parseadd (ExprDesc* Expr) ** not a numeric constant, and the scale factor is not one ** (no scaling), we must take the long way over the stack. */ - if (ED_IsLocAbs (Expr)) { + if (ED_IsLocNone (Expr)) { /* Numeric constant, scale lhs */ Expr->IVal *= ScaleFactor; /* Generate the code for the add */ @@ -2588,7 +2599,7 @@ static void parseadd (ExprDesc* Expr) /* Integer addition */ flags |= typeadjust (Expr, &Expr2, 1); /* Generate the code for the add */ - if (ED_IsLocAbs (Expr)) { + if (ED_IsLocNone (Expr)) { /* Numeric constant */ g_inc (flags, Expr->IVal); } else { @@ -2601,8 +2612,8 @@ static void parseadd (ExprDesc* Expr) flags = CF_INT; } - /* Result is a rvalue in primary register */ - ED_MakeRValExpr (Expr); + /* Result is an rvalue in primary register */ + ED_FinalizeRValLoad (Expr); } } else { @@ -2692,8 +2703,8 @@ static void parseadd (ExprDesc* Expr) } - /* Result is a rvalue in primary register */ - ED_MakeRValExpr (Expr); + /* Result is an rvalue in primary register */ + ED_FinalizeRValLoad (Expr); } /* Condition codes not set */ @@ -2825,8 +2836,8 @@ static void parsesub (ExprDesc* Expr) g_scale (flags, -rscale); } - /* Result is a rvalue in the primary register */ - ED_MakeRValExpr (Expr); + /* Result is an rvalue in the primary register */ + ED_FinalizeRValLoad (Expr); ED_MarkAsUntested (Expr); } @@ -2860,8 +2871,8 @@ static void parsesub (ExprDesc* Expr) ** the lhs is const, we have to remove this mark, since this is no ** longer true, lhs is on stack instead. */ - if (ED_IsLocAbs (Expr)) { - ED_MakeRValExpr (Expr); + if (ED_IsLocNone (Expr)) { + ED_FinalizeRValLoad (Expr); } /* Adjust operand types */ flags = typeadjust (Expr, &Expr2, 0); @@ -2879,8 +2890,8 @@ static void parsesub (ExprDesc* Expr) g_scale (flags, -rscale); } - /* Result is a rvalue in the primary register */ - ED_MakeRValExpr (Expr); + /* Result is an rvalue in the primary register */ + ED_FinalizeRValLoad (Expr); ED_MarkAsUntested (Expr); } } @@ -3070,7 +3081,7 @@ static void hieAnd (ExprDesc* Expr, unsigned TrueLab, int* BoolOp) g_defcodelabel (FalseLab); /* The result is an rvalue in primary */ - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); ED_TestDone (Expr); /* Condition codes are set */ } } @@ -3133,7 +3144,7 @@ static void hieOr (ExprDesc *Expr) } /* The result is an rvalue in primary */ - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); ED_TestDone (Expr); /* Condition codes are set */ } @@ -3189,7 +3200,7 @@ static void hieQuest (ExprDesc* Expr) if (!IsTypeVoid (Expr2.Type)) { /* Load it into the primary */ LoadExpr (CF_NONE, &Expr2); - ED_MakeRValExpr (&Expr2); + ED_FinalizeRValLoad (&Expr2); Expr2.Type = PtrConversion (Expr2.Type); } @@ -3212,7 +3223,7 @@ static void hieQuest (ExprDesc* Expr) if (!IsTypeVoid (Expr3.Type)) { /* Load it into the primary */ LoadExpr (CF_NONE, &Expr3); - ED_MakeRValExpr (&Expr3); + ED_FinalizeRValLoad (&Expr3); Expr3.Type = PtrConversion (Expr3.Type); } @@ -3278,7 +3289,7 @@ static void hieQuest (ExprDesc* Expr) g_defcodelabel (TrueLab); /* Setup the target expression */ - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); Expr->Type = ResultType; } } @@ -3294,7 +3305,7 @@ static void opeq (const GenDesc* Gen, ExprDesc* Expr, const char* Op) int MustScale; /* op= can only be used with lvalues */ - if (!ED_IsLVal (Expr)) { + if (ED_IsRVal (Expr)) { Error ("Invalid lvalue in assignment"); return; } @@ -3396,7 +3407,7 @@ static void opeq (const GenDesc* Gen, ExprDesc* Expr, const char* Op) Gen->Func (g_typeadjust (flags, TypeOf (Expr2.Type)), 0); } Store (Expr, 0); - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); } @@ -3410,7 +3421,7 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *Expr, const char* Op) int MustScale; - /* We're currently only able to handle some adressing modes */ + /* We're currently only able to handle some addressing modes */ if (ED_GetLoc (Expr) == E_LOC_EXPR || ED_GetLoc (Expr) == E_LOC_PRIMARY) { /* Use generic routine */ opeq (Gen, Expr, Op); @@ -3487,7 +3498,7 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *Expr, const char* Op) switch (ED_GetLoc (Expr)) { case E_LOC_ABS: - /* Absolute: numeric address or const */ + /* Absolute numeric addressed variable */ if (Gen->Tok == TOK_PLUS_ASSIGN) { g_addeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal); } else { @@ -3536,8 +3547,8 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *Expr, const char* Op) Internal ("Invalid location in Store(): 0x%04X", ED_GetLoc (Expr)); } - /* Expression is a rvalue in the primary now */ - ED_MakeRValExpr (Expr); + /* Expression is an rvalue in the primary now */ + ED_FinalizeRValLoad (Expr); } diff --git a/src/cc65/exprdesc.c b/src/cc65/exprdesc.c index 46377ac6b..5ff848fb7 100644 --- a/src/cc65/exprdesc.c +++ b/src/cc65/exprdesc.c @@ -80,6 +80,39 @@ void ED_MakeBitField (ExprDesc* Expr, unsigned BitOffs, unsigned BitWidth) +#if !defined(HAVE_INLINE) +int ED_IsLocQuasiConst (const ExprDesc* Expr) +/* Return true if the expression is a constant location of some sort or on the +** stack. +*/ +{ + return ED_IsLocConst (Expr) || ED_IsLocStack (Expr); +} +#endif + + + +#if !defined(HAVE_INLINE) +int ED_IsLocPrimaryOrExpr (const ExprDesc* Expr) +/* Return true if the expression is E_LOC_PRIMARY or E_LOC_EXPR */ +{ + return ED_IsLocPrimary (Expr) || ED_IsLocExpr (Expr); +} +#endif + + + +#if !defined(HAVE_INLINE) +int ED_IsIndExpr (const ExprDesc* Expr) +/* Check if the expression is a reference to its value */ +{ + return (Expr->Flags & E_ADDRESS_OF) == 0 && + !ED_IsLocNone (Expr) && !ED_IsLocPrimary (Expr); +} +#endif + + + void ED_SetCodeRange (ExprDesc* Expr, const CodeMark* Start, const CodeMark* End) /* Set the code range for this expression */ { @@ -115,8 +148,9 @@ const char* ED_GetLabelName (const ExprDesc* Expr, long Offs) /* Generate a label depending on the location */ switch (ED_GetLoc (Expr)) { + case E_LOC_NONE: case E_LOC_ABS: - /* Absolute: numeric address or const */ + /* Absolute numeric addressed variable */ SB_Printf (&Buf, "$%04X", (int)(Offs & 0xFFFF)); break; @@ -168,11 +202,11 @@ int ED_GetStackOffs (const ExprDesc* Expr, int Offs) ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, Type* Type) -/* Make Expr an absolute const with the given value and type. */ +/* Replace Expr with an absolute const with the given value and type */ { Expr->Sym = 0; Expr->Type = Type; - Expr->Flags = E_LOC_ABS | E_RTYPE_RVAL | (Expr->Flags & E_HAVE_MARKS); + Expr->Flags = E_LOC_NONE | E_RTYPE_RVAL | (Expr->Flags & E_HAVE_MARKS); Expr->Name = 0; Expr->IVal = Value; Expr->FVal = FP_D_Make (0.0); @@ -182,11 +216,11 @@ ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, Type* Type) ExprDesc* ED_MakeConstAbsInt (ExprDesc* Expr, long Value) -/* Make Expr a constant integer expression with the given value */ +/* Replace Expr with a constant integer expression with the given value */ { Expr->Sym = 0; Expr->Type = type_int; - Expr->Flags = E_LOC_ABS | E_RTYPE_RVAL | (Expr->Flags & E_HAVE_MARKS); + Expr->Flags = E_LOC_NONE | E_RTYPE_RVAL | (Expr->Flags & E_HAVE_MARKS); Expr->Name = 0; Expr->IVal = Value; Expr->FVal = FP_D_Make (0.0); @@ -195,14 +229,13 @@ ExprDesc* ED_MakeConstAbsInt (ExprDesc* Expr, long Value) -ExprDesc* ED_MakeRValExpr (ExprDesc* Expr) -/* Convert Expr into a rvalue which is in the primary register without an -** offset. -*/ +ExprDesc* ED_FinalizeRValLoad (ExprDesc* Expr) +/* Finalize the result of LoadExpr to be an rvalue in the primary register */ { Expr->Sym = 0; - Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE | E_BITFIELD | E_NEED_TEST | E_CC_SET); - Expr->Flags |= (E_LOC_EXPR | E_RTYPE_RVAL); + Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE | E_BITFIELD | E_ADDRESS_OF); + Expr->Flags &= ~(E_NEED_TEST | E_CC_SET); + Expr->Flags |= (E_LOC_PRIMARY | E_RTYPE_RVAL); Expr->Name = 0; Expr->IVal = 0; /* No offset */ Expr->FVal = FP_D_Make (0.0); @@ -211,18 +244,106 @@ ExprDesc* ED_MakeRValExpr (ExprDesc* Expr) -ExprDesc* ED_MakeLValExpr (ExprDesc* Expr) -/* Convert Expr into a lvalue which is in the primary register without an -** offset. +ExprDesc* ED_AddrExpr (ExprDesc* Expr) +/* Take address of Expr. The result is always an rvalue */ +{ + switch (Expr->Flags & E_MASK_LOC) { + case E_LOC_NONE: + Error ("Cannot get the address of a numeric constant"); + break; + + case E_LOC_EXPR: + Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE); + Expr->Flags |= E_LOC_PRIMARY | E_RTYPE_RVAL; + break; + + default: + if ((Expr->Flags & E_ADDRESS_OF) == 0) { + Expr->Flags &= ~E_MASK_RTYPE; + Expr->Flags |= E_ADDRESS_OF | E_RTYPE_RVAL; + } else { + /* Due to the way we handle arrays, this may happen if we take + ** the address of a pointer to an array element. + */ + if (!IsTypePtr (Expr->Type)) { + Error ("Cannot get the address of an address"); + } + Expr->Flags &= ~E_MASK_RTYPE; + Expr->Flags |= E_RTYPE_RVAL; + } + break; + } + return Expr; +} + + + +ExprDesc* ED_IndExpr (ExprDesc* Expr) +/* Dereference Expr */ +{ + switch (Expr->Flags & E_MASK_LOC) { + case E_LOC_NONE: + Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE); + Expr->Flags |= E_LOC_ABS | E_RTYPE_LVAL; + break; + + case E_LOC_PRIMARY: + Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE); + Expr->Flags |= E_LOC_EXPR | E_RTYPE_LVAL; + break; + + default: + if ((Expr->Flags & E_ADDRESS_OF) != 0) { + Expr->Flags &= ~(E_MASK_RTYPE | E_ADDRESS_OF); + Expr->Flags |= E_RTYPE_LVAL; + } else { + /* Due to the limitation of LoadExpr, this may happen after we + ** have loaded the value from a referenced address, in which + ** case the content in the primary no longer refers to the + ** original address. We simply mark this as E_LOC_EXPR so that + ** some info about the original location can be retained. + ** If it's really meant to dereference a "pointer value", it + ** should be done in two steps where the pointervalue should + ** be the manually loaded first before a call into this, and + ** the offset should be manually cleared somewhere outside. + */ + Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE); + Expr->Flags |= E_LOC_EXPR | E_RTYPE_LVAL; + } + break; + } + return Expr; +} + + + +#if !defined(HAVE_INLINE) +int ED_IsAbs (const ExprDesc* Expr) +/* Return true if the expression denotes a numeric value or address. */ +{ + return (Expr->Flags & (E_MASK_LOC)) == (E_LOC_NONE) || + (Expr->Flags & (E_MASK_LOC|E_ADDRESS_OF)) == (E_LOC_ABS|E_ADDRESS_OF); +} +#endif + + + +#if !defined(HAVE_INLINE) +int ED_IsConstAbs (const ExprDesc* Expr) +/* Return true if the expression denotes a constant absolute value. This can be +** a numeric constant, cast to any type. */ { - Expr->Sym = 0; - Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE | E_BITFIELD | E_NEED_TEST | E_CC_SET); - Expr->Flags |= (E_LOC_EXPR | E_RTYPE_LVAL); - Expr->Name = 0; - Expr->IVal = 0; /* No offset */ - Expr->FVal = FP_D_Make (0.0); - return Expr; + return ED_IsRVal (Expr) && ED_IsAbs (Expr); +} +#endif + + + +int ED_IsConstAbsInt (const ExprDesc* Expr) +/* Return true if the expression is a constant (numeric) integer. */ +{ + return ED_IsConstAbs (Expr) && IsClassInt (Expr->Type); } @@ -233,16 +354,27 @@ int ED_IsConst (const ExprDesc* Expr) ** similar. */ { - return ED_IsRVal (Expr) && (Expr->Flags & E_LOC_CONST) != 0; + return (Expr->Flags & E_MASK_LOC) == E_LOC_NONE || ED_IsConstAddr (Expr); } -int ED_IsConstAbsInt (const ExprDesc* Expr) -/* Return true if the expression is a constant (numeric) integer. */ +int ED_IsConstAddr (const ExprDesc* Expr) +/* Return true if the expression denotes a constant address of some sort. This +** can be the address of a global variable (maybe with offset) or similar. +*/ { - return (Expr->Flags & (E_MASK_LOC|E_MASK_RTYPE)) == (E_LOC_ABS|E_RTYPE_RVAL) && - IsClassInt (Expr->Type); + return ED_IsAddrExpr (Expr) && ED_IsLocConst (Expr); +} + + + +int ED_IsQuasiConstAddr (const ExprDesc* Expr) +/* Return true if the expression denotes a quasi-constant address of some sort. +** This can be a constant address or a stack variable address. +*/ +{ + return ED_IsAddrExpr (Expr) && ED_IsLocQuasiConst (Expr); } @@ -251,7 +383,7 @@ int ED_IsNullPtr (const ExprDesc* Expr) /* Return true if the given expression is a NULL pointer constant */ { return (Expr->Flags & (E_MASK_LOC|E_MASK_RTYPE|E_BITFIELD)) == - (E_LOC_ABS|E_RTYPE_RVAL) && + (E_LOC_NONE|E_RTYPE_RVAL) && Expr->IVal == 0 && IsClassInt (Expr->Type); } @@ -293,6 +425,11 @@ void PrintExprDesc (FILE* F, ExprDesc* E) Flags = E->Flags; Sep = '('; fprintf (F, "Flags: 0x%04X ", Flags); + if ((Flags & E_MASK_LOC) == E_LOC_NONE) { + fprintf (F, "%cE_LOC_NONE", Sep); + Flags &= ~E_LOC_NONE; + Sep = ','; + } if (Flags & E_LOC_ABS) { fprintf (F, "%cE_LOC_ABS", Sep); Flags &= ~E_LOC_ABS; @@ -353,6 +490,11 @@ void PrintExprDesc (FILE* F, ExprDesc* E) Flags &= ~E_CC_SET; Sep = ','; } + if (Flags & E_ADDRESS_OF) { + fprintf (F, "%cE_ADDRESS_OF", Sep); + Flags &= ~E_ADDRESS_OF; + Sep = ','; + } if (Flags) { fprintf (F, "%c,0x%04X", Sep, Flags); Sep = ','; diff --git a/src/cc65/exprdesc.h b/src/cc65/exprdesc.h index e86534902..a61c5d814 100644 --- a/src/cc65/exprdesc.h +++ b/src/cc65/exprdesc.h @@ -59,22 +59,57 @@ /* Defines for the flags field of the expression descriptor */ enum { - /* Location: Where is the value we're talking about? */ + /* Location: Where is the value we're talking about? + ** + ** Remarks: + ** - E_LOC_ refers to any other than E_LOC_NONE and E_LOC_PRIMARY. + ** - E_LOC_EXPR can be regarded as a generalized E_LOC_. + ** - E_LOC_NONE can be regarded as E_LOC_PRIMARY + E_ADDRESS_OF unless + ** remarked otherwise (see below). + ** - An E_LOC_NONE value is not considered to be an "address". + ** - ref-load doesn't change the location, while rval-load puts into the + ** primary register a "temporary" that is the straight integer rvalue or + ** a "delegate" to the real rvalue somewhere else. + ** - ref-load doesn't change the rval/lval category of the expression, + ** while rval-load converts it to an rvalue if it wasn't. + ** - In practice, ref-load is unimplemented, and can be simulated with + ** adding E_ADDRESS_OF temporaily through LoadExpr + FinalizeLoad, + ** whilst val-load is done with LoadExpr + FinalizeRValLoad. + ** + ** E_LOC_NONE -- ref-load -> + E_LOADED (int rvalue) + ** E_LOC_PRIMARY -- ref-load -> + E_LOADED (unchanged) + ** E_LOC_ -- ref-load -> + E_LOADED (reference lvalue) + ** + E_ADDRESS_OF -- ref-load -> + E_LOADED (address rvalue) + ** E_LOC_NONE -- val-load -> E_LOC_PRIMARY (int rvalue) + ** E_LOC_PRIMARY -- val-load -> E_LOC_PRIMARY (unchanged) + ** E_LOC_ -- val-load -> E_LOC_PRIMARY (rvalue/delegate) + ** + E_ADDRESS_OF -- val-load -> E_LOC_PRIMARY (address rvalue) + ** E_LOC_NONE -- take address -> (error) + ** E_LOC_PRIMARY -- take address -> + E_ADDRESS_OF (or error) + ** E_LOC_EXPR -- take address -> E_LOC_PRIMARY (address) + ** E_LOC_ -- take address -> + E_ADDRESS_OF (address) + ** + E_ADDRESS_OF -- take address -> (error) + ** E_LOC_NONE -- dereference -> E_LOC_ABS (lvalue reference) + ** E_LOC_PRIMARY -- dereference -> E_LOC_EXPR (lvalue reference) + ** E_LOC_ -- dereference -> E_LOC_EXPR (pointed-to-value, must load) + ** + E_ADDRESS_OF -- dereference -> (lvalue reference) + */ E_MASK_LOC = 0x00FF, - E_LOC_ABS = 0x0001, /* Absolute: numeric address or const */ + E_LOC_NONE = 0x0000, /* Pure rvalue with no storage */ + E_LOC_ABS = 0x0001, /* Absolute numeric addressed variable */ E_LOC_GLOBAL = 0x0002, /* Global variable */ E_LOC_STATIC = 0x0004, /* Static variable */ E_LOC_REGISTER = 0x0008, /* Register variable */ E_LOC_STACK = 0x0010, /* Value on the stack */ - E_LOC_PRIMARY = 0x0020, /* The primary register */ - E_LOC_EXPR = 0x0040, /* An expression in the primary register */ + E_LOC_PRIMARY = 0x0020, /* Temporary in primary register */ + E_LOC_EXPR = 0x0040, /* A location that the primary register points to */ E_LOC_LITERAL = 0x0080, /* Literal in the literal pool */ /* Constant location of some sort (only if rval) */ - E_LOC_CONST = E_LOC_ABS | E_LOC_GLOBAL | E_LOC_STATIC | + E_LOC_CONST = E_LOC_NONE | E_LOC_ABS | E_LOC_GLOBAL | E_LOC_STATIC | E_LOC_REGISTER | E_LOC_LITERAL, - /* Reference? */ + /* lvalue/rvalue in C language's sense */ E_MASK_RTYPE = 0x0100, E_RTYPE_RVAL = 0x0000, E_RTYPE_LVAL = 0x0100, @@ -88,6 +123,10 @@ enum { E_HAVE_MARKS = 0x1000, /* Code marks are valid */ + E_LOADED = 0x4000, /* Expression is loaded in primary */ + + E_ADDRESS_OF = 0x8000, /* Expression is the address of the lvalue */ + }; /* Forward */ @@ -135,8 +174,18 @@ INLINE int ED_GetLoc (const ExprDesc* Expr) #endif #if defined(HAVE_INLINE) -INLINE int ED_IsLocAbs (const ExprDesc* Expr) +INLINE int ED_IsLocNone (const ExprDesc* Expr) /* Return true if the expression is an absolute value */ +{ + return (Expr->Flags & E_MASK_LOC) == E_LOC_NONE; +} +#else +# define ED_IsLocNone(Expr) (((Expr)->Flags & E_MASK_LOC) == E_LOC_NONE) +#endif + +#if defined(HAVE_INLINE) +INLINE int ED_IsLocAbs (const ExprDesc* Expr) +/* Return true if the expression is referenced with an absolute address */ { return (Expr->Flags & E_MASK_LOC) == E_LOC_ABS; } @@ -151,7 +200,7 @@ INLINE int ED_IsLocRegister (const ExprDesc* Expr) return (Expr->Flags & E_MASK_LOC) == E_LOC_REGISTER; } #else -# define ED_IsLocRegister(Expr) (((Expr)->Flags & E_MASK_LOC) == E_LOC_REGISTER) +# define ED_IsLocRegister(Expr) (((Expr)->Flags & E_MASK_LOC) == E_LOC_REGISTER) #endif #if defined(HAVE_INLINE) @@ -198,50 +247,25 @@ INLINE int ED_IsLocLiteral (const ExprDesc* Expr) INLINE int ED_IsLocConst (const ExprDesc* Expr) /* Return true if the expression is a constant location of some sort */ { - return (Expr->Flags & E_LOC_CONST) != 0; + return ((Expr)->Flags & E_MASK_LOC & ~E_LOC_CONST) == 0; } #else -# define ED_IsLocConst(Expr) (((Expr)->Flags & E_LOC_CONST) != 0) +# define ED_IsLocConst(Expr) (((Expr)->Flags & E_MASK_LOC & ~E_LOC_CONST) == 0) #endif #if defined(HAVE_INLINE) -INLINE int ED_IsLVal (const ExprDesc* Expr) -/* Return true if the expression is a reference */ +INLINE int ED_IsLocQuasiConst (const ExprDesc* Expr) +/* Return true if the expression is a constant location of some sort or on the +** stack. +*/ { - return (Expr->Flags & E_MASK_RTYPE) == E_RTYPE_LVAL; + return ED_IsLocConst (Expr) || ED_IsLocStack (Expr); } #else -# define ED_IsLVal(Expr) (((Expr)->Flags & E_MASK_RTYPE) == E_RTYPE_LVAL) -#endif - -#if defined(HAVE_INLINE) -INLINE int ED_IsRVal (const ExprDesc* Expr) -/* Return true if the expression is a rvalue */ -{ - return (Expr->Flags & E_MASK_RTYPE) == E_RTYPE_RVAL; -} -#else -# define ED_IsRVal(Expr) (((Expr)->Flags & E_MASK_RTYPE) == E_RTYPE_RVAL) -#endif - -#if defined(HAVE_INLINE) -INLINE void ED_MakeLVal (ExprDesc* Expr) -/* Make the expression a lvalue. */ -{ - Expr->Flags |= E_RTYPE_LVAL; -} -#else -# define ED_MakeLVal(Expr) do { (Expr)->Flags |= E_RTYPE_LVAL; } while (0) -#endif - -#if defined(HAVE_INLINE) -INLINE void ED_MakeRVal (ExprDesc* Expr) -/* Make the expression a rvalue. */ -{ - Expr->Flags &= ~E_RTYPE_LVAL; -} -#else -# define ED_MakeRVal(Expr) do { (Expr)->Flags &= ~E_RTYPE_LVAL; } while (0) +int ED_IsLocQuasiConst (const ExprDesc* Expr); +/* Return true if the expression denotes a constant address of some sort. This +** can be the address of a global variable (maybe with offset) or similar. +*/ #endif #if defined(HAVE_INLINE) @@ -308,6 +332,52 @@ INLINE void ED_MarkAsUntested (ExprDesc* Expr) # define ED_MarkAsUntested(Expr) do { (Expr)->Flags &= ~E_CC_SET; } while (0) #endif +#if defined(HAVE_INLINE) +INLINE int ED_IsLoaded (const ExprDesc* Expr) +/* Check if the expression is loaded. +** NOTE: This is currently unused and not working due to code complexity. +*/ +{ + return (Expr->Flags & E_LOADED) != 0; +} +#else +# define ED_IsLoaded(Expr) (((Expr)->Flags & E_LOADED) != 0) +#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 */ +{ + return ED_IsLocPrimary (Expr) || ED_IsLocExpr (Expr); +} +#else +int ED_IsLocPrimaryOrExpr (const ExprDesc* Expr); +/* Return true if the expression is E_LOC_PRIMARY or E_LOC_EXPR */ +#endif + +#if defined(HAVE_INLINE) +INLINE int ED_IsAddrExpr (const ExprDesc* Expr) +/* Check if the expression is taken address of instead of its value. +*/ +{ + return (Expr->Flags & E_ADDRESS_OF) != 0; +} +#else +# define ED_IsAddrExpr(Expr) (((Expr)->Flags & E_ADDRESS_OF) != 0) +#endif + +#if defined(HAVE_INLINE) +INLINE int ED_IsIndExpr (const ExprDesc* Expr) +/* Check if the expression is a reference to its value */ +{ + return (Expr->Flags & E_ADDRESS_OF) == 0 && + !ED_IsLocNone (Expr) && !ED_IsLocPrimary (Expr); +} +#else +int ED_IsIndExpr (const ExprDesc* Expr); +/* Check if the expression is a reference to its value */ +#endif + void ED_SetCodeRange (ExprDesc* Expr, const CodeMark* Start, const CodeMark* End); /* Set the code range for this expression */ @@ -326,26 +396,79 @@ int ED_GetStackOffs (const ExprDesc* Expr, int Offs); */ ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, Type* Type); -/* Make Expr an absolute const with the given value and type. */ +/* Replace Expr with an absolute const with the given value and type */ ExprDesc* ED_MakeConstAbsInt (ExprDesc* Expr, long Value); -/* Make Expr a constant integer expression with the given value */ +/* Replace Expr with an constant integer with the given value */ -ExprDesc* ED_MakeRValExpr (ExprDesc* Expr); -/* Convert Expr into a rvalue which is in the primary register without an -** offset. -*/ +ExprDesc* ED_FinalizeRValLoad (ExprDesc* Expr); +/* Finalize the result of LoadExpr to be an rvalue in the primary register */ -ExprDesc* ED_MakeLValExpr (ExprDesc* Expr); -/* Convert Expr into a lvalue which is in the primary register without an -** offset. -*/ +#if defined(HAVE_INLINE) +INLINE int ED_IsLVal (const ExprDesc* Expr) +/* Return true if the expression is a reference */ +{ + return ((Expr)->Flags & E_MASK_RTYPE) == E_RTYPE_LVAL; +} +#else +# define ED_IsLVal(Expr) (((Expr)->Flags & E_MASK_RTYPE) == E_RTYPE_LVAL) +#endif -int ED_IsConst (const ExprDesc* Expr); -/* Return true if the expression denotes a constant of some sort. This can be a -** numeric constant, the address of a global variable (maybe with offset) or -** similar. +#if defined(HAVE_INLINE) +INLINE int ED_IsRVal (const ExprDesc* Expr) +/* Return true if the expression is an rvalue */ +{ + return ((Expr)->Flags & E_MASK_RTYPE) == E_RTYPE_RVAL; +} +#else +# define ED_IsRVal(Expr) (((Expr)->Flags & E_MASK_RTYPE) == E_RTYPE_RVAL) +#endif + +#if defined(HAVE_INLINE) +INLINE void ED_MarkExprAsLVal (ExprDesc* Expr) +/* Mark the expression as an lvalue. +** HINT: Consider using ED_IndExpr instead of this, unless you know what +** consequence there will be, as there are both a big part in the code +** assuming rvalue = const and a big part assuming rvalue = address. */ +{ + Expr->Flags |= E_RTYPE_LVAL; +} +#else +# define ED_MarkExprAsLVal(Expr) do { (Expr)->Flags |= E_RTYPE_LVAL; } while (0) +#endif + +#if defined(HAVE_INLINE) +INLINE void ED_MarkExprAsRVal (ExprDesc* Expr) +/* Mark the expression as an rvalue. +** HINT: Consider using ED_AddrExpr instead of this, unless you know what +** consequence there will be, as there are both a big part in the code +** assuming rvalue = const and a big part assuming rvalue = address. +*/ +{ + Expr->Flags &= ~E_RTYPE_LVAL; +} +#else +# define ED_MarkExprAsRVal(Expr) do { (Expr)->Flags &= ~E_RTYPE_LVAL; } while (0) +#endif + +ExprDesc* ED_AddrExpr (ExprDesc* Expr); +/* Take address of Expr */ + +ExprDesc* ED_IndExpr (ExprDesc* Expr); +/* Dereference Expr */ + +#if defined(HAVE_INLINE) +INLINE int ED_IsAbs (const ExprDesc* Expr) +/* Return true if the expression denotes a numeric value or address. */ +{ + return (Expr->Flags & (E_MASK_LOC)) == (E_LOC_NONE) || + (Expr->Flags & (E_MASK_LOC|E_ADDRESS_OF)) == (E_LOC_ABS|E_ADDRESS_OF); +} +#else +int ED_IsAbs (const ExprDesc* Expr); +/* Return true if the expression denotes a numeric value or address. */ +#endif #if defined(HAVE_INLINE) INLINE int ED_IsConstAbs (const ExprDesc* Expr) @@ -353,16 +476,34 @@ INLINE int ED_IsConstAbs (const ExprDesc* Expr) ** a numeric constant, cast to any type. */ { - return (Expr->Flags & (E_MASK_LOC|E_MASK_RTYPE)) == (E_LOC_ABS|E_RTYPE_RVAL); + return ED_IsRVal (Expr) && ED_IsAbs (Expr); } #else -# define ED_IsConstAbs(E) \ - (((E)->Flags & (E_MASK_LOC|E_MASK_RTYPE)) == (E_LOC_ABS|E_RTYPE_RVAL)) +int ED_IsConstAbs (const ExprDesc* Expr); +/* Return true if the expression denotes a constant absolute value. This can be +** a numeric constant, cast to any type. +*/ #endif int ED_IsConstAbsInt (const ExprDesc* Expr); /* Return true if the expression is a constant (numeric) integer. */ +int ED_IsConst (const ExprDesc* Expr); +/* Return true if the expression denotes a constant of some sort. This can be a +** numeric constant, the address of a global variable (maybe with offset) or +** similar. +*/ + +int ED_IsConstAddr (const ExprDesc* Expr); +/* Return true if the expression denotes a constant address of some sort. This +** can be the address of a global variable (maybe with offset) or similar. +*/ + +int ED_IsQuasiConstAddr (const ExprDesc* Expr); +/* Return true if the expression denotes a quasi-constant address of some sort. +** This can be a constant address or a stack variable address. +*/ + int ED_IsNullPtr (const ExprDesc* Expr); /* Return true if the given expression is a NULL pointer constant */ diff --git a/src/cc65/loadexpr.c b/src/cc65/loadexpr.c index fa37c6bbd..7eef174e2 100644 --- a/src/cc65/loadexpr.c +++ b/src/cc65/loadexpr.c @@ -48,14 +48,14 @@ -static void LoadConstant (unsigned Flags, ExprDesc* Expr) -/* Load the primary register with some constant value. */ +static void LoadAddress (unsigned Flags, ExprDesc* Expr) +/* Load the primary register with some address value. */ { switch (ED_GetLoc (Expr)) { case E_LOC_ABS: - /* Number constant */ - g_getimmed (Flags | TypeOf (Expr->Type) | CF_CONST, Expr->IVal, 0); + /* Numberic address */ + g_getimmed (Flags | CF_IMM | CF_CONST, Expr->IVal, 0); break; case E_LOC_GLOBAL: @@ -83,25 +83,38 @@ static void LoadConstant (unsigned Flags, ExprDesc* Expr) g_leasp (Expr->IVal); break; + case E_LOC_EXPR: + if (Expr->IVal != 0) { + /* We have an expression in the primary plus a constant + ** offset. Adjust the value in the primary accordingly. + */ + g_inc (Flags | CF_CONST, Expr->IVal); + } + break; + default: - Internal ("Unknown constant type: %04X", Expr->Flags); + Internal ("Unknown address type: %04X", Expr->Flags); } } void LoadExpr (unsigned Flags, struct ExprDesc* Expr) -/* Load an expression into the primary register if it is not already there. */ +/* Load an expression into the primary register if it is not already there. +** Note: This function can't modify the content in Expr since there are many +** instances of the "GetCodePos + LoadExpr (maybe indirectly) + RemoveCode" +** code pattern here and there which assumes that Expr should be unchanged, +** unfortunately. +*/ { - if (ED_IsLVal (Expr)) { + if (!ED_IsAddrExpr (Expr)) { - /* Dereferenced lvalue. If this is a bit field its type is unsigned. - ** But if the field is completely contained in the lower byte, we will - ** throw away the high byte anyway and may therefore load just the - ** low byte. + /* Lvalue. If this is a bit field its type is unsigned. But if the + ** field is completely contained in the lower byte, we will throw away + ** the high byte anyway and may therefore load just the low byte. */ if (ED_IsBitField (Expr)) { - Flags |= (Expr->BitOffs + Expr->BitWidth <= CHAR_BITS)? CF_CHAR : CF_INT; + Flags |= (Expr->BitOffs + Expr->BitWidth <= CHAR_BITS) ? CF_CHAR : CF_INT; Flags |= CF_UNSIGNED; } else { Flags |= TypeOf (Expr->Type); @@ -110,10 +123,16 @@ void LoadExpr (unsigned Flags, struct ExprDesc* Expr) Flags |= CF_TEST; } + /* Load the content of Expr */ switch (ED_GetLoc (Expr)) { + case E_LOC_NONE: + /* Immediate number constant */ + g_getimmed (Flags | CF_IMM | TypeOf (Expr->Type) | CF_CONST, Expr->IVal, 0); + break; + case E_LOC_ABS: - /* Absolute: numeric address or const */ + /* Absolute numeric addressed variable */ g_getstatic (Flags | CF_ABSOLUTE, Expr->IVal, 0); break; @@ -139,7 +158,15 @@ void LoadExpr (unsigned Flags, struct ExprDesc* Expr) break; case E_LOC_PRIMARY: - /* The primary register - just test if necessary */ + /* The primary register */ + if (Expr->IVal != 0) { + /* We have an expression in the primary plus a constant + ** offset. Adjust the value in the primary accordingly. + */ + g_inc (Flags | CF_CONST, Expr->IVal); + + /* We might want to clear the offset, but we can't */ + } if (Flags & CF_TEST) { g_test (Flags); } @@ -148,6 +175,13 @@ void LoadExpr (unsigned Flags, struct ExprDesc* Expr) case E_LOC_EXPR: /* Reference to address in primary with offset in Expr */ g_getind (Flags, Expr->IVal); + + /* Since the content in primary is now overwritten with the + ** dereference value, we might want to change the expression + ** loc to E_LOC_PRIMARY as well. That way we could be able to + ** call this function as many times as we want. Unfortunately, + ** we can't. + */ break; default: @@ -173,24 +207,14 @@ void LoadExpr (unsigned Flags, struct ExprDesc* Expr) ED_TestDone (Expr); } else { - /* An rvalue */ - if (ED_IsLocExpr (Expr)) { - if (Expr->IVal != 0) { - /* We have an expression in the primary plus a constant - ** offset. Adjust the value in the primary accordingly. - */ - Flags |= TypeOf (Expr->Type); - g_inc (Flags | CF_CONST, Expr->IVal); - } - } else { - /* Constant of some sort, load it into the primary */ - LoadConstant (Flags, Expr); - } + /* An address */ + Flags |= CF_INT | CF_UNSIGNED; + /* Constant of some sort, load it into the primary */ + LoadAddress (Flags, Expr); /* Are we testing this value? */ if (ED_NeedsTest (Expr)) { /* Yes, force a test */ - Flags |= TypeOf (Expr->Type); g_test (Flags); ED_TestDone (Expr); } diff --git a/src/cc65/locals.c b/src/cc65/locals.c index d0aab7f9c..9f8ee86ef 100644 --- a/src/cc65/locals.c +++ b/src/cc65/locals.c @@ -260,7 +260,7 @@ static void ParseAutoDecl (Declaration* Decl) Flags |= CF_CONST; } else { LoadExpr (CF_NONE, &Expr); - ED_MakeRVal (&Expr); + ED_MarkExprAsRVal (&Expr); } /* Push the value */ diff --git a/src/cc65/shiftexpr.c b/src/cc65/shiftexpr.c index c61514f43..c7aea5255 100644 --- a/src/cc65/shiftexpr.c +++ b/src/cc65/shiftexpr.c @@ -173,8 +173,8 @@ void ShiftExpr (struct ExprDesc* Expr) goto Next; } - /* If we're shifting an integer or unsigned to the right, the - ** lhs has a const address, and the shift count is larger than 8, + /* If we're shifting an integer or unsigned to the right, the lhs + ** has a quasi-const address, and the shift count is larger than 8, ** we can load just the high byte as a char with the correct ** signedness, and reduce the shift count by 8. If the remaining ** shift count is zero, we're done. @@ -182,7 +182,7 @@ void ShiftExpr (struct ExprDesc* Expr) if (Tok == TOK_SHR && IsTypeInt (Expr->Type) && ED_IsLVal (Expr) && - (ED_IsLocConst (Expr) || ED_IsLocStack (Expr)) && + ED_IsLocQuasiConst (Expr) && Expr2.IVal >= 8) { Type* OldType; @@ -227,8 +227,8 @@ void ShiftExpr (struct ExprDesc* Expr) } MakeRVal: - /* We have a rvalue in the primary now */ - ED_MakeRValExpr (Expr); + /* We have an rvalue in the primary now */ + ED_FinalizeRValLoad (Expr); Next: /* Set the type of the result */ diff --git a/src/cc65/stdfunc.c b/src/cc65/stdfunc.c index 2d4317ef8..6d61f2750 100644 --- a/src/cc65/stdfunc.c +++ b/src/cc65/stdfunc.c @@ -343,7 +343,7 @@ static void StdFunc_memcpy (FuncDesc* F attribute ((unused)), ExprDesc* Expr) ** address calculation could overflow in the linker. */ int AllowOneIndex = !ED_IsLocRegister (&Arg2.Expr) && - !(ED_IsLocAbs (&Arg2.Expr) && Arg2.Expr.IVal < 256); + !(ED_IsLocNone (&Arg2.Expr) && Arg2.Expr.IVal < 256); /* Calculate the real stack offset */ Offs = ED_GetStackOffs (&Arg1.Expr, 0); @@ -421,7 +421,7 @@ static void StdFunc_memcpy (FuncDesc* F attribute ((unused)), ExprDesc* Expr) ** address calculation could overflow in the linker. */ int AllowOneIndex = !ED_IsLocRegister (&Arg1.Expr) && - !(ED_IsLocAbs (&Arg1.Expr) && Arg1.Expr.IVal < 256); + !(ED_IsLocNone (&Arg1.Expr) && Arg1.Expr.IVal < 256); /* Calculate the real stack offset */ Offs = ED_GetStackOffs (&Arg2.Expr, 0); @@ -520,7 +520,7 @@ static void StdFunc_memcpy (FuncDesc* F attribute ((unused)), ExprDesc* Expr) AddCodeLine ("lda ptr1"); /* The function result is an rvalue in the primary register */ - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); Expr->Type = GetFuncReturn (Expr->Type); /* Bail out, no need for further processing */ @@ -529,7 +529,7 @@ static void StdFunc_memcpy (FuncDesc* F attribute ((unused)), ExprDesc* Expr) } /* The function result is an rvalue in the primary register */ - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); Expr->Type = GetFuncReturn (Expr->Type); ExitPoint: @@ -743,7 +743,7 @@ static void StdFunc_memset (FuncDesc* F attribute ((unused)), ExprDesc* Expr) AddCodeLine ("lda ptr1"); /* The function result is an rvalue in the primary register */ - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); Expr->Type = GetFuncReturn (Expr->Type); /* Bail out, no need for further processing */ @@ -752,7 +752,7 @@ static void StdFunc_memset (FuncDesc* F attribute ((unused)), ExprDesc* Expr) } /* The function result is an rvalue in the primary register */ - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); Expr->Type = GetFuncReturn (Expr->Type); ExitPoint: @@ -955,7 +955,7 @@ static void StdFunc_strcmp (FuncDesc* F attribute ((unused)), ExprDesc* Expr) } /* The function result is an rvalue in the primary register */ - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); Expr->Type = GetFuncReturn (Expr->Type); /* We expect the closing brace */ @@ -1069,7 +1069,7 @@ static void StdFunc_strcpy (FuncDesc* F attribute ((unused)), ExprDesc* Expr) ** address calculation could overflow in the linker. */ int AllowOneIndex = !ED_IsLocRegister (&Arg1.Expr) && - !(ED_IsLocAbs (&Arg1.Expr) && Arg1.Expr.IVal < 256); + !(ED_IsLocNone (&Arg1.Expr) && Arg1.Expr.IVal < 256); /* Calculate the real stack offset */ int Offs = ED_GetStackOffs (&Arg2.Expr, 0); @@ -1116,7 +1116,7 @@ static void StdFunc_strcpy (FuncDesc* F attribute ((unused)), ExprDesc* Expr) ** address calculation could overflow in the linker. */ int AllowOneIndex = !ED_IsLocRegister (&Arg2.Expr) && - !(ED_IsLocAbs (&Arg2.Expr) && Arg2.Expr.IVal < 256); + !(ED_IsLocNone (&Arg2.Expr) && Arg2.Expr.IVal < 256); /* Calculate the real stack offset */ int Offs = ED_GetStackOffs (&Arg1.Expr, 0); @@ -1153,7 +1153,7 @@ static void StdFunc_strcpy (FuncDesc* F attribute ((unused)), ExprDesc* Expr) } /* The function result is an rvalue in the primary register */ - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); Expr->Type = GetFuncReturn (Expr->Type); ExitPoint: @@ -1250,7 +1250,7 @@ static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr) AddCodeLine ("tya"); /* The function result is an rvalue in the primary register */ - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); Expr->Type = type_size_t; /* Bail out, no need for further processing */ @@ -1279,7 +1279,7 @@ static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr) AddCodeLine ("ldx #$00"); /* The function result is an rvalue in the primary register */ - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); Expr->Type = type_size_t; /* Bail out, no need for further processing */ @@ -1304,7 +1304,7 @@ static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr) AddCodeLine ("tya"); /* The function result is an rvalue in the primary register */ - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); Expr->Type = type_size_t; /* Bail out, no need for further processing */ @@ -1333,7 +1333,7 @@ static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr) AddCodeLine ("tya"); /* The function result is an rvalue in the primary register */ - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); Expr->Type = type_size_t; /* Bail out, no need for further processing */ @@ -1348,7 +1348,7 @@ static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr) AddCodeLine ("jsr _%s", Func_strlen); /* The function result is an rvalue in the primary register */ - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); Expr->Type = type_size_t; ExitPoint: diff --git a/src/cc65/typeconv.c b/src/cc65/typeconv.c index 21ad33f12..e8d581f54 100644 --- a/src/cc65/typeconv.c +++ b/src/cc65/typeconv.c @@ -70,7 +70,7 @@ static void DoConversion (ExprDesc* Expr, const Type* NewType) ** conversion void -> void. */ if (IsTypeVoid (NewType)) { - ED_MakeRVal (Expr); /* Never an lvalue */ + ED_MarkExprAsRVal (Expr); /* Never an lvalue */ goto ExitPoint; } @@ -105,10 +105,10 @@ static void DoConversion (ExprDesc* Expr, const Type* NewType) g_typecast (TypeOf (NewType), TypeOf (OldType) | CF_FORCECHAR); /* Value is now in primary and an rvalue */ - ED_MakeRValExpr (Expr); + ED_FinalizeRValLoad (Expr); } - } else if (ED_IsLocAbs (Expr)) { + } else if (ED_IsConstAbs (Expr)) { /* A cast of a constant numeric value to another type. Be sure ** to handle sign extension correctly. @@ -136,6 +136,15 @@ static void DoConversion (ExprDesc* Expr, const Type* NewType) } } + /* Do the integer constant <-> absolute address conversion if necessary */ + if (IsClassPtr (NewType)) { + Expr->Flags &= ~E_LOC_NONE; + Expr->Flags |= E_LOC_ABS | E_ADDRESS_OF; + } else if (IsClassInt (NewType)) { + Expr->Flags &= ~(E_LOC_ABS | E_ADDRESS_OF); + Expr->Flags |= E_LOC_NONE; + } + } else { /* The value is not a constant. If the sizes of the types are @@ -150,8 +159,8 @@ static void DoConversion (ExprDesc* Expr, const Type* NewType) /* Emit typecast code. */ g_typecast (TypeOf (NewType), TypeOf (OldType) | CF_FORCECHAR); - /* Value is now a rvalue in the primary */ - ED_MakeRValExpr (Expr); + /* Value is now an rvalue in the primary */ + ED_FinalizeRValLoad (Expr); } }