]> git.sur5r.net Git - cc65/blobdiff - src/cc65/expr.c
Add fast path for char postdec
[cc65] / src / cc65 / expr.c
index d615993c42b3ddd7bd216309d97a71ef5da02584..e5c1a17b91b5b0cef39448c040eb98cbf58e295e 100644 (file)
@@ -1,7 +1,7 @@
 /* expr.c
 **
 ** 1998-06-21, Ullrich von Bassewitz
-** 2015-04-19, Greg King
+** 2015-06-26, Greg King
 */
 
 
@@ -50,6 +50,7 @@
 /* Generator attributes */
 #define GEN_NOPUSH      0x01            /* Don't push lhs */
 #define GEN_COMM        0x02            /* Operator is commutative */
+#define GEN_NOFUNC      0x04            /* Not allowed for function pointers */
 
 /* Map a generator function and its attributes to a token */
 typedef struct {
@@ -1533,25 +1534,34 @@ static void PostInc (ExprDesc* Expr)
     /* Get the data type */
     Flags = TypeOf (Expr->Type);
 
-    /* Push the address if needed */
-    PushAddr (Expr);
+    /* Fast path: char */
+    if ((Flags & CF_CHAR) == CF_CHAR && ED_GetLoc(Expr) & (E_LOC_GLOBAL | E_LOC_STATIC)) {
 
-    /* Fetch the value and save it (since it's the result of the expression) */
-    LoadExpr (CF_NONE, Expr);
-    g_save (Flags | CF_FORCECHAR);
+        LoadExpr (CF_NONE, Expr);
+        AddCodeLine ("inc %s", ED_GetLabelName(Expr, 0));
 
-    /* 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);
+        /* 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);
+
+        /* 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);
+        }
 
-    /* Restore the original value in the primary register */
-    g_restore (Flags | CF_FORCECHAR);
+        /* 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 */
     ED_MakeRValExpr (Expr);
@@ -1580,25 +1590,34 @@ static void PostDec (ExprDesc* Expr)
     /* Get the data type */
     Flags = TypeOf (Expr->Type);
 
-    /* Push the address if needed */
-    PushAddr (Expr);
+    /* Fast path: char */
+    if ((Flags & CF_CHAR) == CF_CHAR && ED_GetLoc(Expr) & (E_LOC_GLOBAL | E_LOC_STATIC)) {
 
-    /* Fetch the value and save it (since it's the result of the expression) */
-    LoadExpr (CF_NONE, Expr);
-    g_save (Flags | CF_FORCECHAR);
+        LoadExpr (CF_NONE, Expr);
+        AddCodeLine ("dec %s", ED_GetLabelName(Expr, 0));
 
-    /* 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);
+        /* 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);
+
+        /* 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);
+        }
 
-    /* Restore the original value in the primary register */
-    g_restore (Flags | CF_FORCECHAR);
+        /* 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 */
     ED_MakeRValExpr (Expr);
@@ -1713,8 +1732,13 @@ void hie10 (ExprDesc* Expr)
                 } else {
                     Error ("Illegal indirection");
                 }
-                /* The * operator yields an lvalue */
-                ED_MakeLVal (Expr);
+                /* If the expression points to an array, then don't convert the
+                ** address -- it already is the location of the first element.
+                */
+                if (!IsTypeArray (Expr->Type)) {
+                    /* The * operator yields an lvalue */
+                    ED_MakeLVal (Expr);
+                }
             }
             break;
 
@@ -2037,6 +2061,11 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
         Tok = CurTok.Tok;
         NextToken ();
 
+        /* If lhs is a function, convert it to pointer to function */
+        if (IsTypeFunc (Expr->Type)) {
+            Expr->Type = PointerTo (Expr->Type);
+        }
+
         /* Get the lhs on stack */
         GetCodePos (&Mark1);
         ltype = TypeOf (Expr->Type);
@@ -2054,6 +2083,11 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
         /* Get the right hand side */
         MarkedExprWithCheck (hienext, &Expr2);
 
+        /* If rhs is a function, convert it to pointer to function */
+        if (IsTypeFunc (Expr2.Type)) {
+            Expr2.Type = PointerTo (Expr2.Type);
+        }
+
         /* Check for a constant expression */
         rconst = (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2));
         if (!rconst) {
@@ -2061,6 +2095,22 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
             LoadExpr (CF_NONE, &Expr2);
         }
 
