From 4f056031f4951dac5d6100dad7f5a1f023dcd273 Mon Sep 17 00:00:00 2001
From: Shinichiro Hamaji <shinichiro.hamaji _at_ gmail.com>
Date: Mon, 16 Mar 2009 02:24:45 +0900
Subject: [PATCH] Support long long bitfields for all architectures.

- Modified gv() and vstore(), added vpushll().
- Added a test case for long long bitfields.
- Tested on x86 and x86-64.
---
 tcc.c     | 41 +++++++++++++++++++++++++++++++----------
 tcctest.c | 15 +++++++++++++++
 2 files changed, 46 insertions(+), 10 deletions(-)

diff --git a/tcc.c b/tcc.c
index b4207998..3e40300d 100644
--- a/tcc.c
+++ b/tcc.c
@@ -844,6 +844,7 @@ static int is_compatible_parameter_types(CType *type1, CType *type2);
 int ieee_finite(double d);
 void error(const char *fmt, ...);
 void vpushi(int v);
+void vpushll(long long v);
 void vrott(int n);
 void vnrott(int n);
 void lexpand_nr(void);
@@ -4663,6 +4664,16 @@ void vpushi(int v)
     vsetc(&int_type, VT_CONST, &cval);
 }
 
+/* push long long constant */
+void vpushll(long long v)
+{
+    CValue cval;
+    CType ctype;
+    ctype.t = VT_LLONG;
+    cval.ull = v;
+    vsetc(&ctype, VT_CONST, &cval);
+}
+
 /* Return a static symbol pointing to a section */
 static Sym *get_sym_ref(CType *type, Section *sec, 
                         unsigned long offset, unsigned long size)
@@ -4971,20 +4982,25 @@ int gv(int rc)
     /* NOTE: get_reg can modify vstack[] */
     if (vtop->type.t & VT_BITFIELD) {
         CType type;
+        int bits = 32;
         bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f;
         bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
         /* remove bit field info to avoid loops */
         vtop->type.t &= ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT));
         /* cast to int to propagate signedness in following ops */
-        type.t = VT_INT;
+        if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
+            type.t = VT_LLONG;
+            bits = 64;
+        } else
+            type.t = VT_INT;
         if((vtop->type.t & VT_UNSIGNED) ||
            (vtop->type.t & VT_BTYPE) == VT_BOOL)
             type.t |= VT_UNSIGNED;
         gen_cast(&type);
         /* generate shifts */
-        vpushi(32 - (bit_pos + bit_size));
+        vpushi(bits - (bit_pos + bit_size));
         gen_op(TOK_SHL);
-        vpushi(32 - bit_size);
+        vpushi(bits - bit_size);
         /* NOTE: transformed to SHR if unsigned */
         gen_op(TOK_SAR);
         r = gv(rc);
@@ -6628,14 +6644,22 @@ void vstore(void)
 
         /* mask and shift source */
         if((ft & VT_BTYPE) != VT_BOOL) {
-            vpushi((1 << bit_size) - 1);
+            if((ft & VT_BTYPE) == VT_LLONG) {
+                vpushll((1ULL << bit_size) - 1ULL);
+            } else {
+                vpushi((1 << bit_size) - 1);
+            }
             gen_op('&');
         }
         vpushi(bit_pos);
         gen_op(TOK_SHL);
         /* load destination, mask and or with source */
         vswap();
-        vpushi(~(((1 << bit_size) - 1) << bit_pos));
+        if((ft & VT_BTYPE) == VT_LLONG) {
+            vpushll(~(((1ULL << bit_size) - 1ULL) << bit_pos));
+        } else {
+            vpushi(~(((1 << bit_size) - 1) << bit_pos));
+        }
         gen_op('&');
         gen_op('|');
         /* store result */
@@ -6947,11 +6971,8 @@ static void struct_decl(CType *type, int u)
                             bt != VT_BYTE && 
                             bt != VT_SHORT &&
                             bt != VT_BOOL &&
-                            bt != VT_ENUM
-#ifdef TCC_TARGET_X86_64
-                            && bt != VT_LLONG
-#endif
-                            )
+                            bt != VT_ENUM &&
+                            bt != VT_LLONG)
                             error("bitfields must have scalar type");
                         bsize = size * 8;
                         if (bit_size > bsize) {
diff --git a/tcctest.c b/tcctest.c
index 050f522f..012a51b9 100644
--- a/tcctest.c
+++ b/tcctest.c
@@ -1375,6 +1375,21 @@ void bitfield_test(void)
         printf("st1.f2 == -1\n");
     else 
         printf("st1.f2 != -1\n");
+
+    /* bit sizes below must be bigger than 32 since GCC doesn't allow
+       long-long bitfields whose size is not bigger than int */
+    struct sbf2 {
+        long long f1 : 45;
+        long long : 2;
+        long long f2 : 35;
+        unsigned long long f3 : 38;
+    } st2;
+    st2.f1 = 0x123456789ULL;
+    a = 120;
+    st2.f2 = (long long)a << 25;
+    st2.f3 = a;
+    st2.f2++;
+    printf("%lld %lld %lld\n", st2.f1, st2.f2, st2.f3);
 }
 
 #ifdef __x86_64__