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:
committed by
grischka
parent
62e73da612
commit
4f056031f4
41
tcc.c
41
tcc.c
@ -844,6 +844,7 @@ static int is_compatible_parameter_types(CType *type1, CType *type2);
|
|||||||
int ieee_finite(double d);
|
int ieee_finite(double d);
|
||||||
void error(const char *fmt, ...);
|
void error(const char *fmt, ...);
|
||||||
void vpushi(int v);
|
void vpushi(int v);
|
||||||
|
void vpushll(long long v);
|
||||||
void vrott(int n);
|
void vrott(int n);
|
||||||
void vnrott(int n);
|
void vnrott(int n);
|
||||||
void lexpand_nr(void);
|
void lexpand_nr(void);
|
||||||
@ -4663,6 +4664,16 @@ void vpushi(int v)
|
|||||||
vsetc(&int_type, VT_CONST, &cval);
|
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 */
|
/* Return a static symbol pointing to a section */
|
||||||
static Sym *get_sym_ref(CType *type, Section *sec,
|
static Sym *get_sym_ref(CType *type, Section *sec,
|
||||||
unsigned long offset, unsigned long size)
|
unsigned long offset, unsigned long size)
|
||||||
@ -4971,20 +4982,25 @@ int gv(int rc)
|
|||||||
/* NOTE: get_reg can modify vstack[] */
|
/* NOTE: get_reg can modify vstack[] */
|
||||||
if (vtop->type.t & VT_BITFIELD) {
|
if (vtop->type.t & VT_BITFIELD) {
|
||||||
CType type;
|
CType type;
|
||||||
|
int bits = 32;
|
||||||
bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f;
|
bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f;
|
||||||
bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
|
bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
|
||||||
/* remove bit field info to avoid loops */
|
/* remove bit field info to avoid loops */
|
||||||
vtop->type.t &= ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT));
|
vtop->type.t &= ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT));
|
||||||
/* cast to int to propagate signedness in following ops */
|
/* 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) ||
|
if((vtop->type.t & VT_UNSIGNED) ||
|
||||||
(vtop->type.t & VT_BTYPE) == VT_BOOL)
|
(vtop->type.t & VT_BTYPE) == VT_BOOL)
|
||||||
type.t |= VT_UNSIGNED;
|
type.t |= VT_UNSIGNED;
|
||||||
gen_cast(&type);
|
gen_cast(&type);
|
||||||
/* generate shifts */
|
/* generate shifts */
|
||||||
vpushi(32 - (bit_pos + bit_size));
|
vpushi(bits - (bit_pos + bit_size));
|
||||||
gen_op(TOK_SHL);
|
gen_op(TOK_SHL);
|
||||||
vpushi(32 - bit_size);
|
vpushi(bits - bit_size);
|
||||||
/* NOTE: transformed to SHR if unsigned */
|
/* NOTE: transformed to SHR if unsigned */
|
||||||
gen_op(TOK_SAR);
|
gen_op(TOK_SAR);
|
||||||
r = gv(rc);
|
r = gv(rc);
|
||||||
@ -6628,14 +6644,22 @@ void vstore(void)
|
|||||||
|
|
||||||
/* mask and shift source */
|
/* mask and shift source */
|
||||||
if((ft & VT_BTYPE) != VT_BOOL) {
|
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('&');
|
gen_op('&');
|
||||||
}
|
}
|
||||||
vpushi(bit_pos);
|
vpushi(bit_pos);
|
||||||
gen_op(TOK_SHL);
|
gen_op(TOK_SHL);
|
||||||
/* load destination, mask and or with source */
|
/* load destination, mask and or with source */
|
||||||
vswap();
|
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('&');
|
||||||
gen_op('|');
|
gen_op('|');
|
||||||
/* store result */
|
/* store result */
|
||||||
@ -6947,11 +6971,8 @@ static void struct_decl(CType *type, int u)
|
|||||||
bt != VT_BYTE &&
|
bt != VT_BYTE &&
|
||||||
bt != VT_SHORT &&
|
bt != VT_SHORT &&
|
||||||
bt != VT_BOOL &&
|
bt != VT_BOOL &&
|
||||||
bt != VT_ENUM
|
bt != VT_ENUM &&
|
||||||
#ifdef TCC_TARGET_X86_64
|
bt != VT_LLONG)
|
||||||
&& bt != VT_LLONG
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
error("bitfields must have scalar type");
|
error("bitfields must have scalar type");
|
||||||
bsize = size * 8;
|
bsize = size * 8;
|
||||||
if (bit_size > bsize) {
|
if (bit_size > bsize) {
|
||||||
|
|||||||
15
tcctest.c
15
tcctest.c
@ -1375,6 +1375,21 @@ void bitfield_test(void)
|
|||||||
printf("st1.f2 == -1\n");
|
printf("st1.f2 == -1\n");
|
||||||
else
|
else
|
||||||
printf("st1.f2 != -1\n");
|
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__
|
#ifdef __x86_64__
|
||||||
|
|||||||
Reference in New Issue
Block a user