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.
This commit is contained in:
Shinichiro Hamaji 2009-03-16 02:24:45 +09:00 committed by grischka
parent 62e73da612
commit 4f056031f4
2 changed files with 46 additions and 10 deletions

41
tcc.c
View File

@ -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) {

View File

@ -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__