update gen_cast
This commit is contained in:
parent
35475b5423
commit
89372dc482
10 changed files with 376 additions and 283 deletions
10
arm64-gen.c
10
arm64-gen.c
|
@ -1718,6 +1718,16 @@ ST_FUNC void gen_cvt_sxtw(void)
|
||||||
o(0x93407c00 | r | r << 5); // sxtw x(r),w(r)
|
o(0x93407c00 | r | r << 5); // sxtw x(r),w(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* char/short to int conversion */
|
||||||
|
ST_FUNC void gen_cvt_csti(int t)
|
||||||
|
{
|
||||||
|
int r = intr(gv(RC_INT));
|
||||||
|
o(0x13001c00
|
||||||
|
| ((t & VT_BTYPE) == VT_SHORT) << 13
|
||||||
|
| (uint32_t)!!(t & VT_UNSIGNED) << 30
|
||||||
|
| r | r << 5); // [su]xt[bh] w(r),w(r)
|
||||||
|
}
|
||||||
|
|
||||||
ST_FUNC void gen_cvt_itof(int t)
|
ST_FUNC void gen_cvt_itof(int t)
|
||||||
{
|
{
|
||||||
if (t == VT_LDOUBLE) {
|
if (t == VT_LDOUBLE) {
|
||||||
|
|
13
i386-gen.c
13
i386-gen.c
|
@ -1048,6 +1048,19 @@ ST_FUNC void gen_cvt_ftof(int t)
|
||||||
gv(RC_FLOAT);
|
gv(RC_FLOAT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* char/short to int conversion */
|
||||||
|
ST_FUNC void gen_cvt_csti(int t)
|
||||||
|
{
|
||||||
|
int r, sz, xl;
|
||||||
|
r = gv(RC_INT);
|
||||||
|
sz = !(t & VT_UNSIGNED);
|
||||||
|
xl = (t & VT_BTYPE) == VT_SHORT;
|
||||||
|
o(0xc0b60f /* mov[sz] %a[xl], %eax */
|
||||||
|
| (sz << 3 | xl) << 8
|
||||||
|
| (r << 3 | r) << 16
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/* computed goto support */
|
/* computed goto support */
|
||||||
ST_FUNC void ggoto(void)
|
ST_FUNC void ggoto(void)
|
||||||
{
|
{
|
||||||
|
|
3
libtcc.c
3
libtcc.c
|
@ -1965,7 +1965,8 @@ reparse:
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TCC_OPTION_W:
|
case TCC_OPTION_W:
|
||||||
if (set_flag(s, options_W, optarg) < 0)
|
s->warn_none = 0;
|
||||||
|
if (optarg[0] && set_flag(s, options_W, optarg) < 0)
|
||||||
goto unsupported_option;
|
goto unsupported_option;
|
||||||
break;
|
break;
|
||||||
case TCC_OPTION_w:
|
case TCC_OPTION_w:
|
||||||
|
|
20
tcc.h
20
tcc.h
|
@ -926,9 +926,9 @@ struct filespec {
|
||||||
#define VT_JMPI 0x0035 /* value is the consequence of jmp false (odd) */
|
#define VT_JMPI 0x0035 /* value is the consequence of jmp false (odd) */
|
||||||
#define VT_LVAL 0x0100 /* var is an lvalue */
|
#define VT_LVAL 0x0100 /* var is an lvalue */
|
||||||
#define VT_SYM 0x0200 /* a symbol value is added */
|
#define VT_SYM 0x0200 /* a symbol value is added */
|
||||||
#define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for
|
#define VT_MUSTCAST 0x0C00 /* value must be casted to be correct (used for
|
||||||
char/short stored in integer registers) */
|
char/short stored in integer registers) */
|
||||||
#define VT_MUSTBOUND 0x0800 /* bound checking must be done before
|
#define VT_MUSTBOUND 0x4000 /* bound checking must be done before
|
||||||
dereferencing value */
|
dereferencing value */
|
||||||
#define VT_BOUNDED 0x8000 /* value is bounded. The address of the
|
#define VT_BOUNDED 0x8000 /* value is bounded. The address of the
|
||||||
bounding function call point is in vc */
|
bounding function call point is in vc */
|
||||||
|
@ -986,6 +986,11 @@ struct filespec {
|
||||||
#define VT_ASM (VT_VOID | VT_UNSIGNED)
|
#define VT_ASM (VT_VOID | VT_UNSIGNED)
|
||||||
#define IS_ASM_SYM(sym) (((sym)->type.t & (VT_BTYPE | VT_ASM)) == VT_ASM)
|
#define IS_ASM_SYM(sym) (((sym)->type.t & (VT_BTYPE | VT_ASM)) == VT_ASM)
|
||||||
|
|
||||||
|
/* general: set/get the pseudo-bitfield value for bit-mask M */
|
||||||
|
#define BFVAL(M,N) ((unsigned)((M) & ~((M) << 1)) * (N))
|
||||||
|
#define BFGET(X,M) (((X) & (M)) / BFVAL(M,1))
|
||||||
|
#define BFSET(X,M,N) ((X) = ((X) & ~(M)) | BFVAL(M,N))
|
||||||
|
|
||||||
/* token values */
|
/* token values */
|
||||||
|
|
||||||
/* warning: the following compare tokens depend on i386 asm code */
|
/* warning: the following compare tokens depend on i386 asm code */
|
||||||
|
@ -1359,7 +1364,7 @@ ST_DATA Sym *local_stack;
|
||||||
ST_DATA Sym *local_label_stack;
|
ST_DATA Sym *local_label_stack;
|
||||||
ST_DATA Sym *global_label_stack;
|
ST_DATA Sym *global_label_stack;
|
||||||
ST_DATA Sym *define_stack;
|
ST_DATA Sym *define_stack;
|
||||||
ST_DATA CType char_pointer_type, func_old_type, int_type, size_type;
|
ST_DATA CType int_type, func_old_type, char_pointer_type;
|
||||||
ST_DATA SValue *vtop;
|
ST_DATA SValue *vtop;
|
||||||
ST_DATA int rsym, anon_sym, ind, loc;
|
ST_DATA int rsym, anon_sym, ind, loc;
|
||||||
|
|
||||||
|
@ -1598,6 +1603,7 @@ ST_FUNC void gen_le16(int c);
|
||||||
ST_FUNC void gen_le32(int c);
|
ST_FUNC void gen_le32(int c);
|
||||||
ST_FUNC void gen_addr32(int r, Sym *sym, int c);
|
ST_FUNC void gen_addr32(int r, Sym *sym, int c);
|
||||||
ST_FUNC void gen_addrpc32(int r, Sym *sym, int c);
|
ST_FUNC void gen_addrpc32(int r, Sym *sym, int c);
|
||||||
|
ST_FUNC void gen_cvt_csti(int t);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
|
@ -1612,6 +1618,8 @@ ST_FUNC void gen_opl(int op);
|
||||||
#ifdef TCC_TARGET_PE
|
#ifdef TCC_TARGET_PE
|
||||||
ST_FUNC void gen_vla_result(int addr);
|
ST_FUNC void gen_vla_result(int addr);
|
||||||
#endif
|
#endif
|
||||||
|
ST_FUNC void gen_cvt_sxtw(void);
|
||||||
|
ST_FUNC void gen_cvt_csti(int t);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ------------ arm-gen.c ------------ */
|
/* ------------ arm-gen.c ------------ */
|
||||||
|
@ -1624,22 +1632,24 @@ ST_FUNC void arm_init(struct TCCState *s);
|
||||||
|
|
||||||
/* ------------ arm64-gen.c ------------ */
|
/* ------------ arm64-gen.c ------------ */
|
||||||
#ifdef TCC_TARGET_ARM64
|
#ifdef TCC_TARGET_ARM64
|
||||||
ST_FUNC void gen_cvt_sxtw(void);
|
|
||||||
ST_FUNC void gen_opl(int op);
|
ST_FUNC void gen_opl(int op);
|
||||||
ST_FUNC void gfunc_return(CType *func_type);
|
ST_FUNC void gfunc_return(CType *func_type);
|
||||||
ST_FUNC void gen_va_start(void);
|
ST_FUNC void gen_va_start(void);
|
||||||
ST_FUNC void gen_va_arg(CType *t);
|
ST_FUNC void gen_va_arg(CType *t);
|
||||||
ST_FUNC void gen_clear_cache(void);
|
ST_FUNC void gen_clear_cache(void);
|
||||||
|
ST_FUNC void gen_cvt_sxtw(void);
|
||||||
|
ST_FUNC void gen_cvt_csti(int t);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ------------ riscv64-gen.c ------------ */
|
/* ------------ riscv64-gen.c ------------ */
|
||||||
#ifdef TCC_TARGET_RISCV64
|
#ifdef TCC_TARGET_RISCV64
|
||||||
ST_FUNC void gen_cvt_sxtw(void);
|
|
||||||
ST_FUNC void gen_opl(int op);
|
ST_FUNC void gen_opl(int op);
|
||||||
//ST_FUNC void gfunc_return(CType *func_type);
|
//ST_FUNC void gfunc_return(CType *func_type);
|
||||||
ST_FUNC void gen_va_start(void);
|
ST_FUNC void gen_va_start(void);
|
||||||
ST_FUNC void arch_transfer_ret_regs(int);
|
ST_FUNC void arch_transfer_ret_regs(int);
|
||||||
|
ST_FUNC void gen_cvt_sxtw(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ------------ c67-gen.c ------------ */
|
/* ------------ c67-gen.c ------------ */
|
||||||
#ifdef TCC_TARGET_C67
|
#ifdef TCC_TARGET_C67
|
||||||
#endif
|
#endif
|
||||||
|
|
478
tccgen.c
478
tccgen.c
|
@ -79,8 +79,18 @@ ST_DATA int func_var; /* true if current function is variadic (used by return in
|
||||||
ST_DATA int func_vc;
|
ST_DATA int func_vc;
|
||||||
static int last_line_num, new_file, func_ind; /* debug info control */
|
static int last_line_num, new_file, func_ind; /* debug info control */
|
||||||
ST_DATA const char *funcname;
|
ST_DATA const char *funcname;
|
||||||
|
ST_DATA CType int_type, func_old_type, char_pointer_type;
|
||||||
|
|
||||||
ST_DATA CType char_pointer_type, func_old_type, int_type, size_type, ptrdiff_type;
|
#if PTR_SIZE == 4
|
||||||
|
#define VT_SIZE_T (VT_INT | VT_UNSIGNED)
|
||||||
|
#define VT_PTRDIFF_T VT_INT
|
||||||
|
#elif LONG_SIZE == 4
|
||||||
|
#define VT_SIZE_T (VT_LLONG | VT_UNSIGNED)
|
||||||
|
#define VT_PTRDIFF_T VT_LLONG
|
||||||
|
#else
|
||||||
|
#define VT_SIZE_T (VT_LONG | VT_LLONG | VT_UNSIGNED)
|
||||||
|
#define VT_PTRDIFF_T (VT_LONG | VT_LLONG)
|
||||||
|
#endif
|
||||||
|
|
||||||
ST_DATA struct switch_t {
|
ST_DATA struct switch_t {
|
||||||
struct case_t {
|
struct case_t {
|
||||||
|
@ -149,6 +159,7 @@ static void skip_or_save_block(TokenString **str);
|
||||||
static void gv_dup(void);
|
static void gv_dup(void);
|
||||||
static int get_temp_local_var(int size,int align);
|
static int get_temp_local_var(int size,int align);
|
||||||
static void clear_temp_local_var_list();
|
static void clear_temp_local_var_list();
|
||||||
|
static void cast_error(CType *st, CType *dt);
|
||||||
|
|
||||||
ST_INLN int is_float(int t)
|
ST_INLN int is_float(int t)
|
||||||
{
|
{
|
||||||
|
@ -162,6 +173,7 @@ ST_INLN int is_float(int t)
|
||||||
static inline int is_integer_btype(int bt)
|
static inline int is_integer_btype(int bt)
|
||||||
{
|
{
|
||||||
return bt == VT_BYTE
|
return bt == VT_BYTE
|
||||||
|
|| bt == VT_BOOL
|
||||||
|| bt == VT_SHORT
|
|| bt == VT_SHORT
|
||||||
|| bt == VT_INT
|
|| bt == VT_INT
|
||||||
|| bt == VT_LLONG;
|
|| bt == VT_LLONG;
|
||||||
|
@ -439,16 +451,6 @@ ST_FUNC void tccgen_init(TCCState *s1)
|
||||||
int_type.t = VT_INT;
|
int_type.t = VT_INT;
|
||||||
char_pointer_type.t = VT_BYTE;
|
char_pointer_type.t = VT_BYTE;
|
||||||
mk_pointer(&char_pointer_type);
|
mk_pointer(&char_pointer_type);
|
||||||
#if PTR_SIZE == 4
|
|
||||||
size_type.t = VT_INT | VT_UNSIGNED;
|
|
||||||
ptrdiff_type.t = VT_INT;
|
|
||||||
#elif LONG_SIZE == 4
|
|
||||||
size_type.t = VT_LLONG | VT_UNSIGNED;
|
|
||||||
ptrdiff_type.t = VT_LLONG;
|
|
||||||
#else
|
|
||||||
size_type.t = VT_LONG | VT_LLONG | VT_UNSIGNED;
|
|
||||||
ptrdiff_type.t = VT_LONG | VT_LLONG;
|
|
||||||
#endif
|
|
||||||
func_old_type.t = VT_FUNC;
|
func_old_type.t = VT_FUNC;
|
||||||
func_old_type.ref = sym_push(SYM_FIELD, &int_type, 0, 0);
|
func_old_type.ref = sym_push(SYM_FIELD, &int_type, 0, 0);
|
||||||
func_old_type.ref->f.func_call = FUNC_CDECL;
|
func_old_type.ref->f.func_call = FUNC_CDECL;
|
||||||
|
@ -922,29 +924,13 @@ ST_FUNC void vpop(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* push constant of type "type" with useless value */
|
/* push constant of type "type" with useless value */
|
||||||
ST_FUNC void vpush(CType *type)
|
static void vpush(CType *type)
|
||||||
{
|
{
|
||||||
vset(type, VT_CONST, 0);
|
vset(type, VT_CONST, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* push integer constant */
|
|
||||||
ST_FUNC void vpushi(int v)
|
|
||||||
{
|
|
||||||
CValue cval;
|
|
||||||
cval.i = v;
|
|
||||||
vsetc(&int_type, VT_CONST, &cval);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* push a pointer sized constant */
|
|
||||||
static void vpushs(addr_t v)
|
|
||||||
{
|
|
||||||
CValue cval;
|
|
||||||
cval.i = v;
|
|
||||||
vsetc(&size_type, VT_CONST, &cval);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* push arbitrary 64bit constant */
|
/* push arbitrary 64bit constant */
|
||||||
ST_FUNC void vpush64(int ty, unsigned long long v)
|
static void vpush64(int ty, unsigned long long v)
|
||||||
{
|
{
|
||||||
CValue cval;
|
CValue cval;
|
||||||
CType ctype;
|
CType ctype;
|
||||||
|
@ -954,6 +940,18 @@ ST_FUNC void vpush64(int ty, unsigned long long v)
|
||||||
vsetc(&ctype, VT_CONST, &cval);
|
vsetc(&ctype, VT_CONST, &cval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* push integer constant */
|
||||||
|
ST_FUNC void vpushi(int v)
|
||||||
|
{
|
||||||
|
vpush64(VT_INT, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* push a pointer sized constant */
|
||||||
|
static void vpushs(addr_t v)
|
||||||
|
{
|
||||||
|
vpush64(VT_SIZE_T, v);
|
||||||
|
}
|
||||||
|
|
||||||
/* push long long constant */
|
/* push long long constant */
|
||||||
static inline void vpushll(long long v)
|
static inline void vpushll(long long v)
|
||||||
{
|
{
|
||||||
|
@ -963,7 +961,6 @@ static inline void vpushll(long long v)
|
||||||
ST_FUNC void vset(CType *type, int r, int v)
|
ST_FUNC void vset(CType *type, int r, int v)
|
||||||
{
|
{
|
||||||
CValue cval;
|
CValue cval;
|
||||||
|
|
||||||
cval.i = v;
|
cval.i = v;
|
||||||
vsetc(type, r, &cval);
|
vsetc(type, r, &cval);
|
||||||
}
|
}
|
||||||
|
@ -1099,6 +1096,23 @@ static int gvtst(int inv, int t)
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* generate a zero or nozero test */
|
||||||
|
static void gen_test_zero(int op)
|
||||||
|
{
|
||||||
|
if (vtop->r == VT_CMP) {
|
||||||
|
int j;
|
||||||
|
if (op == TOK_EQ) {
|
||||||
|
j = vtop->jfalse;
|
||||||
|
vtop->jfalse = vtop->jtrue;
|
||||||
|
vtop->jtrue = j;
|
||||||
|
vtop->cmp_op ^= 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vpushi(0);
|
||||||
|
gen_op(op);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
/* push a symbol value of TYPE */
|
/* push a symbol value of TYPE */
|
||||||
static inline void vpushsym(CType *type, Sym *sym)
|
static inline void vpushsym(CType *type, Sym *sym)
|
||||||
|
@ -1350,44 +1364,34 @@ ST_FUNC void save_reg(int r)
|
||||||
if seen up to (vtop - n) stack entry */
|
if seen up to (vtop - n) stack entry */
|
||||||
ST_FUNC void save_reg_upstack(int r, int n)
|
ST_FUNC void save_reg_upstack(int r, int n)
|
||||||
{
|
{
|
||||||
int l, saved, size, align;
|
int l, size, align, bt;
|
||||||
SValue *p, *p1, sv;
|
SValue *p, *p1, sv;
|
||||||
CType *type;
|
|
||||||
|
|
||||||
if ((r &= VT_VALMASK) >= VT_CONST)
|
if ((r &= VT_VALMASK) >= VT_CONST)
|
||||||
return;
|
return;
|
||||||
if (nocode_wanted)
|
if (nocode_wanted)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* modify all stack values */
|
|
||||||
saved = 0;
|
|
||||||
l = 0;
|
l = 0;
|
||||||
for(p = vstack, p1 = vtop - n; p <= p1; p++) {
|
for(p = vstack, p1 = vtop - n; p <= p1; p++) {
|
||||||
if ((p->r & VT_VALMASK) == r || (p->r2 & VT_VALMASK) == r) {
|
if ((p->r & VT_VALMASK) == r || p->r2 == r) {
|
||||||
/* must save value on stack if not already done */
|
/* must save value on stack if not already done */
|
||||||
if (!saved) {
|
if (!l) {
|
||||||
/* NOTE: must reload 'r' because r might be equal to r2 */
|
bt = p->type.t & VT_BTYPE;
|
||||||
r = p->r & VT_VALMASK;
|
if (bt == VT_VOID)
|
||||||
/* store register in the stack */
|
continue;
|
||||||
type = &p->type;
|
if ((p->r & VT_LVAL) || bt == VT_FUNC)
|
||||||
if ((p->r & VT_LVAL) ||
|
bt = VT_PTR;
|
||||||
(!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG))
|
sv.type.t = bt;
|
||||||
#if PTR_SIZE == 8
|
size = type_size(&sv.type, &align);
|
||||||
type = &char_pointer_type;
|
|
||||||
#else
|
|
||||||
type = &int_type;
|
|
||||||
#endif
|
|
||||||
size = type_size(type, &align);
|
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
if (tcc_state->do_bounds_check)
|
if (tcc_state->do_bounds_check)
|
||||||
l = loc = (loc - size) & -align;
|
l = loc = (loc - size) & -align;
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
l=get_temp_local_var(size,align);
|
l = get_temp_local_var(size,align);
|
||||||
sv.type.t = type->t;
|
|
||||||
sv.r = VT_LOCAL | VT_LVAL;
|
sv.r = VT_LOCAL | VT_LVAL;
|
||||||
sv.c.i = l;
|
sv.c.i = l;
|
||||||
store(r, &sv);
|
store(p->r & VT_VALMASK, &sv);
|
||||||
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
|
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
|
||||||
/* x86 specific: need to pop fp register ST0 if saved */
|
/* x86 specific: need to pop fp register ST0 if saved */
|
||||||
if (r == TREG_ST0) {
|
if (r == TREG_ST0) {
|
||||||
|
@ -1395,11 +1399,10 @@ ST_FUNC void save_reg_upstack(int r, int n)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* special long long case */
|
/* special long long case */
|
||||||
if (p->r2 < VT_CONST && USING_TWO_WORDS(type->t)) {
|
if (p->r2 < VT_CONST && USING_TWO_WORDS(bt)) {
|
||||||
sv.c.i += PTR_SIZE;
|
sv.c.i += PTR_SIZE;
|
||||||
store(p->r2, &sv);
|
store(p->r2, &sv);
|
||||||
}
|
}
|
||||||
saved = 1;
|
|
||||||
}
|
}
|
||||||
/* mark that stack entry as being saved on the stack */
|
/* mark that stack entry as being saved on the stack */
|
||||||
if (p->r & VT_LVAL) {
|
if (p->r & VT_LVAL) {
|
||||||
|
@ -1771,7 +1774,7 @@ ST_FUNC int gv(int rc)
|
||||||
if (!r_ok)
|
if (!r_ok)
|
||||||
r = get_reg(rc);
|
r = get_reg(rc);
|
||||||
if (rc2) {
|
if (rc2) {
|
||||||
int load_type = (bt == VT_QFLOAT) ? VT_DOUBLE : ptrdiff_type.t;
|
int load_type = (bt == VT_QFLOAT) ? VT_DOUBLE : VT_PTRDIFF_T;
|
||||||
int original_type = vtop->type.t;
|
int original_type = vtop->type.t;
|
||||||
|
|
||||||
/* two register type load :
|
/* two register type load :
|
||||||
|
@ -1793,9 +1796,9 @@ ST_FUNC int gv(int rc)
|
||||||
vdup();
|
vdup();
|
||||||
vtop[-1].r = r; /* save register value */
|
vtop[-1].r = r; /* save register value */
|
||||||
/* increment pointer to get second word */
|
/* increment pointer to get second word */
|
||||||
vtop->type.t = ptrdiff_type.t;
|
vtop->type.t = VT_PTRDIFF_T;
|
||||||
gaddrof();
|
gaddrof();
|
||||||
vpushi(PTR_SIZE);
|
vpushs(PTR_SIZE);
|
||||||
gen_op('+');
|
gen_op('+');
|
||||||
vtop->r |= VT_LVAL;
|
vtop->r |= VT_LVAL;
|
||||||
vtop->type.t = load_type;
|
vtop->type.t = load_type;
|
||||||
|
@ -2521,7 +2524,7 @@ redo:
|
||||||
}
|
}
|
||||||
vrott(3);
|
vrott(3);
|
||||||
gen_opic(op);
|
gen_opic(op);
|
||||||
vtop->type.t = ptrdiff_type.t;
|
vtop->type.t = VT_PTRDIFF_T;
|
||||||
vswap();
|
vswap();
|
||||||
gen_op(TOK_PDIV);
|
gen_op(TOK_PDIV);
|
||||||
} else {
|
} else {
|
||||||
|
@ -2712,41 +2715,17 @@ static void gen_cvt_ftoi1(int t)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* force char or short cast */
|
/* special delayed cast for char/short */
|
||||||
static void force_charshort_cast(int t)
|
static void force_charshort_cast(void)
|
||||||
{
|
{
|
||||||
int bits, dbt;
|
int sbt = BFGET(vtop->r, VT_MUSTCAST) == 2 ? VT_LLONG : VT_INT;
|
||||||
|
int dbt = vtop->type.t;
|
||||||
/* cannot cast static initializers */
|
vtop->r &= ~VT_MUSTCAST;
|
||||||
if (STATIC_DATA_WANTED)
|
vtop->type.t = sbt;
|
||||||
return;
|
gen_cast_s(dbt == VT_BOOL ? VT_BYTE|VT_UNSIGNED : dbt);
|
||||||
|
vtop->type.t = dbt;
|
||||||
dbt = t & VT_BTYPE;
|
|
||||||
/* XXX: add optimization if lvalue : just change type and offset */
|
|
||||||
if (dbt == VT_BYTE)
|
|
||||||
bits = 8;
|
|
||||||
else
|
|
||||||
bits = 16;
|
|
||||||
if (t & VT_UNSIGNED) {
|
|
||||||
vpushi((1 << bits) - 1);
|
|
||||||
gen_op('&');
|
|
||||||
} else {
|
|
||||||
if ((vtop->type.t & VT_BTYPE) == VT_LLONG)
|
|
||||||
bits = 64 - bits;
|
|
||||||
else
|
|
||||||
bits = 32 - bits;
|
|
||||||
vpushi(bits);
|
|
||||||
gen_op(TOK_SHL);
|
|
||||||
/* result must be signed or the SAR is converted to an SHL
|
|
||||||
This was not the case when "t" was a signed short
|
|
||||||
and the last value on the stack was an unsigned int */
|
|
||||||
vtop->type.t &= ~VT_UNSIGNED;
|
|
||||||
vpushi(bits);
|
|
||||||
gen_op(TOK_SAR);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* cast 'vtop' to 'type'. Casting to bitfields is forbidden. */
|
|
||||||
static void gen_cast_s(int t)
|
static void gen_cast_s(int t)
|
||||||
{
|
{
|
||||||
CType type;
|
CType type;
|
||||||
|
@ -2755,31 +2734,33 @@ static void gen_cast_s(int t)
|
||||||
gen_cast(&type);
|
gen_cast(&type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* cast 'vtop' to 'type'. Casting to bitfields is forbidden. */
|
||||||
static void gen_cast(CType *type)
|
static void gen_cast(CType *type)
|
||||||
{
|
{
|
||||||
int sbt, dbt, sf, df, c, p;
|
int sbt, dbt, sf, df, c;
|
||||||
|
int dbt_bt, sbt_bt, ds, ss, bits, trunc;
|
||||||
|
|
||||||
/* special delayed cast for char/short */
|
/* special delayed cast for char/short */
|
||||||
/* XXX: in some cases (multiple cascaded casts), it may still
|
if (vtop->r & VT_MUSTCAST)
|
||||||
be incorrect */
|
force_charshort_cast();
|
||||||
if (vtop->r & VT_MUSTCAST) {
|
|
||||||
vtop->r &= ~VT_MUSTCAST;
|
|
||||||
force_charshort_cast(vtop->type.t);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* bitfields first get cast to ints */
|
/* bitfields first get cast to ints */
|
||||||
if (vtop->type.t & VT_BITFIELD) {
|
if (vtop->type.t & VT_BITFIELD)
|
||||||
gv(RC_INT);
|
gv(RC_INT);
|
||||||
}
|
|
||||||
|
|
||||||
dbt = type->t & (VT_BTYPE | VT_UNSIGNED);
|
dbt = type->t & (VT_BTYPE | VT_UNSIGNED);
|
||||||
sbt = vtop->type.t & (VT_BTYPE | VT_UNSIGNED);
|
sbt = vtop->type.t & (VT_BTYPE | VT_UNSIGNED);
|
||||||
|
if (sbt == VT_FUNC)
|
||||||
|
sbt = VT_PTR;
|
||||||
|
|
||||||
|
again:
|
||||||
if (sbt != dbt) {
|
if (sbt != dbt) {
|
||||||
sf = is_float(sbt);
|
sf = is_float(sbt);
|
||||||
df = is_float(dbt);
|
df = is_float(dbt);
|
||||||
|
dbt_bt = dbt & VT_BTYPE;
|
||||||
|
sbt_bt = sbt & VT_BTYPE;
|
||||||
|
|
||||||
c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
|
c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
|
||||||
p = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == (VT_CONST | VT_SYM);
|
|
||||||
#if !defined TCC_IS_NATIVE && !defined TCC_IS_NATIVE_387
|
#if !defined TCC_IS_NATIVE && !defined TCC_IS_NATIVE_387
|
||||||
c &= (dbt != VT_LDOUBLE) | !!nocode_wanted;
|
c &= (dbt != VT_LDOUBLE) | !!nocode_wanted;
|
||||||
#endif
|
#endif
|
||||||
|
@ -2792,7 +2773,7 @@ static void gen_cast(CType *type)
|
||||||
vtop->c.ld = vtop->c.d;
|
vtop->c.ld = vtop->c.d;
|
||||||
|
|
||||||
if (df) {
|
if (df) {
|
||||||
if ((sbt & VT_BTYPE) == VT_LLONG) {
|
if (sbt_bt == VT_LLONG) {
|
||||||
if ((sbt & VT_UNSIGNED) || !(vtop->c.i >> 63))
|
if ((sbt & VT_UNSIGNED) || !(vtop->c.i >> 63))
|
||||||
vtop->c.ld = vtop->c.i;
|
vtop->c.ld = vtop->c.i;
|
||||||
else
|
else
|
||||||
|
@ -2808,164 +2789,173 @@ static void gen_cast(CType *type)
|
||||||
vtop->c.f = (float)vtop->c.ld;
|
vtop->c.f = (float)vtop->c.ld;
|
||||||
else if (dbt == VT_DOUBLE)
|
else if (dbt == VT_DOUBLE)
|
||||||
vtop->c.d = (double)vtop->c.ld;
|
vtop->c.d = (double)vtop->c.ld;
|
||||||
} else if (sf && dbt == (VT_LLONG|VT_UNSIGNED)) {
|
|
||||||
vtop->c.i = vtop->c.ld;
|
|
||||||
} else if (sf && dbt == VT_BOOL) {
|
} else if (sf && dbt == VT_BOOL) {
|
||||||
vtop->c.i = (vtop->c.ld != 0);
|
vtop->c.i = (vtop->c.ld != 0);
|
||||||
} else {
|
} else {
|
||||||
if(sf)
|
if(sf)
|
||||||
vtop->c.i = vtop->c.ld;
|
vtop->c.i = vtop->c.ld;
|
||||||
else if (sbt == (VT_LLONG|VT_UNSIGNED))
|
else if (sbt_bt == VT_LLONG || (PTR_SIZE == 8 && sbt == VT_PTR))
|
||||||
;
|
;
|
||||||
else if (sbt & VT_UNSIGNED)
|
else if (sbt & VT_UNSIGNED)
|
||||||
vtop->c.i = (uint32_t)vtop->c.i;
|
vtop->c.i = (uint32_t)vtop->c.i;
|
||||||
#if PTR_SIZE == 8
|
else
|
||||||
else if (sbt == VT_PTR)
|
vtop->c.i = ((uint32_t)vtop->c.i | -(vtop->c.i & 0x80000000));
|
||||||
;
|
|
||||||
#endif
|
|
||||||
else if (sbt != VT_LLONG)
|
|
||||||
vtop->c.i = ((uint32_t)vtop->c.i |
|
|
||||||
-(vtop->c.i & 0x80000000));
|
|
||||||
|
|
||||||
if (dbt == (VT_LLONG|VT_UNSIGNED))
|
if (dbt_bt == VT_LLONG || (PTR_SIZE == 8 && dbt == VT_PTR))
|
||||||
;
|
;
|
||||||
else if (dbt == VT_BOOL)
|
else if (dbt == VT_BOOL)
|
||||||
vtop->c.i = (vtop->c.i != 0);
|
vtop->c.i = (vtop->c.i != 0);
|
||||||
#if PTR_SIZE == 8
|
else {
|
||||||
else if (dbt == VT_PTR)
|
uint32_t m = dbt_bt == VT_BYTE ? 0xff :
|
||||||
;
|
dbt_bt == VT_SHORT ? 0xffff :
|
||||||
#endif
|
0xffffffff;
|
||||||
else if (dbt != VT_LLONG) {
|
|
||||||
uint32_t m = ((dbt & VT_BTYPE) == VT_BYTE ? 0xff :
|
|
||||||
(dbt & VT_BTYPE) == VT_SHORT ? 0xffff :
|
|
||||||
0xffffffff);
|
|
||||||
vtop->c.i &= m;
|
vtop->c.i &= m;
|
||||||
if (!(dbt & VT_UNSIGNED))
|
if (!(dbt & VT_UNSIGNED))
|
||||||
vtop->c.i |= -(vtop->c.i & ((m >> 1) + 1));
|
vtop->c.i |= -(vtop->c.i & ((m >> 1) + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (p && dbt == VT_BOOL) {
|
goto done;
|
||||||
|
|
||||||
|
} else if (dbt == VT_BOOL
|
||||||
|
&& (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM))
|
||||||
|
== (VT_CONST | VT_SYM)) {
|
||||||
|
/* addresses are considered non-zero (see tcctest.c:sinit23) */
|
||||||
vtop->r = VT_CONST;
|
vtop->r = VT_CONST;
|
||||||
vtop->c.i = 1;
|
vtop->c.i = 1;
|
||||||
} else {
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cannot generate code for global or static initializers */
|
||||||
|
if (STATIC_DATA_WANTED)
|
||||||
|
goto done;
|
||||||
|
|
||||||
/* non constant case: generate code */
|
/* non constant case: generate code */
|
||||||
|
if (dbt == VT_BOOL) {
|
||||||
|
gen_test_zero(TOK_NE);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sf || df) {
|
||||||
if (sf && df) {
|
if (sf && df) {
|
||||||
/* convert from fp to fp */
|
/* convert from fp to fp */
|
||||||
gen_cvt_ftof(dbt);
|
gen_cvt_ftof(dbt);
|
||||||
} else if (df) {
|
} else if (df) {
|
||||||
/* convert int to fp */
|
/* convert int to fp */
|
||||||
gen_cvt_itof1(dbt);
|
gen_cvt_itof1(dbt);
|
||||||
} else if (sf) {
|
} else {
|
||||||
/* convert fp to int */
|
/* convert fp to int */
|
||||||
if (dbt == VT_BOOL) {
|
sbt = dbt;
|
||||||
vpushi(0);
|
if (dbt_bt != VT_LLONG && dbt_bt != VT_INT)
|
||||||
gen_op(TOK_NE);
|
sbt = VT_INT;
|
||||||
} else {
|
gen_cvt_ftoi1(sbt);
|
||||||
/* we handle char/short/etc... with generic code */
|
goto again; /* may need char/short cast */
|
||||||
if (dbt != (VT_INT | VT_UNSIGNED) &&
|
}
|
||||||
dbt != (VT_LLONG | VT_UNSIGNED) &&
|
goto done;
|
||||||
dbt != VT_LLONG)
|
}
|
||||||
dbt = VT_INT;
|
|
||||||
gen_cvt_ftoi1(dbt);
|
ds = btype_size(dbt_bt);
|
||||||
if (dbt == VT_INT && (type->t & (VT_BTYPE | VT_UNSIGNED)) != dbt) {
|
ss = btype_size(sbt_bt);
|
||||||
/* additional cast for char/short... */
|
if (ds == 0 || ss == 0) {
|
||||||
vtop->type.t = dbt;
|
if (dbt_bt == VT_VOID)
|
||||||
gen_cast(type);
|
goto done;
|
||||||
|
cast_error(&vtop->type, type);
|
||||||
|
}
|
||||||
|
if (IS_ENUM(type->t) && type->ref->c < 0)
|
||||||
|
tcc_error("cast to incomplete type");
|
||||||
|
|
||||||
|
/* same size and no sign conversion needed */
|
||||||
|
if (ds == ss && ds >= 4)
|
||||||
|
goto done;
|
||||||
|
if (dbt_bt == VT_PTR || sbt_bt == VT_PTR) {
|
||||||
|
tcc_warning("cast between pointer and integer of different size");
|
||||||
|
if (sbt_bt == VT_PTR) {
|
||||||
|
/* put integer type to allow logical operations below */
|
||||||
|
vtop->type.t = (PTR_SIZE == 8 ? VT_LLONG : VT_INT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* processor allows { int a = 0, b = *(char*)&a; }
|
||||||
|
That means that if we cast to less width, we can just
|
||||||
|
change the type and read it still later. */
|
||||||
|
#define ALLOW_SUBTYPE_ACCESS 1
|
||||||
|
|
||||||
|
if (ALLOW_SUBTYPE_ACCESS && (vtop->r & VT_LVAL)) {
|
||||||
|
/* value still in memory */
|
||||||
|
if (ds <= ss)
|
||||||
|
goto done;
|
||||||
|
/* ss <= 4 here */
|
||||||
|
if (ds <= 4) {
|
||||||
|
gv(RC_INT);
|
||||||
|
goto done; /* no 64bit envolved */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gv(RC_INT);
|
||||||
|
|
||||||
|
trunc = 0;
|
||||||
#if PTR_SIZE == 4
|
#if PTR_SIZE == 4
|
||||||
} else if ((dbt & VT_BTYPE) == VT_LLONG) {
|
if (ds == 8) {
|
||||||
if ((sbt & VT_BTYPE) != VT_LLONG) {
|
|
||||||
/* scalar to long long */
|
|
||||||
/* machine independent conversion */
|
|
||||||
gv(RC_INT);
|
|
||||||
/* generate high word */
|
/* generate high word */
|
||||||
if (sbt == (VT_INT | VT_UNSIGNED)) {
|
if (sbt & VT_UNSIGNED) {
|
||||||
vpushi(0);
|
vpushi(0);
|
||||||
gv(RC_INT);
|
gv(RC_INT);
|
||||||
} else {
|
} else {
|
||||||
if (sbt == VT_PTR) {
|
|
||||||
/* cast from pointer to int before we apply
|
|
||||||
shift operation, which pointers don't support*/
|
|
||||||
gen_cast_s(VT_INT);
|
|
||||||
}
|
|
||||||
gv_dup();
|
gv_dup();
|
||||||
vpushi(31);
|
vpushi(31);
|
||||||
gen_op(TOK_SAR);
|
gen_op(TOK_SAR);
|
||||||
}
|
}
|
||||||
/* patch second register */
|
lbuild(dbt);
|
||||||
vtop[-1].r2 = vtop->r;
|
} else if (ss == 8) {
|
||||||
vpop();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
} else if ((dbt & VT_BTYPE) == VT_LLONG ||
|
|
||||||
(dbt & VT_BTYPE) == VT_PTR ||
|
|
||||||
(dbt & VT_BTYPE) == VT_FUNC) {
|
|
||||||
if ((sbt & VT_BTYPE) != VT_LLONG &&
|
|
||||||
(sbt & VT_BTYPE) != VT_PTR &&
|
|
||||||
(sbt & VT_BTYPE) != VT_FUNC) {
|
|
||||||
/* need to convert from 32bit to 64bit */
|
|
||||||
gv(RC_INT);
|
|
||||||
if (sbt != (VT_INT | VT_UNSIGNED)) {
|
|
||||||
#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_RISCV64)
|
|
||||||
gen_cvt_sxtw();
|
|
||||||
#elif defined(TCC_TARGET_X86_64)
|
|
||||||
int r = gv(RC_INT);
|
|
||||||
/* x86_64 specific: movslq */
|
|
||||||
o(0x6348);
|
|
||||||
o(0xc0 + (REG_VALUE(r) << 3) + REG_VALUE(r));
|
|
||||||
#else
|
|
||||||
#error
|
|
||||||
#endif
|
|
||||||
} else if (sbt & VT_UNSIGNED) {
|
|
||||||
#if defined(TCC_TARGET_RISCV64)
|
|
||||||
/* RISC-V keeps 32bit vals in registers sign-extended.
|
|
||||||
So here we need a zero-extension. */
|
|
||||||
vtop->type.t = VT_LLONG;
|
|
||||||
vpushi(32);
|
|
||||||
gen_op(TOK_SHL);
|
|
||||||
vpushi(32);
|
|
||||||
gen_op(TOK_SHR);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} else if (dbt == VT_BOOL) {
|
|
||||||
/* scalar to bool */
|
|
||||||
vpushi(0);
|
|
||||||
gen_op(TOK_NE);
|
|
||||||
} else if ((dbt & VT_BTYPE) == VT_BYTE ||
|
|
||||||
(dbt & VT_BTYPE) == VT_SHORT) {
|
|
||||||
if (sbt == VT_PTR) {
|
|
||||||
vtop->type.t = VT_INT;
|
|
||||||
tcc_warning("nonportable conversion from pointer to char/short");
|
|
||||||
}
|
|
||||||
force_charshort_cast(dbt);
|
|
||||||
} else if ((dbt & VT_BTYPE) == VT_INT) {
|
|
||||||
/* scalar to int */
|
|
||||||
if ((sbt & VT_BTYPE) == VT_LLONG) {
|
|
||||||
#if PTR_SIZE == 4
|
|
||||||
/* from long long: just take low order word */
|
/* from long long: just take low order word */
|
||||||
lexpand();
|
lexpand();
|
||||||
vpop();
|
vpop();
|
||||||
|
}
|
||||||
|
ss = 4;
|
||||||
|
|
||||||
|
#elif PTR_SIZE == 8
|
||||||
|
if (ds == 8) {
|
||||||
|
/* need to convert from 32bit to 64bit */
|
||||||
|
if (sbt & VT_UNSIGNED) {
|
||||||
|
#if defined(TCC_TARGET_RISCV64)
|
||||||
|
/* RISC-V keeps 32bit vals in registers sign-extended.
|
||||||
|
So here we need a zero-extension. */
|
||||||
|
trunc = 32;
|
||||||
#else
|
#else
|
||||||
if (dbt & VT_UNSIGNED) {
|
goto done;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
gen_cvt_sxtw();
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
ss = ds, ds = 4, dbt = sbt;
|
||||||
|
} else if (ss == 8) {
|
||||||
/* XXX some architectures (e.g. risc-v) would like it
|
/* XXX some architectures (e.g. risc-v) would like it
|
||||||
better for this merely being a 32-to-64 sign or zero-
|
better for this merely being a 32-to-64 sign or zero-
|
||||||
extension. */
|
extension. */
|
||||||
vpushi(0xffffffff);
|
trunc = 32; /* zero upper 32 bits */
|
||||||
vtop->type.t |= VT_UNSIGNED;
|
|
||||||
gen_op('&');
|
|
||||||
} else {
|
} else {
|
||||||
|
ss = 4;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (ds >= ss)
|
||||||
|
goto done;
|
||||||
|
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 || defined TCC_TARGET_ARM64
|
||||||
|
if (ss == 4) {
|
||||||
|
gen_cvt_csti(dbt);
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
bits = (ss - ds) * 8;
|
||||||
|
/* for unsigned, gen_op will convert SAR to SHR */
|
||||||
|
vtop->type.t = (ss == 8 ? VT_LLONG : VT_INT) | (dbt & VT_UNSIGNED);
|
||||||
|
vpushi(bits);
|
||||||
|
gen_op(TOK_SHL);
|
||||||
|
vpushi(bits - trunc);
|
||||||
|
gen_op(TOK_SAR);
|
||||||
|
vpushi(trunc);
|
||||||
|
gen_op(TOK_SHR);
|
||||||
}
|
}
|
||||||
if ((vtop->r & VT_LVAL)
|
done:
|
||||||
&& (dbt & VT_BTYPE) != (sbt & VT_BTYPE))
|
|
||||||
gv(RC_INT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vtop->type = *type;
|
vtop->type = *type;
|
||||||
vtop->type.t &= ~ ( VT_CONSTANT | VT_VOLATILE | VT_ARRAY );
|
vtop->type.t &= ~ ( VT_CONSTANT | VT_VOLATILE | VT_ARRAY );
|
||||||
}
|
}
|
||||||
|
@ -3293,25 +3283,30 @@ static void type_to_str(char *buf, int buf_size,
|
||||||
no_var: ;
|
no_var: ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cast_error(CType *st, CType *dt)
|
||||||
|
{
|
||||||
|
char buf1[256], buf2[256];
|
||||||
|
type_to_str(buf1, sizeof(buf1), st, NULL);
|
||||||
|
type_to_str(buf2, sizeof(buf2), dt, NULL);
|
||||||
|
tcc_error("cannot convert '%s' to '%s'", buf1, buf2);
|
||||||
|
}
|
||||||
|
|
||||||
/* verify type compatibility to store vtop in 'dt' type */
|
/* verify type compatibility to store vtop in 'dt' type */
|
||||||
static void verify_assign_cast(CType *dt)
|
static void verify_assign_cast(CType *dt)
|
||||||
{
|
{
|
||||||
CType *st, *type1, *type2;
|
CType *st, *type1, *type2;
|
||||||
char buf1[256], buf2[256];
|
|
||||||
int dbt, sbt, qualwarn, lvl;
|
int dbt, sbt, qualwarn, lvl;
|
||||||
|
|
||||||
st = &vtop->type; /* source type */
|
st = &vtop->type; /* source type */
|
||||||
dbt = dt->t & VT_BTYPE;
|
dbt = dt->t & VT_BTYPE;
|
||||||
sbt = st->t & VT_BTYPE;
|
sbt = st->t & VT_BTYPE;
|
||||||
if (sbt == VT_VOID || dbt == VT_VOID) {
|
|
||||||
if (sbt == VT_VOID && dbt == VT_VOID)
|
|
||||||
; /* It is Ok if both are void */
|
|
||||||
else
|
|
||||||
tcc_error("cannot cast from/to void");
|
|
||||||
}
|
|
||||||
if (dt->t & VT_CONSTANT)
|
if (dt->t & VT_CONSTANT)
|
||||||
tcc_warning("assignment of read-only location");
|
tcc_warning("assignment of read-only location");
|
||||||
switch(dbt) {
|
switch(dbt) {
|
||||||
|
case VT_VOID:
|
||||||
|
if (sbt != dbt)
|
||||||
|
tcc_error("assignment to void expression");
|
||||||
|
break;
|
||||||
case VT_PTR:
|
case VT_PTR:
|
||||||
/* special cases for pointers */
|
/* special cases for pointers */
|
||||||
/* '0' can also be a pointer */
|
/* '0' can also be a pointer */
|
||||||
|
@ -3376,9 +3371,7 @@ static void verify_assign_cast(CType *dt)
|
||||||
case_VT_STRUCT:
|
case_VT_STRUCT:
|
||||||
if (!is_compatible_unqualified_types(dt, st)) {
|
if (!is_compatible_unqualified_types(dt, st)) {
|
||||||
error:
|
error:
|
||||||
type_to_str(buf1, sizeof(buf1), st, NULL);
|
cast_error(st, dt);
|
||||||
type_to_str(buf2, sizeof(buf2), dt, NULL);
|
|
||||||
tcc_error("cannot cast '%s' to '%s'", buf1, buf2);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3495,7 +3488,7 @@ ST_FUNC void vstore(void)
|
||||||
if ((vtop->r & VT_MUSTCAST)
|
if ((vtop->r & VT_MUSTCAST)
|
||||||
&& btype_size(dbt) > btype_size(sbt)
|
&& btype_size(dbt) > btype_size(sbt)
|
||||||
)
|
)
|
||||||
force_charshort_cast(dbt);
|
force_charshort_cast();
|
||||||
delayed_cast = 1;
|
delayed_cast = 1;
|
||||||
} else {
|
} else {
|
||||||
gen_cast(&vtop[-1].type);
|
gen_cast(&vtop[-1].type);
|
||||||
|
@ -3512,7 +3505,7 @@ ST_FUNC void vstore(void)
|
||||||
gv(RC_TYPE(dbt)); /* generate value */
|
gv(RC_TYPE(dbt)); /* generate value */
|
||||||
|
|
||||||
if (delayed_cast) {
|
if (delayed_cast) {
|
||||||
vtop->r |= VT_MUSTCAST;
|
vtop->r |= BFVAL(VT_MUSTCAST, (sbt == VT_LLONG) + 1);
|
||||||
//tcc_warning("deley cast %x -> %x", sbt, dbt);
|
//tcc_warning("deley cast %x -> %x", sbt, dbt);
|
||||||
vtop->type.t = ft & VT_TYPE;
|
vtop->type.t = ft & VT_TYPE;
|
||||||
}
|
}
|
||||||
|
@ -3521,7 +3514,7 @@ ST_FUNC void vstore(void)
|
||||||
if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) {
|
if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) {
|
||||||
SValue sv;
|
SValue sv;
|
||||||
r = get_reg(RC_INT);
|
r = get_reg(RC_INT);
|
||||||
sv.type.t = ptrdiff_type.t;
|
sv.type.t = VT_PTRDIFF_T;
|
||||||
sv.r = VT_LOCAL | VT_LVAL;
|
sv.r = VT_LOCAL | VT_LVAL;
|
||||||
sv.c.i = vtop[-1].c.i;
|
sv.c.i = vtop[-1].c.i;
|
||||||
load(r, &sv);
|
load(r, &sv);
|
||||||
|
@ -3532,12 +3525,12 @@ ST_FUNC void vstore(void)
|
||||||
/* two word case handling :
|
/* two word case handling :
|
||||||
store second register at word + 4 (or +8 for x86-64) */
|
store second register at word + 4 (or +8 for x86-64) */
|
||||||
if (USING_TWO_WORDS(dbt)) {
|
if (USING_TWO_WORDS(dbt)) {
|
||||||
int load_type = (dbt == VT_QFLOAT) ? VT_DOUBLE : ptrdiff_type.t;
|
int load_type = (dbt == VT_QFLOAT) ? VT_DOUBLE : VT_PTRDIFF_T;
|
||||||
vtop[-1].type.t = load_type;
|
vtop[-1].type.t = load_type;
|
||||||
store(r, vtop - 1);
|
store(r, vtop - 1);
|
||||||
vswap();
|
vswap();
|
||||||
/* convert to int to increment easily */
|
/* convert to int to increment easily */
|
||||||
vtop->type.t = ptrdiff_type.t;
|
vtop->type.t = VT_PTRDIFF_T;
|
||||||
gaddrof();
|
gaddrof();
|
||||||
vpushs(PTR_SIZE);
|
vpushs(PTR_SIZE);
|
||||||
gen_op('+');
|
gen_op('+');
|
||||||
|
@ -4861,6 +4854,8 @@ static void gfunc_param_typed(Sym *func, Sym *arg)
|
||||||
type.t = vtop->type.t & (VT_BTYPE | VT_UNSIGNED);
|
type.t = vtop->type.t & (VT_BTYPE | VT_UNSIGNED);
|
||||||
type.ref = vtop->type.ref;
|
type.ref = vtop->type.ref;
|
||||||
gen_cast(&type);
|
gen_cast(&type);
|
||||||
|
} else if (vtop->r & VT_MUSTCAST) {
|
||||||
|
force_charshort_cast();
|
||||||
}
|
}
|
||||||
} else if (arg == NULL) {
|
} else if (arg == NULL) {
|
||||||
tcc_error("too many arguments to function");
|
tcc_error("too many arguments to function");
|
||||||
|
@ -5094,16 +5089,7 @@ ST_FUNC void unary(void)
|
||||||
case '!':
|
case '!':
|
||||||
next();
|
next();
|
||||||
unary();
|
unary();
|
||||||
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
|
gen_test_zero(TOK_EQ);
|
||||||
gen_cast_s(VT_BOOL);
|
|
||||||
vtop->c.i = !vtop->c.i;
|
|
||||||
} else if (vtop->r == VT_CMP) {
|
|
||||||
vtop->cmp_op ^= 1;
|
|
||||||
n = vtop->jfalse, vtop->jfalse = vtop->jtrue, vtop->jtrue = n;
|
|
||||||
} else {
|
|
||||||
vpushi(0);
|
|
||||||
gen_op(TOK_EQ);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case '~':
|
case '~':
|
||||||
next();
|
next();
|
||||||
|
@ -6491,17 +6477,23 @@ again:
|
||||||
next();
|
next();
|
||||||
|
|
||||||
} else if (t == TOK_RETURN) {
|
} else if (t == TOK_RETURN) {
|
||||||
a = tok != ';';
|
|
||||||
b = (func_vt.t & VT_BTYPE) != VT_VOID;
|
b = (func_vt.t & VT_BTYPE) != VT_VOID;
|
||||||
if (a)
|
if (tok != ';') {
|
||||||
gexpr(), gen_assign_cast(&func_vt);
|
gexpr();
|
||||||
leave_scope(root_scope);
|
if (b) {
|
||||||
if (a && b)
|
gen_assign_cast(&func_vt);
|
||||||
gfunc_return(&func_vt);
|
} else {
|
||||||
else if (a)
|
if (vtop->type.t != VT_VOID)
|
||||||
|
tcc_warning("void function returns a value");
|
||||||
vtop--;
|
vtop--;
|
||||||
else if (b)
|
}
|
||||||
tcc_warning("'return' with no value.");
|
} else if (b) {
|
||||||
|
tcc_warning("'return' with no value");
|
||||||
|
b = 0;
|
||||||
|
}
|
||||||
|
leave_scope(root_scope);
|
||||||
|
if (b)
|
||||||
|
gfunc_return(&func_vt);
|
||||||
skip(';');
|
skip(';');
|
||||||
/* jump unless last stmt in top-level block */
|
/* jump unless last stmt in top-level block */
|
||||||
if (tok != '}' || local_scope != 1)
|
if (tok != '}' || local_scope != 1)
|
||||||
|
|
|
@ -269,6 +269,7 @@ cross-test :
|
||||||
$(TOP)/arm-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
$(TOP)/arm-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||||
$(TOP)/arm-wince-tcc$(EXESUF) $(TCCFLAGS-win) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
$(TOP)/arm-wince-tcc$(EXESUF) $(TCCFLAGS-win) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||||
$(TOP)/arm64-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
$(TOP)/arm64-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||||
|
$(TOP)/riscv64-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||||
$(TOP)/c67-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
$(TOP)/c67-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||||
$(TOP)/i386-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/win32/examples/hello_win.c && echo "ok"
|
$(TOP)/i386-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/win32/examples/hello_win.c && echo "ok"
|
||||||
$(TOP)/x86_64-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/win32/examples/hello_win.c && echo "ok"
|
$(TOP)/x86_64-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/win32/examples/hello_win.c && echo "ok"
|
||||||
|
|
|
@ -16,6 +16,10 @@
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef __TINYC__
|
||||||
|
typedef __SIZE_TYPE__ uintptr_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#define LONG_LONG_FORMAT "%lld"
|
#define LONG_LONG_FORMAT "%lld"
|
||||||
#define ULONG_LONG_FORMAT "%llu"
|
#define ULONG_LONG_FORMAT "%llu"
|
||||||
|
@ -1163,7 +1167,7 @@ void struct_test()
|
||||||
s->f3 = 1;
|
s->f3 = 1;
|
||||||
printf("st2: %d %d %d\n",
|
printf("st2: %d %d %d\n",
|
||||||
s->f1, s->f2, s->f3);
|
s->f1, s->f2, s->f3);
|
||||||
printf("str_addr=%x\n", (int)st1.str - (int)&st1.f1);
|
printf("str_addr=%x\n", (int)(uintptr_t)st1.str - (int)(uintptr_t)&st1.f1);
|
||||||
|
|
||||||
/* align / size tests */
|
/* align / size tests */
|
||||||
printf("aligntest1 sizeof=%d alignof=%d\n",
|
printf("aligntest1 sizeof=%d alignof=%d\n",
|
||||||
|
@ -1203,10 +1207,17 @@ void struct_test()
|
||||||
printf("Large: offsetof(compound_head)=%d\n", (int)((char*)&ls.compound_head - (char*)&ls));
|
printf("Large: offsetof(compound_head)=%d\n", (int)((char*)&ls.compound_head - (char*)&ls));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* simulate char/short return value with undefined upper bits */
|
||||||
|
static int __csf(int x) { return x; }
|
||||||
|
static void *_csf = __csf;
|
||||||
|
#define csf(t,n) ((t(*)(int))_csf)(n)
|
||||||
|
|
||||||
/* XXX: depend on endianness */
|
/* XXX: depend on endianness */
|
||||||
void char_short_test()
|
void char_short_test()
|
||||||
{
|
{
|
||||||
int var1, var2;
|
int var1, var2;
|
||||||
|
char var3;
|
||||||
|
long long var4;
|
||||||
|
|
||||||
printf("char_short:\n");
|
printf("char_short:\n");
|
||||||
|
|
||||||
|
@ -1230,6 +1241,34 @@ void char_short_test()
|
||||||
printf("var1=%x\n", var1);
|
printf("var1=%x\n", var1);
|
||||||
*(int *)&var1 = 0x08090a0b;
|
*(int *)&var1 = 0x08090a0b;
|
||||||
printf("var1=%x\n", var1);
|
printf("var1=%x\n", var1);
|
||||||
|
|
||||||
|
var1 = 0x778899aa;
|
||||||
|
var4 = 0x11223344aa998877ULL;
|
||||||
|
var1 = var3 = var1 + 1;
|
||||||
|
var4 = var3 = var4 + 1;
|
||||||
|
printf("promote char/short assign %d "LONG_LONG_FORMAT"\n", var1, var4);
|
||||||
|
var1 = 0x778899aa;
|
||||||
|
var4 = 0x11223344aa998877ULL;
|
||||||
|
printf("promote char/short assign VA %d %d\n", var3 = var1 + 1, var3 = var4 + 1);
|
||||||
|
printf("promote char/short cast VA %d %d\n", (char)(var1 + 1), (char)(var4 + 1));
|
||||||
|
var1 = csf(unsigned char,0x89898989);
|
||||||
|
var4 = csf(char,0xabababab);
|
||||||
|
printf("promote char/short funcret %d "LONG_LONG_FORMAT"\n", var1, var4);
|
||||||
|
printf("promote char/short fumcret VA %d %d %d %d\n",
|
||||||
|
csf(unsigned short,0xcdcdcdcd),
|
||||||
|
csf(short,0xefefefef),
|
||||||
|
csf(_Bool,0x33221100),
|
||||||
|
csf(_Bool,0x33221101));
|
||||||
|
var3 = -10;
|
||||||
|
var1 = (char)(unsigned char)(var3 + 1);
|
||||||
|
var4 = (char)(unsigned char)(var3 + 1);
|
||||||
|
printf("promote multicast (char)(unsigned char) %d "LONG_LONG_FORMAT"\n", var1, var4);
|
||||||
|
var4 = 0x11223344aa998877ULL;
|
||||||
|
var4 = (unsigned)(int)(var4 + 1);
|
||||||
|
printf("promote multicast (unsigned)(int) "LONG_LONG_FORMAT"\n", var4);
|
||||||
|
var4 = 0x11223344bbaa9988ULL;
|
||||||
|
var4 = (unsigned)(char)(var4 + 1);
|
||||||
|
printf("promote multicast (unsigned)(char) "LONG_LONG_FORMAT"\n", var4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************/
|
/******************/
|
||||||
|
@ -1679,6 +1718,10 @@ void cast_test()
|
||||||
printf("sizeof(-(char)'a') = %d\n", sizeof(-(char)'a'));
|
printf("sizeof(-(char)'a') = %d\n", sizeof(-(char)'a'));
|
||||||
printf("sizeof(~(char)'a') = %d\n", sizeof(-(char)'a'));
|
printf("sizeof(~(char)'a') = %d\n", sizeof(-(char)'a'));
|
||||||
|
|
||||||
|
#ifdef __TINYC__
|
||||||
|
# pragma comment(option, "-w")
|
||||||
|
#endif
|
||||||
|
|
||||||
/* from pointer to integer types */
|
/* from pointer to integer types */
|
||||||
printf("%d %d %ld %ld %lld %lld\n",
|
printf("%d %d %ld %ld %lld %lld\n",
|
||||||
(int)p, (unsigned int)p,
|
(int)p, (unsigned int)p,
|
||||||
|
@ -1689,6 +1732,10 @@ void cast_test()
|
||||||
printf("%p %p %p %p\n",
|
printf("%p %p %p %p\n",
|
||||||
(void *)a, (void *)b, (void *)c, (void *)d);
|
(void *)a, (void *)b, (void *)c, (void *)d);
|
||||||
|
|
||||||
|
#ifdef __TINYC__
|
||||||
|
# pragma comment(option, "-W")
|
||||||
|
#endif
|
||||||
|
|
||||||
/* int to int with sign set */
|
/* int to int with sign set */
|
||||||
printf("0x%lx\n", (unsigned long)(int)ul);
|
printf("0x%lx\n", (unsigned long)(int)ul);
|
||||||
}
|
}
|
||||||
|
@ -2347,7 +2394,7 @@ void funcptr_test()
|
||||||
|
|
||||||
/* Check that we can align functions */
|
/* Check that we can align functions */
|
||||||
func = aligned_function;
|
func = aligned_function;
|
||||||
printf("aligned_function (should be zero): %d\n", ((int)func) & 15);
|
printf("aligned_function (should be zero): %d\n", ((int)(uintptr_t)func) & 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lloptest(long long a, long long b)
|
void lloptest(long long a, long long b)
|
||||||
|
@ -2549,6 +2596,9 @@ void longlong_test(void)
|
||||||
unsigned long long u = 0x8000000000000001ULL;
|
unsigned long long u = 0x8000000000000001ULL;
|
||||||
u = (unsigned)(u + 1);
|
u = (unsigned)(u + 1);
|
||||||
printf("long long u=" ULONG_LONG_FORMAT "\n", u);
|
printf("long long u=" ULONG_LONG_FORMAT "\n", u);
|
||||||
|
u = 0x11223344aa998877ULL;
|
||||||
|
u = (unsigned)(int)(u + 1);
|
||||||
|
printf("long long u=" ULONG_LONG_FORMAT "\n", u);
|
||||||
|
|
||||||
/* was a problem with missing save_regs in gen_opl on 32-bit platforms */
|
/* was a problem with missing save_regs in gen_opl on 32-bit platforms */
|
||||||
char cc = 78;
|
char cc = 78;
|
||||||
|
@ -2897,10 +2947,6 @@ void c99_vla_test(int size1, int size2)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef __TINYC__
|
|
||||||
typedef __SIZE_TYPE__ uintptr_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void sizeof_test(void)
|
void sizeof_test(void)
|
||||||
{
|
{
|
||||||
int a;
|
int a;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* Check some way in where code suppression caused various
|
/* Check some way in where code suppression caused various
|
||||||
miscompilations. */
|
miscompilations. */
|
||||||
extern int printf (const char *, ...);
|
extern int printf (const char *, ...);
|
||||||
typedef unsigned long size_t;
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
|
||||||
size_t _brk_start, _brk_end;
|
size_t _brk_start, _brk_end;
|
||||||
void * extend_brk(size_t size, size_t align)
|
void * extend_brk(size_t size, size_t align)
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
[test_local_data_noerror]
|
[test_local_data_noerror]
|
||||||
96_nodata_wanted.c:25: warning: assignment makes integer from pointer without a cast
|
96_nodata_wanted.c:25: warning: assignment makes integer from pointer without a cast
|
||||||
96_nodata_wanted.c:25: warning: nonportable conversion from pointer to char/short
|
96_nodata_wanted.c:25: warning: cast between pointer and integer of different size
|
||||||
|
|
||||||
[test_data_suppression_off]
|
[test_data_suppression_off]
|
||||||
data:
|
data:
|
||||||
|
|
30
x86_64-gen.c
30
x86_64-gen.c
|
@ -524,7 +524,7 @@ void load(int r, SValue *sv)
|
||||||
o(0xf024);
|
o(0xf024);
|
||||||
o(0xf02444dd); /* fldl -0x10(%rsp) */
|
o(0xf02444dd); /* fldl -0x10(%rsp) */
|
||||||
} else {
|
} else {
|
||||||
orex(1,r,v, 0x89);
|
orex(is64_type(ft), r, v, 0x89);
|
||||||
o(0xc0 + REG_VALUE(r) + REG_VALUE(v) * 8); /* mov v, r */
|
o(0xc0 + REG_VALUE(r) + REG_VALUE(v) * 8); /* mov v, r */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -598,16 +598,13 @@ void store(int r, SValue *v)
|
||||||
if (fr == VT_CONST || fr == VT_LOCAL || (v->r & VT_LVAL)) {
|
if (fr == VT_CONST || fr == VT_LOCAL || (v->r & VT_LVAL)) {
|
||||||
gen_modrm64(op64, r, v->r, v->sym, fc);
|
gen_modrm64(op64, r, v->r, v->sym, fc);
|
||||||
} else if (fr != r) {
|
} else if (fr != r) {
|
||||||
/* XXX: don't we really come here? */
|
orex(1, fr, r, op64);
|
||||||
abort();
|
|
||||||
o(0xc0 + fr + r * 8); /* mov r, fr */
|
o(0xc0 + fr + r * 8); /* mov r, fr */
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (fr == VT_CONST || fr == VT_LOCAL || (v->r & VT_LVAL)) {
|
if (fr == VT_CONST || fr == VT_LOCAL || (v->r & VT_LVAL)) {
|
||||||
gen_modrm(r, v->r, v->sym, fc);
|
gen_modrm(r, v->r, v->sym, fc);
|
||||||
} else if (fr != r) {
|
} else if (fr != r) {
|
||||||
/* XXX: don't we really come here? */
|
|
||||||
abort();
|
|
||||||
o(0xc0 + fr + r * 8); /* mov r, fr */
|
o(0xc0 + fr + r * 8); /* mov r, fr */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2248,6 +2245,29 @@ void gen_cvt_ftoi(int t)
|
||||||
vtop->r = r;
|
vtop->r = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate sign extension from 32 to 64 bits:
|
||||||
|
ST_FUNC void gen_cvt_sxtw(void)
|
||||||
|
{
|
||||||
|
int r = gv(RC_INT);
|
||||||
|
/* x86_64 specific: movslq */
|
||||||
|
o(0x6348);
|
||||||
|
o(0xc0 + (REG_VALUE(r) << 3) + REG_VALUE(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* char/short to int conversion */
|
||||||
|
ST_FUNC void gen_cvt_csti(int t)
|
||||||
|
{
|
||||||
|
int r, sz, xl, ll;
|
||||||
|
r = gv(RC_INT);
|
||||||
|
sz = !(t & VT_UNSIGNED);
|
||||||
|
xl = (t & VT_BTYPE) == VT_SHORT;
|
||||||
|
ll = (vtop->type.t & VT_BTYPE) == VT_LLONG;
|
||||||
|
orex(ll, r, 0, 0xc0b60f /* mov[sz] %a[xl], %eax */
|
||||||
|
| (sz << 3 | xl) << 8
|
||||||
|
| (REG_VALUE(r) << 3 | REG_VALUE(r)) << 16
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/* computed goto support */
|
/* computed goto support */
|
||||||
void ggoto(void)
|
void ggoto(void)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue