tccgen: introduce TOK_NEG for unary minus
for floats (currently only). On x86_64 uses built-in fp constants (in libtcc1.c) to avoid multiple anonymous instances. Also: win32/i386: use __alloca for big struct stack store - use new function int tok_alloc_const(const char*); - change alloca86.S to preserve EDX tccelf.c: fix a warning with 'roinf_use'
This commit is contained in:
parent
a5865fab22
commit
aeb8f427e2
11 changed files with 145 additions and 100 deletions
|
@ -1207,7 +1207,7 @@ ST_FUNC int asm_parse_regvar (int t)
|
||||||
s = table_ident[t - TOK_IDENT]->str;
|
s = table_ident[t - TOK_IDENT]->str;
|
||||||
if (s[0] != '%')
|
if (s[0] != '%')
|
||||||
return -1;
|
return -1;
|
||||||
t = tok_alloc(s+1, strlen(s)-1)->tok;
|
t = tok_alloc_const(s + 1);
|
||||||
unget_tok(t);
|
unget_tok(t);
|
||||||
unget_tok('%');
|
unget_tok('%');
|
||||||
parse_operand(tcc_state, &op);
|
parse_operand(tcc_state, &op);
|
||||||
|
@ -1488,7 +1488,7 @@ ST_FUNC void subst_asm_operand(CString *add_str,
|
||||||
in the C symbol table when later looking up
|
in the C symbol table when later looking up
|
||||||
this name. So enter them now into the asm label
|
this name. So enter them now into the asm label
|
||||||
list when we still know the symbol. */
|
list when we still know the symbol. */
|
||||||
get_asm_sym(tok_alloc(name, strlen(name))->tok, sv->sym);
|
get_asm_sym(tok_alloc_const(name), sv->sym);
|
||||||
}
|
}
|
||||||
if (tcc_state->leading_underscore)
|
if (tcc_state->leading_underscore)
|
||||||
cstr_ccat(add_str, '_');
|
cstr_ccat(add_str, '_');
|
||||||
|
@ -1698,7 +1698,6 @@ ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
|
||||||
ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)
|
ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)
|
||||||
{
|
{
|
||||||
int reg;
|
int reg;
|
||||||
TokenSym *ts;
|
|
||||||
#ifdef TCC_TARGET_X86_64
|
#ifdef TCC_TARGET_X86_64
|
||||||
unsigned int type;
|
unsigned int type;
|
||||||
#endif
|
#endif
|
||||||
|
@ -1707,8 +1706,7 @@ ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)
|
||||||
!strcmp(str, "cc") ||
|
!strcmp(str, "cc") ||
|
||||||
!strcmp(str, "flags"))
|
!strcmp(str, "flags"))
|
||||||
return;
|
return;
|
||||||
ts = tok_alloc(str, strlen(str));
|
reg = tok_alloc_const(str);
|
||||||
reg = ts->tok;
|
|
||||||
if (reg >= TOK_ASM_eax && reg <= TOK_ASM_edi) {
|
if (reg >= TOK_ASM_eax && reg <= TOK_ASM_edi) {
|
||||||
reg -= TOK_ASM_eax;
|
reg -= TOK_ASM_eax;
|
||||||
} else if (reg >= TOK_ASM_ax && reg <= TOK_ASM_di) {
|
} else if (reg >= TOK_ASM_ax && reg <= TOK_ASM_di) {
|
||||||
|
|
38
i386-gen.c
38
i386-gen.c
|
@ -423,26 +423,20 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||||
size = (size + 3) & ~3;
|
size = (size + 3) & ~3;
|
||||||
/* allocate the necessary size on stack */
|
/* allocate the necessary size on stack */
|
||||||
#ifdef TCC_TARGET_PE
|
#ifdef TCC_TARGET_PE
|
||||||
if (size >= 0x4096) {
|
if (size >= 4096) {
|
||||||
/* cannot call alloca with bound checking. Do stack probing. */
|
r = get_reg(RC_EAX);
|
||||||
o(0x50); // push %eax
|
oad(0x68, size); // push size
|
||||||
oad(0xb8, size - 4); // mov size-4,%eax
|
/* cannot call normal 'alloca' with bound checking */
|
||||||
oad(0x3d, 4096); // p1: cmp $4096,%eax
|
gen_static_call(tok_alloc_const("__alloca"));
|
||||||
o(0x1476); // jbe <p2>
|
gadd_sp(4);
|
||||||
oad(0x248485,-4096); // test %eax,-4096(%esp)
|
} else
|
||||||
oad(0xec81, 4096); // sub $4096,%esp
|
|
||||||
oad(0x2d, 4096); // sub $4096,%eax
|
|
||||||
o(0xe5eb); // jmp <p1>
|
|
||||||
o(0xc429); // p2: sub %eax,%esp
|
|
||||||
oad(0xc481, size - 4); // add size-4,%esp
|
|
||||||
o(0x58); // pop %eax
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
oad(0xec81, size); /* sub $xxx, %esp */
|
{
|
||||||
/* generate structure store */
|
oad(0xec81, size); /* sub $xxx, %esp */
|
||||||
r = get_reg(RC_INT);
|
/* generate structure store */
|
||||||
o(0x89); /* mov %esp, r */
|
r = get_reg(RC_INT);
|
||||||
o(0xe0 + r);
|
o(0xe089 + (r << 8)); /* mov %esp, r */
|
||||||
|
}
|
||||||
vset(&vtop->type, r | VT_LVAL, 0);
|
vset(&vtop->type, r | VT_LVAL, 0);
|
||||||
vswap();
|
vswap();
|
||||||
vstore();
|
vstore();
|
||||||
|
@ -844,6 +838,12 @@ ST_FUNC void gen_opf(int op)
|
||||||
{
|
{
|
||||||
int a, ft, fc, swapped, r;
|
int a, ft, fc, swapped, r;
|
||||||
|
|
||||||
|
if (op == TOK_NEG) { /* unary minus */
|
||||||
|
gv(RC_FLOAT);
|
||||||
|
o(0xe0d9); /* fchs */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* convert constants to memory references */
|
/* convert constants to memory references */
|
||||||
if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
|
if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
|
||||||
vswap();
|
vswap();
|
||||||
|
|
|
@ -7,30 +7,30 @@
|
||||||
# define _(s) s
|
# define _(s) s
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
.globl _(alloca)
|
.globl _(alloca), _(__alloca)
|
||||||
_(alloca):
|
_(alloca):
|
||||||
pop %edx
|
_(__alloca):
|
||||||
pop %eax
|
push %ebp
|
||||||
|
mov %esp,%ebp
|
||||||
|
mov 8(%ebp),%eax
|
||||||
add $3,%eax
|
add $3,%eax
|
||||||
and $-4,%eax
|
and $-4,%eax
|
||||||
jz p3
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
jmp .+16 #p2
|
||||||
p1:
|
p1:
|
||||||
cmp $4096,%eax
|
|
||||||
jbe p2
|
|
||||||
test %eax,-4096(%esp)
|
|
||||||
sub $4096,%esp
|
sub $4096,%esp
|
||||||
sub $4096,%eax
|
sub $4096,%eax
|
||||||
jmp p1
|
test %eax,(%esp)
|
||||||
p2:
|
p2:
|
||||||
|
cmp $4096,%eax
|
||||||
|
jae p1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sub %eax,%esp
|
sub %eax,%esp
|
||||||
mov %esp,%eax
|
mov 4(%ebp),%eax
|
||||||
p3:
|
mov 0(%ebp),%ebp
|
||||||
push %edx
|
add $8,%esp
|
||||||
push %edx
|
push %eax
|
||||||
|
lea 8(%esp),%eax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
/* ---------------------------------------------- */
|
/* ---------------------------------------------- */
|
||||||
|
|
|
@ -625,3 +625,9 @@ long long __fixxfdi (long double a1)
|
||||||
return s ? ret : -ret;
|
return s ? ret : -ret;
|
||||||
}
|
}
|
||||||
#endif /* !ARM */
|
#endif /* !ARM */
|
||||||
|
|
||||||
|
#if defined __x86_64__
|
||||||
|
/* float constants used for unary minus operation */
|
||||||
|
const float __mzerosf = -0.0;
|
||||||
|
const double __mzerodf = -0.0;
|
||||||
|
#endif
|
||||||
|
|
2
tcc.h
2
tcc.h
|
@ -1090,6 +1090,7 @@ struct filespec {
|
||||||
#define TOK_SHL '<' /* shift left */
|
#define TOK_SHL '<' /* shift left */
|
||||||
#define TOK_SAR '>' /* signed shift right */
|
#define TOK_SAR '>' /* signed shift right */
|
||||||
#define TOK_SHR 0x8b /* unsigned shift right */
|
#define TOK_SHR 0x8b /* unsigned shift right */
|
||||||
|
#define TOK_NEG TOK_MID /* unary minus operation (for floats) */
|
||||||
|
|
||||||
#define TOK_ARROW 0xa0 /* -> */
|
#define TOK_ARROW 0xa0 /* -> */
|
||||||
#define TOK_DOTS 0xa1 /* three dots */
|
#define TOK_DOTS 0xa1 /* three dots */
|
||||||
|
@ -1378,6 +1379,7 @@ ST_DATA TokenSym **table_ident;
|
||||||
#define IS_NUM 4
|
#define IS_NUM 4
|
||||||
|
|
||||||
ST_FUNC TokenSym *tok_alloc(const char *str, int len);
|
ST_FUNC TokenSym *tok_alloc(const char *str, int len);
|
||||||
|
ST_FUNC int tok_alloc_const(const char *str);
|
||||||
ST_FUNC const char *get_tok_str(int v, CValue *cv);
|
ST_FUNC const char *get_tok_str(int v, CValue *cv);
|
||||||
ST_FUNC void begin_macro(TokenString *str, int alloc);
|
ST_FUNC void begin_macro(TokenString *str, int alloc);
|
||||||
ST_FUNC void end_macro(void);
|
ST_FUNC void end_macro(void);
|
||||||
|
|
19
tccasm.c
19
tccasm.c
|
@ -27,11 +27,8 @@ static Section *last_text_section; /* to handle .previous asm directive */
|
||||||
ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
|
ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
|
||||||
{
|
{
|
||||||
char buf[64];
|
char buf[64];
|
||||||
TokenSym *ts;
|
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "L..%u", n);
|
snprintf(buf, sizeof(buf), "L..%u", n);
|
||||||
ts = tok_alloc(buf, strlen(buf));
|
return tok_alloc_const(buf);
|
||||||
return ts->tok;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global);
|
static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global);
|
||||||
|
@ -54,12 +51,11 @@ static int asm2cname(int v, int *addeddot)
|
||||||
if (!name)
|
if (!name)
|
||||||
return v;
|
return v;
|
||||||
if (name[0] == '_') {
|
if (name[0] == '_') {
|
||||||
v = tok_alloc(name + 1, strlen(name) - 1)->tok;
|
v = tok_alloc_const(name + 1);
|
||||||
} else if (!strchr(name, '.')) {
|
} else if (!strchr(name, '.')) {
|
||||||
int n = strlen(name) + 2;
|
|
||||||
char newname[256];
|
char newname[256];
|
||||||
snprintf(newname, sizeof newname, ".%s", name);
|
snprintf(newname, sizeof newname, ".%s", name);
|
||||||
v = tok_alloc(newname, n - 1)->tok;
|
v = tok_alloc_const(newname);
|
||||||
*addeddot = 1;
|
*addeddot = 1;
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
|
@ -111,11 +107,10 @@ ST_FUNC Sym* get_asm_sym(int name, Sym *csym)
|
||||||
|
|
||||||
static Sym* asm_section_sym(TCCState *s1, Section *sec)
|
static Sym* asm_section_sym(TCCState *s1, Section *sec)
|
||||||
{
|
{
|
||||||
char buf[100];
|
char buf[100]; int label; Sym *sym;
|
||||||
int label = tok_alloc(buf,
|
snprintf(buf, sizeof buf, "L.%s", sec->name);
|
||||||
snprintf(buf, sizeof buf, "L.%s", sec->name)
|
label = tok_alloc_const(buf);
|
||||||
)->tok;
|
sym = asm_label_find(label);
|
||||||
Sym *sym = asm_label_find(label);
|
|
||||||
return sym ? sym : asm_new_label1(s1, label, 1, sec->sh_num, 0);
|
return sym ? sym : asm_new_label1(s1, label, 1, sec->sh_num, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
9
tccelf.c
9
tccelf.c
|
@ -2511,9 +2511,12 @@ static int elf_output_file(TCCState *s1, const char *filename)
|
||||||
{
|
{
|
||||||
int i, ret, phnum, phfill, shnum, file_type, file_offset, *sec_order;
|
int i, ret, phnum, phfill, shnum, file_type, file_offset, *sec_order;
|
||||||
struct dyn_inf dyninf = {0};
|
struct dyn_inf dyninf = {0};
|
||||||
struct ro_inf roinf, *roinf_use = &roinf;
|
struct ro_inf roinf;
|
||||||
ElfW(Phdr) *phdr;
|
ElfW(Phdr) *phdr;
|
||||||
Section *strsec, *interp, *dynamic, *dynstr, *note = NULL;
|
Section *strsec, *interp, *dynamic, *dynstr, *note = NULL;
|
||||||
|
#ifndef ELF_OBJ_ONLY
|
||||||
|
struct ro_inf *roinf_use = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
file_type = s1->output_type;
|
file_type = s1->output_type;
|
||||||
|
|
||||||
|
@ -2648,10 +2651,8 @@ static int elf_output_file(TCCState *s1, const char *filename)
|
||||||
#if !TARGETOS_FreeBSD && !TARGETOS_NetBSD && !defined(__APPLE__) && !defined(_WIN32)
|
#if !TARGETOS_FreeBSD && !TARGETOS_NetBSD && !defined(__APPLE__) && !defined(_WIN32)
|
||||||
/* GNU_RELRO */
|
/* GNU_RELRO */
|
||||||
if (file_type != TCC_OUTPUT_OBJ)
|
if (file_type != TCC_OUTPUT_OBJ)
|
||||||
phnum++;
|
phnum++, roinf_use = &roinf;
|
||||||
else
|
|
||||||
#endif
|
#endif
|
||||||
roinf_use = NULL;
|
|
||||||
|
|
||||||
/* allocate program segment headers */
|
/* allocate program segment headers */
|
||||||
phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr)));
|
phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr)));
|
||||||
|
|
97
tccgen.c
97
tccgen.c
|
@ -2790,6 +2790,33 @@ static void gen_opic(int op)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined TCC_TARGET_X86_64 || defined TCC_TARGET_I386
|
||||||
|
# define gen_negf gen_opf
|
||||||
|
#else
|
||||||
|
/* XXX: implement in gen_opf() for other backends too */
|
||||||
|
void gen_negf(int op)
|
||||||
|
{
|
||||||
|
/* In IEEE negate(x) isn't subtract(0,x). Without NaNs it's
|
||||||
|
subtract(-0, x), but with them it's really a sign flip
|
||||||
|
operation. We implement this with bit manipulation and have
|
||||||
|
to do some type reinterpretation for this, which TCC can do
|
||||||
|
only via memory. */
|
||||||
|
|
||||||
|
int align, size, bt;
|
||||||
|
|
||||||
|
size = type_size(&vtop->type, &align);
|
||||||
|
bt = vtop->type.t & VT_BTYPE;
|
||||||
|
save_reg(gv(RC_TYPE(bt)));
|
||||||
|
vdup();
|
||||||
|
incr_bf_adr(size - 1);
|
||||||
|
vdup();
|
||||||
|
vpushi(0x80); /* flip sign */
|
||||||
|
gen_op('^');
|
||||||
|
vstore();
|
||||||
|
vpop();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* generate a floating point operation with constant propagation */
|
/* generate a floating point operation with constant propagation */
|
||||||
static void gen_opif(int op)
|
static void gen_opif(int op)
|
||||||
{
|
{
|
||||||
|
@ -2803,6 +2830,9 @@ static void gen_opif(int op)
|
||||||
|
|
||||||
v1 = vtop - 1;
|
v1 = vtop - 1;
|
||||||
v2 = vtop;
|
v2 = vtop;
|
||||||
|
if (op == TOK_NEG)
|
||||||
|
v1 = v2;
|
||||||
|
|
||||||
/* currently, we cannot do computations with forward symbols */
|
/* currently, we cannot do computations with forward symbols */
|
||||||
c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
|
c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
|
||||||
c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
|
c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
|
||||||
|
@ -2817,29 +2847,43 @@ static void gen_opif(int op)
|
||||||
f1 = v1->c.ld;
|
f1 = v1->c.ld;
|
||||||
f2 = v2->c.ld;
|
f2 = v2->c.ld;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE: we only do constant propagation if finite number (not
|
/* NOTE: we only do constant propagation if finite number (not
|
||||||
NaN or infinity) (ANSI spec) */
|
NaN or infinity) (ANSI spec) */
|
||||||
if (!ieee_finite(f1) || !ieee_finite(f2))
|
if (!(ieee_finite(f1) || !ieee_finite(f2)) && !const_wanted)
|
||||||
goto general_case;
|
goto general_case;
|
||||||
|
|
||||||
switch(op) {
|
switch(op) {
|
||||||
case '+': f1 += f2; break;
|
case '+': f1 += f2; break;
|
||||||
case '-': f1 -= f2; break;
|
case '-': f1 -= f2; break;
|
||||||
case '*': f1 *= f2; break;
|
case '*': f1 *= f2; break;
|
||||||
case '/':
|
case '/':
|
||||||
if (f2 == 0.0) {
|
if (f2 == 0.0) {
|
||||||
|
union { float f; unsigned u; } x1, x2, y;
|
||||||
/* If not in initializer we need to potentially generate
|
/* If not in initializer we need to potentially generate
|
||||||
FP exceptions at runtime, otherwise we want to fold. */
|
FP exceptions at runtime, otherwise we want to fold. */
|
||||||
if (!const_wanted)
|
if (!const_wanted)
|
||||||
goto general_case;
|
goto general_case;
|
||||||
|
/* the run-time result of 0.0/0.0 on x87, also of other compilers
|
||||||
|
when used to compile the f1 /= f2 below, would be -nan */
|
||||||
|
x1.f = f1, x2.f = f2;
|
||||||
|
if (f1 == 0.0)
|
||||||
|
y.u = 0x7fc00000; /* nan */
|
||||||
|
else
|
||||||
|
y.u = 0x7f800000; /* infinity */
|
||||||
|
y.u |= (x1.u ^ x2.u) & 0x80000000; /* set sign */
|
||||||
|
f1 = y.f;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
f1 /= f2;
|
f1 /= f2;
|
||||||
break;
|
break;
|
||||||
|
case TOK_NEG:
|
||||||
|
f1 = -f1;
|
||||||
|
goto unary_result;
|
||||||
/* XXX: also handles tests ? */
|
/* XXX: also handles tests ? */
|
||||||
default:
|
default:
|
||||||
goto general_case;
|
goto general_case;
|
||||||
}
|
}
|
||||||
|
vtop--;
|
||||||
|
unary_result:
|
||||||
/* XXX: overflow test ? */
|
/* XXX: overflow test ? */
|
||||||
if (v1->type.t == VT_FLOAT) {
|
if (v1->type.t == VT_FLOAT) {
|
||||||
v1->c.f = f1;
|
v1->c.f = f1;
|
||||||
|
@ -2848,10 +2892,13 @@ static void gen_opif(int op)
|
||||||
} else {
|
} else {
|
||||||
v1->c.ld = f1;
|
v1->c.ld = f1;
|
||||||
}
|
}
|
||||||
vtop--;
|
|
||||||
} else {
|
} else {
|
||||||
general_case:
|
general_case:
|
||||||
gen_opf(op);
|
if (op == TOK_NEG) {
|
||||||
|
gen_negf(op);
|
||||||
|
} else {
|
||||||
|
gen_opf(op);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5878,44 +5925,8 @@ ST_FUNC void unary(void)
|
||||||
case '-':
|
case '-':
|
||||||
next();
|
next();
|
||||||
unary();
|
unary();
|
||||||
t = vtop->type.t & VT_BTYPE;
|
if (is_float(vtop->type.t)) {
|
||||||
if (is_float(t)) {
|
gen_opif(TOK_NEG);
|
||||||
if ((vtop->r & VT_VALMASK) == VT_CONST) {
|
|
||||||
/* This is what gen_opif would do if we had a NEG operation. */
|
|
||||||
if (t == VT_FLOAT)
|
|
||||||
vtop->c.f = -vtop->c.f;
|
|
||||||
else if (t == VT_DOUBLE)
|
|
||||||
vtop->c.d = -vtop->c.d;
|
|
||||||
else
|
|
||||||
vtop->c.ld = -vtop->c.ld;
|
|
||||||
} else {
|
|
||||||
/* In IEEE negate(x) isn't subtract(0,x). Without NaNs it's
|
|
||||||
subtract(-0, x), but with them it's really a sign flip
|
|
||||||
operation. We implement this with bit manipulation and have
|
|
||||||
to do some type reinterpretation for this, which TCC can do
|
|
||||||
only via memory. */
|
|
||||||
int align, size = type_size(&vtop->type, &align);
|
|
||||||
save_reg(gv(RC_TYPE(t)));
|
|
||||||
vdup();
|
|
||||||
gaddrof();
|
|
||||||
vtop->type = char_pointer_type;
|
|
||||||
/* Byte of sign bit. For big endian, this would have to
|
|
||||||
add zero always. */
|
|
||||||
#if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_I386)
|
|
||||||
/* sizeof long double is 12 or 16 here, but it's
|
|
||||||
really the 80bit extended float format. */
|
|
||||||
if (t == VT_LDOUBLE)
|
|
||||||
size = 10;
|
|
||||||
#endif
|
|
||||||
vpushi(size - 1);
|
|
||||||
gen_op('+');
|
|
||||||
indir();
|
|
||||||
vdup();
|
|
||||||
vpushi(0x80); /* flip sign */
|
|
||||||
gen_op('^');
|
|
||||||
vstore();
|
|
||||||
vpop();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
vpushi(0);
|
vpushi(0);
|
||||||
vswap();
|
vswap();
|
||||||
|
|
6
tccpp.c
6
tccpp.c
|
@ -487,6 +487,12 @@ ST_FUNC TokenSym *tok_alloc(const char *str, int len)
|
||||||
return tok_alloc_new(pts, str, len);
|
return tok_alloc_new(pts, str, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ST_FUNC int tok_alloc_const(const char *str)
|
||||||
|
{
|
||||||
|
return tok_alloc(str, strlen(str))->tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* XXX: buffer overflow */
|
/* XXX: buffer overflow */
|
||||||
/* XXX: float tokens */
|
/* XXX: float tokens */
|
||||||
ST_FUNC const char *get_tok_str(int v, CValue *cv)
|
ST_FUNC const char *get_tok_str(int v, CValue *cv)
|
||||||
|
|
2
tcctok.h
2
tcctok.h
|
@ -100,6 +100,8 @@
|
||||||
DEF(TOK___NAN__, "__nan__")
|
DEF(TOK___NAN__, "__nan__")
|
||||||
DEF(TOK___SNAN__, "__snan__")
|
DEF(TOK___SNAN__, "__snan__")
|
||||||
DEF(TOK___INF__, "__inf__")
|
DEF(TOK___INF__, "__inf__")
|
||||||
|
DEF(TOK___mzerosf, "__mzerosf")
|
||||||
|
DEF(TOK___mzerodf, "__mzerodf")
|
||||||
|
|
||||||
/* attribute identifiers */
|
/* attribute identifiers */
|
||||||
/* XXX: handle all tokens generically since speed is not critical */
|
/* XXX: handle all tokens generically since speed is not critical */
|
||||||
|
|
28
x86_64-gen.c
28
x86_64-gen.c
|
@ -1813,14 +1813,38 @@ void gen_opl(int op)
|
||||||
gen_opi(op);
|
gen_opi(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vpush_const(int t, int v)
|
||||||
|
{
|
||||||
|
CType ctype = { t | VT_CONSTANT, 0 };
|
||||||
|
vpushsym(&ctype, external_global_sym(v, &ctype));
|
||||||
|
vtop->r |= VT_LVAL;
|
||||||
|
}
|
||||||
|
|
||||||
/* generate a floating point operation 'v = t1 op t2' instruction. The
|
/* generate a floating point operation 'v = t1 op t2' instruction. The
|
||||||
two operands are guaranteed to have the same floating point type */
|
two operands are guaranteed to have the same floating point type */
|
||||||
/* XXX: need to use ST1 too */
|
/* XXX: need to use ST1 too */
|
||||||
void gen_opf(int op)
|
void gen_opf(int op)
|
||||||
{
|
{
|
||||||
int a, ft, fc, swapped, r;
|
int a, ft, fc, swapped, r;
|
||||||
int float_type =
|
int bt = vtop->type.t & VT_BTYPE;
|
||||||
(vtop->type.t & VT_BTYPE) == VT_LDOUBLE ? RC_ST0 : RC_FLOAT;
|
int float_type = bt == VT_LDOUBLE ? RC_ST0 : RC_FLOAT;
|
||||||
|
|
||||||
|
if (op == TOK_NEG) { /* unary minus */
|
||||||
|
gv(float_type);
|
||||||
|
if (float_type == RC_ST0) {
|
||||||
|
o(0xe0d9); /* fchs */
|
||||||
|
} else {
|
||||||
|
/* -0.0, in libtcc1.c */
|
||||||
|
vpush_const(bt, bt == VT_FLOAT ? TOK___mzerosf : TOK___mzerodf);
|
||||||
|
gv(RC_FLOAT);
|
||||||
|
if (bt == VT_DOUBLE)
|
||||||
|
o(0x66);
|
||||||
|
/* xorp[sd] %xmm1, %xmm0 */
|
||||||
|
o(0xc0570f | (REG_VALUE(vtop[0].r) + REG_VALUE(vtop[-1].r)*8) << 16);
|
||||||
|
vtop--;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* convert constants to memory references */
|
/* convert constants to memory references */
|
||||||
if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
|
if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue