diff --git a/arm-gen.c b/arm-gen.c index d6efb19e..92b2ee7d 100644 --- a/arm-gen.c +++ b/arm-gen.c @@ -59,7 +59,7 @@ #define RC_F7 0x4000 #endif #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 */ /* pretty names for the registers */ @@ -89,7 +89,7 @@ enum { /* return registers for function */ #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 */ #ifdef TCC_ARM_EABI @@ -1542,7 +1542,7 @@ void gen_opi(int op) case '%': #ifdef TCC_ARM_EABI func=TOK___aeabi_idivmod; - retreg=REG_LRET; + retreg=REG_IRE2; #else func=TOK___modsi3; #endif @@ -1551,7 +1551,7 @@ void gen_opi(int op) case TOK_UMOD: #ifdef TCC_ARM_EABI func=TOK___aeabi_uidivmod; - retreg=REG_LRET; + retreg=REG_IRE2; #else func=TOK___umodsi3; #endif @@ -1942,7 +1942,7 @@ void gen_opf(int op) /* convert integers to fp 't' type. Must handle 'int', 'unsigned int' and 'long long' cases. */ -ST_FUNC void gen_cvt_itof1(int t) +ST_FUNC void gen_cvt_itof(int t) { uint32_t r, r2; int bt; @@ -2075,7 +2075,7 @@ void gen_cvt_ftoi(int t) gfunc_call(1); vpushi(0); if(t == VT_LLONG) - vtop->r2 = REG_LRET; + vtop->r2 = REG_IRE2; vtop->r = REG_IRET; return; } diff --git a/c67-gen.c b/c67-gen.c index f8c854ea..d9b87d32 100644 --- a/c67-gen.c +++ b/c67-gen.c @@ -56,7 +56,7 @@ #define RC_C67_B12 0x04000000 #define RC_C67_B13 0x08000000 #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 */ /* pretty names for the registers */ @@ -89,7 +89,7 @@ enum { /* return registers for function */ #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 */ /* defined if function parameters must be evaluated in reverse order */ @@ -2392,7 +2392,7 @@ void gen_opf(int op) gfunc_call(2); vpushi(0); vtop->r = REG_FRET; - vtop->r2 = REG_LRET; + vtop->r2 = REG_IRE2; } else { // must call intrinsic SP floating point divide diff --git a/i386-gen.c b/i386-gen.c index 6ff096ad..396df8b3 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -37,7 +37,7 @@ #define RC_EBX 0x0040 #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 */ /* pretty names for the registers */ @@ -52,7 +52,7 @@ enum { /* return registers for function */ #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 */ /* 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(0x242cdf); /* fildll (%esp) */ o(0x08c483); /* add $8, %esp */ + vtop->r2 = VT_CONST; } else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) { /* unsigned int to float/double/long double */ @@ -1037,7 +1038,7 @@ ST_FUNC void gen_cvt_ftoi(int t) vpushi(0); vtop->r = REG_IRET; if ((t & VT_BTYPE) == VT_LLONG) - vtop->r2 = REG_LRET; + vtop->r2 = REG_IRE2; } /* convert from one floating point type to another */ diff --git a/riscv64-gen.c b/riscv64-gen.c index b4cad369..07adda5d 100644 --- a/riscv64-gen.c +++ b/riscv64-gen.c @@ -13,9 +13,11 @@ #define RC_F(x) (1 << (10 + (x))) // x = 0..7 #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 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 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(0x13, 0, 2, 2, d); // addi sp, sp, v EI(0x67, 0, 0, 1, 0); // jalr x0, 0(x1), aka ret + large_ofs_ind = ind; if (v >= (1 << 11)) { - large_ofs_ind = ind; 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) EI(0x13, 0, 5, 5, (v-16) << 20 >> 20); // addi t0, t0, lo(v) diff --git a/tcc.h b/tcc.h index 0271f236..867d4a4f 100644 --- a/tcc.h +++ b/tcc.h @@ -1521,10 +1521,6 @@ ST_FUNC void *tcc_get_symbol_err(TCCState *s, const char *name); #ifndef TCC_TARGET_PE 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 uint8_t *parse_comment(uint8_t *p); -ST_FUNC void minp(void); -ST_INLN void inp(void); -ST_FUNC int handle_eob(void); #endif /* ------------ 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_opf(int op); 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 ggoto(void); #ifndef TCC_TARGET_C67 ST_FUNC void o(unsigned int c); #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_restore(int addr); 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); #endif ST_FUNC void arm_init(struct TCCState *s); -ST_FUNC void gen_cvt_itof1(int t); #endif /* ------------ arm64-gen.c ------------ */ diff --git a/tccgen.c b/tccgen.c index 82e67e19..f966fcc2 100644 --- a/tccgen.c +++ b/tccgen.c @@ -152,9 +152,112 @@ static void clear_temp_local_var_list(); ST_INLN int is_float(int t) { - int bt; - bt = t & VT_BTYPE; - return bt == VT_LDOUBLE || bt == VT_DOUBLE || bt == VT_FLOAT || bt == VT_QFLOAT; + int bt = t & VT_BTYPE; + return bt == VT_LDOUBLE + || 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 @@ -1291,11 +1394,8 @@ ST_FUNC void save_reg_upstack(int r, int n) o(0xd8dd); /* fstp %st(0) */ } #endif - /* special long long case. Ideally r2 would always - be VT_CONST is the type is smaller than a double-word - 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) { + /* special long long case */ + if (p->r2 < VT_CONST && USING_TWO_WORDS(type->t)) { sv.c.i += PTR_SIZE; 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). */ 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[] */ if (vtop->type.t & VT_BITFIELD) { @@ -1654,94 +1755,62 @@ ST_FUNC int gv(int rc) if (vtop->r & VT_MUSTBOUND) gbound(); #endif + + bt = vtop->type.t & VT_BTYPE; + #ifdef TCC_TARGET_RISCV64 /* XXX mega hack */ - if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE && rc == RC_FLOAT) + if (bt == VT_LDOUBLE && rc == RC_FLOAT) rc = RC_INT; #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: - constant - lvalue (need to dereference pointer) - already a register, but not in the right class */ - if (r >= VT_CONST - || (vtop->r & VT_LVAL) - || !(reg_classes[r] & rc) -#ifdef TCC_TARGET_RISCV64 - || ((vtop->type.t & VT_BTYPE) == VT_QLONG && (vtop->r2 >= NB_REGS || !(reg_classes[vtop->r2] & rc2))) - || ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE && (vtop->r2 >= NB_REGS || !(reg_classes[vtop->r2] & rc2))) -#elif PTR_SIZE == 8 - || ((vtop->type.t & VT_BTYPE) == VT_QLONG && !(reg_classes[vtop->r2] & rc2)) - || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT && !(reg_classes[vtop->r2] & rc2)) -#else - || ((vtop->type.t & VT_BTYPE) == VT_LLONG && !(reg_classes[vtop->r2] & rc2)) -#endif - ) - { - 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 + r = vtop->r & VT_VALMASK; + r_ok = !(vtop->r & VT_LVAL) && (r < VT_CONST) && (reg_classes[r] & rc); + r2_ok = !rc2 || ((vtop->r2 < VT_CONST) && (reg_classes[vtop->r2] & rc2)); + + if (!r_ok || !r2_ok) { + if (!r_ok) + r = get_reg(rc); + if (rc2) { + int load_type = (bt == VT_QFLOAT) ? VT_DOUBLE : ptrdiff_type.t; + int original_type = vtop->type.t; + + /* two register type load : + expand to two words temporarily */ if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { /* load constant */ - ll = vtop->c.i; + unsigned long long ll = vtop->c.i; vtop->c.i = ll; /* first word */ load(r, vtop); vtop->r = r; /* save register value */ vpushi(ll >> 32); /* second word */ - } else -#endif - if (vtop->r & VT_LVAL) { - /* 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 */ + } else if (vtop->r & VT_LVAL) { + /* We do not want to modifier the long long pointer here. + So we save any other instances down the stack */ save_reg_upstack(vtop->r, 1); - #endif /* load from memory */ vtop->type.t = load_type; load(r, vtop); vdup(); vtop[-1].r = r; /* save register value */ /* increment pointer to get second word */ - vtop->type.t = addr_type; + vtop->type.t = ptrdiff_type.t; gaddrof(); - vpushi(load_size); + vpushi(PTR_SIZE); gen_op('+'); vtop->r |= VT_LVAL; vtop->type.t = load_type; } else { /* move registers */ - load(r, vtop); + if (!r_ok) + load(r, vtop); + if (r2_ok && vtop->r2 < VT_CONST) + goto done; vdup(); vtop[-1].r = r; /* save register value */ vtop->r = vtop[-1].r2; @@ -1753,6 +1822,7 @@ ST_FUNC int gv(int rc) vpop(); /* write second register */ vtop->r2 = r2; + done: vtop->type.t = original_type; } else if ((vtop->r & VT_LVAL) && !is_float(vtop->type.t)) { int t1, t; @@ -1781,7 +1851,7 @@ ST_FUNC int gv(int rc) vtop->r = r; #ifdef TCC_TARGET_C67 /* uses register pairs for doubles */ - if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) + if (bt == VT_DOUBLE) vtop->r2 = r+1; #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 /* expand 64bit on stack in two ints */ ST_FUNC void lexpand(void) @@ -1885,8 +1925,7 @@ static void lbuild(int t) register */ static void gv_dup(void) { - int rc, t, r, r1; - SValue sv; + int t, rc, r; t = vtop->type.t; #if PTR_SIZE == 4 @@ -1908,34 +1947,16 @@ static void gv_dup(void) vswap(); lbuild(t); vswap(); - } else -#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; + return; } +#endif + /* duplicate value */ + rc = RC_TYPE(t); + gv(rc); + r = get_reg(rc); + vdup(); + load(r, vtop); + vtop->r = r; } #if PTR_SIZE == 4 @@ -1945,7 +1966,7 @@ static void gen_opl(int op) int t, a, b, op1, c, i; int func; unsigned short reg_iret = REG_IRET; - unsigned short reg_lret = REG_LRET; + unsigned short reg_lret = REG_IRE2; SValue tmp; switch(op) { @@ -2422,11 +2443,6 @@ static inline int is_null_pointer(SValue *p) 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 */ 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); } -#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 */ 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)) == (VT_LLONG | VT_UNSIGNED)) { @@ -2685,22 +2700,20 @@ static void gen_cvt_itof1(int t) vrott(2); gfunc_call(1); vpushi(0); - vtop->r = reg_fret(t); + PUT_R_RET(vtop, t); } else { gen_cvt_itof(t); } -#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 */ static void gen_cvt_ftoi1(int t) { -#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64 - gen_cvt_ftoi(t); -#else int st; - if (t == (VT_LLONG | VT_UNSIGNED)) { /* not handled natively */ st = vtop->type.t & VT_BTYPE; @@ -2715,15 +2728,12 @@ static void gen_cvt_ftoi1(int t) vrott(2); gfunc_call(1); vpushi(0); - vtop->r = REG_IRET; -#if PTR_SIZE == 4 - vtop->r2 = REG_LRET; -#endif + PUT_R_RET(vtop, t); } else { gen_cvt_ftoi(t); } -#endif } +#endif /* force char or short cast */ static void force_charshort_cast(int t) @@ -3311,9 +3321,8 @@ static void type_to_str(char *buf, int buf_size, no_var: ; } -/* verify type compatibility to store vtop in 'dt' type, and generate - casts if needed. */ -static void gen_assign_cast(CType *dt) +/* verify type compatibility to store vtop in 'dt' type */ +static void verify_assign_cast(CType *dt) { CType *st, *type1, *type2; char buf1[256], buf2[256]; @@ -3401,31 +3410,24 @@ static void gen_assign_cast(CType *dt) } break; } +} + +static void gen_assign_cast(CType *dt) +{ + verify_assign_cast(dt); gen_cast(dt); } /* store vtop in lvalue pushed on stack */ 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; sbt = vtop->type.t & VT_BTYPE; dbt = ft & VT_BTYPE; - if ((((sbt == VT_INT || sbt == VT_SHORT) && dbt == VT_BYTE) || - (sbt == VT_INT && dbt == VT_SHORT)) - && !(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); - } + + verify_assign_cast(&vtop[-1].type); if (sbt == VT_STRUCT) { /* if structure, only generate pointer */ @@ -3457,8 +3459,8 @@ ST_FUNC void vstore(void) /* type size */ vpushi(size); gfunc_call(3); - /* leave source on stack */ + } else if (ft & VT_BITFIELD) { /* bitfield store handling */ @@ -3470,20 +3472,22 @@ ST_FUNC void vstore(void) /* remove bit field info to avoid loops */ vtop[-1].type.t = ft & ~VT_STRUCT_MASK; - if ((ft & VT_BTYPE) == VT_BOOL) { + if (dbt == VT_BOOL) { gen_cast(&vtop[-1].type); vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED); } - 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) { - gen_cast_s((ft & VT_BTYPE) == VT_LLONG ? VT_LLONG : VT_INT); store_packed_bf(bit_pos, bit_size); } else { unsigned long long mask = (1ULL << bit_size) - 1; - if ((ft & VT_BTYPE) != VT_BOOL) { + if (dbt != VT_BOOL) { /* mask source */ - if ((vtop[-1].type.t & VT_BTYPE) == VT_LLONG) + if (dbt == VT_LLONG) vpushll(mask); else vpushi((unsigned)mask); @@ -3497,7 +3501,7 @@ ST_FUNC void vstore(void) vdup(); vrott(3); /* load destination, mask and or with source */ - if ((vtop->type.t & VT_BTYPE) == VT_LLONG) + if (dbt == VT_LLONG) vpushll(~(mask << bit_pos)); else vpushi(~((unsigned)mask << bit_pos)); @@ -3511,6 +3515,20 @@ ST_FUNC void vstore(void) } else if (dbt == VT_VOID) { --vtop; } 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 /* bound check case */ if (vtop[-1].r & VT_MUSTBOUND) { @@ -3519,53 +3537,37 @@ ST_FUNC void vstore(void) vswap(); } #endif - rc = RC_INT; - if (is_float(ft)) { - rc = RC_FLOAT; -#ifdef TCC_TARGET_X86_64 - if ((ft & VT_BTYPE) == VT_LDOUBLE) { - rc = RC_ST0; - } else if ((ft & VT_BTYPE) == VT_QFLOAT) { - rc = RC_FRET; - } -#elif defined TCC_TARGET_RISCV64 - if (dbt == VT_LDOUBLE) - rc = RC_INT; -#endif + gv(RC_TYPE(dbt)); /* generate value */ + + if (delayed_cast) { + vtop->r |= VT_MUSTCAST; + //tcc_warning("deley cast %x -> %x", sbt, dbt); + vtop->type.t = ft & VT_TYPE; } - r = gv(rc); /* generate value */ + /* if lvalue was saved on stack, must read it */ if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) { SValue sv; - t = get_reg(RC_INT); -#if PTR_SIZE == 8 - sv.type.t = VT_PTR; -#else - sv.type.t = VT_INT; -#endif + r = get_reg(RC_INT); + sv.type.t = ptrdiff_type.t; sv.r = VT_LOCAL | VT_LVAL; sv.c.i = vtop[-1].c.i; - load(t, &sv); - vtop[-1].r = t | VT_LVAL; + load(r, &sv); + 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 - if (dbt == VT_QLONG || dbt == VT_LDOUBLE) { - int addr_type = VT_LLONG, load_size = 8, load_type = VT_LLONG; -#elif PTR_SIZE == 8 - if (((ft & VT_BTYPE) == VT_QLONG) || ((ft & 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 ((ft & VT_BTYPE) == VT_LLONG) { - int addr_type = VT_INT, load_size = 4, load_type = VT_INT; -#endif + + r = vtop->r & VT_VALMASK; + /* two word case handling : + store second register at word + 4 (or +8 for x86-64) */ + if (USING_TWO_WORDS(dbt)) { + int load_type = (dbt == VT_QFLOAT) ? VT_DOUBLE : ptrdiff_type.t; vtop[-1].type.t = load_type; store(r, vtop - 1); vswap(); /* convert to int to increment easily */ - vtop->type.t = addr_type; + vtop->type.t = ptrdiff_type.t; gaddrof(); - vpushi(load_size); + vpushs(PTR_SIZE); gen_op('+'); vtop->r |= VT_LVAL; vswap(); @@ -3573,12 +3575,11 @@ ST_FUNC void vstore(void) /* XXX: it works because r2 is spilled last ! */ store(vtop->r2, vtop - 1); } else { + /* single word */ store(r, vtop - 1); } - vswap(); 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) { /* 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; + PUT_R_RET(&ret, ret.type.t); } if (tok != ')') { for(;;) { @@ -6069,22 +6049,11 @@ static void expr_cond(void) gaddrof(); } - rc = RC_INT; - if (is_float(type.t)) { - rc = RC_FLOAT; -#ifdef TCC_TARGET_X86_64 - if ((type.t & VT_BTYPE) == VT_LDOUBLE) { - 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; - } + rc = RC_TYPE(type.t); + /* for long longs, we use fixed registers to avoid having + to handle a complicated move */ + if (USING_TWO_WORDS(type.t)) + rc = RC_RET(type.t); tt = r2 = 0; if (c < 0) { @@ -6214,7 +6183,7 @@ static void gfunc_return(CType *func_type) vstore(); } else { /* returning structure packed into registers */ - int r, size, addr, align; + int size, addr, align, rc; size = type_size(func_type,&align); if ((vtop->r != (VT_LOCAL | VT_LVAL) || (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); } vtop->type = ret_type; - if (is_float(ret_type.t)) - r = rc_fret(ret_type.t); - else - r = RC_IRET; - + rc = RC_RET(ret_type.t); if (ret_nregs == 1) - gv(r); + gv(rc); else { for (;;) { vdup(); - gv(r); + gv(rc); vpop(); if (--ret_nregs == 0) break; /* We assume that when a structure is returned in multiple registers, their classes are consecutive values of the suite s(n) = 2^n */ - r <<= 1; + rc <<= 1; vtop->c.i += regsize; } } } - } else if (is_float(func_type->t)) { - gv(rc_fret(func_type->t)); } else { - gv(RC_IRET); + gv(RC_RET(func_type->t)); } vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ } diff --git a/x86_64-gen.c b/x86_64-gen.c index bdbd137d..5c3d2e32 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -49,9 +49,9 @@ #define RC_XMM6 0x40000 #define RC_XMM7 0x80000 #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_QRET RC_XMM1 /* function return: second float register */ +#define RC_FRE2 RC_XMM1 /* function return: second float register */ /* pretty names for the registers */ enum { @@ -86,9 +86,9 @@ enum { /* return registers for function */ #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_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 */ #define INVERT_FUNC_PARAMS