changeset 535:8591acf8ce9f

Fix gen_opic() to properly &&, ||, and == NULL against symbols. Add test.
author Rob Landley <rob@landley.net>
date Mon, 10 Dec 2007 16:11:21 -0600
parents c9e388620dcc
children 26d8033259bc
files tcc.c tests/tcctest.c
diffstat 2 files changed, 29 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/tcc.c	Sun Dec 09 15:37:23 2007 -0600
+++ b/tcc.c	Mon Dec 10 16:11:21 2007 -0600
@@ -4436,10 +4436,11 @@
 /* handle long long constant and various machine independent optimizations */
 void gen_opic(int op)
 {
-    int c1, c2, t1, t2;
+    int c1, c2, t1, t2, squash;
     SValue *v1, *v2;
     long long l1, l2;
 
+    /* Grab the two symbols to operate on, their types, and their values */
     v1 = vtop - 1;
     v2 = vtop;
     t1 = v1->type.t & VT_BTYPE;
@@ -4447,12 +4448,21 @@
     l1 = (t1 == VT_LLONG) ? v1->c.ll : v1->c.i;
     l2 = (t2 == VT_LLONG) ? v2->c.ll : v2->c.i;
 
-    /* For forward symbols we can only constify &&, || or == NULL */
-    c2 = VT_SYM;
-    if (op == TOK_EQ && (v1->c.ll == 0 || v2->c.ll == 0)) c2 = 0;
-    if (op == TOK_LAND || op == TOK_LOR) c2 = 0;
-    c1 = (v1->r & (VT_VALMASK | VT_LVAL | c2)) == VT_CONST;
-    c2 = (v2->r & (VT_VALMASK | VT_LVAL | c2)) == VT_CONST;
+    /* For forward symbols we can only constify &&, || or == NULL.  If we
+       do so, we need to remove VT_SYM from the resulting type. */
+    squash = VT_SYM;
+    if (op == TOK_LAND || op == TOK_LOR ||
+        (op == TOK_EQ && (v1->c.ll == 0 || v2->c.ll == 0)))
+    {
+        squash = 0;
+        if (v1->r & VT_SYM) l1=1;
+        if (v2->r & VT_SYM) l2=1;
+    } else c2 = VT_SYM;
+
+    /* Are both arguments constant? */
+
+    c1 = (v1->r & (VT_VALMASK | VT_LVAL | squash)) == VT_CONST;
+    c2 = (v2->r & (VT_VALMASK | VT_LVAL | squash)) == VT_CONST;
 
     if (c1 && c2) {
         switch(op) {
@@ -4502,6 +4512,8 @@
             goto general_case;
         }
         v1->c.ll = l1;
+        // If v1 was a symbol, the resulting type is an int.
+        if (!squash) v1->r &= ~VT_SYM;
         vtop--;
     } else {
         /* if commutative ops, put c2 as constant */
@@ -4548,7 +4560,7 @@
             vtop--;
             vtop->c.ll += l2;
         } else {
-        general_case:
+general_case:
             /* call low level op generator */
             if (cur_text_section) {
                 if (t1 == VT_LLONG|| t2 == VT_LLONG) gen_opl(op);
--- a/tests/tcctest.c	Sun Dec 09 15:37:23 2007 -0600
+++ b/tests/tcctest.c	Mon Dec 10 16:11:21 2007 -0600
@@ -714,6 +714,13 @@
     printf("res= %d %d\n", a, b);
 }
 
+int constant_i = "blah" && 0;
+int constant_j = "blah" || 0;
+int constant_k = vpop && 0;
+int constant_l = "blah" && 1;
+int constant_m = "blah" || 1;
+int constant_n = 0 || vpop;
+
 void constant_expr_test()
 {
     int a;
@@ -722,6 +729,8 @@
     printf("%d\n", a * 16);
     printf("%d\n", a * 1);
     printf("%d\n", a + 0);
+    printf("%d %d %d %d %d %d\n",constant_i,constant_j,constant_k,constant_l,
+        constant_m,constant_n);
 }
 
 int tab4[10];