tccgen.c: cleanup reg classes
wrap some copy&paste code into functions
This commit is contained in:
parent
ff3b5ee91c
commit
5914f4d57d
7 changed files with 246 additions and 287 deletions
12
arm-gen.c
12
arm-gen.c
|
@ -59,7 +59,7 @@
|
||||||
#define RC_F7 0x4000
|
#define RC_F7 0x4000
|
||||||
#endif
|
#endif
|
||||||
#define RC_IRET RC_R0 /* function return: integer register */
|
#define RC_IRET RC_R0 /* function return: integer register */
|
||||||
#define RC_LRET RC_R1 /* function return: second integer register */
|
#define RC_IRE2 RC_R1 /* function return: second integer register */
|
||||||
#define RC_FRET RC_F0 /* function return: float register */
|
#define RC_FRET RC_F0 /* function return: float register */
|
||||||
|
|
||||||
/* pretty names for the registers */
|
/* pretty names for the registers */
|
||||||
|
@ -89,7 +89,7 @@ enum {
|
||||||
|
|
||||||
/* return registers for function */
|
/* return registers for function */
|
||||||
#define REG_IRET TREG_R0 /* single word int return register */
|
#define REG_IRET TREG_R0 /* single word int return register */
|
||||||
#define REG_LRET TREG_R1 /* second word return register (for long long) */
|
#define REG_IRE2 TREG_R1 /* second word return register (for long long) */
|
||||||
#define REG_FRET TREG_F0 /* float return register */
|
#define REG_FRET TREG_F0 /* float return register */
|
||||||
|
|
||||||
#ifdef TCC_ARM_EABI
|
#ifdef TCC_ARM_EABI
|
||||||
|
@ -1542,7 +1542,7 @@ void gen_opi(int op)
|
||||||
case '%':
|
case '%':
|
||||||
#ifdef TCC_ARM_EABI
|
#ifdef TCC_ARM_EABI
|
||||||
func=TOK___aeabi_idivmod;
|
func=TOK___aeabi_idivmod;
|
||||||
retreg=REG_LRET;
|
retreg=REG_IRE2;
|
||||||
#else
|
#else
|
||||||
func=TOK___modsi3;
|
func=TOK___modsi3;
|
||||||
#endif
|
#endif
|
||||||
|
@ -1551,7 +1551,7 @@ void gen_opi(int op)
|
||||||
case TOK_UMOD:
|
case TOK_UMOD:
|
||||||
#ifdef TCC_ARM_EABI
|
#ifdef TCC_ARM_EABI
|
||||||
func=TOK___aeabi_uidivmod;
|
func=TOK___aeabi_uidivmod;
|
||||||
retreg=REG_LRET;
|
retreg=REG_IRE2;
|
||||||
#else
|
#else
|
||||||
func=TOK___umodsi3;
|
func=TOK___umodsi3;
|
||||||
#endif
|
#endif
|
||||||
|
@ -1942,7 +1942,7 @@ void gen_opf(int op)
|
||||||
|
|
||||||
/* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
|
/* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
|
||||||
and 'long long' cases. */
|
and 'long long' cases. */
|
||||||
ST_FUNC void gen_cvt_itof1(int t)
|
ST_FUNC void gen_cvt_itof(int t)
|
||||||
{
|
{
|
||||||
uint32_t r, r2;
|
uint32_t r, r2;
|
||||||
int bt;
|
int bt;
|
||||||
|
@ -2075,7 +2075,7 @@ void gen_cvt_ftoi(int t)
|
||||||
gfunc_call(1);
|
gfunc_call(1);
|
||||||
vpushi(0);
|
vpushi(0);
|
||||||
if(t == VT_LLONG)
|
if(t == VT_LLONG)
|
||||||
vtop->r2 = REG_LRET;
|
vtop->r2 = REG_IRE2;
|
||||||
vtop->r = REG_IRET;
|
vtop->r = REG_IRET;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
#define RC_C67_B12 0x04000000
|
#define RC_C67_B12 0x04000000
|
||||||
#define RC_C67_B13 0x08000000
|
#define RC_C67_B13 0x08000000
|
||||||
#define RC_IRET RC_C67_A4 /* function return: integer register */
|
#define RC_IRET RC_C67_A4 /* function return: integer register */
|
||||||
#define RC_LRET RC_C67_A5 /* function return: second integer register */
|
#define RC_IRE2 RC_C67_A5 /* function return: second integer register */
|
||||||
#define RC_FRET RC_C67_A4 /* function return: float register */
|
#define RC_FRET RC_C67_A4 /* function return: float register */
|
||||||
|
|
||||||
/* pretty names for the registers */
|
/* pretty names for the registers */
|
||||||
|
@ -89,7 +89,7 @@ enum {
|
||||||
|
|
||||||
/* return registers for function */
|
/* return registers for function */
|
||||||
#define REG_IRET TREG_C67_A4 /* single word int return register */
|
#define REG_IRET TREG_C67_A4 /* single word int return register */
|
||||||
#define REG_LRET TREG_C67_A5 /* second word return register (for long long) */
|
#define REG_IRE2 TREG_C67_A5 /* second word return register (for long long) */
|
||||||
#define REG_FRET TREG_C67_A4 /* float return register */
|
#define REG_FRET TREG_C67_A4 /* float return register */
|
||||||
|
|
||||||
/* defined if function parameters must be evaluated in reverse order */
|
/* defined if function parameters must be evaluated in reverse order */
|
||||||
|
@ -2392,7 +2392,7 @@ void gen_opf(int op)
|
||||||
gfunc_call(2);
|
gfunc_call(2);
|
||||||
vpushi(0);
|
vpushi(0);
|
||||||
vtop->r = REG_FRET;
|
vtop->r = REG_FRET;
|
||||||
vtop->r2 = REG_LRET;
|
vtop->r2 = REG_IRE2;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// must call intrinsic SP floating point divide
|
// must call intrinsic SP floating point divide
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
#define RC_EBX 0x0040
|
#define RC_EBX 0x0040
|
||||||
|
|
||||||
#define RC_IRET RC_EAX /* function return: integer register */
|
#define RC_IRET RC_EAX /* function return: integer register */
|
||||||
#define RC_LRET RC_EDX /* function return: second integer register */
|
#define RC_IRE2 RC_EDX /* function return: second integer register */
|
||||||
#define RC_FRET RC_ST0 /* function return: float register */
|
#define RC_FRET RC_ST0 /* function return: float register */
|
||||||
|
|
||||||
/* pretty names for the registers */
|
/* pretty names for the registers */
|
||||||
|
@ -52,7 +52,7 @@ enum {
|
||||||
|
|
||||||
/* return registers for function */
|
/* return registers for function */
|
||||||
#define REG_IRET TREG_EAX /* single word int return register */
|
#define REG_IRET TREG_EAX /* single word int return register */
|
||||||
#define REG_LRET TREG_EDX /* second word return register (for long long) */
|
#define REG_IRE2 TREG_EDX /* second word return register (for long long) */
|
||||||
#define REG_FRET TREG_ST0 /* float return register */
|
#define REG_FRET TREG_ST0 /* float return register */
|
||||||
|
|
||||||
/* defined if function parameters must be evaluated in reverse order */
|
/* defined if function parameters must be evaluated in reverse order */
|
||||||
|
@ -1004,6 +1004,7 @@ ST_FUNC void gen_cvt_itof(int t)
|
||||||
o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
|
o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
|
||||||
o(0x242cdf); /* fildll (%esp) */
|
o(0x242cdf); /* fildll (%esp) */
|
||||||
o(0x08c483); /* add $8, %esp */
|
o(0x08c483); /* add $8, %esp */
|
||||||
|
vtop->r2 = VT_CONST;
|
||||||
} else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) ==
|
} else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) ==
|
||||||
(VT_INT | VT_UNSIGNED)) {
|
(VT_INT | VT_UNSIGNED)) {
|
||||||
/* unsigned int to float/double/long double */
|
/* unsigned int to float/double/long double */
|
||||||
|
@ -1037,7 +1038,7 @@ ST_FUNC void gen_cvt_ftoi(int t)
|
||||||
vpushi(0);
|
vpushi(0);
|
||||||
vtop->r = REG_IRET;
|
vtop->r = REG_IRET;
|
||||||
if ((t & VT_BTYPE) == VT_LLONG)
|
if ((t & VT_BTYPE) == VT_LLONG)
|
||||||
vtop->r2 = REG_LRET;
|
vtop->r2 = REG_IRE2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert from one floating point type to another */
|
/* convert from one floating point type to another */
|
||||||
|
|
|
@ -13,9 +13,11 @@
|
||||||
#define RC_F(x) (1 << (10 + (x))) // x = 0..7
|
#define RC_F(x) (1 << (10 + (x))) // x = 0..7
|
||||||
|
|
||||||
#define RC_IRET (RC_R(0)) // int return register class
|
#define RC_IRET (RC_R(0)) // int return register class
|
||||||
|
#define RC_IRE2 (RC_R(1)) // int 2nd return register class
|
||||||
#define RC_FRET (RC_F(0)) // float return register class
|
#define RC_FRET (RC_F(0)) // float return register class
|
||||||
|
|
||||||
#define REG_IRET (TREG_R(0)) // int return register number
|
#define REG_IRET (TREG_R(0)) // int return register number
|
||||||
|
#define REG_IRE2 (TREG_R(1)) // int 2nd return register number
|
||||||
#define REG_FRET (TREG_F(0)) // float return register number
|
#define REG_FRET (TREG_F(0)) // float return register number
|
||||||
|
|
||||||
#define PTR_SIZE 8
|
#define PTR_SIZE 8
|
||||||
|
@ -744,8 +746,8 @@ ST_FUNC void gfunc_epilog(void)
|
||||||
EI(0x03, 3, 8, 2, d - 16 - num_va_regs * 8); // ld s0, v-16(sp)
|
EI(0x03, 3, 8, 2, d - 16 - num_va_regs * 8); // ld s0, v-16(sp)
|
||||||
EI(0x13, 0, 2, 2, d); // addi sp, sp, v
|
EI(0x13, 0, 2, 2, d); // addi sp, sp, v
|
||||||
EI(0x67, 0, 0, 1, 0); // jalr x0, 0(x1), aka ret
|
EI(0x67, 0, 0, 1, 0); // jalr x0, 0(x1), aka ret
|
||||||
|
large_ofs_ind = ind;
|
||||||
if (v >= (1 << 11)) {
|
if (v >= (1 << 11)) {
|
||||||
large_ofs_ind = ind;
|
|
||||||
EI(0x13, 0, 8, 2, d - num_va_regs * 8); // addi s0, sp, d
|
EI(0x13, 0, 8, 2, d - num_va_regs * 8); // addi s0, sp, d
|
||||||
o(0x37 | (5 << 7) | ((0x800 + (v-16)) & 0xfffff000)); //lui t0, upper(v)
|
o(0x37 | (5 << 7) | ((0x800 + (v-16)) & 0xfffff000)); //lui t0, upper(v)
|
||||||
EI(0x13, 0, 5, 5, (v-16) << 20 >> 20); // addi t0, t0, lo(v)
|
EI(0x13, 0, 5, 5, (v-16) << 20 >> 20); // addi t0, t0, lo(v)
|
||||||
|
|
9
tcc.h
9
tcc.h
|
@ -1521,10 +1521,6 @@ ST_FUNC void *tcc_get_symbol_err(TCCState *s, const char *name);
|
||||||
#ifndef TCC_TARGET_PE
|
#ifndef TCC_TARGET_PE
|
||||||
ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level);
|
ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level);
|
||||||
ST_FUNC int tcc_load_ldscript(TCCState *s1, int fd);
|
ST_FUNC int tcc_load_ldscript(TCCState *s1, int fd);
|
||||||
ST_FUNC uint8_t *parse_comment(uint8_t *p);
|
|
||||||
ST_FUNC void minp(void);
|
|
||||||
ST_INLN void inp(void);
|
|
||||||
ST_FUNC int handle_eob(void);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ------------ xxx-link.c ------------ */
|
/* ------------ xxx-link.c ------------ */
|
||||||
|
@ -1566,14 +1562,12 @@ ST_FUNC int gjmp_append(int n, int t);
|
||||||
ST_FUNC void gen_opi(int op);
|
ST_FUNC void gen_opi(int op);
|
||||||
ST_FUNC void gen_opf(int op);
|
ST_FUNC void gen_opf(int op);
|
||||||
ST_FUNC void gen_cvt_ftoi(int t);
|
ST_FUNC void gen_cvt_ftoi(int t);
|
||||||
|
ST_FUNC void gen_cvt_itof(int t);
|
||||||
ST_FUNC void gen_cvt_ftof(int t);
|
ST_FUNC void gen_cvt_ftof(int t);
|
||||||
ST_FUNC void ggoto(void);
|
ST_FUNC void ggoto(void);
|
||||||
#ifndef TCC_TARGET_C67
|
#ifndef TCC_TARGET_C67
|
||||||
ST_FUNC void o(unsigned int c);
|
ST_FUNC void o(unsigned int c);
|
||||||
#endif
|
#endif
|
||||||
#ifndef TCC_TARGET_ARM
|
|
||||||
ST_FUNC void gen_cvt_itof(int t);
|
|
||||||
#endif
|
|
||||||
ST_FUNC void gen_vla_sp_save(int addr);
|
ST_FUNC void gen_vla_sp_save(int addr);
|
||||||
ST_FUNC void gen_vla_sp_restore(int addr);
|
ST_FUNC void gen_vla_sp_restore(int addr);
|
||||||
ST_FUNC void gen_vla_alloc(CType *type, int align);
|
ST_FUNC void gen_vla_alloc(CType *type, int align);
|
||||||
|
@ -1632,7 +1626,6 @@ ST_FUNC void gen_vla_result(int addr);
|
||||||
PUB_FUNC const char *default_elfinterp(struct TCCState *s);
|
PUB_FUNC const char *default_elfinterp(struct TCCState *s);
|
||||||
#endif
|
#endif
|
||||||
ST_FUNC void arm_init(struct TCCState *s);
|
ST_FUNC void arm_init(struct TCCState *s);
|
||||||
ST_FUNC void gen_cvt_itof1(int t);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ------------ arm64-gen.c ------------ */
|
/* ------------ arm64-gen.c ------------ */
|
||||||
|
|
487
tccgen.c
487
tccgen.c
|
@ -152,9 +152,112 @@ static void clear_temp_local_var_list();
|
||||||
|
|
||||||
ST_INLN int is_float(int t)
|
ST_INLN int is_float(int t)
|
||||||
{
|
{
|
||||||
int bt;
|
int bt = t & VT_BTYPE;
|
||||||
bt = t & VT_BTYPE;
|
return bt == VT_LDOUBLE
|
||||||
return bt == VT_LDOUBLE || bt == VT_DOUBLE || bt == VT_FLOAT || bt == VT_QFLOAT;
|
|| bt == VT_DOUBLE
|
||||||
|
|| bt == VT_FLOAT
|
||||||
|
|| bt == VT_QFLOAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int is_integer_btype(int bt)
|
||||||
|
{
|
||||||
|
return bt == VT_BYTE
|
||||||
|
|| bt == VT_SHORT
|
||||||
|
|| bt == VT_INT
|
||||||
|
|| bt == VT_LLONG;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int btype_size(int bt)
|
||||||
|
{
|
||||||
|
return bt == VT_BYTE || bt == VT_BOOL ? 1 :
|
||||||
|
bt == VT_SHORT ? 2 :
|
||||||
|
bt == VT_INT ? 4 :
|
||||||
|
bt == VT_LLONG ? 8 :
|
||||||
|
bt == VT_PTR ? PTR_SIZE : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns function return register from type */
|
||||||
|
static int R_RET(int t)
|
||||||
|
{
|
||||||
|
if (!is_float(t))
|
||||||
|
return REG_IRET;
|
||||||
|
#ifdef TCC_TARGET_X86_64
|
||||||
|
if ((t & VT_BTYPE) == VT_LDOUBLE)
|
||||||
|
return TREG_ST0;
|
||||||
|
#elif defined TCC_TARGET_RISCV64
|
||||||
|
if ((t & VT_BTYPE) == VT_LDOUBLE)
|
||||||
|
return REG_IRET;
|
||||||
|
#endif
|
||||||
|
return REG_FRET;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns 2nd function return register, if any */
|
||||||
|
static int R2_RET(int t)
|
||||||
|
{
|
||||||
|
t &= VT_BTYPE;
|
||||||
|
#if PTR_SIZE == 4
|
||||||
|
if (t == VT_LLONG)
|
||||||
|
return REG_IRE2;
|
||||||
|
#elif defined TCC_TARGET_X86_64
|
||||||
|
if (t == VT_QLONG)
|
||||||
|
return REG_IRE2;
|
||||||
|
if (t == VT_QFLOAT)
|
||||||
|
return REG_FRE2;
|
||||||
|
#elif defined TCC_TARGET_RISCV64
|
||||||
|
if (t == VT_LDOUBLE)
|
||||||
|
return REG_IRE2;
|
||||||
|
#endif
|
||||||
|
return VT_CONST;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns true for two-word types */
|
||||||
|
#define USING_TWO_WORDS(t) (R2_RET(t) != VT_CONST)
|
||||||
|
|
||||||
|
/* put function return registers to stack value */
|
||||||
|
static void PUT_R_RET(SValue *sv, int t)
|
||||||
|
{
|
||||||
|
sv->r = R_RET(t), sv->r2 = R2_RET(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns function return register class for type t */
|
||||||
|
static int RC_RET(int t)
|
||||||
|
{
|
||||||
|
return reg_classes[R_RET(t)] & ~(RC_FLOAT | RC_INT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns generic register class for type t */
|
||||||
|
static int RC_TYPE(int t)
|
||||||
|
{
|
||||||
|
if (!is_float(t))
|
||||||
|
return RC_INT;
|
||||||
|
#ifdef TCC_TARGET_X86_64
|
||||||
|
if ((t & VT_BTYPE) == VT_LDOUBLE)
|
||||||
|
return RC_ST0;
|
||||||
|
if ((t & VT_BTYPE) == VT_QFLOAT)
|
||||||
|
return RC_FRET;
|
||||||
|
#elif defined TCC_TARGET_RISCV64
|
||||||
|
if ((t & VT_BTYPE) == VT_LDOUBLE)
|
||||||
|
return RC_INT;
|
||||||
|
#endif
|
||||||
|
return RC_FLOAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns 2nd register class corresponding to t and rc */
|
||||||
|
static int RC2_TYPE(int t, int rc)
|
||||||
|
{
|
||||||
|
if (!USING_TWO_WORDS(t))
|
||||||
|
return 0;
|
||||||
|
#ifdef RC_IRE2
|
||||||
|
if (rc == RC_IRET)
|
||||||
|
return RC_IRE2;
|
||||||
|
#endif
|
||||||
|
#ifdef RC_FRE2
|
||||||
|
if (rc == RC_FRET)
|
||||||
|
return RC_FRE2;
|
||||||
|
#endif
|
||||||
|
if (rc & RC_FLOAT)
|
||||||
|
return RC_FLOAT;
|
||||||
|
return RC_INT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we use our own 'finite' function to avoid potential problems with
|
/* we use our own 'finite' function to avoid potential problems with
|
||||||
|
@ -1291,11 +1394,8 @@ ST_FUNC void save_reg_upstack(int r, int n)
|
||||||
o(0xd8dd); /* fstp %st(0) */
|
o(0xd8dd); /* fstp %st(0) */
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* special long long case. Ideally r2 would always
|
/* special long long case */
|
||||||
be VT_CONST is the type is smaller than a double-word
|
if (p->r2 < VT_CONST && USING_TWO_WORDS(type->t)) {
|
||||||
type. Not all routines (e.g. gen_cast with _ftoi) are
|
|
||||||
careful to clear r2, though. */
|
|
||||||
if ((p->r2 & VT_VALMASK) < VT_CONST && size > PTR_SIZE) {
|
|
||||||
sv.c.i += PTR_SIZE;
|
sv.c.i += PTR_SIZE;
|
||||||
store(p->r2, &sv);
|
store(p->r2, &sv);
|
||||||
}
|
}
|
||||||
|
@ -1598,7 +1698,8 @@ static int adjust_bf(SValue *sv, int bit_pos, int bit_size)
|
||||||
register value (such as structures). */
|
register value (such as structures). */
|
||||||
ST_FUNC int gv(int rc)
|
ST_FUNC int gv(int rc)
|
||||||
{
|
{
|
||||||
int r, bit_pos, bit_size, size, align, rc2;
|
int r, r2, r_ok, r2_ok, rc2, bt;
|
||||||
|
int bit_pos, bit_size, size, align;
|
||||||
|
|
||||||
/* NOTE: get_reg can modify vstack[] */
|
/* NOTE: get_reg can modify vstack[] */
|
||||||
if (vtop->type.t & VT_BITFIELD) {
|
if (vtop->type.t & VT_BITFIELD) {
|
||||||
|
@ -1654,94 +1755,62 @@ ST_FUNC int gv(int rc)
|
||||||
if (vtop->r & VT_MUSTBOUND)
|
if (vtop->r & VT_MUSTBOUND)
|
||||||
gbound();
|
gbound();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bt = vtop->type.t & VT_BTYPE;
|
||||||
|
|
||||||
#ifdef TCC_TARGET_RISCV64
|
#ifdef TCC_TARGET_RISCV64
|
||||||
/* XXX mega hack */
|
/* XXX mega hack */
|
||||||
if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE && rc == RC_FLOAT)
|
if (bt == VT_LDOUBLE && rc == RC_FLOAT)
|
||||||
rc = RC_INT;
|
rc = RC_INT;
|
||||||
#endif
|
#endif
|
||||||
|
rc2 = RC2_TYPE(bt, rc);
|
||||||
|
|
||||||
r = vtop->r & VT_VALMASK;
|
|
||||||
rc2 = (rc & RC_FLOAT) ? RC_FLOAT : RC_INT;
|
|
||||||
#ifndef TCC_TARGET_ARM64
|
|
||||||
#ifndef TCC_TARGET_RISCV64 /* XXX: remove the whole LRET/QRET class */
|
|
||||||
if (rc == RC_IRET)
|
|
||||||
rc2 = RC_LRET;
|
|
||||||
#ifdef TCC_TARGET_X86_64
|
|
||||||
else if (rc == RC_FRET)
|
|
||||||
rc2 = RC_QRET;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
/* need to reload if:
|
/* need to reload if:
|
||||||
- constant
|
- constant
|
||||||
- lvalue (need to dereference pointer)
|
- lvalue (need to dereference pointer)
|
||||||
- already a register, but not in the right class */
|
- already a register, but not in the right class */
|
||||||
if (r >= VT_CONST
|
r = vtop->r & VT_VALMASK;
|
||||||
|| (vtop->r & VT_LVAL)
|
r_ok = !(vtop->r & VT_LVAL) && (r < VT_CONST) && (reg_classes[r] & rc);
|
||||||
|| !(reg_classes[r] & rc)
|
r2_ok = !rc2 || ((vtop->r2 < VT_CONST) && (reg_classes[vtop->r2] & rc2));
|
||||||
#ifdef TCC_TARGET_RISCV64
|
|
||||||
|| ((vtop->type.t & VT_BTYPE) == VT_QLONG && (vtop->r2 >= NB_REGS || !(reg_classes[vtop->r2] & rc2)))
|
if (!r_ok || !r2_ok) {
|
||||||
|| ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE && (vtop->r2 >= NB_REGS || !(reg_classes[vtop->r2] & rc2)))
|
if (!r_ok)
|
||||||
#elif PTR_SIZE == 8
|
r = get_reg(rc);
|
||||||
|| ((vtop->type.t & VT_BTYPE) == VT_QLONG && !(reg_classes[vtop->r2] & rc2))
|
if (rc2) {
|
||||||
|| ((vtop->type.t & VT_BTYPE) == VT_QFLOAT && !(reg_classes[vtop->r2] & rc2))
|
int load_type = (bt == VT_QFLOAT) ? VT_DOUBLE : ptrdiff_type.t;
|
||||||
#else
|
int original_type = vtop->type.t;
|
||||||
|| ((vtop->type.t & VT_BTYPE) == VT_LLONG && !(reg_classes[vtop->r2] & rc2))
|
|
||||||
#endif
|
/* two register type load :
|
||||||
)
|
expand to two words temporarily */
|
||||||
{
|
|
||||||
r = get_reg(rc);
|
|
||||||
#ifdef TCC_TARGET_RISCV64
|
|
||||||
if (((vtop->type.t & VT_BTYPE) == VT_QLONG) || ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE)) {
|
|
||||||
int addr_type = VT_LLONG, load_size = 8, load_type = VT_LLONG;
|
|
||||||
#elif PTR_SIZE == 8
|
|
||||||
if (((vtop->type.t & VT_BTYPE) == VT_QLONG) || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT)) {
|
|
||||||
int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE;
|
|
||||||
#else
|
|
||||||
if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
|
|
||||||
int addr_type = VT_INT, load_size = 4, load_type = VT_INT;
|
|
||||||
unsigned long long ll;
|
|
||||||
#endif
|
|
||||||
int r2, original_type;
|
|
||||||
original_type = vtop->type.t;
|
|
||||||
/* two register type load : expand to two words
|
|
||||||
temporarily */
|
|
||||||
#if PTR_SIZE == 4
|
|
||||||
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
|
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
|
||||||
/* load constant */
|
/* load constant */
|
||||||
ll = vtop->c.i;
|
unsigned long long ll = vtop->c.i;
|
||||||
vtop->c.i = ll; /* first word */
|
vtop->c.i = ll; /* first word */
|
||||||
load(r, vtop);
|
load(r, vtop);
|
||||||
vtop->r = r; /* save register value */
|
vtop->r = r; /* save register value */
|
||||||
vpushi(ll >> 32); /* second word */
|
vpushi(ll >> 32); /* second word */
|
||||||
} else
|
} else if (vtop->r & VT_LVAL) {
|
||||||
#endif
|
/* We do not want to modifier the long long pointer here.
|
||||||
if (vtop->r & VT_LVAL) {
|
So we save any other instances down the stack */
|
||||||
/* We do not want to modifier the long long
|
|
||||||
pointer here, so the safest (and less
|
|
||||||
efficient) is to save all the other registers
|
|
||||||
in the stack. XXX: totally inefficient. */
|
|
||||||
#if 0
|
|
||||||
save_regs(1);
|
|
||||||
#else
|
|
||||||
/* lvalue_save: save only if used further down the stack */
|
|
||||||
save_reg_upstack(vtop->r, 1);
|
save_reg_upstack(vtop->r, 1);
|
||||||
#endif
|
|
||||||
/* load from memory */
|
/* load from memory */
|
||||||
vtop->type.t = load_type;
|
vtop->type.t = load_type;
|
||||||
load(r, vtop);
|
load(r, vtop);
|
||||||
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 = addr_type;
|
vtop->type.t = ptrdiff_type.t;
|
||||||
gaddrof();
|
gaddrof();
|
||||||
vpushi(load_size);
|
vpushi(PTR_SIZE);
|
||||||
gen_op('+');
|
gen_op('+');
|
||||||
vtop->r |= VT_LVAL;
|
vtop->r |= VT_LVAL;
|
||||||
vtop->type.t = load_type;
|
vtop->type.t = load_type;
|
||||||
} else {
|
} else {
|
||||||
/* move registers */
|
/* move registers */
|
||||||
load(r, vtop);
|
if (!r_ok)
|
||||||
|
load(r, vtop);
|
||||||
|
if (r2_ok && vtop->r2 < VT_CONST)
|
||||||
|
goto done;
|
||||||
vdup();
|
vdup();
|
||||||
vtop[-1].r = r; /* save register value */
|
vtop[-1].r = r; /* save register value */
|
||||||
vtop->r = vtop[-1].r2;
|
vtop->r = vtop[-1].r2;
|
||||||
|
@ -1753,6 +1822,7 @@ ST_FUNC int gv(int rc)
|
||||||
vpop();
|
vpop();
|
||||||
/* write second register */
|
/* write second register */
|
||||||
vtop->r2 = r2;
|
vtop->r2 = r2;
|
||||||
|
done:
|
||||||
vtop->type.t = original_type;
|
vtop->type.t = original_type;
|
||||||
} else if ((vtop->r & VT_LVAL) && !is_float(vtop->type.t)) {
|
} else if ((vtop->r & VT_LVAL) && !is_float(vtop->type.t)) {
|
||||||
int t1, t;
|
int t1, t;
|
||||||
|
@ -1781,7 +1851,7 @@ ST_FUNC int gv(int rc)
|
||||||
vtop->r = r;
|
vtop->r = r;
|
||||||
#ifdef TCC_TARGET_C67
|
#ifdef TCC_TARGET_C67
|
||||||
/* uses register pairs for doubles */
|
/* uses register pairs for doubles */
|
||||||
if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
|
if (bt == VT_DOUBLE)
|
||||||
vtop->r2 = r+1;
|
vtop->r2 = r+1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -1817,36 +1887,6 @@ ST_FUNC void gv2(int rc1, int rc2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TCC_TARGET_ARM64
|
|
||||||
/* wrapper around RC_FRET to return a register by type */
|
|
||||||
static int rc_fret(int t)
|
|
||||||
{
|
|
||||||
#ifdef TCC_TARGET_X86_64
|
|
||||||
if (t == VT_LDOUBLE) {
|
|
||||||
return RC_ST0;
|
|
||||||
}
|
|
||||||
#elif defined TCC_TARGET_RISCV64
|
|
||||||
if (t == VT_LDOUBLE)
|
|
||||||
return RC_IRET;
|
|
||||||
#endif
|
|
||||||
return RC_FRET;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* wrapper around REG_FRET to return a register by type */
|
|
||||||
static int reg_fret(int t)
|
|
||||||
{
|
|
||||||
#ifdef TCC_TARGET_X86_64
|
|
||||||
if (t == VT_LDOUBLE) {
|
|
||||||
return TREG_ST0;
|
|
||||||
}
|
|
||||||
#elif defined TCC_TARGET_RISCV64
|
|
||||||
if (t == VT_LDOUBLE)
|
|
||||||
return REG_IRET;
|
|
||||||
#endif
|
|
||||||
return REG_FRET;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if PTR_SIZE == 4
|
#if PTR_SIZE == 4
|
||||||
/* expand 64bit on stack in two ints */
|
/* expand 64bit on stack in two ints */
|
||||||
ST_FUNC void lexpand(void)
|
ST_FUNC void lexpand(void)
|
||||||
|
@ -1885,8 +1925,7 @@ static void lbuild(int t)
|
||||||
register */
|
register */
|
||||||
static void gv_dup(void)
|
static void gv_dup(void)
|
||||||
{
|
{
|
||||||
int rc, t, r, r1;
|
int t, rc, r;
|
||||||
SValue sv;
|
|
||||||
|
|
||||||
t = vtop->type.t;
|
t = vtop->type.t;
|
||||||
#if PTR_SIZE == 4
|
#if PTR_SIZE == 4
|
||||||
|
@ -1908,34 +1947,16 @@ static void gv_dup(void)
|
||||||
vswap();
|
vswap();
|
||||||
lbuild(t);
|
lbuild(t);
|
||||||
vswap();
|
vswap();
|
||||||
} else
|
return;
|
||||||
#endif
|
|
||||||
{
|
|
||||||
/* duplicate value */
|
|
||||||
rc = RC_INT;
|
|
||||||
sv.type.t = VT_INT;
|
|
||||||
if (is_float(t)) {
|
|
||||||
rc = RC_FLOAT;
|
|
||||||
#ifdef TCC_TARGET_X86_64
|
|
||||||
if ((t & VT_BTYPE) == VT_LDOUBLE) {
|
|
||||||
rc = RC_ST0;
|
|
||||||
}
|
|
||||||
#elif defined TCC_TARGET_RISCV64
|
|
||||||
if ((t & VT_BTYPE) == VT_LDOUBLE)
|
|
||||||
rc = RC_INT;
|
|
||||||
#endif
|
|
||||||
sv.type.t = t;
|
|
||||||
}
|
|
||||||
r = gv(rc);
|
|
||||||
r1 = get_reg(rc);
|
|
||||||
sv.r = r;
|
|
||||||
sv.c.i = 0;
|
|
||||||
load(r1, &sv); /* move r to r1 */
|
|
||||||
vdup();
|
|
||||||
/* duplicates value */
|
|
||||||
if (r != r1)
|
|
||||||
vtop->r = r1;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
/* duplicate value */
|
||||||
|
rc = RC_TYPE(t);
|
||||||
|
gv(rc);
|
||||||
|
r = get_reg(rc);
|
||||||
|
vdup();
|
||||||
|
load(r, vtop);
|
||||||
|
vtop->r = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PTR_SIZE == 4
|
#if PTR_SIZE == 4
|
||||||
|
@ -1945,7 +1966,7 @@ static void gen_opl(int op)
|
||||||
int t, a, b, op1, c, i;
|
int t, a, b, op1, c, i;
|
||||||
int func;
|
int func;
|
||||||
unsigned short reg_iret = REG_IRET;
|
unsigned short reg_iret = REG_IRET;
|
||||||
unsigned short reg_lret = REG_LRET;
|
unsigned short reg_lret = REG_IRE2;
|
||||||
SValue tmp;
|
SValue tmp;
|
||||||
|
|
||||||
switch(op) {
|
switch(op) {
|
||||||
|
@ -2422,11 +2443,6 @@ static inline int is_null_pointer(SValue *p)
|
||||||
0 == (pointed_type(&p->type)->t & (VT_CONSTANT | VT_VOLATILE))
|
0 == (pointed_type(&p->type)->t & (VT_CONSTANT | VT_VOLATILE))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
static inline int is_integer_btype(int bt)
|
|
||||||
{
|
|
||||||
return (bt == VT_BYTE || bt == VT_SHORT ||
|
|
||||||
bt == VT_INT || bt == VT_LLONG);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check types for comparison or subtraction of pointers */
|
/* check types for comparison or subtraction of pointers */
|
||||||
static void check_comparison_pointer_types(SValue *p1, SValue *p2, int op)
|
static void check_comparison_pointer_types(SValue *p1, SValue *p2, int op)
|
||||||
|
@ -2664,13 +2680,12 @@ redo:
|
||||||
gv(is_float(vtop->type.t & VT_BTYPE) ? RC_FLOAT : RC_INT);
|
gv(is_float(vtop->type.t & VT_BTYPE) ? RC_FLOAT : RC_INT);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TCC_TARGET_ARM
|
#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64 || defined TCC_TARGET_ARM
|
||||||
|
#define gen_cvt_itof1 gen_cvt_itof
|
||||||
|
#else
|
||||||
/* generic itof for unsigned long long case */
|
/* generic itof for unsigned long long case */
|
||||||
static void gen_cvt_itof1(int t)
|
static void gen_cvt_itof1(int t)
|
||||||
{
|
{
|
||||||
#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64
|
|
||||||
gen_cvt_itof(t);
|
|
||||||
#else
|
|
||||||
if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) ==
|
if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) ==
|
||||||
(VT_LLONG | VT_UNSIGNED)) {
|
(VT_LLONG | VT_UNSIGNED)) {
|
||||||
|
|
||||||
|
@ -2685,22 +2700,20 @@ static void gen_cvt_itof1(int t)
|
||||||
vrott(2);
|
vrott(2);
|
||||||
gfunc_call(1);
|
gfunc_call(1);
|
||||||
vpushi(0);
|
vpushi(0);
|
||||||
vtop->r = reg_fret(t);
|
PUT_R_RET(vtop, t);
|
||||||
} else {
|
} else {
|
||||||
gen_cvt_itof(t);
|
gen_cvt_itof(t);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64
|
||||||
|
#define gen_cvt_ftoi1 gen_cvt_ftoi
|
||||||
|
#else
|
||||||
/* generic ftoi for unsigned long long case */
|
/* generic ftoi for unsigned long long case */
|
||||||
static void gen_cvt_ftoi1(int t)
|
static void gen_cvt_ftoi1(int t)
|
||||||
{
|
{
|
||||||
#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64
|
|
||||||
gen_cvt_ftoi(t);
|
|
||||||
#else
|
|
||||||
int st;
|
int st;
|
||||||
|
|
||||||
if (t == (VT_LLONG | VT_UNSIGNED)) {
|
if (t == (VT_LLONG | VT_UNSIGNED)) {
|
||||||
/* not handled natively */
|
/* not handled natively */
|
||||||
st = vtop->type.t & VT_BTYPE;
|
st = vtop->type.t & VT_BTYPE;
|
||||||
|
@ -2715,15 +2728,12 @@ static void gen_cvt_ftoi1(int t)
|
||||||
vrott(2);
|
vrott(2);
|
||||||
gfunc_call(1);
|
gfunc_call(1);
|
||||||
vpushi(0);
|
vpushi(0);
|
||||||
vtop->r = REG_IRET;
|
PUT_R_RET(vtop, t);
|
||||||
#if PTR_SIZE == 4
|
|
||||||
vtop->r2 = REG_LRET;
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
gen_cvt_ftoi(t);
|
gen_cvt_ftoi(t);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* force char or short cast */
|
/* force char or short cast */
|
||||||
static void force_charshort_cast(int t)
|
static void force_charshort_cast(int t)
|
||||||
|
@ -3311,9 +3321,8 @@ static void type_to_str(char *buf, int buf_size,
|
||||||
no_var: ;
|
no_var: ;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* verify type compatibility to store vtop in 'dt' type, and generate
|
/* verify type compatibility to store vtop in 'dt' type */
|
||||||
casts if needed. */
|
static void verify_assign_cast(CType *dt)
|
||||||
static void gen_assign_cast(CType *dt)
|
|
||||||
{
|
{
|
||||||
CType *st, *type1, *type2;
|
CType *st, *type1, *type2;
|
||||||
char buf1[256], buf2[256];
|
char buf1[256], buf2[256];
|
||||||
|
@ -3401,31 +3410,24 @@ static void gen_assign_cast(CType *dt)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_assign_cast(CType *dt)
|
||||||
|
{
|
||||||
|
verify_assign_cast(dt);
|
||||||
gen_cast(dt);
|
gen_cast(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* store vtop in lvalue pushed on stack */
|
/* store vtop in lvalue pushed on stack */
|
||||||
ST_FUNC void vstore(void)
|
ST_FUNC void vstore(void)
|
||||||
{
|
{
|
||||||
int sbt, dbt, ft, r, t, size, align, bit_size, bit_pos, rc, delayed_cast;
|
int sbt, dbt, ft, r, size, align, bit_size, bit_pos, delayed_cast;
|
||||||
|
|
||||||
ft = vtop[-1].type.t;
|
ft = vtop[-1].type.t;
|
||||||
sbt = vtop->type.t & VT_BTYPE;
|
sbt = vtop->type.t & VT_BTYPE;
|
||||||
dbt = ft & VT_BTYPE;
|
dbt = ft & VT_BTYPE;
|
||||||
if ((((sbt == VT_INT || sbt == VT_SHORT) && dbt == VT_BYTE) ||
|
|
||||||
(sbt == VT_INT && dbt == VT_SHORT))
|
verify_assign_cast(&vtop[-1].type);
|
||||||
&& !(vtop->type.t & VT_BITFIELD)) {
|
|
||||||
/* optimize char/short casts */
|
|
||||||
delayed_cast = VT_MUSTCAST;
|
|
||||||
vtop->type.t = ft & VT_TYPE;
|
|
||||||
/* XXX: factorize */
|
|
||||||
if (ft & VT_CONSTANT)
|
|
||||||
tcc_warning("assignment of read-only location");
|
|
||||||
} else {
|
|
||||||
delayed_cast = 0;
|
|
||||||
if (!(ft & VT_BITFIELD))
|
|
||||||
gen_assign_cast(&vtop[-1].type);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sbt == VT_STRUCT) {
|
if (sbt == VT_STRUCT) {
|
||||||
/* if structure, only generate pointer */
|
/* if structure, only generate pointer */
|
||||||
|
@ -3457,8 +3459,8 @@ ST_FUNC void vstore(void)
|
||||||
/* type size */
|
/* type size */
|
||||||
vpushi(size);
|
vpushi(size);
|
||||||
gfunc_call(3);
|
gfunc_call(3);
|
||||||
|
|
||||||
/* leave source on stack */
|
/* leave source on stack */
|
||||||
|
|
||||||
} else if (ft & VT_BITFIELD) {
|
} else if (ft & VT_BITFIELD) {
|
||||||
/* bitfield store handling */
|
/* bitfield store handling */
|
||||||
|
|
||||||
|
@ -3470,20 +3472,22 @@ ST_FUNC void vstore(void)
|
||||||
/* remove bit field info to avoid loops */
|
/* remove bit field info to avoid loops */
|
||||||
vtop[-1].type.t = ft & ~VT_STRUCT_MASK;
|
vtop[-1].type.t = ft & ~VT_STRUCT_MASK;
|
||||||
|
|
||||||
if ((ft & VT_BTYPE) == VT_BOOL) {
|
if (dbt == VT_BOOL) {
|
||||||
gen_cast(&vtop[-1].type);
|
gen_cast(&vtop[-1].type);
|
||||||
vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED);
|
vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED);
|
||||||
}
|
}
|
||||||
|
|
||||||
r = adjust_bf(vtop - 1, bit_pos, bit_size);
|
r = adjust_bf(vtop - 1, bit_pos, bit_size);
|
||||||
|
if (dbt != VT_BOOL) {
|
||||||
|
gen_cast(&vtop[-1].type);
|
||||||
|
dbt = vtop[-1].type.t & VT_BTYPE;
|
||||||
|
}
|
||||||
if (r == VT_STRUCT) {
|
if (r == VT_STRUCT) {
|
||||||
gen_cast_s((ft & VT_BTYPE) == VT_LLONG ? VT_LLONG : VT_INT);
|
|
||||||
store_packed_bf(bit_pos, bit_size);
|
store_packed_bf(bit_pos, bit_size);
|
||||||
} else {
|
} else {
|
||||||
unsigned long long mask = (1ULL << bit_size) - 1;
|
unsigned long long mask = (1ULL << bit_size) - 1;
|
||||||
if ((ft & VT_BTYPE) != VT_BOOL) {
|
if (dbt != VT_BOOL) {
|
||||||
/* mask source */
|
/* mask source */
|
||||||
if ((vtop[-1].type.t & VT_BTYPE) == VT_LLONG)
|
if (dbt == VT_LLONG)
|
||||||
vpushll(mask);
|
vpushll(mask);
|
||||||
else
|
else
|
||||||
vpushi((unsigned)mask);
|
vpushi((unsigned)mask);
|
||||||
|
@ -3497,7 +3501,7 @@ ST_FUNC void vstore(void)
|
||||||
vdup();
|
vdup();
|
||||||
vrott(3);
|
vrott(3);
|
||||||
/* load destination, mask and or with source */
|
/* load destination, mask and or with source */
|
||||||
if ((vtop->type.t & VT_BTYPE) == VT_LLONG)
|
if (dbt == VT_LLONG)
|
||||||
vpushll(~(mask << bit_pos));
|
vpushll(~(mask << bit_pos));
|
||||||
else
|
else
|
||||||
vpushi(~((unsigned)mask << bit_pos));
|
vpushi(~((unsigned)mask << bit_pos));
|
||||||
|
@ -3511,6 +3515,20 @@ ST_FUNC void vstore(void)
|
||||||
} else if (dbt == VT_VOID) {
|
} else if (dbt == VT_VOID) {
|
||||||
--vtop;
|
--vtop;
|
||||||
} else {
|
} else {
|
||||||
|
/* optimize char/short casts */
|
||||||
|
delayed_cast = 0;
|
||||||
|
if ((dbt == VT_BYTE || dbt == VT_SHORT)
|
||||||
|
&& is_integer_btype(sbt)
|
||||||
|
) {
|
||||||
|
if ((vtop->r & VT_MUSTCAST)
|
||||||
|
&& btype_size(dbt) > btype_size(sbt)
|
||||||
|
)
|
||||||
|
force_charshort_cast(dbt);
|
||||||
|
delayed_cast = 1;
|
||||||
|
} else {
|
||||||
|
gen_cast(&vtop[-1].type);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
/* bound check case */
|
/* bound check case */
|
||||||
if (vtop[-1].r & VT_MUSTBOUND) {
|
if (vtop[-1].r & VT_MUSTBOUND) {
|
||||||
|
@ -3519,53 +3537,37 @@ ST_FUNC void vstore(void)
|
||||||
vswap();
|
vswap();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
rc = RC_INT;
|
gv(RC_TYPE(dbt)); /* generate value */
|
||||||
if (is_float(ft)) {
|
|
||||||
rc = RC_FLOAT;
|
if (delayed_cast) {
|
||||||
#ifdef TCC_TARGET_X86_64
|
vtop->r |= VT_MUSTCAST;
|
||||||
if ((ft & VT_BTYPE) == VT_LDOUBLE) {
|
//tcc_warning("deley cast %x -> %x", sbt, dbt);
|
||||||
rc = RC_ST0;
|
vtop->type.t = ft & VT_TYPE;
|
||||||
} else if ((ft & VT_BTYPE) == VT_QFLOAT) {
|
|
||||||
rc = RC_FRET;
|
|
||||||
}
|
|
||||||
#elif defined TCC_TARGET_RISCV64
|
|
||||||
if (dbt == VT_LDOUBLE)
|
|
||||||
rc = RC_INT;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
r = gv(rc); /* generate value */
|
|
||||||
/* if lvalue was saved on stack, must read it */
|
/* if lvalue was saved on stack, must read it */
|
||||||
if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) {
|
if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) {
|
||||||
SValue sv;
|
SValue sv;
|
||||||
t = get_reg(RC_INT);
|
r = get_reg(RC_INT);
|
||||||
#if PTR_SIZE == 8
|
sv.type.t = ptrdiff_type.t;
|
||||||
sv.type.t = VT_PTR;
|
|
||||||
#else
|
|
||||||
sv.type.t = VT_INT;
|
|
||||||
#endif
|
|
||||||
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(t, &sv);
|
load(r, &sv);
|
||||||
vtop[-1].r = t | VT_LVAL;
|
vtop[-1].r = r | VT_LVAL;
|
||||||
}
|
}
|
||||||
/* two word case handling : store second register at word + 4 (or +8 for x86-64) */
|
|
||||||
#ifdef TCC_TARGET_RISCV64
|
r = vtop->r & VT_VALMASK;
|
||||||
if (dbt == VT_QLONG || dbt == VT_LDOUBLE) {
|
/* two word case handling :
|
||||||
int addr_type = VT_LLONG, load_size = 8, load_type = VT_LLONG;
|
store second register at word + 4 (or +8 for x86-64) */
|
||||||
#elif PTR_SIZE == 8
|
if (USING_TWO_WORDS(dbt)) {
|
||||||
if (((ft & VT_BTYPE) == VT_QLONG) || ((ft & VT_BTYPE) == VT_QFLOAT)) {
|
int load_type = (dbt == VT_QFLOAT) ? VT_DOUBLE : ptrdiff_type.t;
|
||||||
int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE;
|
|
||||||
#else
|
|
||||||
if ((ft & VT_BTYPE) == VT_LLONG) {
|
|
||||||
int addr_type = VT_INT, load_size = 4, load_type = VT_INT;
|
|
||||||
#endif
|
|
||||||
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 = addr_type;
|
vtop->type.t = ptrdiff_type.t;
|
||||||
gaddrof();
|
gaddrof();
|
||||||
vpushi(load_size);
|
vpushs(PTR_SIZE);
|
||||||
gen_op('+');
|
gen_op('+');
|
||||||
vtop->r |= VT_LVAL;
|
vtop->r |= VT_LVAL;
|
||||||
vswap();
|
vswap();
|
||||||
|
@ -3573,12 +3575,11 @@ ST_FUNC void vstore(void)
|
||||||
/* XXX: it works because r2 is spilled last ! */
|
/* XXX: it works because r2 is spilled last ! */
|
||||||
store(vtop->r2, vtop - 1);
|
store(vtop->r2, vtop - 1);
|
||||||
} else {
|
} else {
|
||||||
|
/* single word */
|
||||||
store(r, vtop - 1);
|
store(r, vtop - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
vswap();
|
vswap();
|
||||||
vtop--; /* NOT vpop() because on x86 it would flush the fp stack */
|
vtop--; /* NOT vpop() because on x86 it would flush the fp stack */
|
||||||
vtop->r |= delayed_cast;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5632,29 +5633,8 @@ special_math_val:
|
||||||
|
|
||||||
if (ret_nregs > 0) {
|
if (ret_nregs > 0) {
|
||||||
/* return in register */
|
/* return in register */
|
||||||
if (is_float(ret.type.t)) {
|
|
||||||
ret.r = reg_fret(ret.type.t);
|
|
||||||
#ifdef TCC_TARGET_X86_64
|
|
||||||
if ((ret.type.t & VT_BTYPE) == VT_QFLOAT)
|
|
||||||
ret.r2 = REG_QRET;
|
|
||||||
#elif defined TCC_TARGET_RISCV64
|
|
||||||
if ((ret.type.t & VT_BTYPE) == VT_LDOUBLE)
|
|
||||||
ret.r2 = ret.r + 1;
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
#ifndef TCC_TARGET_ARM64
|
|
||||||
#ifndef TCC_TARGET_RISCV64
|
|
||||||
#ifdef TCC_TARGET_X86_64
|
|
||||||
if ((ret.type.t & VT_BTYPE) == VT_QLONG)
|
|
||||||
#else
|
|
||||||
if ((ret.type.t & VT_BTYPE) == VT_LLONG)
|
|
||||||
#endif
|
|
||||||
ret.r2 = REG_LRET;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
ret.r = REG_IRET;
|
|
||||||
}
|
|
||||||
ret.c.i = 0;
|
ret.c.i = 0;
|
||||||
|
PUT_R_RET(&ret, ret.type.t);
|
||||||
}
|
}
|
||||||
if (tok != ')') {
|
if (tok != ')') {
|
||||||
for(;;) {
|
for(;;) {
|
||||||
|
@ -6069,22 +6049,11 @@ static void expr_cond(void)
|
||||||
gaddrof();
|
gaddrof();
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = RC_INT;
|
rc = RC_TYPE(type.t);
|
||||||
if (is_float(type.t)) {
|
/* for long longs, we use fixed registers to avoid having
|
||||||
rc = RC_FLOAT;
|
to handle a complicated move */
|
||||||
#ifdef TCC_TARGET_X86_64
|
if (USING_TWO_WORDS(type.t))
|
||||||
if ((type.t & VT_BTYPE) == VT_LDOUBLE) {
|
rc = RC_RET(type.t);
|
||||||
rc = RC_ST0;
|
|
||||||
}
|
|
||||||
#elif defined TCC_TARGET_RISCV64
|
|
||||||
if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE)
|
|
||||||
rc = RC_INT;
|
|
||||||
#endif
|
|
||||||
} else if ((type.t & VT_BTYPE) == VT_LLONG) {
|
|
||||||
/* for long longs, we use fixed registers to avoid having
|
|
||||||
to handle a complicated move */
|
|
||||||
rc = RC_IRET;
|
|
||||||
}
|
|
||||||
|
|
||||||
tt = r2 = 0;
|
tt = r2 = 0;
|
||||||
if (c < 0) {
|
if (c < 0) {
|
||||||
|
@ -6214,7 +6183,7 @@ static void gfunc_return(CType *func_type)
|
||||||
vstore();
|
vstore();
|
||||||
} else {
|
} else {
|
||||||
/* returning structure packed into registers */
|
/* returning structure packed into registers */
|
||||||
int r, size, addr, align;
|
int size, addr, align, rc;
|
||||||
size = type_size(func_type,&align);
|
size = type_size(func_type,&align);
|
||||||
if ((vtop->r != (VT_LOCAL | VT_LVAL) ||
|
if ((vtop->r != (VT_LOCAL | VT_LVAL) ||
|
||||||
(vtop->c.i & (ret_align-1)))
|
(vtop->c.i & (ret_align-1)))
|
||||||
|
@ -6229,32 +6198,26 @@ static void gfunc_return(CType *func_type)
|
||||||
vset(&ret_type, VT_LOCAL | VT_LVAL, addr);
|
vset(&ret_type, VT_LOCAL | VT_LVAL, addr);
|
||||||
}
|
}
|
||||||
vtop->type = ret_type;
|
vtop->type = ret_type;
|
||||||
if (is_float(ret_type.t))
|
rc = RC_RET(ret_type.t);
|
||||||
r = rc_fret(ret_type.t);
|
|
||||||
else
|
|
||||||
r = RC_IRET;
|
|
||||||
|
|
||||||
if (ret_nregs == 1)
|
if (ret_nregs == 1)
|
||||||
gv(r);
|
gv(rc);
|
||||||
else {
|
else {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
vdup();
|
vdup();
|
||||||
gv(r);
|
gv(rc);
|
||||||
vpop();
|
vpop();
|
||||||
if (--ret_nregs == 0)
|
if (--ret_nregs == 0)
|
||||||
break;
|
break;
|
||||||
/* We assume that when a structure is returned in multiple
|
/* We assume that when a structure is returned in multiple
|
||||||
registers, their classes are consecutive values of the
|
registers, their classes are consecutive values of the
|
||||||
suite s(n) = 2^n */
|
suite s(n) = 2^n */
|
||||||
r <<= 1;
|
rc <<= 1;
|
||||||
vtop->c.i += regsize;
|
vtop->c.i += regsize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (is_float(func_type->t)) {
|
|
||||||
gv(rc_fret(func_type->t));
|
|
||||||
} else {
|
} else {
|
||||||
gv(RC_IRET);
|
gv(RC_RET(func_type->t));
|
||||||
}
|
}
|
||||||
vtop--; /* NOT vpop() because on x86 it would flush the fp stack */
|
vtop--; /* NOT vpop() because on x86 it would flush the fp stack */
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,9 +49,9 @@
|
||||||
#define RC_XMM6 0x40000
|
#define RC_XMM6 0x40000
|
||||||
#define RC_XMM7 0x80000
|
#define RC_XMM7 0x80000
|
||||||
#define RC_IRET RC_RAX /* function return: integer register */
|
#define RC_IRET RC_RAX /* function return: integer register */
|
||||||
#define RC_LRET RC_RDX /* function return: second integer register */
|
#define RC_IRE2 RC_RDX /* function return: second integer register */
|
||||||
#define RC_FRET RC_XMM0 /* function return: float register */
|
#define RC_FRET RC_XMM0 /* function return: float register */
|
||||||
#define RC_QRET RC_XMM1 /* function return: second float register */
|
#define RC_FRE2 RC_XMM1 /* function return: second float register */
|
||||||
|
|
||||||
/* pretty names for the registers */
|
/* pretty names for the registers */
|
||||||
enum {
|
enum {
|
||||||
|
@ -86,9 +86,9 @@ enum {
|
||||||
|
|
||||||
/* return registers for function */
|
/* return registers for function */
|
||||||
#define REG_IRET TREG_RAX /* single word int return register */
|
#define REG_IRET TREG_RAX /* single word int return register */
|
||||||
#define REG_LRET TREG_RDX /* second word return register (for long long) */
|
#define REG_IRE2 TREG_RDX /* second word return register (for long long) */
|
||||||
#define REG_FRET TREG_XMM0 /* float return register */
|
#define REG_FRET TREG_XMM0 /* float return register */
|
||||||
#define REG_QRET TREG_XMM1 /* second float return register */
|
#define REG_FRE2 TREG_XMM1 /* second float return register */
|
||||||
|
|
||||||
/* defined if function parameters must be evaluated in reverse order */
|
/* defined if function parameters must be evaluated in reverse order */
|
||||||
#define INVERT_FUNC_PARAMS
|
#define INVERT_FUNC_PARAMS
|
||||||
|
|
Loading…
Reference in a new issue