+        /* Some operations aren't allowed on function pointers */
+        if ((Gen->Flags & GEN_NOFUNC) != 0) {
+            /* Output only one message even if both sides are wrong */
+            if (IsTypeFuncPtr (Expr->Type)) {
+                Error ("Invalid left operand for relational operator");
+                /* Avoid further errors */
+                ED_MakeConstAbsInt (Expr, 0);
+                ED_MakeConstAbsInt (&Expr2, 0);
+            } else if (IsTypeFuncPtr (Expr2.Type)) {
+                Error ("Invalid right operand for relational operator");
+                /* Avoid further errors */
+                ED_MakeConstAbsInt (Expr, 0);
+                ED_MakeConstAbsInt (&Expr2, 0);
+            }
+        }
+
         /* Make sure, the types are compatible */
         if (IsClassInt (Expr->Type)) {
             if (!IsClassInt (Expr2.Type) && !(IsClassPtr(Expr2.Type) && ED_IsNullPtr(Expr))) {
@@ -2073,8 +2123,8 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
                 */
                 Type* left  = Indirect (Expr->Type);
                 Type* right = Indirect (Expr2.Type);
-                if (TypeCmp (left, right) < TC_EQUAL && left->C != T_VOID && right->C != T_VOID) {
-                    /* Incomatible pointers */
+                if (TypeCmp (left, right) < TC_QUAL_DIFF && left->C != T_VOID && right->C != T_VOID) {
+                    /* Incompatible pointers */
                     Error ("Incompatible types");
                 }
             } else if (!ED_IsNullPtr (&Expr2)) {
@@ -2358,7 +2408,6 @@ static void parseadd (ExprDesc* Expr)
     Type* lhst;                 /* Type of left hand side */
     Type* rhst;                 /* Type of right hand side */
 
-
     /* Skip the PLUS token */
     NextToken ();
 
@@ -2541,7 +2590,7 @@ static void parseadd (ExprDesc* Expr)
                 flags = CF_PTR;
             } else if (IsClassInt (lhst) && IsClassPtr (rhst)) {
                 /* Left is int, right is pointer, must scale lhs */
-                g_tosint (TypeOf (rhst));       /* Make sure, TOS is int */
+                g_tosint (TypeOf (lhst));       /* Make sure TOS is int */
                 g_swap (CF_INT);                /* Swap TOS and primary */
                 g_scale (CF_INT, CheckedPSizeOf (rhst));
                 /* Operate on pointers, result type is a pointer */
@@ -2575,7 +2624,6 @@ static void parseadd (ExprDesc* Expr)
 
     /* Condition codes not set */
     ED_MarkAsUntested (Expr);
-
 }
 
 
@@ -2595,6 +2643,13 @@ static void parsesub (ExprDesc* Expr)
     int rscale;                 /* Scale factor for the result */
 
 
+    /* lhs cannot be function or pointer to function */
+    if (IsTypeFunc (Expr->Type) || IsTypeFuncPtr (Expr->Type)) {
+        Error ("Invalid left operand for binary operator `-'");
+        /* Make it pointer to char to avoid further errors */
+        Expr->Type = type_uchar;
+    }
+
     /* Skip the MINUS token */
     NextToken ();
 
@@ -2611,6 +2666,13 @@ static void parsesub (ExprDesc* Expr)
     /* Parse the right hand side */
     MarkedExprWithCheck (hie9, &Expr2);
 
+    /* rhs cannot be function or pointer to function */
+    if (IsTypeFunc (Expr2.Type) || IsTypeFuncPtr (Expr2.Type)) {
+        Error ("Invalid right operand for binary operator `-'");
+        /* Make it pointer to char to avoid further errors */
+        Expr2.Type = type_uchar;
+    }
+
     /* Check for a constant rhs expression */
     if (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) {
 
@@ -2770,11 +2832,11 @@ static void hie6 (ExprDesc* Expr)
 /* Handle greater-than type comparators */
 {
     static const GenDesc hie6_ops [] = {
-        { TOK_LT,       GEN_NOPUSH,     g_lt    },
-        { TOK_LE,       GEN_NOPUSH,     g_le    },
-        { TOK_GE,       GEN_NOPUSH,     g_ge    },
-        { TOK_GT,       GEN_NOPUSH,     g_gt    },
-        { TOK_INVALID,  0,              0       }
+        { TOK_LT,       GEN_NOPUSH | GEN_NOFUNC,     g_lt    },
+        { TOK_LE,       GEN_NOPUSH | GEN_NOFUNC,     g_le    },
+        { TOK_GE,       GEN_NOPUSH | GEN_NOFUNC,     g_ge    },
+        { TOK_GT,       GEN_NOPUSH | GEN_NOFUNC,     g_gt    },
+        { TOK_INVALID,  0,                           0       }
     };
     hie_compare (hie6_ops, Expr, ShiftExpr);
 }