mirror of
https://github.com/mirror/tinycc.git
synced 2025-01-19 05:30:07 +08:00
Expansion code again for x86_64-gen
This commit is contained in:
parent
2b2e7f85d7
commit
9e3713facd
12
tcc.h
12
tcc.h
@ -39,6 +39,7 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#ifdef CONFIG_TCCASSERT
|
#ifdef CONFIG_TCCASSERT
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@ -358,8 +359,8 @@ typedef union CValue {
|
|||||||
/* value on stack */
|
/* value on stack */
|
||||||
typedef struct SValue {
|
typedef struct SValue {
|
||||||
CType type; /* type */
|
CType type; /* type */
|
||||||
unsigned short r; /* register + flags */
|
unsigned int r; /* register + flags */
|
||||||
unsigned short r2; /* second register, used for 'long long'
|
unsigned int r2; /* second register, used for 'long long'
|
||||||
type. If not used, set to VT_CONST */
|
type. If not used, set to VT_CONST */
|
||||||
CValue c; /* constant, if VT_CONST */
|
CValue c; /* constant, if VT_CONST */
|
||||||
struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST) */
|
struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST) */
|
||||||
@ -781,6 +782,7 @@ struct TCCState {
|
|||||||
#define VT_VOLATILE 0x1000 /* volatile modifier */
|
#define VT_VOLATILE 0x1000 /* volatile modifier */
|
||||||
#define VT_DEFSIGN 0x2000 /* signed type */
|
#define VT_DEFSIGN 0x2000 /* signed type */
|
||||||
#define VT_VLA 0x00020000 /* VLA type (also has VT_PTR and VT_ARRAY) */
|
#define VT_VLA 0x00020000 /* VLA type (also has VT_PTR and VT_ARRAY) */
|
||||||
|
#define VT_VLS 0x00080000 /* VLA type (also has VT_PTR and VT_STRUCT) */
|
||||||
|
|
||||||
/* storage */
|
/* storage */
|
||||||
#define VT_EXTERN 0x00000080 /* extern definition */
|
#define VT_EXTERN 0x00000080 /* extern definition */
|
||||||
@ -791,14 +793,14 @@ struct TCCState {
|
|||||||
#define VT_EXPORT 0x00008000 /* win32: data exported from dll */
|
#define VT_EXPORT 0x00008000 /* win32: data exported from dll */
|
||||||
#define VT_WEAK 0x00010000 /* weak symbol */
|
#define VT_WEAK 0x00010000 /* weak symbol */
|
||||||
#define VT_TLS 0x00040000 /* thread-local storage */
|
#define VT_TLS 0x00040000 /* thread-local storage */
|
||||||
#define VT_VIS_SHIFT 19 /* shift for symbol visibility, overlapping
|
#define VT_VIS_SHIFT 20 /* shift for symbol visibility, overlapping
|
||||||
bitfield values, because bitfields never
|
bitfield values, because bitfields never
|
||||||
have linkage and hence never have
|
have linkage and hence never have
|
||||||
visibility. */
|
visibility. */
|
||||||
#define VT_VIS_SIZE 2 /* We have four visibilities. */
|
#define VT_VIS_SIZE 2 /* We have four visibilities. */
|
||||||
#define VT_VIS_MASK (((1 << VT_VIS_SIZE)-1) << VT_VIS_SHIFT)
|
#define VT_VIS_MASK (((1 << VT_VIS_SIZE)-1) << VT_VIS_SHIFT)
|
||||||
|
|
||||||
#define VT_STRUCT_SHIFT 19 /* shift for bitfield shift values (max: 32 - 2*6) */
|
#define VT_STRUCT_SHIFT 20 /* shift for bitfield shift values (max: 32 - 2*6) */
|
||||||
|
|
||||||
|
|
||||||
/* type mask (except storage) */
|
/* type mask (except storage) */
|
||||||
@ -1185,7 +1187,7 @@ ST_DATA Sym *define_stack;
|
|||||||
ST_DATA CType char_pointer_type, func_old_type, int_type, size_type;
|
ST_DATA CType char_pointer_type, func_old_type, int_type, size_type;
|
||||||
ST_DATA SValue __vstack[1+/*to make bcheck happy*/ VSTACK_SIZE], *vtop;
|
ST_DATA SValue __vstack[1+/*to make bcheck happy*/ VSTACK_SIZE], *vtop;
|
||||||
#define vstack (__vstack + 1)
|
#define vstack (__vstack + 1)
|
||||||
ST_DATA int rsym, anon_sym, ind, loc;
|
ST_DATA int rsym, anon_sym, ind, loc, ex_rc;
|
||||||
|
|
||||||
ST_DATA int const_wanted; /* true if constant wanted */
|
ST_DATA int const_wanted; /* true if constant wanted */
|
||||||
ST_DATA int nocode_wanted; /* true if no code generation wanted for an expression */
|
ST_DATA int nocode_wanted; /* true if no code generation wanted for an expression */
|
||||||
|
186
tccgen.c
186
tccgen.c
@ -28,7 +28,7 @@
|
|||||||
rsym: return symbol
|
rsym: return symbol
|
||||||
anon_sym: anonymous symbol index
|
anon_sym: anonymous symbol index
|
||||||
*/
|
*/
|
||||||
ST_DATA int rsym, anon_sym, ind, loc;
|
ST_DATA int rsym, anon_sym, ind, loc, ex_rc;
|
||||||
|
|
||||||
ST_DATA Section *text_section, *data_section, *bss_section; /* predefined sections */
|
ST_DATA Section *text_section, *data_section, *bss_section; /* predefined sections */
|
||||||
ST_DATA Section *cur_text_section; /* current section where function code is generated */
|
ST_DATA Section *cur_text_section; /* current section where function code is generated */
|
||||||
@ -525,41 +525,6 @@ static void vdup(void)
|
|||||||
vpushv(vtop);
|
vpushv(vtop);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int align_size(int size)
|
|
||||||
{
|
|
||||||
#ifdef TCC_TARGET_X86_64
|
|
||||||
if(size > 4)
|
|
||||||
return 8;
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
if(size > 2)
|
|
||||||
return 4;
|
|
||||||
else if(size > 1)
|
|
||||||
return 2;
|
|
||||||
else
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int loc_stack(int size, int is_sub){
|
|
||||||
int l, align;
|
|
||||||
align = align_size(size);
|
|
||||||
size = (size + align - 1) & - align;
|
|
||||||
if(is_sub){
|
|
||||||
pop_stack -= size;
|
|
||||||
if(pop_stack >= 0)
|
|
||||||
l = loc + pop_stack;
|
|
||||||
else{
|
|
||||||
loc += pop_stack;
|
|
||||||
l = loc &= -align;
|
|
||||||
pop_stack = 0;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
pop_stack += size;
|
|
||||||
l = loc + pop_stack;
|
|
||||||
}
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* save r to the memory stack, and mark it as being free */
|
/* save r to the memory stack, and mark it as being free */
|
||||||
ST_FUNC void save_reg(int r)
|
ST_FUNC void save_reg(int r)
|
||||||
{
|
{
|
||||||
@ -762,25 +727,28 @@ static void gbound(void)
|
|||||||
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, i;
|
int r, bit_pos, bit_size, size, align, i, ft, sbt;
|
||||||
int rc2;
|
int rc2;
|
||||||
|
|
||||||
|
ft = vtop->type.t;
|
||||||
|
sbt = ft & VT_BTYPE;
|
||||||
/* NOTE: get_reg can modify vstack[] */
|
/* NOTE: get_reg can modify vstack[] */
|
||||||
if (vtop->type.t & VT_BITFIELD) {
|
if (ft & VT_BITFIELD) {
|
||||||
CType type;
|
CType type;
|
||||||
int bits = 32;
|
int bits;
|
||||||
bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f;
|
bit_pos = (ft >> VT_STRUCT_SHIFT) & 0x3f;
|
||||||
bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
|
bit_size = (ft >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
|
||||||
/* remove bit field info to avoid loops */
|
/* remove bit field info to avoid loops */
|
||||||
vtop->type.t &= ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT));
|
ft = vtop->type.t &= ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT));
|
||||||
/* cast to int to propagate signedness in following ops */
|
/* cast to int to propagate signedness in following ops */
|
||||||
if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
|
if (sbt == VT_LLONG) {
|
||||||
type.t = VT_LLONG;
|
type.t = VT_LLONG;
|
||||||
bits = 64;
|
bits = 64;
|
||||||
} else
|
} else{
|
||||||
type.t = VT_INT;
|
type.t = VT_INT;
|
||||||
if((vtop->type.t & VT_UNSIGNED) ||
|
bits = 32;
|
||||||
(vtop->type.t & VT_BTYPE) == VT_BOOL)
|
}
|
||||||
|
if((ft & VT_UNSIGNED) || sbt == VT_BOOL)
|
||||||
type.t |= VT_UNSIGNED;
|
type.t |= VT_UNSIGNED;
|
||||||
gen_cast(&type);
|
gen_cast(&type);
|
||||||
/* generate shifts */
|
/* generate shifts */
|
||||||
@ -837,41 +805,39 @@ ST_FUNC int gv(int rc)
|
|||||||
gbound();
|
gbound();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
r = vtop->r & VT_VALMASK;
|
r = vtop->r & VT_VALMASK;
|
||||||
rc2 = (rc & RC_FLOAT) ? RC_FLOAT : RC_INT;
|
if((rc & ~RC_MASK) && (rc != RC_ST0))
|
||||||
if (rc == RC_IRET)
|
rc2 = ex_rc;
|
||||||
rc2 = RC_LRET;
|
else
|
||||||
#ifdef TCC_TARGET_X86_64
|
rc2 = (rc & RC_FLOAT) ? RC_FLOAT : RC_INT;
|
||||||
else if (rc == RC_FRET)
|
|
||||||
rc2 = RC_QRET;
|
|
||||||
#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
|
if (r >= VT_CONST || (vtop->r & VT_LVAL) || !(reg_classes[r] & rc)
|
||||||
|| (vtop->r & VT_LVAL)
|
|
||||||
|| !(reg_classes[r] & rc)
|
|
||||||
#ifdef TCC_TARGET_X86_64
|
#ifdef TCC_TARGET_X86_64
|
||||||
|| ((vtop->type.t & VT_BTYPE) == VT_QLONG && !(reg_classes[vtop->r2] & rc2))
|
|| (sbt == VT_QLONG && !(reg_classes[vtop->r2] & rc2))
|
||||||
|| ((vtop->type.t & VT_BTYPE) == VT_QFLOAT && !(reg_classes[vtop->r2] & rc2))
|
|| (sbt == VT_QFLOAT && !(reg_classes[vtop->r2] & rc2))
|
||||||
#else
|
#else
|
||||||
|| ((vtop->type.t & VT_BTYPE) == VT_LLONG && !(reg_classes[vtop->r2] & rc2))
|
|| (sbt == VT_LLONG && !(reg_classes[vtop->r2] & rc2))
|
||||||
#endif
|
#endif
|
||||||
)
|
|| vtop->c.i)
|
||||||
{
|
{
|
||||||
r = get_reg(rc);
|
r = get_reg(rc);
|
||||||
#ifdef TCC_TARGET_X86_64
|
#ifdef TCC_TARGET_X86_64
|
||||||
if (((vtop->type.t & VT_BTYPE) == VT_QLONG) || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT)) {
|
if ((sbt == VT_QLONG) || (sbt == VT_QFLOAT))
|
||||||
int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE;
|
|
||||||
#else
|
#else
|
||||||
if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
|
if (sbt == VT_LLONG)
|
||||||
int addr_type = VT_INT, load_size = 4, load_type = VT_INT;
|
#endif
|
||||||
|
{
|
||||||
|
#ifdef TCC_TARGET_X86_64
|
||||||
|
int load_size = 8, load_type = (sbt == VT_QLONG) ? VT_LLONG : VT_DOUBLE;
|
||||||
|
#else
|
||||||
|
int load_size = 4, load_type = VT_INT;
|
||||||
unsigned long long ll;
|
unsigned long long ll;
|
||||||
#endif
|
#endif
|
||||||
int r2, original_type;
|
int r2;
|
||||||
original_type = vtop->type.t;
|
|
||||||
/* two register type load : expand to two words
|
/* two register type load : expand to two words
|
||||||
temporarily */
|
temporarily */
|
||||||
#ifndef TCC_TARGET_X86_64
|
#ifndef TCC_TARGET_X86_64
|
||||||
@ -884,20 +850,19 @@ ST_FUNC int gv(int rc)
|
|||||||
vpushi(ll >> 32); /* second word */
|
vpushi(ll >> 32); /* second word */
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
if (r >= VT_CONST || /* XXX: test to VT_CONST incorrect ? */
|
/* XXX: test to VT_CONST incorrect ? */
|
||||||
(vtop->r & VT_LVAL)) {
|
if (r >= VT_CONST || (vtop->r & VT_LVAL)) {
|
||||||
/* We do not want to modifier the long long
|
/* We do not want to modifier the long long
|
||||||
pointer here, so the safest (and less
|
pointer here, so the safest (and less
|
||||||
efficient) is to save all the other registers
|
efficient) is to save all the other registers
|
||||||
in the stack. XXX: totally inefficient. */
|
in the regs. use VT_TMP XXX: totally inefficient. */
|
||||||
save_regs(1);
|
|
||||||
/* 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 | VT_TMP; /* lock register value */
|
||||||
/* increment pointer to get second word */
|
/* increment pointer to get second word */
|
||||||
vtop->type.t = addr_type;
|
vtop->type = char_pointer_type;
|
||||||
gaddrof();
|
gaddrof();
|
||||||
vpushi(load_size);
|
vpushi(load_size);
|
||||||
gen_op('+');
|
gen_op('+');
|
||||||
@ -907,23 +872,23 @@ ST_FUNC int gv(int rc)
|
|||||||
/* move registers */
|
/* move registers */
|
||||||
load(r, vtop);
|
load(r, vtop);
|
||||||
vdup();
|
vdup();
|
||||||
vtop[-1].r = r; /* save register value */
|
vtop[-1].r = r | VT_TMP; /* lock register value */
|
||||||
vtop->r = vtop[-1].r2;
|
vtop->r = vtop[-1].r2;
|
||||||
}
|
}
|
||||||
/* Allocate second register. Here we rely on the fact that
|
/* Allocate second register. Here we rely on the fact that
|
||||||
get_reg() tries first to free r2 of an SValue. */
|
get_reg() tries first to free r2 of an SValue. */
|
||||||
r2 = get_reg(rc2);
|
r2 = get_reg(rc2);
|
||||||
load(r2, vtop);
|
load(r2, vtop);
|
||||||
vpop();
|
vtop--;
|
||||||
/* write second register */
|
/* write second register */
|
||||||
vtop->r2 = r2;
|
vtop->r2 = r2;
|
||||||
vtop->type.t = original_type;
|
vtop->r &= ~VT_TMP;
|
||||||
} else if ((vtop->r & VT_LVAL) && !is_float(vtop->type.t)) {
|
vtop->type.t = ft;
|
||||||
int t1, t;
|
} else if ((vtop->r & VT_LVAL) && !is_float(ft)) {
|
||||||
|
int t;
|
||||||
/* lvalue of scalar type : need to use lvalue type
|
/* lvalue of scalar type : need to use lvalue type
|
||||||
because of possible cast */
|
because of possible cast */
|
||||||
t = vtop->type.t;
|
t = ft;
|
||||||
t1 = t;
|
|
||||||
/* compute memory access type */
|
/* compute memory access type */
|
||||||
if (vtop->r & VT_REF)
|
if (vtop->r & VT_REF)
|
||||||
#ifdef TCC_TARGET_X86_64
|
#ifdef TCC_TARGET_X86_64
|
||||||
@ -940,7 +905,7 @@ ST_FUNC int gv(int rc)
|
|||||||
vtop->type.t = t;
|
vtop->type.t = t;
|
||||||
load(r, vtop);
|
load(r, vtop);
|
||||||
/* restore wanted type */
|
/* restore wanted type */
|
||||||
vtop->type.t = t1;
|
vtop->type.t = ft;
|
||||||
} else {
|
} else {
|
||||||
/* one register type load */
|
/* one register type load */
|
||||||
load(r, vtop);
|
load(r, vtop);
|
||||||
@ -994,6 +959,7 @@ static int rc_fret(int t)
|
|||||||
return RC_ST0;
|
return RC_ST0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
ex_rc = RC_QRET;
|
||||||
return RC_FRET;
|
return RC_FRET;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2116,31 +2082,30 @@ ST_FUNC int type_size(CType *type, int *a)
|
|||||||
{
|
{
|
||||||
Sym *s;
|
Sym *s;
|
||||||
int bt;
|
int bt;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
bt = type->t & VT_BTYPE;
|
bt = type->t & VT_BTYPE;
|
||||||
if (bt == VT_STRUCT) {
|
if (bt == VT_STRUCT) {
|
||||||
|
assert(!(type->t & VT_VLS));
|
||||||
/* struct/union */
|
/* struct/union */
|
||||||
s = type->ref;
|
s = type->ref;
|
||||||
*a = s->r;
|
*a = s->r;
|
||||||
return s->c;
|
size = s->c;
|
||||||
} else if (bt == VT_PTR) {
|
} else if (bt == VT_PTR) {
|
||||||
if (type->t & VT_ARRAY) {
|
if (type->t & VT_ARRAY) {
|
||||||
int ts;
|
int ts;
|
||||||
|
|
||||||
s = type->ref;
|
s = type->ref;
|
||||||
ts = type_size(&s->type, a);
|
ts = type_size(&s->type, a);
|
||||||
|
|
||||||
if (ts < 0 && s->c < 0)
|
if (ts < 0 && s->c < 0)
|
||||||
ts = -ts;
|
ts = -ts;
|
||||||
|
size = (size_t)ts * s->c;
|
||||||
return ts * s->c;
|
|
||||||
} else {
|
} else {
|
||||||
*a = PTR_SIZE;
|
*a = PTR_SIZE;
|
||||||
return PTR_SIZE;
|
size = PTR_SIZE;
|
||||||
}
|
}
|
||||||
} else if (bt == VT_LDOUBLE) {
|
} else if (bt == VT_LDOUBLE) {
|
||||||
*a = LDOUBLE_ALIGN;
|
*a = LDOUBLE_ALIGN;
|
||||||
return LDOUBLE_SIZE;
|
size = LDOUBLE_SIZE;
|
||||||
} else if (bt == VT_DOUBLE || bt == VT_LLONG) {
|
} else if (bt == VT_DOUBLE || bt == VT_LLONG) {
|
||||||
#ifdef TCC_TARGET_I386
|
#ifdef TCC_TARGET_I386
|
||||||
#ifdef TCC_TARGET_PE
|
#ifdef TCC_TARGET_PE
|
||||||
@ -2157,21 +2122,23 @@ ST_FUNC int type_size(CType *type, int *a)
|
|||||||
#else
|
#else
|
||||||
*a = 8;
|
*a = 8;
|
||||||
#endif
|
#endif
|
||||||
return 8;
|
size = 8;
|
||||||
} else if (bt == VT_INT || bt == VT_ENUM || bt == VT_FLOAT) {
|
} else if (bt == VT_INT || bt == VT_ENUM || bt == VT_FLOAT) {
|
||||||
*a = 4;
|
*a = 4;
|
||||||
return 4;
|
size = 4;
|
||||||
} else if (bt == VT_SHORT) {
|
} else if (bt == VT_SHORT) {
|
||||||
*a = 2;
|
*a = 2;
|
||||||
return 2;
|
size = 2;
|
||||||
} else if (bt == VT_QLONG || bt == VT_QFLOAT) {
|
} else if (bt == VT_QLONG || bt == VT_QFLOAT) {
|
||||||
*a = 8;
|
*a = 8;
|
||||||
return 16;
|
size = 16;
|
||||||
} else {
|
} else {
|
||||||
/* char, void, function, _Bool */
|
/* char, void, function, _Bool */
|
||||||
*a = 1;
|
*a = 1;
|
||||||
return 1;
|
size = 1;
|
||||||
}
|
}
|
||||||
|
assert(size == (int)size);
|
||||||
|
return (int)size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* push type size as known at runtime time on top of value stack. Put
|
/* push type size as known at runtime time on top of value stack. Put
|
||||||
@ -2600,24 +2567,19 @@ ST_FUNC void vstore(void)
|
|||||||
bit_size = (ft >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
|
bit_size = (ft >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
|
||||||
/* remove bit field info to avoid loops */
|
/* remove bit field info to avoid loops */
|
||||||
vtop[-1].type.t = ft & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT));
|
vtop[-1].type.t = ft & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT));
|
||||||
|
|
||||||
/* duplicate source into other register */
|
/* duplicate source into other register */
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* duplicate destination */
|
|
||||||
vdup();
|
|
||||||
vtop[-1] = vtop[-2];
|
|
||||||
|
|
||||||
/* duplicate destination */
|
/* duplicate destination */
|
||||||
vdup();
|
vdup();
|
||||||
vtop[-1] = vtop[-2];
|
vtop[-1] = vtop[-2];
|
||||||
|
|
||||||
/* mask and shift source */
|
/* mask and shift source */
|
||||||
if((ft & VT_BTYPE) != VT_BOOL) {
|
if(dbt != VT_BOOL) {
|
||||||
if((ft & VT_BTYPE) == VT_LLONG) {
|
if(dbt == VT_LLONG) {
|
||||||
vpushll((1ULL << bit_size) - 1ULL);
|
vpushll((1ULL << bit_size) - 1ULL);
|
||||||
} else {
|
} else {
|
||||||
vpushi((1 << bit_size) - 1);
|
vpushi((1 << bit_size) - 1);
|
||||||
@ -2628,7 +2590,7 @@ ST_FUNC void vstore(void)
|
|||||||
gen_op(TOK_SHL);
|
gen_op(TOK_SHL);
|
||||||
/* load destination, mask and or with source */
|
/* load destination, mask and or with source */
|
||||||
vswap();
|
vswap();
|
||||||
if((ft & VT_BTYPE) == VT_LLONG) {
|
if(dbt == VT_LLONG) {
|
||||||
vpushll(~(((1ULL << bit_size) - 1ULL) << bit_pos));
|
vpushll(~(((1ULL << bit_size) - 1ULL) << bit_pos));
|
||||||
} else {
|
} else {
|
||||||
vpushi(~(((1 << bit_size) - 1) << bit_pos));
|
vpushi(~(((1 << bit_size) - 1) << bit_pos));
|
||||||
@ -2637,10 +2599,6 @@ ST_FUNC void vstore(void)
|
|||||||
gen_op('|');
|
gen_op('|');
|
||||||
/* store result */
|
/* store result */
|
||||||
vstore();
|
vstore();
|
||||||
|
|
||||||
/* pop off shifted source from "duplicate source..." above */
|
|
||||||
vpop();
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
/* bound check case */
|
/* bound check case */
|
||||||
@ -4772,7 +4730,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
|
|||||||
vstore();
|
vstore();
|
||||||
} else {
|
} else {
|
||||||
/* returning structure packed into registers */
|
/* returning structure packed into registers */
|
||||||
int r, size, addr, align;
|
int rc, size, addr, align;
|
||||||
size = type_size(&func_vt,&align);
|
size = type_size(&func_vt,&align);
|
||||||
if ((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & (ret_align-1)))
|
if ((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & (ret_align-1)))
|
||||||
&& (align & (ret_align-1))) {
|
&& (align & (ret_align-1))) {
|
||||||
@ -4786,18 +4744,20 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
|
|||||||
}
|
}
|
||||||
vtop->type = ret_type;
|
vtop->type = ret_type;
|
||||||
if (is_float(ret_type.t))
|
if (is_float(ret_type.t))
|
||||||
r = rc_fret(ret_type.t);
|
rc = rc_fret(ret_type.t);
|
||||||
else
|
else{
|
||||||
r = RC_IRET;
|
rc = RC_IRET;
|
||||||
|
ex_rc = RC_LRET;
|
||||||
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
gv(r);
|
gv(rc);
|
||||||
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;
|
||||||
/* XXX: compatible with arm only: ret_align == register_size */
|
/* XXX: compatible with arm only: ret_align == register_size */
|
||||||
vtop->c.i += ret_align;
|
vtop->c.i += ret_align;
|
||||||
vtop->r = VT_LOCAL | VT_LVAL;
|
vtop->r = VT_LOCAL | VT_LVAL;
|
||||||
|
132
x86_64-gen.c
132
x86_64-gen.c
@ -487,31 +487,24 @@ void load(int r, SValue *sv)
|
|||||||
orex(0,r,0,0);
|
orex(0,r,0,0);
|
||||||
oad(0xb8 + REG_VALUE(r), t ^ 1); /* mov $0, r */
|
oad(0xb8 + REG_VALUE(r), t ^ 1); /* mov $0, r */
|
||||||
} else if (v != r) {
|
} else if (v != r) {
|
||||||
if ((r >= TREG_XMM0) && (r <= TREG_XMM7)) {
|
if (reg_classes[r] & RC_FLOAT) {
|
||||||
if (v == TREG_ST0) {
|
if(v == TREG_ST0){
|
||||||
/* gen_cvt_ftof(VT_DOUBLE); */
|
/* gen_cvt_ftof(VT_DOUBLE); */
|
||||||
o(0xf0245cdd); /* fstpl -0x10(%rsp) */
|
o(0xf0245cdd); /* fstpl -0x10(%rsp) */
|
||||||
/* movsd -0x10(%rsp),%xmmN */
|
/* movsd -0x10(%rsp),%xmm0 */
|
||||||
o(0x100ff2);
|
o(0x100ff2);
|
||||||
o(0x44 + REG_VALUE(r)*8); /* %xmmN */
|
o(0xf02444 + REG_VALUE(r)*8);
|
||||||
o(0xf024);
|
}else if(reg_classes[v] & RC_FLOAT){
|
||||||
} else {
|
o(0x7e0ff3);
|
||||||
assert((v >= TREG_XMM0) && (v <= TREG_XMM7));
|
o(0xc0 + REG_VALUE(v) + REG_VALUE(r)*8);
|
||||||
if ((ft & VT_BTYPE) == VT_FLOAT) {
|
}else
|
||||||
o(0x100ff3);
|
assert(0);
|
||||||
} else {
|
|
||||||
assert((ft & VT_BTYPE) == VT_DOUBLE);
|
|
||||||
o(0x100ff2);
|
|
||||||
}
|
|
||||||
o(0xc0 + REG_VALUE(v) + REG_VALUE(r)*8);
|
|
||||||
}
|
|
||||||
} else if (r == TREG_ST0) {
|
} else if (r == TREG_ST0) {
|
||||||
assert((v >= TREG_XMM0) && (v <= TREG_XMM7));
|
assert(reg_classes[v] & RC_FLOAT);
|
||||||
/* gen_cvt_ftof(VT_LDOUBLE); */
|
/* gen_cvt_ftof(VT_LDOUBLE); */
|
||||||
/* movsd %xmmN,-0x10(%rsp) */
|
/* movsd %xmm0,-0x10(%rsp) */
|
||||||
o(0x110ff2);
|
o(0x110ff2);
|
||||||
o(0x44 + REG_VALUE(r)*8); /* %xmmN */
|
o(0xf02444 + REG_VALUE(v)*8);
|
||||||
o(0xf024);
|
|
||||||
o(0xf02444dd); /* fldl -0x10(%rsp) */
|
o(0xf02444dd); /* fldl -0x10(%rsp) */
|
||||||
} else {
|
} else {
|
||||||
orex(1,r,v, 0x89);
|
orex(1,r,v, 0x89);
|
||||||
@ -522,82 +515,56 @@ void load(int r, SValue *sv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* store register 'r' in lvalue 'v' */
|
/* store register 'r' in lvalue 'v' */
|
||||||
void store(int r, SValue *v)
|
void store(int r, SValue *sv)
|
||||||
{
|
{
|
||||||
int fr, bt, ft, fc;
|
int fr, bt, ft, fc, ll, v;
|
||||||
int op64 = 0;
|
|
||||||
/* store the REX prefix in this variable when PIC is enabled */
|
|
||||||
int pic = 0;
|
|
||||||
|
|
||||||
#ifdef TCC_TARGET_PE
|
#ifdef TCC_TARGET_PE
|
||||||
SValue v2;
|
SValue v2;
|
||||||
v = pe_getimport(v, &v2);
|
sv = pe_getimport(sv, &v2);
|
||||||
#endif
|
#endif
|
||||||
|
ft = sv->type.t & ~VT_DEFSIGN;
|
||||||
ft = v->type.t;
|
fc = sv->c.ul;
|
||||||
fc = v->c.ul;
|
fr = sv->r;
|
||||||
fr = v->r & VT_VALMASK;
|
|
||||||
bt = ft & VT_BTYPE;
|
bt = ft & VT_BTYPE;
|
||||||
|
ll = is64_type(ft);
|
||||||
|
v = fr & VT_VALMASK;
|
||||||
|
|
||||||
#ifndef TCC_TARGET_PE
|
//#ifndef TCC_TARGET_PE
|
||||||
/* we need to access the variable via got */
|
/* we need to access the variable via got */
|
||||||
if (fr == VT_CONST && (v->r & VT_SYM)) {
|
// if (fr == VT_CONST && (v->r & VT_SYM)) {
|
||||||
/* mov xx(%rip), %r11 */
|
/* mov xx(%rip), %r11 */
|
||||||
o(0x1d8b4c);
|
// o(0x1d8b4c);
|
||||||
gen_gotpcrel(TREG_R11, v->sym, v->c.ul);
|
// gen_gotpcrel(TREG_R11, v->sym, v->c.ul);
|
||||||
pic = is64_type(bt) ? 0x49 : 0x41;
|
//pic = is64_type(bt) ? 0x49 : 0x41;
|
||||||
}
|
// }
|
||||||
#endif
|
//#endif
|
||||||
|
|
||||||
/* XXX: incorrect if float reg to reg */
|
/* XXX: incorrect if float reg to reg */
|
||||||
if (bt == VT_FLOAT) {
|
if (bt == VT_FLOAT) {
|
||||||
o(0x66);
|
orex(0, fr, r, 0x110ff3); /* movss */
|
||||||
o(pic);
|
|
||||||
o(0x7e0f); /* movd */
|
|
||||||
r = REG_VALUE(r);
|
|
||||||
} else if (bt == VT_DOUBLE) {
|
} else if (bt == VT_DOUBLE) {
|
||||||
o(0x66);
|
orex(0, fr, r, 0x110ff2);/* movds */
|
||||||
o(pic);
|
|
||||||
o(0xd60f); /* movq */
|
|
||||||
r = REG_VALUE(r);
|
|
||||||
} else if (bt == VT_LDOUBLE) {
|
} else if (bt == VT_LDOUBLE) {
|
||||||
o(0xc0d9); /* fld %st(0) */
|
o(0xc0d9); /* fld %st(0) */
|
||||||
o(pic);
|
orex(0, fr, r, 0xdb);/* fstpt */
|
||||||
o(0xdb); /* fstpt */
|
|
||||||
r = 7;
|
r = 7;
|
||||||
} else {
|
} else {
|
||||||
if (bt == VT_SHORT)
|
if (bt == VT_SHORT)
|
||||||
o(0x66);
|
o(0x66);
|
||||||
o(pic);
|
if (bt == VT_BYTE || bt == VT_BOOL)
|
||||||
if (bt == VT_BYTE || bt == VT_BOOL)
|
orex(ll, fr, r, 0x88);
|
||||||
orex(0, 0, r, 0x88);
|
else{
|
||||||
else if (is64_type(bt))
|
orex(ll, fr, r, 0x89);
|
||||||
op64 = 0x89;
|
}
|
||||||
else
|
|
||||||
orex(0, 0, r, 0x89);
|
|
||||||
}
|
|
||||||
if (pic) {
|
|
||||||
/* xxx r, (%r11) where xxx is mov, movq, fld, or etc */
|
|
||||||
if (op64)
|
|
||||||
o(op64);
|
|
||||||
o(3 + (r << 3));
|
|
||||||
} else if (op64) {
|
|
||||||
if (fr == VT_CONST || fr == VT_LOCAL || (v->r & VT_LVAL)) {
|
|
||||||
gen_modrm64(op64, r, v->r, v->sym, fc);
|
|
||||||
} else if (fr != r) {
|
|
||||||
/* XXX: don't we really come here? */
|
|
||||||
abort();
|
|
||||||
o(0xc0 + fr + r * 8); /* mov r, fr */
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (fr == VT_CONST || fr == VT_LOCAL || (v->r & VT_LVAL)) {
|
|
||||||
gen_modrm(r, v->r, v->sym, fc);
|
|
||||||
} else if (fr != r) {
|
|
||||||
/* XXX: don't we really come here? */
|
|
||||||
abort();
|
|
||||||
o(0xc0 + fr + r * 8); /* mov r, fr */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (v == VT_CONST || v == VT_LOCAL || (fr & VT_LVAL)) {
|
||||||
|
gen_modrm(r, fr, sv->sym, fc);
|
||||||
|
} else if (v != r) {
|
||||||
|
/* XXX: don't we really come here? */
|
||||||
|
abort();
|
||||||
|
o(0xc0 + REG_VALUE(v) + REG_VALUE(r)*8); /* mov r, fr */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 'is_jmp' is '1' if it is a jump */
|
/* 'is_jmp' is '1' if it is a jump */
|
||||||
@ -618,10 +585,9 @@ static void gcall_or_jmp(int is_jmp)
|
|||||||
oad(0xe8 + is_jmp, vtop->c.ul - 4); /* call/jmp im */
|
oad(0xe8 + is_jmp, vtop->c.ul - 4); /* call/jmp im */
|
||||||
} else {
|
} else {
|
||||||
/* otherwise, indirect call */
|
/* otherwise, indirect call */
|
||||||
r = TREG_R11;
|
r = get_reg(RC_INT1);
|
||||||
load(r, vtop);
|
load(r, vtop);
|
||||||
o(0x41); /* REX */
|
orex(0, r, 0, 0xff); /* REX call/jmp *r */
|
||||||
o(0xff); /* call/jmp *r */
|
|
||||||
o(0xd0 + REG_VALUE(r) + (is_jmp << 4));
|
o(0xd0 + REG_VALUE(r) + (is_jmp << 4));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -997,7 +963,7 @@ static X86_64_Mode classify_x86_64_inner(CType *ty)
|
|||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *palign, int *reg_count)
|
static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *palign, int *reg_count)
|
||||||
{
|
{
|
||||||
X86_64_Mode mode;
|
X86_64_Mode mode;
|
||||||
int size, align, ret_t = 0;
|
int size, align, ret_t = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user