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