/* */
/* */
/* */
-/* (C) 2002-2004 Ullrich von Bassewitz */
-/* Römerstraße 52 */
-/* D-70794 Filderstadt */
-/* EMail: uz@cc65.org */
+/* (C) 2002-2010, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
#include <string.h>
/* common */
+#include "fp.h"
#include "inline.h"
/* cc65 */
+#include "asmcode.h"
#include "datatype.h"
/* Defines for the flags field of the expression descriptor */
-#define E_MREG 0x0110U /* Special: Expression is primary register */
-#define E_MGLOBAL 0x0080U /* Reference to static variable */
-#define E_MLOCAL 0x0040U /* Reference to local variable (stack offset) */
-#define E_MCONST 0x0020U /* Constant value */
-#define E_MEXPR 0x0010U /* Result is in primary register */
-#define E_MEOFFS 0x0011U /* Base is in primary register, const offset */
-
-#define E_MCTYPE 0x0007U /* Type of a constant */
-#define E_TCONST 0x0000U /* Constant */
-#define E_TGLAB 0x0001U /* Global label */
-#define E_TLIT 0x0002U /* Literal of some kind */
-#define E_TLOFFS 0x0003U /* Constant stack offset */
-#define E_TLLAB 0x0004U /* Local label */
-#define E_TREGISTER 0x0005U /* Register variable */
-
-#define E_RVAL 0x0000U /* Expression node is a value */
-#define E_LVAL 0x1000U /* Expression node is a reference */
-
-/* Defines for the test field of the expression descriptor */
-#define E_CC 0x0001U /* expr has set cond codes apropos result value */
-#define E_FORCETEST 0x0002U /* if expr has NOT set CC, force a test */
+enum {
+ /* Location: Where is the value we're talking about? */
+ E_MASK_LOC = 0x00FF,
+ E_LOC_ABS = 0x0001, /* Absolute: numeric address or const */
+ 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_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_REGISTER | E_LOC_LITERAL,
+
+ /* Reference? */
+ E_MASK_RTYPE = 0x0100,
+ E_RTYPE_RVAL = 0x0000,
+ E_RTYPE_LVAL = 0x0100,
+
+ /* Bit-field? */
+ E_BITFIELD = 0x0200,
+
+ /* Test */
+ E_NEED_TEST = 0x0400, /* Expression needs a test to set cc */
+ E_CC_SET = 0x0800, /* Condition codes are set */
+
+ E_HAVE_MARKS = 0x1000, /* Code marks are valid */
+
+};
+
+/* Forward */
+struct Literal;
/* Describe the result of an expression */
typedef struct ExprDesc ExprDesc;
struct ExprDesc {
- struct SymEntry* Sym; /* Symbol table entry if known */
- type* Type; /* Type array of expression */
- long ConstVal;/* Value if expression constant */
- unsigned short Flags;
- unsigned short Test; /* */
- unsigned long Name; /* Name or label number */
+ struct SymEntry* Sym; /* Symbol table entry if known */
+ Type* Type; /* Type array of expression */
+ unsigned Flags;
+ unsigned long Name; /* Name or label number */
+ long IVal; /* Integer value if expression constant */
+ Double FVal; /* Floating point value */
+ struct Literal* LVal; /* Literal value */
+
+ /* Bit field stuff */
+ unsigned BitOffs; /* Bit offset for bit fields */
+ unsigned BitWidth; /* Bit width for bit fields */
+
+ /* Start and end of generated code */
+ CodeMark Start;
+ CodeMark End;
};
/*****************************************************************************/
-/* Code */
+/* Code */
/*****************************************************************************/
-#if defined(HAVE_INLINE)
-INLINE ExprDesc* InitExprDesc (ExprDesc* Expr)
+ExprDesc* ED_Init (ExprDesc* Expr);
/* Initialize an ExprDesc */
+
+#if defined(HAVE_INLINE)
+INLINE int ED_GetLoc (const ExprDesc* Expr)
+/* Return the location flags from the expression */
+{
+ return (Expr->Flags & E_MASK_LOC);
+}
+#else
+# define ED_GetLoc(Expr) ((Expr)->Flags & E_MASK_LOC)
+#endif
+
+#if defined(HAVE_INLINE)
+INLINE int ED_IsLocAbs (const ExprDesc* Expr)
+/* Return true if the expression is an absolute value */
+{
+ return (Expr->Flags & E_MASK_LOC) == E_LOC_ABS;
+}
+#else
+# define ED_IsLocAbs(Expr) (((Expr)->Flags & E_MASK_LOC) == E_LOC_ABS)
+#endif
+
+#if defined(HAVE_INLINE)
+INLINE int ED_IsLocRegister (const ExprDesc* Expr)
+/* Return true if the expression is located in a register */
+{
+ return (Expr->Flags & E_MASK_LOC) == E_LOC_REGISTER;
+}
+#else
+# define ED_IsLocRegister(Expr) (((Expr)->Flags & E_MASK_LOC) == E_LOC_REGISTER)
+#endif
+
+#if defined(HAVE_INLINE)
+INLINE int ED_IsLocStack (const ExprDesc* Expr)
+/* Return true if the expression is located on the stack */
{
- return memset (Expr, 0, sizeof (*Expr));
+ return (Expr->Flags & E_MASK_LOC) == E_LOC_STACK;
}
#else
-# define InitExprDesc(E) memset ((E), 0, sizeof (*(E)))
+# define ED_IsLocStack(Expr) (((Expr)->Flags & E_MASK_LOC) == E_LOC_STACK)
+#endif
+
+#if defined(HAVE_INLINE)
+INLINE int ED_IsLocPrimary (const ExprDesc* Expr)
+/* Return true if the expression is an expression in the register pseudo variable */
+{
+ return (Expr->Flags & E_MASK_LOC) == E_LOC_PRIMARY;
+}
+#else
+# define ED_IsLocPrimary(Expr) (((Expr)->Flags & E_MASK_LOC) == E_LOC_PRIMARY)
+#endif
+
+#if defined(HAVE_INLINE)
+INLINE int ED_IsLocExpr (const ExprDesc* Expr)
+/* Return true if the expression is an expression in the primary */
+{
+ return (Expr->Flags & E_MASK_LOC) == E_LOC_EXPR;
+}
+#else
+# define ED_IsLocExpr(Expr) (((Expr)->Flags & E_MASK_LOC) == E_LOC_EXPR)
+#endif
+
+#if defined(HAVE_INLINE)
+INLINE int ED_IsLocLiteral (const ExprDesc* Expr)
+/* Return true if the expression is a string from the literal pool */
+{
+ return (Expr->Flags & E_MASK_LOC) == E_LOC_LITERAL;
+}
+#else
+# define ED_IsLocLiteral(Expr) (((Expr)->Flags & E_MASK_LOC) == E_LOC_LITERAL)
+#endif
+
+#if defined(HAVE_INLINE)
+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;
+}
+#else
+# define ED_IsLocConst(Expr) (((Expr)->Flags & E_LOC_CONST) != 0)
#endif
#if defined(HAVE_INLINE)
INLINE int ED_IsLVal (const ExprDesc* Expr)
/* Return true if the expression is a reference */
{
- return (Expr->Flags & E_LVAL) != 0;
+ return (Expr->Flags & E_MASK_RTYPE) == E_RTYPE_LVAL;
}
#else
-# define ED_IsLVal(Expr) (((Expr)->Flags & E_LVAL) != 0)
+# 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_LVAL) == 0;
+ return (Expr->Flags & E_MASK_RTYPE) == E_RTYPE_RVAL;
}
#else
-# define ED_IsRVal(Expr) (((Expr)->Flags & E_LVAL) == 0)
+# define ED_IsRVal(Expr) (((Expr)->Flags & E_MASK_RTYPE) == E_RTYPE_RVAL)
#endif
#if defined(HAVE_INLINE)
-INLINE int ED_SetValType (ExprDesc* Expr, int Ref)
-/* Set the reference flag for an expression and return it (the flag) */
+INLINE void ED_MakeLVal (ExprDesc* Expr)
+/* Make the expression a lvalue. */
{
- Expr->Flags = Ref? (Expr->Flags | E_LVAL) : (Expr->Flags & ~E_LVAL);
- return Ref;
+ Expr->Flags |= E_RTYPE_LVAL;
}
#else
-/* Beware: Just one occurance of R below, since it may have side effects! */
-# define ED_SetValType(E, R) \
- (((E)->Flags = (R)? ((E)->Flags | E_LVAL) : ((E)->Flags & ~E_LVAL)), \
- ED_IsLVal (E))
+# define ED_MakeLVal(Expr) do { (Expr)->Flags |= E_RTYPE_LVAL; } while (0)
#endif
#if defined(HAVE_INLINE)
-INLINE int ED_MakeLVal (ExprDesc* Expr)
-/* Make the expression a lvalue and return true */
+INLINE void ED_MakeRVal (ExprDesc* Expr)
+/* Make the expression a rvalue. */
{
- return ED_SetValType (Expr, 1);
+ Expr->Flags &= ~E_RTYPE_LVAL;
}
#else
-# define ED_MakeLVal(Expr) ED_SetValType (Expr, 1)
+# define ED_MakeRVal(Expr) do { (Expr)->Flags &= ~E_RTYPE_LVAL; } while (0)
#endif
#if defined(HAVE_INLINE)
-INLINE int ED_MakeRVal (ExprDesc* Expr)
-/* Make the expression a rvalue and return false */
+INLINE int ED_IsBitField (const ExprDesc* Expr)
+/* Return true if the expression is a bit field */
{
- return ED_SetValType (Expr, 0);
+ return (Expr->Flags & E_BITFIELD) != 0;
}
#else
-# define ED_MakeRVal(Expr) ED_SetValType (Expr, 0)
+# define ED_IsBitField(Expr) (((Expr)->Flags & E_BITFIELD) != 0)
#endif
-ExprDesc* ED_MakeConstInt (ExprDesc* Expr, long Value);
+void ED_MakeBitField (ExprDesc* Expr, unsigned BitOffs, unsigned BitWidth);
+/* Make this expression a bit field expression */
+
+#if defined(HAVE_INLINE)
+INLINE void ED_MarkForTest (ExprDesc* Expr)
+/* Mark the expression for a test. */
+{
+ Expr->Flags |= E_NEED_TEST;
+}
+#else
+# define ED_MarkForTest(Expr) do { (Expr)->Flags |= E_NEED_TEST; } while (0)
+#endif
+
+#if defined(HAVE_INLINE)
+INLINE int ED_NeedsTest (const ExprDesc* Expr)
+/* Check if the expression needs a test. */
+{
+ return (Expr->Flags & E_NEED_TEST) != 0;
+}
+#else
+# define ED_NeedsTest(Expr) (((Expr)->Flags & E_NEED_TEST) != 0)
+#endif
+
+#if defined(HAVE_INLINE)
+INLINE void ED_TestDone (ExprDesc* Expr)
+/* Mark the expression as tested and condition codes set. */
+{
+ Expr->Flags = (Expr->Flags & ~E_NEED_TEST) | E_CC_SET;
+}
+#else
+# define ED_TestDone(Expr) \
+ do { (Expr)->Flags = ((Expr)->Flags & ~E_NEED_TEST) | E_CC_SET; } while (0)
+#endif
+
+#if defined(HAVE_INLINE)
+INLINE int ED_IsTested (const ExprDesc* Expr)
+/* Check if the expression has set the condition codes. */
+{
+ return (Expr->Flags & E_CC_SET) != 0;
+}
+#else
+# define ED_IsTested(Expr) (((Expr)->Flags & E_CC_SET) != 0)
+#endif
+
+#if defined(HAVE_INLINE)
+INLINE void ED_MarkAsUntested (ExprDesc* Expr)
+/* Mark the expression as not tested (condition codes not set). */
+{
+ Expr->Flags &= ~E_CC_SET;
+}
+#else
+# define ED_MarkAsUntested(Expr) do { (Expr)->Flags &= ~E_CC_SET; } while (0)
+#endif
+
+void ED_SetCodeRange (ExprDesc* Expr, const CodeMark* Start, const CodeMark* End);
+/* Set the code range for this expression */
+
+int ED_CodeRangeIsEmpty (const ExprDesc* Expr);
+/* Return true if no code was output for this expression */
+
+const char* ED_GetLabelName (const ExprDesc* Expr, long Offs);
+/* Return the assembler label name of the given expression. Beware: This
+ * function may use a static buffer, so the name may get "lost" on the second
+ * call to the function.
+ */
+
+int ED_GetStackOffs (const ExprDesc* Expr, int Offs);
+/* Get the stack offset of an address on the stack in Expr taking into account
+ * an additional offset in Offs.
+ */
+
+ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, Type* Type);
+/* Make Expr 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 */
+ExprDesc* ED_MakeRValExpr (ExprDesc* Expr);
+/* Convert Expr into a rvalue which is in the primary register without an
+ * offset.
+ */
+
+ExprDesc* ED_MakeLValExpr (ExprDesc* Expr);
+/* Convert Expr into a lvalue which is in the primary register without an
+ * offset.
+ */
+
+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_IsConstAbs (const ExprDesc* Expr)
+/* Return true if the expression denotes a constant absolute value. This can be
+ * a numeric constant, cast to any type.
+ */
+{
+ return (Expr->Flags & (E_MASK_LOC|E_MASK_RTYPE)) == (E_LOC_ABS|E_RTYPE_RVAL);
+}
+#else
+# define ED_IsConstAbs(E) \
+ (((E)->Flags & (E_MASK_LOC|E_MASK_RTYPE)) == (E_LOC_ABS|E_RTYPE_RVAL))
+#endif
+
+int ED_IsConstAbsInt (const ExprDesc* Expr);
+/* Return true if the expression is a constant (numeric) integer. */
+
+int ED_IsNullPtr (const ExprDesc* Expr);
+/* Return true if the given expression is a NULL pointer constant */
+
+int ED_IsBool (const ExprDesc* Expr);
+/* Return true of the expression can be treated as a boolean, that is, it can
+ * be an operand to a compare operation.
+ */
+
void PrintExprDesc (FILE* F, ExprDesc* Expr);
/* Print an ExprDesc */
-type* ReplaceType (ExprDesc* Expr, const type* NewType);
+Type* ReplaceType (ExprDesc* Expr, const Type* NewType);
/* Replace the type of Expr by a copy of Newtype and return the old type string */