From 4b50557553a507014b433a5e5f297cbee90d919a Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Mon, 28 Apr 2014 12:28:56 +0800 Subject: [PATCH 01/52] add test for abitest.c --- tests/abitest.c | 58 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/tests/abitest.c b/tests/abitest.c index d3e151f..488de1e 100644 --- a/tests/abitest.c +++ b/tests/abitest.c @@ -88,7 +88,7 @@ static int ret_2float_test_callback(void *ptr) { ret_2float_test_type a = {10, 35}; ret_2float_test_type r; r = f(a); - return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1; + return ((r.x == a.x*5) && (r.y == a.y*3) && (f(a).x == a.x*5) && (f(a).y == a.y*3)) ? 0 : -1; } static int ret_2float_test(void) { @@ -116,7 +116,7 @@ static int ret_2double_test_callback(void *ptr) { ret_2double_test_type a = {10, 35}; ret_2double_test_type r; r = f(a); - return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1; + return ((r.x == a.x*5) && (r.y == a.y*3) && (f(a).x == a.x*5) && (f(a).y == a.y*3)) ? 0 : -1; } static int ret_2double_test(void) { @@ -130,6 +130,52 @@ static int ret_2double_test(void) { return run_callback(src, ret_2double_test_callback); } +typedef struct ret_longdouble_test_type_s2 {LONG_DOUBLE x;} ret_longdouble_test_type; +typedef ret_longdouble_test_type (*ret_longdouble_test_function_type) (ret_longdouble_test_type); + +static int ret_longdouble_test_callback2(void *ptr) { + ret_longdouble_test_function_type f = (ret_longdouble_test_function_type)ptr; + ret_longdouble_test_type a = {10}; + ret_longdouble_test_type r; + r = f(a); + printf("%Lf \n", a.x); + printf("%Lf \n", r.x); + return ((r.x == a.x*5) && (f(a).x == a.x*5)) ? 0 : -1; +} + +static int ret_longdouble_test2(void) { + const char *src = + "typedef struct ret_longdouble_test_type_s2 {long double x;} ret_longdouble_test_type;" + "ret_longdouble_test_type f(ret_longdouble_test_type a) {\n" + " ret_longdouble_test_type r = {a.x*5};\n" + " return r;\n" + "}\n"; + + return run_callback(src, ret_longdouble_test_callback2); +} + +typedef struct ret_longlong_test_type_s2 {int x[4];} ret_longlong_test_type; +typedef ret_longlong_test_type (*ret_longlong_test_function_type) (ret_longlong_test_type); + +static int ret_longlong_test_callback2(void *ptr) { + ret_longlong_test_function_type f = (ret_longlong_test_function_type)ptr; + ret_longlong_test_type a = {{10,11,12,13}}; + ret_longlong_test_type r; + r = f(a); + return ((r.x[2] == a.x[2]*5) && (f(a).x[2] == a.x[2]*5)) ? 0 : -1; +} + +static int ret_longlong_test2(void) { + const char *src = + "typedef struct ret_longlong_test_type_s2 {int x[4];} ret_longlong_test_type;" + "ret_longlong_test_type f(ret_longlong_test_type a) {\n" + " ret_longlong_test_type r = {.x[2] = a.x[2]*5};\n" + " return r;\n" + "}\n"; + + return run_callback(src, ret_longlong_test_callback2); +} + /* * reg_pack_test: return a small struct which should be packed into * registers (Win32) during return. @@ -142,7 +188,7 @@ static int reg_pack_test_callback(void *ptr) { reg_pack_test_type a = {10, 35}; reg_pack_test_type r; r = f(a); - return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1; + return ((r.x == a.x*5) && (r.y == a.y*3) && (f(a).x == a.x*5) && (f(a).y == a.y*3)) ? 0 : -1; } static int reg_pack_test(void) { @@ -168,7 +214,7 @@ static int reg_pack_longlong_test_callback(void *ptr) { reg_pack_longlong_test_type a = {10, 35}; reg_pack_longlong_test_type r; r = f(a); - return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1; + return ((r.x == a.x*5) && (r.y == a.y*3) && (f(a).x == a.x*5) && (f(a).y == a.y*3)) ? 0 : -1; } static int reg_pack_longlong_test(void) { @@ -248,7 +294,7 @@ static int two_member_union_test_callback(void *ptr) { two_member_union_test_type a, b; a.x = 34; b = f(a); - return (b.x == a.x*2) ? 0 : -1; + return ((b.x == a.x*2) && (f(a).x == a.x*2)) ? 0 : -1; } static int two_member_union_test(void) { @@ -441,6 +487,8 @@ int main(int argc, char **argv) { RUN_TEST(ret_longdouble_test); RUN_TEST(ret_2float_test); RUN_TEST(ret_2double_test); + RUN_TEST(ret_longlong_test2); + RUN_TEST(ret_longdouble_test2); RUN_TEST(reg_pack_test); RUN_TEST(reg_pack_longlong_test); RUN_TEST(sret_test); From 857f7dbfa65179e6690dbee7ab915fb4458cee11 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Mon, 28 Apr 2014 12:42:36 +0800 Subject: [PATCH 02/52] update static void parse_number(const char *p) for tccpp.c --- tccpp.c | 368 ++++++++++++++++++++++---------------------------------- 1 file changed, 143 insertions(+), 225 deletions(-) diff --git a/tccpp.c b/tccpp.c index 2da65cd..938699e 100644 --- a/tccpp.c +++ b/tccpp.c @@ -1817,234 +1817,152 @@ static void bn_zero(unsigned int *bn) current token */ static void parse_number(const char *p) { - int b, t, shift, frac_bits, s, exp_val, ch; - char *q; - unsigned int bn[BN_SIZE]; - double d; + int b, t, c; - /* number */ - q = token_buf; - ch = *p++; - t = ch; - ch = *p++; - *q++ = t; + c = *p++; + t = *p++; b = 10; - if (t == '.') { - goto float_frac_parse; - } else if (t == '0') { - if (ch == 'x' || ch == 'X') { - q--; - ch = *p++; + if(c=='.'){ + --p; + goto float_frac_parse; + } + if(c == '0'){ + if (t == 'x' || t == 'X') { b = 16; - } else if (tcc_ext && (ch == 'b' || ch == 'B')) { - q--; - ch = *p++; + c = *p++; + } else if (tcc_ext && (t == 'b' || t == 'B')) { b = 2; - } - } - /* parse all digits. cannot check octal numbers at this stage - because of floating point constants */ - while (1) { - if (ch >= 'a' && ch <= 'f') - t = ch - 'a' + 10; - else if (ch >= 'A' && ch <= 'F') - t = ch - 'A' + 10; - else if (isnum(ch)) - t = ch - '0'; - else - break; - if (t >= b) - break; - if (q >= token_buf + STRING_MAX_SIZE) { - num_too_long: - tcc_error("number too long"); - } - *q++ = ch; - ch = *p++; - } - if (ch == '.' || - ((ch == 'e' || ch == 'E') && b == 10) || - ((ch == 'p' || ch == 'P') && (b == 16 || b == 2))) { - if (b != 10) { - /* NOTE: strtox should support that for hexa numbers, but - non ISOC99 libcs do not support it, so we prefer to do - it by hand */ - /* hexadecimal or binary floats */ - /* XXX: handle overflows */ - *q = '\0'; - if (b == 16) - shift = 4; - else - shift = 2; - bn_zero(bn); - q = token_buf; - while (1) { - t = *q++; - if (t == '\0') { - break; - } else if (t >= 'a') { - t = t - 'a' + 10; - } else if (t >= 'A') { - t = t - 'A' + 10; - } else { - t = t - '0'; - } - bn_lshift(bn, shift, t); - } - frac_bits = 0; - if (ch == '.') { - ch = *p++; - while (1) { - t = ch; - if (t >= 'a' && t <= 'f') { - t = t - 'a' + 10; - } else if (t >= 'A' && t <= 'F') { - t = t - 'A' + 10; - } else if (t >= '0' && t <= '9') { - t = t - '0'; - } else { - break; - } - if (t >= b) - tcc_error("invalid digit"); - bn_lshift(bn, shift, t); - frac_bits += shift; - ch = *p++; - } - } - if (ch != 'p' && ch != 'P') - expect("exponent"); - ch = *p++; - s = 1; - exp_val = 0; - if (ch == '+') { - ch = *p++; - } else if (ch == '-') { - s = -1; - ch = *p++; - } - if (ch < '0' || ch > '9') - expect("exponent digits"); - while (ch >= '0' && ch <= '9') { - exp_val = exp_val * 10 + ch - '0'; - ch = *p++; - } - exp_val = exp_val * s; - - /* now we can generate the number */ - /* XXX: should patch directly float number */ - d = (double)bn[1] * 4294967296.0 + (double)bn[0]; - d = ldexp(d, exp_val - frac_bits); - t = toup(ch); - if (t == 'F') { - ch = *p++; - tok = TOK_CFLOAT; - /* float : should handle overflow */ - tokc.f = (float)d; - } else if (t == 'L') { - ch = *p++; -#ifdef TCC_TARGET_PE - tok = TOK_CDOUBLE; - tokc.d = d; -#else - tok = TOK_CLDOUBLE; - /* XXX: not large enough */ - tokc.ld = (long double)d; -#endif - } else { - tok = TOK_CDOUBLE; - tokc.d = d; - } - } else { - /* decimal floats */ - if (ch == '.') { - if (q >= token_buf + STRING_MAX_SIZE) - goto num_too_long; - *q++ = ch; - ch = *p++; - float_frac_parse: - while (ch >= '0' && ch <= '9') { - if (q >= token_buf + STRING_MAX_SIZE) - goto num_too_long; - *q++ = ch; - ch = *p++; - } - } - if (ch == 'e' || ch == 'E') { - if (q >= token_buf + STRING_MAX_SIZE) - goto num_too_long; - *q++ = ch; - ch = *p++; - if (ch == '-' || ch == '+') { - if (q >= token_buf + STRING_MAX_SIZE) - goto num_too_long; - *q++ = ch; - ch = *p++; - } - if (ch < '0' || ch > '9') - expect("exponent digits"); - while (ch >= '0' && ch <= '9') { - if (q >= token_buf + STRING_MAX_SIZE) - goto num_too_long; - *q++ = ch; - ch = *p++; - } - } - *q = '\0'; - t = toup(ch); - errno = 0; - if (t == 'F') { - ch = *p++; - tok = TOK_CFLOAT; - tokc.f = strtof(token_buf, NULL); - } else if (t == 'L') { - ch = *p++; -#ifdef TCC_TARGET_PE - tok = TOK_CDOUBLE; - tokc.d = strtod(token_buf, NULL); -#else - tok = TOK_CLDOUBLE; - tokc.ld = strtold(token_buf, NULL); -#endif - } else { - tok = TOK_CDOUBLE; - tokc.d = strtod(token_buf, NULL); - } - } - } else { - unsigned long long n, n1; - int lcount, ucount; + c = *p++; + }else{ + --p; + } + }else + --p; + if(strchr(p , '.') || (b == 10 && (strchr(p,'e') || strchr(p,'E'))) || + ((b == 2 || b == 16)&& (strchr(p,'p') || strchr(p,'P')))){ + long double ld, sh, fb; + int exp; + /* NOTE: strtox should support that for hexa numbers, but + non ISOC99 libcs do not support it, so we prefer to do + it by hand */ + /* hexadecimal or binary floats */ + /* XXX: handle overflows */ +float_frac_parse: + fb = 1.0L/b; + sh = b; + ld = 0.0; - /* integer number */ - *q = '\0'; - q = token_buf; - if (b == 10 && *q == '0') { + while(1){ + if (c == '\0') + break; + if (c >= 'a' && c <= 'f') + t = c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + t = c - 'A' + 10; + else if(isnum(c)) + t = c - '0'; + else + break; + if (t >= b) + tcc_error("invalid digit"); + ld = ld * b + t; + c = *p++; + } + if (c == '.'){ + c = *p++; + sh = fb; + while (1){ + if (c == '\0') + break; + if (c >= 'a' && c <= 'f') + t = c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + t = c - 'A' + 10; + else if (isnum(c)) + t =c - '0'; + else + break; + if (t >= b){ + if(b == 10 && (c == 'e' || c == 'E' || c == 'f' || c == 'F')) + break; + tcc_error("invalid digit"); + } + ld += sh*t; + sh*=fb; + c = *p++; + } + } + if ((b == 16 || b == 2) && c != 'p' && c != 'P') + expect("exponent"); + if(((c == 'e' || c == 'E') && b == 10) || + ((c == 'p' || c == 'P') && (b == 16 || b == 2))){ + c = *p++; + if(c == '+' || c == '-'){ + if (c == '-') + sh = fb; + c = *p++; + }else + sh = b; + if (!isnum(c)) + expect("exponent digits"); + exp = 0; + do{ + exp = exp * 10 + c - '0'; + c = *p++; + }while(isnum(c)); + while (exp != 0){ + if (exp & 1) + ld *= sh; + exp >>= 1; + sh *= sh; + } + } + t = toup(c); + if (t == 'F') { + c = *p++; + tok = TOK_CFLOAT; + tokc.f = (float)ld; + } else if (t == 'L') { + c = *p++; +#ifdef TCC_TARGET_PE + tok = TOK_CDOUBLE; + tokc.d = (double)ld; +#else + tok = TOK_CLDOUBLE; + tokc.ld = ld; +#endif + } else { + tok = TOK_CDOUBLE; + tokc.d = (double)ld; + } + } else { + uint64_t n = 0, n1; + int warn = 1; + int lcount, ucount; + if (b == 10 && c == '0') { b = 8; - q++; } - n = 0; - while(1) { - t = *q++; - /* no need for checks except for base 10 / 8 errors */ - if (t == '\0') { - break; - } else if (t >= 'a') { - t = t - 'a' + 10; - } else if (t >= 'A') { - t = t - 'A' + 10; - } else { - t = t - '0'; - if (t >= b) - tcc_error("invalid digit"); - } - n1 = n; - n = n * b + t; - /* detect overflow */ - /* XXX: this test is not reliable */ - if (n < n1) - tcc_error("integer constant overflow"); - } - + while(1){ + if (c == '\0') + break; + if (c >= 'a' && c <= 'f') + t = c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + t = c - 'A' + 10; + else if(isnum(c)) + t = c - '0'; + else + break; + if (t >= b) + tcc_error("invalid digit"); + n1 = n; + n = n * b + t; + if (n < n1 && warn){ + tcc_warning("integer constant overflow"); + warn = 0; + } + c = *p++; + } /* XXX: not exactly ANSI compliant */ if ((n & 0xffffffff00000000LL) != 0) { if ((n >> 63) != 0) @@ -2059,7 +1977,7 @@ static void parse_number(const char *p) lcount = 0; ucount = 0; for(;;) { - t = toup(ch); + t = toup(c); if (t == 'L') { if (lcount >= 2) tcc_error("three 'l's in integer constant"); @@ -2074,7 +1992,7 @@ static void parse_number(const char *p) #if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE } #endif - ch = *p++; + c = *p++; } else if (t == 'U') { if (ucount >= 1) tcc_error("two 'u's in integer constant"); @@ -2083,7 +2001,7 @@ static void parse_number(const char *p) tok = TOK_CUINT; else if (tok == TOK_CLLONG) tok = TOK_CULLONG; - ch = *p++; + c = *p++; } else { break; } @@ -2093,7 +2011,7 @@ static void parse_number(const char *p) else tokc.ull = n; } - if (ch) + if (c) tcc_error("invalid number\n"); } From deaee6c2496ecb25858290405fef8ef79aece979 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Mon, 28 Apr 2014 12:53:18 +0800 Subject: [PATCH 03/52] fix tccpp.c --- tccpp.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/tccpp.c b/tccpp.c index 938699e..732c5ea 100644 --- a/tccpp.c +++ b/tccpp.c @@ -58,7 +58,6 @@ static const int *unget_saved_macro_ptr; static int unget_saved_buffer[TOK_MAX_SIZE + 1]; static int unget_buffer_enabled; static TokenSym *hash_ident[TOK_HASH_SIZE]; -static char token_buf[STRING_MAX_SIZE + 1]; /* true if isid(c) || isnum(c) */ static unsigned char isidnum_table[256-CH_EOF]; @@ -1790,29 +1789,6 @@ static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long cstr_wccat(outstr, '\0'); } -/* we use 64 bit numbers */ -#define BN_SIZE 2 - -/* bn = (bn << shift) | or_val */ -static void bn_lshift(unsigned int *bn, int shift, int or_val) -{ - int i; - unsigned int v; - for(i=0;i> (32 - shift); - } -} - -static void bn_zero(unsigned int *bn) -{ - int i; - for(i=0;i Date: Mon, 28 Apr 2014 14:05:55 +0800 Subject: [PATCH 04/52] fix abitest.c for x86_64 bug --- tests/abitest.c | 2 -- x86_64-gen.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/abitest.c b/tests/abitest.c index 488de1e..3ad707a 100644 --- a/tests/abitest.c +++ b/tests/abitest.c @@ -138,8 +138,6 @@ static int ret_longdouble_test_callback2(void *ptr) { ret_longdouble_test_type a = {10}; ret_longdouble_test_type r; r = f(a); - printf("%Lf \n", a.x); - printf("%Lf \n", r.x); return ((r.x == a.x*5) && (f(a).x == a.x*5)) ? 0 : -1; } diff --git a/x86_64-gen.c b/x86_64-gen.c index eb201c8..12893a3 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -981,7 +981,7 @@ static X86_64_Mode classify_x86_64_inner(CType *ty) return x86_64_mode_memory; mode = x86_64_mode_none; - for (; f; f = f->next) + for (f = f->next; f; f = f->next) mode = classify_x86_64_merge(mode, classify_x86_64_inner(&f->type)); return mode; From e20c1eb99e1003c1e59522c136dbb15c52d7cc7c Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Mon, 28 Apr 2014 19:43:02 +0800 Subject: [PATCH 05/52] fix test3 for x86_64-gen.c --- x86_64-gen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x86_64-gen.c b/x86_64-gen.c index 12893a3..ae65328 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -1272,7 +1272,7 @@ void gfunc_call(int nb_args) g(0x00); args_size += size; } else { - assert(mode == x86_64_mode_memory); + //assert(mode == x86_64_mode_memory); /* allocate the necessary size on stack */ o(0x48); From 02e2fe3c260415f4cb1cbcaca9b2403a17f7ff2e Mon Sep 17 00:00:00 2001 From: Thomas Preud'homme Date: Fri, 14 Jun 2013 16:18:16 +0200 Subject: [PATCH 06/52] Add support for load/store of _Bool value Add support for loading _Bool value in i386, x86_64 and arm as well as support for storing _Bool value on arm. --- arm-gen.c | 4 ++-- i386-gen.c | 2 +- x86_64-gen.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arm-gen.c b/arm-gen.c index 250b1d9..eccfdd8 100644 --- a/arm-gen.c +++ b/arm-gen.c @@ -571,7 +571,7 @@ void load(int r, SValue *sv) op=0xE5100000; if(!sign) op|=0x800000; - if ((ft & VT_BTYPE) == VT_BYTE) + if ((ft & VT_BTYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_BOOL) op|=0x400000; o(op|(intr(r)<<12)|fc|(base<<16)); } @@ -699,7 +699,7 @@ void store(int r, SValue *sv) op=0xE5000000; if(!sign) op|=0x800000; - if ((ft & VT_BTYPE) == VT_BYTE) + if ((ft & VT_BTYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_BOOL) op|=0x400000; o(op|(intr(r)<<12)|fc|(base<<16)); } diff --git a/i386-gen.c b/i386-gen.c index 2a4007c..844a482 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -244,7 +244,7 @@ ST_FUNC void load(int r, SValue *sv) } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { o(0xdb); /* fldt */ r = 5; - } else if ((ft & VT_TYPE) == VT_BYTE) { + } else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) { o(0xbe0f); /* movsbl */ } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) { o(0xb60f); /* movzbl */ diff --git a/x86_64-gen.c b/x86_64-gen.c index 2788677..d1bf75c 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -414,7 +414,7 @@ void load(int r, SValue *sv) r = REG_VALUE(r); } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { b = 0xdb, r = 5; /* fldt */ - } else if ((ft & VT_TYPE) == VT_BYTE) { + } else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) { b = 0xbe0f; /* movsbl */ } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) { b = 0xb60f; /* movzbl */ From 515169f21bf6c75a3179822e1dd9e006f5ef4412 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Tue, 29 Apr 2014 23:57:22 +0800 Subject: [PATCH 07/52] Reduce the generation of machine code for x86_64, Less of size --- tcc.h | 8 +- tccgen.c | 3 +- x86_64-gen.c | 484 +++++++++++++++++++++++++-------------------------- 3 files changed, 244 insertions(+), 251 deletions(-) diff --git a/tcc.h b/tcc.h index c93cedf..24b5b5a 100644 --- a/tcc.h +++ b/tcc.h @@ -738,19 +738,21 @@ struct TCCState { #define VT_CMP 0x0033 /* the value is stored in processor flags (in vc) */ #define VT_JMP 0x0034 /* value is the consequence of jmp true (even) */ #define VT_JMPI 0x0035 /* value is the consequence of jmp false (odd) */ -#define VT_REF 0x0040 /* value is pointer to structure rather than address */ +#define TREG_MEM 0x0040 /* x86_64-gen.c add for tcc.h: The current value can be */ +#define VT_REF 0x0080 /* value is pointer to structure rather than address */ #define VT_LVAL 0x0100 /* var is an lvalue */ #define VT_SYM 0x0200 /* a symbol value is added */ #define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for char/short stored in integer registers) */ #define VT_MUSTBOUND 0x0800 /* bound checking must be done before dereferencing value */ -#define VT_BOUNDED 0x8000 /* value is bounded. The address of the - bounding function call point is in vc */ #define VT_LVAL_BYTE 0x1000 /* lvalue is a byte */ #define VT_LVAL_SHORT 0x2000 /* lvalue is a short */ #define VT_LVAL_UNSIGNED 0x4000 /* lvalue is unsigned */ #define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED) +#define VT_BOUNDED 0x8000 /* value is bounded. The address of the + bounding function call point is in vc */ +#define VT_TMP 0x10000 /* types */ #define VT_BTYPE 0x000f /* mask for basic type */ diff --git a/tccgen.c b/tccgen.c index 1a89d4a..71a426a 100644 --- a/tccgen.c +++ b/tccgen.c @@ -909,8 +909,9 @@ ST_FUNC int gv(int rc) /* one register type load */ load(r, vtop); } + vtop->r = r; + vtop->c.ptr_offset = 0; } - vtop->r = r; #ifdef TCC_TARGET_C67 /* uses register pairs for doubles */ if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) diff --git a/x86_64-gen.c b/x86_64-gen.c index ae65328..a8a7e87 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -29,28 +29,38 @@ /* a register can belong to several classes. The classes must be sorted from more general to more precise (see gv2() code which does assumptions on it). */ -#define RC_INT 0x0001 /* generic integer register */ -#define RC_FLOAT 0x0002 /* generic float register */ -#define RC_RAX 0x0004 -#define RC_RCX 0x0008 -#define RC_RDX 0x0010 -#define RC_ST0 0x0080 /* only for long double */ -#define RC_R8 0x0100 -#define RC_R9 0x0200 -#define RC_R10 0x0400 -#define RC_R11 0x0800 -#define RC_XMM0 0x1000 -#define RC_XMM1 0x2000 -#define RC_XMM2 0x4000 -#define RC_XMM3 0x8000 -#define RC_XMM4 0x10000 -#define RC_XMM5 0x20000 -#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_FRET RC_XMM0 /* function return: float register */ -#define RC_QRET RC_XMM1 /* function return: second float register */ +#define RC_INT 0x0001 /* generic integer register */ +#define RC_FLOAT 0x0002 /* generic float register */ +#define RC_RAX 0x0004 +#define RC_RCX 0x0008 +#define RC_RDX 0x0010 +#define RC_ST0 0x0020 /* only for long double */ +#define RC_R8 0x0040 +#define RC_R9 0x0080 +#define RC_XMM0 0x0100 +#define RC_XMM1 0x0200 +#define RC_XMM2 0x0400 +#define RC_XMM3 0x0800 +#define RC_XMM4 0x1000 +#define RC_XMM5 0x2000 +#define RC_XMM6 0x4000 +#define RC_XMM7 0x8000 +#define RC_RSI 0x10000 +#define RC_RDI 0x20000 +#define RC_INT1 0x40000 /* function_pointer */ +#define RC_INT2 0x80000 +#define RC_RBX 0x100000 +#define RC_R10 0x200000 +#define RC_R11 0x400000 +#define RC_R12 0x800000 +#define RC_R13 0x1000000 +#define RC_R14 0x2000000 +#define RC_R15 0x4000000 +#define RC_IRET RC_RAX /* function return: integer register */ +#define RC_LRET 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_MASK (RC_INT|RC_INT1|RC_INT2|RC_FLOAT) /* pretty names for the registers */ enum { @@ -58,6 +68,7 @@ enum { TREG_RCX = 1, TREG_RDX = 2, TREG_RSP = 4, + TREG_ST0 = 5, TREG_RSI = 6, TREG_RDI = 7, @@ -75,13 +86,11 @@ enum { TREG_XMM6 = 22, TREG_XMM7 = 23, - TREG_ST0 = 24, - - TREG_MEM = 0x20, }; #define REX_BASE(reg) (((reg) >> 3) & 1) #define REG_VALUE(reg) ((reg) & 7) +#define FLAG_GOT 0X01 /* return registers for function */ #define REG_IRET TREG_RAX /* single word int return register */ @@ -122,34 +131,30 @@ enum { #include ST_DATA const int reg_classes[NB_REGS] = { - /* eax */ RC_INT | RC_RAX, - /* ecx */ RC_INT | RC_RCX, - /* edx */ RC_INT | RC_RDX, + /* eax */ RC_INT|RC_RAX|RC_INT2, + /* ecx */ RC_INT|RC_RCX|RC_INT2, + /* edx */ RC_INT|RC_RDX, + RC_INT|RC_INT1|RC_INT2|RC_RBX, 0, - 0, - 0, - 0, - 0, - RC_R8, - RC_R9, - RC_R10, - RC_R11, - 0, - 0, - 0, - 0, - /* xmm0 */ RC_FLOAT | RC_XMM0, - /* xmm1 */ RC_FLOAT | RC_XMM1, - /* xmm2 */ RC_FLOAT | RC_XMM2, - /* xmm3 */ RC_FLOAT | RC_XMM3, - /* xmm4 */ RC_FLOAT | RC_XMM4, - /* xmm5 */ RC_FLOAT | RC_XMM5, - /* xmm6 an xmm7 are included so gv() can be used on them, - but they are not tagged with RC_FLOAT because they are - callee saved on Windows */ - RC_XMM6, - RC_XMM7, - /* st0 */ RC_ST0 + /* st0 */ RC_ST0, + RC_RSI|RC_INT2, + RC_RDI|RC_INT2, + RC_INT|RC_R8|RC_INT2, + RC_INT|RC_R9|RC_INT2, + RC_INT|RC_INT1|RC_INT2|RC_R10, + RC_INT|RC_INT1|RC_INT2|RC_R11, + RC_INT|RC_INT1|RC_INT2|RC_R12, + RC_INT|RC_INT1|RC_INT2|RC_R13, + RC_INT|RC_INT1|RC_INT2|RC_R14, + RC_INT|RC_INT1|RC_INT2|RC_R15, + /* xmm0 */ RC_FLOAT | RC_XMM0, + RC_FLOAT|RC_XMM1, + RC_FLOAT|RC_XMM2, + RC_FLOAT|RC_XMM3, + RC_FLOAT|RC_XMM4, + RC_FLOAT|RC_XMM5, + RC_FLOAT|RC_XMM6, + RC_FLOAT|RC_XMM7, }; static unsigned long func_sub_sp_offset; @@ -324,7 +329,7 @@ static void gen_modrm_impl(int op_reg, int r, Sym *sym, int c, int is_got) } else { oad(0x85 | op_reg, c); } - } else if ((r & VT_VALMASK) >= TREG_MEM) { + } else if (r & TREG_MEM) { if (c) { g(0x80 | op_reg | REG_VALUE(r)); gen_le32(c); @@ -1609,39 +1614,42 @@ int gtst(int inv, int t) /* generate an integer binary operation */ void gen_opi(int op) { - int r, fr, opc, c; - int ll, uu, cc; + int r, fr, opc, fc, c, ll, uu, cc, tt2; + fr = vtop[0].r; + fc = vtop->c.ul; ll = is64_type(vtop[-1].type.t); - uu = (vtop[-1].type.t & VT_UNSIGNED) != 0; - cc = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; + cc = (fr & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; + tt2 = (fr & (VT_LVAL | VT_LVAL_TYPE)) == VT_LVAL; switch(op) { case '+': case TOK_ADDC1: /* add with carry generation */ opc = 0; gen_op8: + vswap(); + r = gv(RC_INT); + vswap(); if (cc && (!ll || (int)vtop->c.ll == vtop->c.ll)) { /* constant case */ - vswap(); - r = gv(RC_INT); - vswap(); c = vtop->c.i; if (c == (char)c) { /* XXX: generate inc and dec for smaller code ? */ - orex(ll, r, 0, 0x83); - o(0xc0 | (opc << 3) | REG_VALUE(r)); - g(c); + orex(ll, r, 0, 0x83); + o(0xc0 + REG_VALUE(r) + opc*8); + g(c); } else { orex(ll, r, 0, 0x81); - oad(0xc0 | (opc << 3) | REG_VALUE(r), c); + oad(0xc0 + REG_VALUE(r) + opc*8, c); } } else { - gv2(RC_INT, RC_INT); - r = vtop[-1].r; - fr = vtop[0].r; - orex(ll, r, fr, (opc << 3) | 0x01); - o(0xc0 + REG_VALUE(r) + REG_VALUE(fr) * 8); + if(!tt2) + fr = gv(RC_INT); + orex(ll, fr, r, 0x03 + opc*8); + if(fr >= VT_CONST) + gen_modrm(r, fr, vtop->sym, fc); + else + o(0xc0 + REG_VALUE(fr) + REG_VALUE(r)*8); } vtop--; if (op >= TOK_ULT && op <= TOK_GT) { @@ -1669,11 +1677,27 @@ void gen_opi(int op) opc = 1; goto gen_op8; case '*': - gv2(RC_INT, RC_INT); - r = vtop[-1].r; - fr = vtop[0].r; - orex(ll, fr, r, 0xaf0f); /* imul fr, r */ - o(0xc0 + REG_VALUE(fr) + REG_VALUE(r) * 8); + opc = 5; + vswap(); + r = gv(RC_INT); + vswap(); + if(!tt2) + fr = gv(RC_INT); + if(r == TREG_RAX){ + if(fr != TREG_RDX) + save_reg(TREG_RDX); + orex(ll, fr, r, 0xf7); + if(fr >= VT_CONST) + gen_modrm(opc, fr, vtop->sym, fc); + else + o(0xc0 + REG_VALUE(fr) + opc*8); + }else{ + orex(ll, fr, r, 0xaf0f); /* imul fr, r */ + if(fr >= VT_CONST) + gen_modrm(r, fr, vtop->sym, fc); + else + o(0xc0 + REG_VALUE(fr) + REG_VALUE(r)*8); + } vtop--; break; case TOK_SHL: @@ -1685,47 +1709,62 @@ void gen_opi(int op) case TOK_SAR: opc = 7; gen_shift: - opc = 0xc0 | (opc << 3); if (cc) { /* constant case */ vswap(); r = gv(RC_INT); vswap(); - orex(ll, r, 0, 0xc1); /* shl/shr/sar $xxx, r */ - o(opc | REG_VALUE(r)); - g(vtop->c.i & (ll ? 63 : 31)); + c = vtop->c.i; + if(c == 1){ + orex(ll, r, 0, 0xd1); + o(0xc0 + REG_VALUE(r) + opc*8); + }else{ + orex(ll, r, 0, 0xc1); /* shl/shr/sar $xxx, r */ + o(0xc0 + REG_VALUE(r) + opc*8); + g(c & (ll ? 0x3f : 0x1f)); + } } else { /* we generate the shift in ecx */ gv2(RC_INT, RC_RCX); r = vtop[-1].r; orex(ll, r, 0, 0xd3); /* shl/shr/sar %cl, r */ - o(opc | REG_VALUE(r)); + o(0xc0 + REG_VALUE(r) + opc*8); } vtop--; break; case TOK_UDIV: case TOK_UMOD: + opc = 6; uu = 1; goto divmod; case '/': case '%': case TOK_PDIV: + opc = 7; uu = 0; divmod: /* first operand must be in eax */ /* XXX: need better constraint for second operand */ - gv2(RC_RAX, RC_RCX); - r = vtop[-1].r; - fr = vtop[0].r; - vtop--; - save_reg(TREG_RDX); - orex(ll, 0, 0, uu ? 0xd231 : 0x99); /* xor %edx,%edx : cqto */ - orex(ll, fr, 0, 0xf7); /* div fr, %eax */ - o((uu ? 0xf0 : 0xf8) + REG_VALUE(fr)); + if(!tt2){ + gv2(RC_RAX, RC_INT2); + fr = vtop[0].r; + }else{ + vswap(); + gv(RC_RAX); + vswap(); + } + save_reg(TREG_RDX); + orex(ll, 0, 0, uu ? 0xd231 : 0x99); /* xor %edx,%edx : cdq RDX:RAX <- sign-extend of RAX. */ + orex(ll, fr, 0, 0xf7); /* div fr, %eax */ + if(fr >= VT_CONST) + gen_modrm(opc, fr, vtop->sym, fc); + else + o(0xc0 + REG_VALUE(fr) + opc*8); if (op == '%' || op == TOK_UMOD) r = TREG_RDX; else r = TREG_RAX; + vtop--; vtop->r = r; break; default: @@ -1744,9 +1783,8 @@ void gen_opl(int op) /* XXX: need to use ST1 too */ void gen_opf(int op) { - int a, ft, fc, swapped, r; - int float_type = - (vtop->type.t & VT_BTYPE) == VT_LDOUBLE ? RC_ST0 : RC_FLOAT; + int a, ft, fc, swapped, fr, r; + int float_type = (vtop->type.t & VT_BTYPE) == VT_LDOUBLE ? RC_ST0 : RC_FLOAT; /* convert constants to memory references */ if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { @@ -1757,21 +1795,23 @@ void gen_opf(int op) if ((vtop[0].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) gv(float_type); - /* must put at least one value in the floating point register */ - if ((vtop[-1].r & VT_LVAL) && - (vtop[0].r & VT_LVAL)) { - vswap(); - gv(float_type); - vswap(); - } - swapped = 0; - /* swap the stack if needed so that t1 is the register and t2 is - the memory reference */ - if (vtop[-1].r & VT_LVAL) { - vswap(); - swapped = 1; - } - if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { + swapped = 0; + fc = vtop->c.ul; + ft = vtop->type.t; + + if ((ft & VT_BTYPE) == VT_LDOUBLE) { + /* swap the stack if needed so that t1 is the register and t2 is + the memory reference */ + /* must put at least one value in the floating point register */ + if ((vtop[-1].r & VT_LVAL) && (vtop[0].r & VT_LVAL)) { + vswap(); + gv(float_type); + vswap(); + } + if (vtop[-1].r & VT_LVAL) { + vswap(); + swapped = 1; + } if (op >= TOK_ULT && op <= TOK_GT) { /* load on stack second operand */ load(TREG_ST0, vtop); @@ -1782,10 +1822,10 @@ void gen_opf(int op) swapped = 0; if (swapped) o(0xc9d9); /* fxch %st(1) */ - if (op == TOK_EQ || op == TOK_NE) - o(0xe9da); /* fucompp */ - else - o(0xd9de); /* fcompp */ + if (op == TOK_EQ || op == TOK_NE) + o(0xe9da); /* fucompp */ + else + o(0xd9de); /* fcompp */ o(0xe0df); /* fnstsw %ax */ if (op == TOK_EQ) { o(0x45e480); /* and $0x45, %ah */ @@ -1808,7 +1848,6 @@ void gen_opf(int op) /* no memory reference possible for long double operations */ load(TREG_ST0, vtop); swapped = !swapped; - switch(op) { default: case '+': @@ -1828,63 +1867,45 @@ void gen_opf(int op) a++; break; } - ft = vtop->type.t; - fc = vtop->c.ul; o(0xde); /* fxxxp %st, %st(1) */ o(0xc1 + (a << 3)); vtop--; } } else { + vswap(); + gv(float_type); + vswap(); + fr = vtop->r; + r = vtop[-1].r; if (op >= TOK_ULT && op <= TOK_GT) { - /* if saved lvalue, then we must reload it */ - r = vtop->r; - fc = vtop->c.ul; - if ((r & VT_VALMASK) == VT_LLOCAL) { - SValue v1; - r = get_reg(RC_INT); - v1.type.t = VT_PTR; - v1.r = VT_LOCAL | VT_LVAL; - v1.c.ul = fc; - load(r, &v1); - fc = 0; - } - - if (op == TOK_EQ || op == TOK_NE) { - swapped = 0; - } else { - if (op == TOK_LE || op == TOK_LT) - swapped = !swapped; - if (op == TOK_LE || op == TOK_GE) { - op = 0x93; /* setae */ - } else { - op = 0x97; /* seta */ - } - } - - if (swapped) { - gv(RC_FLOAT); - vswap(); - } - assert(!(vtop[-1].r & VT_LVAL)); - - if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) - o(0x66); - if (op == TOK_EQ || op == TOK_NE) - o(0x2e0f); /* ucomisd */ - else - o(0x2f0f); /* comisd */ - - if (vtop->r & VT_LVAL) { - gen_modrm(vtop[-1].r, r, vtop->sym, fc); - } else { - o(0xc0 + REG_VALUE(vtop[0].r) + REG_VALUE(vtop[-1].r)*8); - } - + switch(op){ + case TOK_LE: + op = TOK_ULE; /* setae */ + break; + case TOK_LT: + op = TOK_ULT; + break; + case TOK_GE: + op = TOK_UGE; + break; + case TOK_GT: + op = TOK_UGT; /* seta */ + break; + } + assert(!(vtop[-1].r & VT_LVAL)); + if ((ft & VT_BTYPE) == VT_DOUBLE) + o(0x66); + o(0x2e0f); /* ucomisd */ + if(fr >= VT_CONST) + gen_modrm(r, fr, vtop->sym, fc); + else + o(0xc0 + REG_VALUE(fr) + REG_VALUE(r)*8); vtop--; vtop->r = VT_CMP; vtop->c.i = op | 0x100; } else { - assert((vtop->type.t & VT_BTYPE) != VT_LDOUBLE); + assert((vtop->type.t & VT_BTYPE) != VT_LDOUBLE); + /* no memory reference possible for long double operations */ switch(op) { default: case '+': @@ -1900,44 +1921,20 @@ void gen_opf(int op) a = 6; break; } - ft = vtop->type.t; - fc = vtop->c.ul; - assert((ft & VT_BTYPE) != VT_LDOUBLE); - - r = vtop->r; - /* if saved lvalue, then we must reload it */ - if ((vtop->r & VT_VALMASK) == VT_LLOCAL) { - SValue v1; - r = get_reg(RC_INT); - v1.type.t = VT_PTR; - v1.r = VT_LOCAL | VT_LVAL; - v1.c.ul = fc; - load(r, &v1); - fc = 0; - } - - assert(!(vtop[-1].r & VT_LVAL)); - if (swapped) { - assert(vtop->r & VT_LVAL); - gv(RC_FLOAT); - vswap(); - } - - if ((ft & VT_BTYPE) == VT_DOUBLE) { - o(0xf2); - } else { - o(0xf3); - } - o(0x0f); - o(0x58 + a); - - if (vtop->r & VT_LVAL) { - gen_modrm(vtop[-1].r, r, vtop->sym, fc); - } else { - o(0xc0 + REG_VALUE(vtop[0].r) + REG_VALUE(vtop[-1].r)*8); - } - - vtop--; + assert((ft & VT_BTYPE) != VT_LDOUBLE); + assert(!(vtop[-1].r & VT_LVAL)); + if ((ft & VT_BTYPE) == VT_DOUBLE) { + o(0xf2); + } else { + o(0xf3); + } + o(0x0f); + o(0x58 + a); + if(fr >= VT_CONST) + gen_modrm(r, fr, vtop->sym, fc); + else + o(0xc0 + REG_VALUE(fr) + REG_VALUE(r)*8); + vtop--; } } } @@ -1946,103 +1943,96 @@ void gen_opf(int op) and 'long long' cases. */ void gen_cvt_itof(int t) { - if ((t & VT_BTYPE) == VT_LDOUBLE) { + int ft, bt, tbt, r; + + ft = vtop->type.t; + bt = ft & VT_BTYPE; + tbt = t & VT_BTYPE; + r = gv(RC_INT); + + if (tbt == VT_LDOUBLE) { save_reg(TREG_ST0); - gv(RC_INT); - if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { + if ((ft & VT_BTYPE) == VT_LLONG) { /* signed long long to float/double/long double (unsigned case is handled generically) */ - o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ + o(0x50 + REG_VALUE(r)); /* push r */ o(0x242cdf); /* fildll (%rsp) */ o(0x08c48348); /* add $8, %rsp */ - } else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == - (VT_INT | VT_UNSIGNED)) { + } else if ((ft & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) { /* unsigned int to float/double/long double */ o(0x6a); /* push $0 */ g(0x00); - o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ + o(0x50 + REG_VALUE(r)); /* push r */ o(0x242cdf); /* fildll (%rsp) */ o(0x10c48348); /* add $16, %rsp */ } else { /* int to float/double/long double */ - o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ + o(0x50 + REG_VALUE(r)); /* push r */ o(0x2404db); /* fildl (%rsp) */ o(0x08c48348); /* add $8, %rsp */ } vtop->r = TREG_ST0; } else { - int r = get_reg(RC_FLOAT); - gv(RC_INT); - o(0xf2 + ((t & VT_BTYPE) == VT_FLOAT?1:0)); - if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == - (VT_INT | VT_UNSIGNED) || - (vtop->type.t & VT_BTYPE) == VT_LLONG) { + int r_xmm; + r_xmm = get_reg(RC_FLOAT); + o(0xf2 + (tbt == VT_FLOAT)); + if ((ft & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED) || bt == VT_LLONG) { o(0x48); /* REX */ } o(0x2a0f); - o(0xc0 + (vtop->r & VT_VALMASK) + REG_VALUE(r)*8); /* cvtsi2sd */ - vtop->r = r; + o(0xc0 + REG_VALUE(r) + REG_VALUE(r_xmm)*8); /* cvtsi2sd or cvtsi2ss */ + vtop->r = r_xmm; } } /* convert from one floating point type to another */ void gen_cvt_ftof(int t) { - int ft, bt, tbt; + int ft, bt, tbt, r; ft = vtop->type.t; bt = ft & VT_BTYPE; tbt = t & VT_BTYPE; - - if (bt == VT_FLOAT) { - gv(RC_FLOAT); + + if(bt == VT_LDOUBLE) + r = get_reg(RC_FLOAT); + else + r = gv(RC_FLOAT); + if (bt == VT_FLOAT) { if (tbt == VT_DOUBLE) { - o(0x140f); /* unpcklps */ - o(0xc0 + REG_VALUE(vtop->r)*9); o(0x5a0f); /* cvtps2pd */ - o(0xc0 + REG_VALUE(vtop->r)*9); + o(0xc0 + REG_VALUE(r) + REG_VALUE(r) * 8); } else if (tbt == VT_LDOUBLE) { - save_reg(RC_ST0); - /* movss %xmm0,-0x10(%rsp) */ + /* movss %xmm0-7,-0x10(%rsp) */ o(0x110ff3); - o(0x44 + REG_VALUE(vtop->r)*8); - o(0xf024); + o(0xf02444 + REG_VALUE(r)*8); o(0xf02444d9); /* flds -0x10(%rsp) */ vtop->r = TREG_ST0; } } else if (bt == VT_DOUBLE) { - gv(RC_FLOAT); if (tbt == VT_FLOAT) { - o(0x140f66); /* unpcklpd */ - o(0xc0 + REG_VALUE(vtop->r)*9); o(0x5a0f66); /* cvtpd2ps */ - o(0xc0 + REG_VALUE(vtop->r)*9); + o(0xc0 + REG_VALUE(r) + REG_VALUE(r) * 8); } else if (tbt == VT_LDOUBLE) { - save_reg(RC_ST0); - /* movsd %xmm0,-0x10(%rsp) */ + /* movsd %xmm0-7,-0x10(%rsp) */ o(0x110ff2); - o(0x44 + REG_VALUE(vtop->r)*8); - o(0xf024); + o(0xf02444 + REG_VALUE(r)*8); o(0xf02444dd); /* fldl -0x10(%rsp) */ vtop->r = TREG_ST0; } } else { - int r; gv(RC_ST0); - r = get_reg(RC_FLOAT); if (tbt == VT_DOUBLE) { o(0xf0245cdd); /* fstpl -0x10(%rsp) */ - /* movsd -0x10(%rsp),%xmm0 */ + /* movsd -0x10(%rsp),%xmm0-7 */ o(0x100ff2); - o(0x44 + REG_VALUE(r)*8); - o(0xf024); + o(0xf02444 + REG_VALUE(r)*8); vtop->r = r; } else if (tbt == VT_FLOAT) { o(0xf0245cd9); /* fstps -0x10(%rsp) */ - /* movss -0x10(%rsp),%xmm0 */ + /* movss -0x10(%rsp),%xmm0-7 */ o(0x100ff3); - o(0x44 + REG_VALUE(r)*8); - o(0xf024); + o(0xf02444 + REG_VALUE(r)*8); vtop->r = r; } } @@ -2051,20 +2041,20 @@ void gen_cvt_ftof(int t) /* convert fp to int 't' type */ void gen_cvt_ftoi(int t) { - int ft, bt, size, r; + int ft, bt, ll, r, r_xmm; + ft = vtop->type.t; bt = ft & VT_BTYPE; + if (bt == VT_LDOUBLE) { gen_cvt_ftof(VT_DOUBLE); bt = VT_DOUBLE; } - - gv(RC_FLOAT); - if (t != VT_INT) - size = 8; + r_xmm = gv(RC_FLOAT); + if ((t & VT_BTYPE) == VT_INT) + ll = 0; else - size = 4; - + ll = 1; r = get_reg(RC_INT); if (bt == VT_FLOAT) { o(0xf3); @@ -2073,8 +2063,8 @@ void gen_cvt_ftoi(int t) } else { assert(0); } - orex(size == 8, r, 0, 0x2c0f); /* cvttss2si or cvttsd2si */ - o(0xc0 + REG_VALUE(vtop->r) + REG_VALUE(r)*8); + orex(ll, r, r_xmm, 0x2c0f); /* cvttss2si or cvttsd2si */ + o(0xc0 + REG_VALUE(r_xmm) + (REG_VALUE(r) << 3)); vtop->r = r; } From 9ff288648b23537c205e4dad16002e2b9ca03203 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Wed, 30 Apr 2014 14:24:44 +0800 Subject: [PATCH 08/52] Restore eda2c756edc4dca004ba217d5bf361235dd9de1f --- arm-gen.c | 83 +++++++++++++++++++++++++++++++++------------------- c67-gen.c | 33 ++++++++++++++++++++- i386-gen.c | 19 +++++++++++- il-gen.c | 15 +++++++++- tccgen.c | 46 ++++++++--------------------- x86_64-gen.c | 19 +++++++++++- 6 files changed, 148 insertions(+), 67 deletions(-) diff --git a/arm-gen.c b/arm-gen.c index 680a490..6da1706 100644 --- a/arm-gen.c +++ b/arm-gen.c @@ -1409,37 +1409,60 @@ void gjmp_addr(int a) /* generate a test. set 'inv' to invert test. Stack entry is popped */ int gtst(int inv, int t) { - int v, r; - uint32_t op; - v = vtop->r & VT_VALMASK; - r=ind; - if (v == VT_CMP) { - op=mapcc(inv?negcc(vtop->c.i):vtop->c.i); - op|=encbranch(r,t,1); - o(op); - t=r; - } else { /* VT_JMP || VT_JMPI */ - if ((v & 1) == inv) { - if(!vtop->c.i) - vtop->c.i=t; - else { - uint32_t *x; - int p,lp; - if(t) { - p = vtop->c.i; - do { - p = decbranch(lp=p); - } while(p); - x = (uint32_t *)(cur_text_section->data + lp); - *x &= 0xff000000; - *x |= encbranch(lp,t,1); - } - t = vtop->c.i; - } - } else { - t = gjmp(t); - gsym(vtop->c.i); + int v, r; + uint32_t op; + v = vtop->r & VT_VALMASK; + r=ind; + if (v == VT_CMP) { + op=mapcc(inv?negcc(vtop->c.i):vtop->c.i); + op|=encbranch(r,t,1); + o(op); + t=r; + } else if (v == VT_JMP || v == VT_JMPI) { + if ((v & 1) == inv) { + if(!vtop->c.i) + vtop->c.i=t; + else { + uint32_t *x; + int p,lp; + if(t) { + p = vtop->c.i; + do { + p = decbranch(lp=p); + } while(p); + x = (uint32_t *)(cur_text_section->data + lp); + *x &= 0xff000000; + *x |= encbranch(lp,t,1); + } + t = vtop->c.i; + } + } else { + t = gjmp(t); + gsym(vtop->c.i); } + } else { + if (is_float(vtop->type.t)) { + r=gv(RC_FLOAT); +#ifdef TCC_ARM_VFP + o(0xEEB50A40|(vfpr(r)<<12)|T2CPR(vtop->type.t)); /* fcmpzX */ + o(0xEEF1FA10); /* fmstat */ +#else + o(0xEE90F118|(fpr(r)<<16)); +#endif + vtop->r = VT_CMP; + vtop->c.i = TOK_NE; + return gtst(inv, t); + } else if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { + /* constant jmp optimization */ + if ((vtop->c.i != 0) != inv) + t = gjmp(t); + } else { + v = gv(RC_INT); + o(0xE3300000|(intr(v)<<16)); + vtop->r = VT_CMP; + vtop->c.i = TOK_NE; + return gtst(inv, t); + } } vtop--; return t; diff --git a/c67-gen.c b/c67-gen.c index a26dfaa..209fa7f 100644 --- a/c67-gen.c +++ b/c67-gen.c @@ -2102,7 +2102,7 @@ int gtst(int inv, int t) C67_NOP(5); t = ind1; //return where we need to patch - } else { /* VT_JMP || VT_JMPI */ + } else if (v == VT_JMP || v == VT_JMPI) { /* && or || optimization */ if ((v & 1) == inv) { /* insert vtop->c jump list in t */ @@ -2128,6 +2128,37 @@ int gtst(int inv, int t) t = gjmp(t); gsym(vtop->c.i); } + } else { + if (is_float(vtop->type.t)) { + vpushi(0); + gen_op(TOK_NE); + } + if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { + /* constant jmp optimization */ + if ((vtop->c.i != 0) != inv) + t = gjmp(t); + } else { + // I think we need to get the value on the stack + // into a register, test it, and generate a branch + // return the address of the branch, so it can be + // later patched + + v = gv(RC_INT); // get value into a reg + ind1 = ind; + C67_MVKL(C67_A0, t); //r=reg to load, constant + C67_MVKH(C67_A0, t); //r=reg to load, constant + + if (v != TREG_EAX && // check if not already in a conditional test reg + v != TREG_EDX && v != TREG_ST0 && v != C67_B2) { + C67_MV(v, C67_B2); + v = C67_B2; + } + + C67_IREG_B_REG(inv, v, C67_A0); // [!R] B.S2x A0 + C67_NOP(5); + t = ind1; //return where we need to patch + ind1 = ind; + } } vtop--; return t; diff --git a/i386-gen.c b/i386-gen.c index ece054b..b9811f5 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -677,7 +677,7 @@ ST_FUNC int gtst(int inv, int t) /* fast case : can jump directly since flags are set */ g(0x0f); t = psym((vtop->c.i - 16) ^ inv, t); - } else { /* VT_JMP || VT_JMPI */ + } else if (v == VT_JMP || v == VT_JMPI) { /* && or || optimization */ if ((v & 1) == inv) { /* insert vtop->c jump list in t */ @@ -690,6 +690,23 @@ ST_FUNC int gtst(int inv, int t) t = gjmp(t); gsym(vtop->c.i); } + } else { + if (is_float(vtop->type.t) || + (vtop->type.t & VT_BTYPE) == VT_LLONG) { + vpushi(0); + gen_op(TOK_NE); + } + if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { + /* constant jmp optimization */ + if ((vtop->c.i != 0) != inv) + t = gjmp(t); + } else { + v = gv(RC_INT); + o(0x85); + o(0xc0 + v * 9); + g(0x0f); + t = psym(0x85 ^ inv, t); + } } vtop--; return t; diff --git a/il-gen.c b/il-gen.c index 9e1ec64..9dafbbf 100644 --- a/il-gen.c +++ b/il-gen.c @@ -516,7 +516,7 @@ int gtst(int inv, int t) break; } t = out_opj(c, t); - } else { /* VT_JMP || VT_JMPI */ + } else if (v == VT_JMP || v == VT_JMPI) { /* && or || optimization */ if ((v & 1) == inv) { /* insert vtop->c jump list in t */ @@ -529,6 +529,19 @@ int gtst(int inv, int t) t = gjmp(t); gsym(vtop->c.i); } + } else { + if (is_float(vtop->t)) { + vpushi(0); + gen_op(TOK_NE); + } + if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_FORWARD)) == VT_CONST) { + /* constant jmp optimization */ + if ((vtop->c.i != 0) != inv) + t = gjmp(t); + } else { + v = gv(RC_INT); + t = out_opj(IL_OP_BRTRUE - inv, t); + } } vtop--; return t; diff --git a/tccgen.c b/tccgen.c index 71a426a..f2e1de0 100644 --- a/tccgen.c +++ b/tccgen.c @@ -92,7 +92,7 @@ static int is_compatible_parameter_types(CType *type1, CType *type2); static void expr_type(CType *type); ST_FUNC void vpush64(int ty, unsigned long long v); ST_FUNC void vpush(CType *type); -ST_FUNC int gvtst(int inv, int t); +ST_FUNC int gtst(int inv, int t); ST_FUNC int is_btype_size(int bt); ST_INLN int is_float(int t) @@ -1128,26 +1128,6 @@ static void gv_dup(void) } } -/* Generate value test - * - * Generate a test for any value (jump, comparison and integers) */ -ST_FUNC int gvtst(int inv, int t) -{ - int v = vtop->r & VT_VALMASK; - if (v != VT_CMP && v != VT_JMP && v != VT_JMPI) { - vpushi(0); - gen_op(TOK_NE); - } - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { - /* constant jmp optimization */ - if ((vtop->c.i != 0) != inv) - t = gjmp(t); - vtop--; - return t; - } - return gtst(inv, t); -} - #ifndef TCC_TARGET_X86_64 /* generate CPU independent (unsigned) long long operations */ static void gen_opl(int op) @@ -1346,13 +1326,13 @@ static void gen_opl(int op) b = 0; gen_op(op1); if (op1 != TOK_NE) { - a = gvtst(1, 0); + a = gtst(1, 0); } if (op != TOK_EQ) { /* generate non equal test */ /* XXX: NOT PORTABLE yet */ if (a == 0) { - b = gvtst(0, 0); + b = gtst(0, 0); } else { #if defined(TCC_TARGET_I386) b = psym(0x850f, 0); @@ -1377,7 +1357,7 @@ static void gen_opl(int op) else if (op1 == TOK_GE) op1 = TOK_UGE; gen_op(op1); - a = gvtst(1, a); + a = gtst(1, a); gsym(b); vseti(VT_JMPI, a); break; @@ -3760,7 +3740,7 @@ ST_FUNC void unary(void) vtop->c.i = vtop->c.i ^ 1; else { save_regs(1); - vseti(VT_JMP, gvtst(1, 0)); + vseti(VT_JMP, gtst(1, 0)); } break; case '~': @@ -4288,7 +4268,7 @@ static void expr_land(void) t = 0; save_regs(1); for(;;) { - t = gvtst(1, t); + t = gtst(1, t); if (tok != TOK_LAND) { vseti(VT_JMPI, t); break; @@ -4308,7 +4288,7 @@ static void expr_lor(void) t = 0; save_regs(1); for(;;) { - t = gvtst(0, t); + t = gtst(0, t); if (tok != TOK_LOR) { vseti(VT_JMP, t); break; @@ -4370,9 +4350,9 @@ static void expr_cond(void) } if (tok == ':' && gnu_ext) { gv_dup(); - tt = gvtst(1, 0); + tt = gtst(1, 0); } else { - tt = gvtst(1, 0); + tt = gtst(1, 0); gexpr(); } type1 = vtop->type; @@ -4618,7 +4598,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, skip('('); gexpr(); skip(')'); - a = gvtst(1, 0); + a = gtst(1, 0); block(bsym, csym, case_sym, def_sym, case_reg, 0); c = tok; if (c == TOK_ELSE) { @@ -4635,7 +4615,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, skip('('); gexpr(); skip(')'); - a = gvtst(1, 0); + a = gtst(1, 0); b = 0; block(&a, &b, case_sym, def_sym, case_reg, 0); gjmp_addr(d); @@ -4814,7 +4794,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, b = 0; if (tok != ';') { gexpr(); - a = gvtst(1, 0); + a = gtst(1, 0); } skip(';'); if (tok != ')') { @@ -4843,7 +4823,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, skip('('); gsym(b); gexpr(); - c = gvtst(0, 0); + c = gtst(0, 0); gsym_addr(c, d); skip(')'); gsym(a); diff --git a/x86_64-gen.c b/x86_64-gen.c index a8a7e87..72709be 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -1593,7 +1593,7 @@ int gtst(int inv, int t) } g(0x0f); t = psym((vtop->c.i - 16) ^ inv, t); - } else { /* VT_JMP || VT_JMPI */ + } else if (v == VT_JMP || v == VT_JMPI) { /* && or || optimization */ if ((v & 1) == inv) { /* insert vtop->c jump list in t */ @@ -1606,6 +1606,23 @@ int gtst(int inv, int t) t = gjmp(t); gsym(vtop->c.i); } + } else { + if (is_float(vtop->type.t) || + (vtop->type.t & VT_BTYPE) == VT_LLONG) { + vpushi(0); + gen_op(TOK_NE); + } + if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { + /* constant jmp optimization */ + if ((vtop->c.i != 0) != inv) + t = gjmp(t); + } else { + v = gv(RC_INT); + orex(0,v,v,0x85); + o(0xc0 + REG_VALUE(v) * 9); + g(0x0f); + t = psym(0x85 ^ inv, t); + } } vtop--; return t; From 5af0ea7fb8d6b2b2a2d3833caad5eda4b43ef595 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Wed, 30 Apr 2014 15:26:45 +0800 Subject: [PATCH 09/52] Fix va_arg bug, Fix type conversion bug, an increase of loc_stack () function is used to manage loc --- lib/libtcc1.c | 110 +++++++++++++------------- tcc.h | 1 + tccgen.c | 199 ++++++++++++++++++++++++++++++------------------ tests/tcctest.c | 23 ++++-- x86_64-gen.c | 57 ++++++++------ 5 files changed, 236 insertions(+), 154 deletions(-) diff --git a/lib/libtcc1.c b/lib/libtcc1.c index 284965e..d7d895a 100644 --- a/lib/libtcc1.c +++ b/lib/libtcc1.c @@ -530,74 +530,77 @@ long double __floatundixf(unsigned long long a) unsigned long long __fixunssfdi (float a1) { - register union float_long fl1; - register int exp; - register unsigned long l; + register union float_long fl1; + register int exp; + register unsigned long l; + int s; + fl1.f = a1; - fl1.f = a1; + if (fl1.l == 0) + return 0; - if (fl1.l == 0) - return (0); + exp = EXP (fl1.l) - EXCESS - 24; - exp = EXP (fl1.l) - EXCESS - 24; - - l = MANT(fl1.l); - if (exp >= 41) - return (unsigned long long)-1; - else if (exp >= 0) - return (unsigned long long)l << exp; - else if (exp >= -23) - return l >> -exp; - else - return 0; + l = MANT(fl1.l); + s = SIGN(fl1.l)? -1: 1; + if (exp >= 64) + return (unsigned long long)-1; + else if (exp >= 0) + return ((unsigned long long)l << exp)*s; + else if (exp >= -23) + return (l >> -exp)*s; + else + return 0; } unsigned long long __fixunsdfdi (double a1) { - register union double_long dl1; - register int exp; - register unsigned long long l; + register union double_long dl1; + register int exp; + register unsigned long long l; + int s; + dl1.d = a1; - dl1.d = a1; + if (dl1.ll == 0) + return (0); - if (dl1.ll == 0) - return (0); + exp = EXPD (dl1) - EXCESSD - 53; - exp = EXPD (dl1) - EXCESSD - 53; - - l = MANTD_LL(dl1); - - if (exp >= 12) - return (unsigned long long)-1; - else if (exp >= 0) - return l << exp; - else if (exp >= -52) - return l >> -exp; - else - return 0; + l = MANTD_LL(dl1); + s = SIGND(dl1)? -1: 1; + if (exp >= 64) + return (unsigned long long)-1; + else if (exp >= 0) + return (l << exp)*s; + else if (exp >= -52) + return (l >> -exp)*s; + else + return 0; } unsigned long long __fixunsxfdi (long double a1) { - register union ldouble_long dl1; - register int exp; - register unsigned long long l; + register union ldouble_long dl1; + register int exp; + register unsigned long long l; + int s; + dl1.ld = a1; - dl1.ld = a1; + if (dl1.l.lower == 0 && dl1.l.upper == 0) + return (0); - if (dl1.l.lower == 0 && dl1.l.upper == 0) - return (0); + exp = EXPLD (dl1) - EXCESSLD - 64; + s = SIGNLD(dl1)? -1: 1; + l = dl1.l.lower; - exp = EXPLD (dl1) - EXCESSLD - 64; - - l = dl1.l.lower; - - if (exp > 0) - return (unsigned long long)-1; - else if (exp >= -63) - return l >> -exp; - else - return 0; + if (exp >= 64) + return (unsigned long long)-1; + else if (exp >= 0) + return ((unsigned long long)l << exp)*s; + else if (exp >= -64) + return (l >> -exp)*s; + else + return 0; } long long __fixsfdi (float a1) @@ -637,7 +640,7 @@ extern void abort(void); #endif enum __va_arg_type { - __va_gen_reg, __va_float_reg, __va_stack + __va_gen_reg, __va_float_reg, __va_ld_reg, __va_stack }; //This should be in sync with the declaration on our include/stdarg.h @@ -688,10 +691,11 @@ void *__va_arg(__va_list_struct *ap, size = 8; goto use_overflow_area; + case __va_ld_reg: + ap->overflow_arg_area = (char*)((intptr_t)(ap->overflow_arg_area + align - 1) & -(intptr_t)align); case __va_stack: use_overflow_area: ap->overflow_arg_area += size; - ap->overflow_arg_area = (char*)((intptr_t)(ap->overflow_arg_area + align - 1) & -(intptr_t)align); return ap->overflow_arg_area - size; default: diff --git a/tcc.h b/tcc.h index 24b5b5a..6a41137 100644 --- a/tcc.h +++ b/tcc.h @@ -1194,6 +1194,7 @@ ST_DATA int func_var; /* true if current function is variadic */ ST_DATA int func_vc; ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */ ST_DATA char *funcname; +ST_DATA int pop_stack; ST_INLN int is_float(int t); ST_FUNC int ieee_finite(double d); diff --git a/tccgen.c b/tccgen.c index f2e1de0..33240cf 100644 --- a/tccgen.c +++ b/tccgen.c @@ -70,6 +70,7 @@ ST_DATA int func_var; /* true if current function is variadic (used by return in ST_DATA int func_vc; ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */ ST_DATA char *funcname; +ST_DATA int pop_stack; ST_DATA CType char_pointer_type, func_old_type, int_type, size_type; @@ -524,6 +525,41 @@ static void vdup(void) 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 */ ST_FUNC void save_reg(int r) { @@ -924,13 +960,10 @@ ST_FUNC int gv(int rc) /* generate vtop[-1] and vtop[0] in resp. classes rc1 and rc2 */ ST_FUNC void gv2(int rc1, int rc2) { - int v; - /* generate more generic register first. But VT_JMP or VT_CMP values must be generated first in all cases to avoid possible reload errors */ - v = vtop[0].r & VT_VALMASK; - if (v != VT_CMP && (v & ~1) != VT_JMP && rc1 <= rc2) { + if (rc1 <= rc2) { vswap(); gv(rc1); vswap(); @@ -1018,6 +1051,7 @@ ST_FUNC void lexpand_nr(void) } #endif +#ifndef TCC_TARGET_X86_64 /* build a long long from two ints */ static void lbuild(int t) { @@ -1026,6 +1060,7 @@ static void lbuild(int t) vtop[-1].type.t = t; vpop(); } +#endif /* rotate n first stack elements to the bottom I1 ... In -> I2 ... In I1 [top is right] @@ -1087,8 +1122,8 @@ static void gv_dup(void) { int rc, t, r, r1; SValue sv; - t = vtop->type.t; +#ifndef TCC_TARGET_X86_64 if ((t & VT_BTYPE) == VT_LLONG) { lexpand(); gv_dup(); @@ -1098,15 +1133,14 @@ static void gv_dup(void) vrotb(4); /* stack: H L L1 H1 */ lbuild(t); - vrotb(3); - vrotb(3); + vrott(3); vswap(); lbuild(t); vswap(); - } else { + } else +#endif + { /* duplicate value */ - rc = RC_INT; - sv.type.t = VT_INT; if (is_float(t)) { rc = RC_FLOAT; #ifdef TCC_TARGET_X86_64 @@ -1114,8 +1148,9 @@ static void gv_dup(void) rc = RC_ST0; } #endif - sv.type.t = t; - } + }else + rc = RC_INT; + sv.type.t = t; r = gv(rc); r1 = get_reg(rc); sv.r = r; @@ -1127,7 +1162,6 @@ static void gv_dup(void) vtop->r = r1; } } - #ifndef TCC_TARGET_X86_64 /* generate CPU independent (unsigned) long long operations */ static void gen_opl(int op) @@ -2441,17 +2475,78 @@ static void gen_assign_cast(CType *dt) gen_cast(dt); } +static void vstore_im(){ + int rc, ft, sbt, dbt, t, r; + ft = vtop[-1].type.t; + sbt = vtop->type.t & VT_BTYPE; + dbt = ft & VT_BTYPE; + if (is_float(ft)) { + rc = RC_FLOAT; +#ifdef TCC_TARGET_X86_64 + if (dbt == VT_LDOUBLE) { + rc = RC_ST0; + } +#endif + }else + rc = RC_INT; + 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); +#ifdef TCC_TARGET_X86_64 + sv.type.t = VT_PTR; +#else + sv.type.t = VT_INT; +#endif + sv.r = VT_LOCAL | VT_LVAL; + sv.c.ul = vtop[-1].c.ul; + load(t, &sv); + vtop[-1].r = t | VT_LVAL; + vtop[-1].c.ul = 0; + } + /* two word case handling : store second register at word + 4 */ +#ifdef TCC_TARGET_X86_64 + if ((dbt == VT_QLONG) || (dbt == VT_QFLOAT)) +#else + if (dbt == VT_LLONG) +#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; +#endif + vtop[-1].type.t = load_type; + store(r, vtop - 1); + vswap(); + /* convert to int to increment easily */ + vtop->type = char_pointer_type; + gaddrof(); + vpushi(load_size); + gen_op('+'); + vtop->r |= VT_LVAL; + vswap(); + vtop[-1].type.t = load_type; + /* XXX: it works because r2 is spilled last ! */ + store(vtop->r2, vtop - 1); + vtop->type.t = ft; + vtop[-1].type.t = ft; + } else { + store(r, vtop - 1); + } +} + /* 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, 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)) { + (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 & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT))); @@ -2507,15 +2602,15 @@ ST_FUNC void vstore(void) vtop[-1].type.t = ft & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); /* duplicate source into other register */ - gv_dup(); - vswap(); - vrott(3); - if((ft & VT_BTYPE) == VT_BOOL) { gen_cast(&vtop[-1].type); vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED); } + /* duplicate destination */ + vdup(); + vtop[-1] = vtop[-2]; + /* duplicate destination */ vdup(); vtop[-1] = vtop[-2]; @@ -2556,56 +2651,7 @@ ST_FUNC void vstore(void) } #endif if (!nocode_wanted) { - 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; - } -#endif - } - 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); -#ifdef TCC_TARGET_X86_64 - sv.type.t = VT_PTR; -#else - sv.type.t = VT_INT; -#endif - sv.r = VT_LOCAL | VT_LVAL; - sv.c.ul = vtop[-1].c.ul; - load(t, &sv); - vtop[-1].r = t | VT_LVAL; - } - /* two word case handling : store second register at word + 4 (or +8 for x86-64) */ -#ifdef TCC_TARGET_X86_64 - 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 - vtop[-1].type.t = load_type; - store(r, vtop - 1); - vswap(); - /* convert to int to increment easily */ - vtop->type.t = addr_type; - gaddrof(); - vpushi(load_size); - gen_op('+'); - vtop->r |= VT_LVAL; - vswap(); - vtop[-1].type.t = load_type; - /* XXX: it works because r2 is spilled last ! */ - store(vtop->r2, vtop - 1); - } else { - store(r, vtop - 1); - } + vstore_im(); } vswap(); vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ @@ -4623,6 +4669,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, gsym_addr(b, d); } else if (tok == '{') { Sym *llabel; + int saved_loc, saved_pop_stack, size; int block_vla_sp_loc, *saved_vla_sp_loc, saved_vla_flags; next(); @@ -4632,7 +4679,10 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, frame_bottom->next = scope_stack_bottom; scope_stack_bottom = frame_bottom; llabel = local_label_stack; - + + saved_loc = loc; + saved_pop_stack = pop_stack; + /* save VLA state */ block_vla_sp_loc = *(saved_vla_sp_loc = vla_sp_loc); if (saved_vla_sp_loc != &vla_sp_root_loc) @@ -4684,7 +4734,12 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, /* pop locally defined symbols */ scope_stack_bottom = scope_stack_bottom->next; sym_pop(&local_stack, s); - + + size = -(loc - saved_loc); + pop_stack = saved_pop_stack; + if(size) + pop_stack += size; + /* Pop VLA frames and restore stack pointer if required */ if (saved_vla_sp_loc != &vla_sp_root_loc) *saved_vla_sp_loc = block_vla_sp_loc; diff --git a/tests/tcctest.c b/tests/tcctest.c index cc8ffd8..ca2ad0b 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -1680,7 +1680,6 @@ void prefix ## fcast(type a)\ printf("ftof: %f %f %Lf\n", fa, da, la);\ ia = (int)a;\ llia = (long long)a;\ - a = (a >= 0) ? a : -a;\ ua = (unsigned int)a;\ llua = (unsigned long long)a;\ printf("ftoi: %d %u %lld %llu\n", ia, ua, llia, llua);\ @@ -1710,6 +1709,18 @@ void prefix ## call(void)\ printf("strto%s: %f\n", #prefix, (double)strto ## prefix("1.2", NULL));\ }\ \ +void prefix ## calc(type x, type y)\ +{\ + x=x*x;y=y*y;\ + printf("%d, %d\n", (int)x, (int)y);\ + x=x-y;y=y-x;\ + printf("%d, %d\n", (int)x, (int)y);\ + x=x/y;y=y/x;\ + printf("%d, %d\n", (int)x, (int)y);\ + x=x+x;y=y+y;\ + printf("%d, %d\n", (int)x, (int)y);\ +}\ +\ void prefix ## signed_zeros(void) \ {\ type x = 0.0, y = -0.0, n, p;\ @@ -1732,7 +1743,7 @@ void prefix ## signed_zeros(void) \ 1.0 / x != 1.0 / p);\ else\ printf ("x != +y; this is wrong!\n");\ - p = -y;\ + p = -y;\ if (x == p)\ printf ("Test 1.0 / x != 1.0 / -y returns %d (should be 0).\n",\ 1.0 / x != 1.0 / p);\ @@ -1748,7 +1759,8 @@ void prefix ## test(void)\ prefix ## fcast(234.6);\ prefix ## fcast(-2334.6);\ prefix ## call();\ - prefix ## signed_zeros();\ + prefix ## calc(1, 1.0000000000000001);\ + prefix ## signed_zeros();\ } FTEST(f, float, float, "%f") @@ -2572,7 +2584,6 @@ int constant_p_var; void builtin_test(void) { -#if GCC_MAJOR >= 3 COMPAT_TYPE(int, int); COMPAT_TYPE(int, unsigned int); COMPAT_TYPE(int, char); @@ -2582,9 +2593,9 @@ void builtin_test(void) COMPAT_TYPE(int *, void *); COMPAT_TYPE(int *, const int *); COMPAT_TYPE(char *, unsigned char *); + COMPAT_TYPE(char, unsigned char); /* space is needed because tcc preprocessor introduces a space between each token */ - COMPAT_TYPE(char * *, void *); -#endif + COMPAT_TYPE(char **, void *); printf("res = %d\n", __builtin_constant_p(1)); printf("res = %d\n", __builtin_constant_p(1 + 2)); printf("res = %d\n", __builtin_constant_p(&constant_p_var)); diff --git a/x86_64-gen.c b/x86_64-gen.c index 72709be..484da3f 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -826,7 +826,7 @@ void gfunc_prolog(CType *func_type) func_ret_sub = 0; func_scratch = 0; - loc = 0; + pop_stack = loc = 0; addr = PTR_SIZE * 2; ind += FUNC_PROLOG_SIZE; @@ -968,12 +968,14 @@ static X86_64_Mode classify_x86_64_inner(CType *ty) case VT_BYTE: case VT_SHORT: case VT_LLONG: + case VT_QLONG: case VT_BOOL: case VT_PTR: case VT_FUNC: case VT_ENUM: return x86_64_mode_integer; case VT_FLOAT: + case VT_QFLOAT: case VT_DOUBLE: return x86_64_mode_sse; case VT_LDOUBLE: return x86_64_mode_x87; @@ -984,7 +986,7 @@ static X86_64_Mode classify_x86_64_inner(CType *ty) // Detect union if (f->next && (f->c == f->next->c)) return x86_64_mode_memory; - + mode = x86_64_mode_none; for (f = f->next; f; f = f->next) mode = classify_x86_64_merge(mode, classify_x86_64_inner(&f->type)); @@ -995,14 +997,14 @@ static X86_64_Mode classify_x86_64_inner(CType *ty) assert(0); } -static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *palign, int *reg_count) +static int classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *palign, int *reg_count) { X86_64_Mode mode; int size, align, ret_t = 0; if (ty->t & (VT_BITFIELD|VT_ARRAY)) { *psize = 8; - *palign = 8; + *palign = 8; *reg_count = 1; ret_t = ty->t; mode = x86_64_mode_integer; @@ -1013,6 +1015,7 @@ static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *p if (size > 16) { mode = x86_64_mode_memory; + ret_t = ty->t; } else { mode = classify_x86_64_inner(ty); switch (mode) { @@ -1021,16 +1024,22 @@ static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *p *reg_count = 2; ret_t = VT_QLONG; } else { - *reg_count = 1; - ret_t = (size > 4) ? VT_LLONG : VT_INT; - } + *reg_count = 1; + if(size > 4) + ret_t = VT_LLONG; + else if(size > 2){ + ret_t = VT_INT; + }else if(size > 1) + ret_t = VT_SHORT; + else + ret_t = VT_BYTE; + } + ret_t |= (ty->t & VT_UNSIGNED); break; - case x86_64_mode_x87: *reg_count = 1; ret_t = VT_LDOUBLE; break; - case x86_64_mode_sse: if (size > 8) { *reg_count = 2; @@ -1040,13 +1049,15 @@ static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *p ret_t = (size > 4) ? VT_DOUBLE : VT_FLOAT; } break; - default: break; /* nothing to be done for x86_64_mode_memory and x86_64_mode_none*/ + default: + ret_t = ty->t; + break; /* nothing to be done for x86_64_mode_memory and x86_64_mode_none*/ } } } if (ret) { - ret->ref = NULL; + ret->ref = ty->ref; ret->t = ret_t; } @@ -1057,12 +1068,13 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty) { /* This definition must be synced with stdarg.h */ enum __va_arg_type { - __va_gen_reg, __va_float_reg, __va_stack - }; + __va_gen_reg, __va_float_reg, __va_ld_reg, __va_stack + }; int size, align, reg_count; X86_64_Mode mode = classify_x86_64_arg(ty, NULL, &size, &align, ®_count); switch (mode) { default: return __va_stack; + case x86_64_mode_x87: return __va_ld_reg; case x86_64_mode_integer: return __va_gen_reg; case x86_64_mode_sse: return __va_float_reg; } @@ -1387,7 +1399,7 @@ void gfunc_prolog(CType *func_type) sym = func_type->ref; addr = PTR_SIZE * 2; - loc = 0; + pop_stack = loc = 0; ind += FUNC_PROLOG_SIZE; func_sub_sp_offset = ind; func_ret_sub = 0; @@ -1398,7 +1410,6 @@ void gfunc_prolog(CType *func_type) /* frame pointer and return address */ seen_stack_size = PTR_SIZE * 2; /* count the number of seen parameters */ - sym = func_type->ref; while ((sym = sym->next) != NULL) { type = &sym->type; mode = classify_x86_64_arg(type, NULL, &size, &align, ®_count); @@ -1439,19 +1450,19 @@ void gfunc_prolog(CType *func_type) o(0xf845c7); gen_le32(seen_stack_size); + o(0xc084);/* test %al,%al */ + o(0x74);/* je */ + g(4*(8 - seen_sse_num) + 3); + /* save all register passing arguments */ for (i = 0; i < 8; i++) { loc -= 16; - o(0xd60f66); /* movq */ + o(0x290f);/* movaps %xmm1-7,-XXX(%rbp) */ gen_modrm(7 - i, VT_LOCAL, NULL, loc); - /* movq $0, loc+8(%rbp) */ - o(0x85c748); - gen_le32(loc + 8); - gen_le32(0); - } - for (i = 0; i < REGN; i++) { - push_arg_reg(REGN-1-i); } + for (i = 0; i < (REGN - seen_reg_num); i++) { + push_arg_reg(REGN-1 - i); + } } sym = func_type->ref; From ba61fd9cd1367589aad7e8056821f88f2e5b550b Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Wed, 30 Apr 2014 17:35:44 +0800 Subject: [PATCH 10/52] rename libtcc1.c --- Makefile | 50 ++++++++++++++++++------------------- lib/Makefile | 16 ++++++------ lib/{libtcc1.c => libcrt.c} | 0 tcc.h | 2 +- tccelf.c | 8 +++--- tccpe.c | 2 +- tests/Makefile | 10 ++++---- tests/abitest.c | 2 +- tests/libtcc_test.c | 2 +- win32/tools/tiny_libmaker.c | 2 +- 10 files changed, 47 insertions(+), 47 deletions(-) rename lib/{libtcc1.c => libcrt.c} (100%) diff --git a/Makefile b/Makefile index 4f18567..3d28f3f 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ endif endif else # not GCC ifeq (-$(findstring clang,$(CC))-,-clang-) -# make clang accept gnuisms in libtcc1.c +# make clang accept gnuisms in libcrt.c CFLAGS+=-fheinous-gnu-extensions endif endif @@ -113,29 +113,29 @@ ifdef CONFIG_WIN64 PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF) NATIVE_FILES=$(WIN64_FILES) PROGS_CROSS=$(WIN32_CROSS) $(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(C67_CROSS) -LIBTCC1_CROSS=lib/i386-win32/libtcc1.a -LIBTCC1=libtcc1.a +LIBTCC1_CROSS=lib/i386-win32/libcrt.a +LIBCRT=libcrt.a else ifdef CONFIG_WIN32 PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF) NATIVE_FILES=$(WIN32_FILES) PROGS_CROSS=$(WIN64_CROSS) $(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(C67_CROSS) -LIBTCC1_CROSS=lib/x86_64-win32/libtcc1.a -LIBTCC1=libtcc1.a +LIBTCC1_CROSS=lib/x86_64-win32/libcrt.a +LIBCRT=libcrt.a else ifeq ($(ARCH),i386) NATIVE_FILES=$(I386_FILES) PROGS_CROSS=$(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(C67_CROSS) -LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a -LIBTCC1=libtcc1.a +LIBTCC1_CROSS=lib/i386-win32/libcrt.a lib/x86_64-win32/libcrt.a +LIBCRT=libcrt.a else ifeq ($(ARCH),x86-64) NATIVE_FILES=$(X86_64_FILES) PROGS_CROSS=$(I386_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(C67_CROSS) -LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a lib/i386/libtcc1.a -LIBTCC1=libtcc1.a +LIBTCC1_CROSS=lib/i386-win32/libcrt.a lib/x86_64-win32/libcrt.a lib/i386/libcrt.a +LIBCRT=libcrt.a else ifeq ($(ARCH),arm) NATIVE_FILES=$(ARM_FILES) PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(C67_CROSS) -LIBTCC1=libtcc1.a -LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a lib/i386/libtcc1.a +LIBCRT=libcrt.a +LIBTCC1_CROSS=lib/i386-win32/libcrt.a lib/x86_64-win32/libcrt.a lib/i386/libcrt.a endif PROGS_CROSS_LINK=$(foreach PROG_CROSS,$(PROGS_CROSS),$($(PROG_CROSS)_LINK)) @@ -143,7 +143,7 @@ ifeq ($(TARGETOS),Darwin) PROGS+=tiny_libmaker$(EXESUF) endif -TCCLIBS = $(LIBTCC1) $(LIBTCC) $(LIBTCC_EXTRA) +TCCLIBS = $(LIBCRT) $(LIBTCC) $(LIBTCC_EXTRA) TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info ifdef CONFIG_CROSS @@ -225,9 +225,9 @@ tiny_libmaker$(EXESUF): win32/tools/tiny_libmaker.c $(CC) -o $@ $< $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) # TinyCC runtime libraries -libtcc1.a : FORCE +libcrt.a : FORCE $(MAKE) -C lib native -lib/%/libtcc1.a : FORCE $(PROGS_CROSS) +lib/%/libcrt.a : FORCE $(PROGS_CROSS) $(MAKE) -C lib cross TARGET=$* FORCE: @@ -258,8 +258,8 @@ endif -$(INSTALL) -m644 tcc-doc.info "$(infodir)" mkdir -p "$(tccdir)" mkdir -p "$(tccdir)/include" -ifneq ($(LIBTCC1),) - $(INSTALL) -m644 $(LIBTCC1) "$(tccdir)" +ifneq ($(LIBCRT),) + $(INSTALL) -m644 $(LIBCRT) "$(tccdir)" endif $(INSTALL) -m644 $(addprefix $(top_srcdir)/include/,$(TCC_INCLUDES)) $(top_srcdir)/tcclib.h "$(tccdir)/include" mkdir -p "$(libdir)" @@ -277,19 +277,19 @@ ifdef CONFIG_CROSS mkdir -p "$(tccdir)/win32/lib/64" ifneq ($(ARCH),i386) mkdir -p "$(tccdir)/i386" - $(INSTALL) -m644 lib/i386/libtcc1.a "$(tccdir)/i386" + $(INSTALL) -m644 lib/i386/libcrt.a "$(tccdir)/i386" cp -r "$(tccdir)/include" "$(tccdir)/i386" endif $(INSTALL) -m644 $(top_srcdir)/win32/lib/*.def "$(tccdir)/win32/lib" - $(INSTALL) -m644 lib/i386-win32/libtcc1.a "$(tccdir)/win32/lib/32" - $(INSTALL) -m644 lib/x86_64-win32/libtcc1.a "$(tccdir)/win32/lib/64" + $(INSTALL) -m644 lib/i386-win32/libcrt.a "$(tccdir)/win32/lib/32" + $(INSTALL) -m644 lib/x86_64-win32/libcrt.a "$(tccdir)/win32/lib/64" cp -r $(top_srcdir)/win32/include/. "$(tccdir)/win32/include" cp -r "$(tccdir)/include" "$(tccdir)/win32" endif uninstall: rm -fv $(foreach P,$(PROGS),"$(bindir)/$P") - rm -fv $(foreach P,$(LIBTCC1),"$(tccdir)/$P") + rm -fv $(foreach P,$(LIBCRT),"$(tccdir)/$P") rm -fv $(foreach P,$(TCC_INCLUDES),"$(tccdir)/include/$P") rm -fv "$(tccdir)/include/tcclib.h" rm -fv "$(docdir)/tcc-doc.html" "$(mandir)/man1/tcc.1" "$(infodir)/tcc-doc.info" @@ -310,7 +310,7 @@ install: $(PROGS) $(TCCLIBS) $(TCCDOCS) mkdir -p "$(tccdir)/doc" mkdir -p "$(tccdir)/libtcc" $(INSTALLBIN) -m755 $(PROGS) "$(tccdir)" - $(INSTALL) -m644 $(LIBTCC1) $(top_srcdir)/win32/lib/*.def "$(tccdir)/lib" + $(INSTALL) -m644 $(LIBCRT) $(top_srcdir)/win32/lib/*.def "$(tccdir)/lib" cp -r $(top_srcdir)/win32/include/. "$(tccdir)/include" cp -r $(top_srcdir)/win32/examples/. "$(tccdir)/examples" $(INSTALL) -m644 $(addprefix $(top_srcdir)/include/,$(TCC_INCLUDES)) $(top_srcdir)/tcclib.h "$(tccdir)/include" @@ -320,8 +320,8 @@ install: $(PROGS) $(TCCLIBS) $(TCCDOCS) ifdef CONFIG_CROSS mkdir -p "$(tccdir)/lib/32" mkdir -p "$(tccdir)/lib/64" - -$(INSTALL) -m644 lib/i386-win32/libtcc1.a "$(tccdir)/lib/32" - -$(INSTALL) -m644 lib/x86_64-win32/libtcc1.a "$(tccdir)/lib/64" + -$(INSTALL) -m644 lib/i386-win32/libcrt.a "$(tccdir)/lib/32" + -$(INSTALL) -m644 lib/x86_64-win32/libcrt.a "$(tccdir)/lib/64" endif uninstall: @@ -340,7 +340,7 @@ tcc-doc.info: tcc-doc.texi -makeinfo $< # in tests subdir -export LIBTCC1 +export LIBCRT %est: $(MAKE) -C tests $@ 'PROGS_CROSS=$(PROGS_CROSS)' @@ -348,7 +348,7 @@ export LIBTCC1 clean: rm -vf $(PROGS) tcc_p$(EXESUF) tcc.pod *~ *.o *.a *.so* *.out *.exe libtcc_test$(EXESUF) $(MAKE) -C tests $@ -ifneq ($(LIBTCC1),) +ifneq ($(LIBCRT),) $(MAKE) -C lib $@ endif diff --git a/lib/Makefile b/lib/Makefile index e9e12f1..4bf2c7e 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,5 +1,5 @@ # -# Tiny C Compiler Makefile for libtcc1.a +# Tiny C Compiler Makefile for libcrt.a # TOP = .. @@ -38,15 +38,15 @@ endif DIR = $(TARGET) -native : ../libtcc1.a -cross : $(DIR)/libtcc1.a +native : ../libcrt.a +cross : $(DIR)/libcrt.a native : TCC = $(TOP)/tcc$(EXESUF) cross : TCC = $(TOP)/$(TARGET)-tcc$(EXESUF) -I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BCHECK_O) -X86_64_O = libtcc1.o alloca86_64.o -ARM_O = libtcc1.o armeabi.o alloca-arm.o +I386_O = libcrt.o alloca86.o alloca86-bt.o $(BCHECK_O) +X86_64_O = libcrt.o alloca86_64.o +ARM_O = libcrt.o armeabi.o alloca-arm.o WIN32_O = $(I386_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o WIN64_O = $(X86_64_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o @@ -83,7 +83,7 @@ ifeq "$(TARGET)" "arm" TGT = -DTCC_TARGET_ARM XCC ?= $(TCC) -B$(TOP) else - $(error libtcc1.a not supported on target '$(TARGET)') + $(error libcrt.a not supported on target '$(TARGET)') endif endif endif @@ -102,7 +102,7 @@ ifdef XAR AR = $(XAR) endif -$(DIR)/libtcc1.a ../libtcc1.a : $(OBJ) $(XAR) +$(DIR)/libcrt.a ../libcrt.a : $(OBJ) $(XAR) $(AR) rcs $@ $(OBJ) $(DIR)/%.o : %.c $(XCC) -c $< -o $@ $(XFLAGS) diff --git a/lib/libtcc1.c b/lib/libcrt.c similarity index 100% rename from lib/libtcc1.c rename to lib/libcrt.c diff --git a/tcc.h b/tcc.h index 6a41137..b12a713 100644 --- a/tcc.h +++ b/tcc.h @@ -274,7 +274,7 @@ # define DEFAULT_ELFINTERP(s) default_elfinterp(s) #endif -/* library to use with CONFIG_USE_LIBGCC instead of libtcc1.a */ +/* library to use with CONFIG_USE_LIBGCC instead of libcrt.a */ #define TCC_LIBGCC USE_MUADIR(CONFIG_SYSROOT "/" CONFIG_LDDIR) "/libgcc_s.so.1" /* -------------------------------------------- */ diff --git a/tccelf.c b/tccelf.c index f0ed22b..5a5d4af 100644 --- a/tccelf.c +++ b/tccelf.c @@ -1443,16 +1443,16 @@ ST_FUNC void tcc_add_runtime(TCCState *s1) #ifdef CONFIG_USE_LIBGCC if (!s1->static_link) { tcc_add_file(s1, TCC_LIBGCC); - tcc_add_support(s1, "libtcc1.a"); + tcc_add_support(s1, "libcrt.a"); } else - tcc_add_support(s1, "libtcc1.a"); + tcc_add_support(s1, "libcrt.a"); #else - tcc_add_support(s1, "libtcc1.a"); + tcc_add_support(s1, "libcrt.a"); #endif } /* tcc_add_bcheck tries to relocate a call to __bound_init in _init so - libtcc1.a must be loaded before for __bound_init to be defined and + libcrt.a must be loaded before for __bound_init to be defined and crtn.o must be loaded after to not finalize _init too early. */ tcc_add_bcheck(s1); diff --git a/tccpe.c b/tccpe.c index b972d75..f7ef99e 100644 --- a/tccpe.c +++ b/tccpe.c @@ -1773,7 +1773,7 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe) if (0 == s1->nostdlib) { static const char *libs[] = { - "libtcc1.a", "msvcrt", "kernel32", "", "user32", "gdi32", NULL + "libcrt.a", "msvcrt", "kernel32", "", "user32", "gdi32", NULL }; const char **pp, *p; for (pp = libs; 0 != (p = *pp); ++pp) { diff --git a/tests/Makefile b/tests/Makefile index e3824ba..a8b41f9 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -66,8 +66,8 @@ RUN_TCC = $(NATIVE_DEFINES) -DONE_SOURCE -run $(top_srcdir)/tcc.c $(TCCFLAGS) DISAS = objdump -d # libtcc test -ifdef LIBTCC1 - LIBTCC1:=$(TOP)/$(LIBTCC1) +ifdef LIBCRT + LIBCRT:=$(TOP)/$(LIBCRT) endif all test : $(TESTS) @@ -89,7 +89,7 @@ hello-run: ../examples/ex1.c @echo ------------ $@ ------------ $(TCC) -run $< -libtest: libtcc_test$(EXESUF) $(LIBTCC1) +libtest: libtcc_test$(EXESUF) $(LIBCRT) @echo ------------ $@ ------------ ./libtcc_test$(EXESUF) lib_path=.. @@ -101,7 +101,7 @@ moretests: $(MAKE) -C tests2 w32-prep: - cp ../libtcc1.a ../lib + cp ../libcrt.a ../lib # test.ref - generate using cc test.ref: tcctest.c @@ -242,4 +242,4 @@ clean: rm -vf *~ *.o *.a *.bin *.i *.ref *.out *.out? *.out?b *.cc \ *-cc *-tcc *.exe \ hello libtcc_test vla_test tcctest[1234] ex? tcc_g tcclib.h \ - ../lib/libtcc1.a + ../lib/libcrt.a diff --git a/tests/abitest.c b/tests/abitest.c index 3ad707a..d840d85 100644 --- a/tests/abitest.c +++ b/tests/abitest.c @@ -468,7 +468,7 @@ int main(int argc, char **argv) { const char *testname = NULL; int retval = EXIT_SUCCESS; - /* if tcclib.h and libtcc1.a are not installed, where can we find them */ + /* if tcclib.h and libcrt.a are not installed, where can we find them */ for (i = 1; i < argc; ++i) { if (!memcmp(argv[i], "lib_path=",9)) tccdir = argv[i] + 9; diff --git a/tests/libtcc_test.c b/tests/libtcc_test.c index bead0ff..4449afa 100644 --- a/tests/libtcc_test.c +++ b/tests/libtcc_test.c @@ -43,7 +43,7 @@ int main(int argc, char **argv) exit(1); } - /* if tcclib.h and libtcc1.a are not installed, where can we find them */ + /* if tcclib.h and libcrt.a are not installed, where can we find them */ if (argc == 2 && !memcmp(argv[1], "lib_path=",9)) tcc_set_lib_path(s, argv[1]+9); diff --git a/win32/tools/tiny_libmaker.c b/win32/tools/tiny_libmaker.c index 62d2a2e..29a692a 100644 --- a/win32/tools/tiny_libmaker.c +++ b/win32/tools/tiny_libmaker.c @@ -1,5 +1,5 @@ /* - * This program is for making libtcc1.a without ar + * This program is for making libcrt.a without ar * tiny_libmaker - tiny elf lib maker * usage: tiny_libmaker [lib] files... * Copyright (c) 2007 Timppa From 2b2e7f85d7119677f0ffdd4c1bde5d3095dead4e Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Wed, 30 Apr 2014 19:30:30 +0800 Subject: [PATCH 11/52] rename i386-tok.h i386-asm.c, add PRINTF_ASM_CODE --- Makefile | 8 +++---- i386-tok.h => asmx86-tok.h | 0 i386-asm.c => asmx86.c | 41 ++++++++++++++++++++++++++----- libtcc.c | 4 ++-- tcc.h | 1 + tccasm.c | 49 ++++++++------------------------------ tcctok.h | 2 +- 7 files changed, 53 insertions(+), 52 deletions(-) rename i386-tok.h => asmx86-tok.h (100%) rename i386-asm.c => asmx86.c (98%) diff --git a/Makefile b/Makefile index 3d28f3f..0f3002b 100644 --- a/Makefile +++ b/Makefile @@ -101,11 +101,11 @@ $(ARM_EABI_CROSS)_LINK = arm-eabi-tcc$(EXESUF) CORE_FILES = tcc.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c tccrun.c CORE_FILES += tcc.h config.h libtcc.h tcctok.h -I386_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h -WIN32_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h tccpe.c -WIN64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h tccpe.c +I386_FILES = $(CORE_FILES) i386-gen.c asmx86.c i386-asm.h asmx86-tok.h +WIN32_FILES = $(CORE_FILES) i386-gen.c asmx86.c i386-asm.h asmx86-tok.h tccpe.c +WIN64_FILES = $(CORE_FILES) x86_64-gen.c asmx86.c x86_64-asm.h tccpe.c WINCE_FILES = $(CORE_FILES) arm-gen.c tccpe.c -X86_64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h +X86_64_FILES = $(CORE_FILES) x86_64-gen.c asmx86.c x86_64-asm.h ARM_FILES = $(CORE_FILES) arm-gen.c C67_FILES = $(CORE_FILES) c67-gen.c tcccoff.c diff --git a/i386-tok.h b/asmx86-tok.h similarity index 100% rename from i386-tok.h rename to asmx86-tok.h diff --git a/i386-asm.c b/asmx86.c similarity index 98% rename from i386-asm.c rename to asmx86.c index a524658..9010c03 100644 --- a/i386-asm.c +++ b/asmx86.c @@ -239,6 +239,36 @@ static const uint16_t op0_codes[] = { #endif }; +#ifdef PRINTF_ASM_CODE +void printf_asm_opcode(){ + const ASMInstr *pa; + int freq[4]; + int op_vals[500]; + int nb_op_vals, i, j; + nb_op_vals = 0; + memset(freq, 0, sizeof(freq)); + for(pa = asm_instrs; pa->sym != 0; pa++) { + freq[pa->nb_ops]++; + for(i=0;inb_ops;i++) { + for(j=0;jop_type[i] == op_vals[j]) + goto found; + } + op_vals[nb_op_vals++] = pa->op_type[i]; + found: ; + } + } + for(i=0;i> 8); g(b); return; - } else if (opcode <= TOK_ASM_alllast) { - tcc_error("bad operand with opcode '%s'", - get_tok_str(opcode, NULL)); + } else if (opcode <= TOK_ASM_alllast) { + tcc_error("bad operand with opcode '%s'", get_tok_str(opcode, NULL)); } else { tcc_error("unknown opcode '%s'", get_tok_str(opcode, NULL)); @@ -1069,7 +1098,7 @@ ST_FUNC void asm_compute_constraints(ASMOperand *operands, uint8_t regs_allocated[NB_ASM_REGS]; /* init fields */ - for(i=0;iinput_index = -1; op->ref_index = -1; @@ -1079,7 +1108,7 @@ ST_FUNC void asm_compute_constraints(ASMOperand *operands, } /* compute constraint priority and evaluate references to output constraints if input constraints */ - for(i=0;iconstraint; str = skip_constraint_modifiers(str); @@ -1499,4 +1528,4 @@ ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str) tcc_error("invalid clobber register '%s'", str); } clobber_regs[reg] = 1; -} +} \ No newline at end of file diff --git a/libtcc.c b/libtcc.c index deda7e6..b9f5952 100644 --- a/libtcc.c +++ b/libtcc.c @@ -52,10 +52,10 @@ ST_DATA struct TCCState *tcc_state; #include "x86_64-gen.c" #endif #ifdef CONFIG_TCC_ASM -#include "tccasm.c" #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 -#include "i386-asm.c" +#include "asmx86.c" #endif +#include "tccasm.c" #endif #ifdef TCC_TARGET_COFF #include "tcccoff.c" diff --git a/tcc.h b/tcc.h index b12a713..d114f53 100644 --- a/tcc.h +++ b/tcc.h @@ -147,6 +147,7 @@ /* #define MEM_DEBUG */ /* assembler debug */ /* #define ASM_DEBUG */ +/* #define PRINTF_ASM_CODE */ /* target selection */ /* #define TCC_TARGET_I386 *//* i386 code generator */ diff --git a/tccasm.c b/tccasm.c index 38efe1c..eec4208 100644 --- a/tccasm.c +++ b/tccasm.c @@ -20,7 +20,6 @@ #include "tcc.h" #ifdef CONFIG_TCC_ASM - ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n) { char buf[64]; @@ -483,7 +482,7 @@ static void asm_parse_directive(TCCState *s1) case TOK_ASM_globl: case TOK_ASM_global: case TOK_ASM_weak: - case TOK_ASM_hidden: + case TOK_ASM_hidden: tok1 = tok; do { Sym *sym; @@ -494,12 +493,12 @@ static void asm_parse_directive(TCCState *s1) sym = label_push(&s1->asm_labels, tok, 0); sym->type.t = VT_VOID; } - if (tok1 != TOK_ASM_hidden) + if (tok1 != TOK_ASM_hidden) sym->type.t &= ~VT_STATIC; if (tok1 == TOK_ASM_weak) sym->type.t |= VT_WEAK; - else if (tok1 == TOK_ASM_hidden) - sym->type.t |= STV_HIDDEN << VT_VIS_SHIFT; + else if (tok1 == TOK_ASM_hidden) + sym->type.t |= STV_HIDDEN << VT_VIS_SHIFT; next(); } while (tok == ','); break; @@ -697,42 +696,15 @@ static void asm_parse_directive(TCCState *s1) } } - /* assemble a file */ static int tcc_assemble_internal(TCCState *s1, int do_preprocess) { int opcode; -#if 0 +#ifdef PRINTF_ASM_CODE + ST_FUNC void printf_asm_opcode(); /* print stats about opcodes */ - { - const ASMInstr *pa; - int freq[4]; - int op_vals[500]; - int nb_op_vals, i, j; - - nb_op_vals = 0; - memset(freq, 0, sizeof(freq)); - for(pa = asm_instrs; pa->sym != 0; pa++) { - freq[pa->nb_ops]++; - for(i=0;inb_ops;i++) { - for(j=0;jop_type[i] == op_vals[j]) - goto found; - } - op_vals[nb_op_vals++] = pa->op_type[i]; - found: ; - } - } - for(i=0;ifilename); + put_elf_sym(symtab_section, 0, 0, ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0, + SHN_ABS, file->filename); ret = tcc_assemble_internal(s1, do_preprocess); @@ -1119,4 +1090,4 @@ ST_FUNC void asm_global_instr(void) cstr_free(&astr); } -#endif /* CONFIG_TCC_ASM */ +#endif /* CONFIG_TCC_ASM */ \ No newline at end of file diff --git a/tcctok.h b/tcctok.h index 735ccdd..6fc8308 100644 --- a/tcctok.h +++ b/tcctok.h @@ -285,5 +285,5 @@ #endif #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 -#include "i386-tok.h" +#include "asmx86-tok.h" #endif From 9e3713facd9d857201326ac2038ab6a8fb64a5fc Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Thu, 1 May 2014 01:48:50 +0800 Subject: [PATCH 12/52] Expansion code again for x86_64-gen --- tcc.h | 12 ++-- tccgen.c | 186 ++++++++++++++++++++------------------------------- x86_64-gen.c | 132 ++++++++++++++---------------------- 3 files changed, 129 insertions(+), 201 deletions(-) diff --git a/tcc.h b/tcc.h index d114f53..d904363 100644 --- a/tcc.h +++ b/tcc.h @@ -39,6 +39,7 @@ #include #include #include +#include #ifdef CONFIG_TCCASSERT #include @@ -358,8 +359,8 @@ typedef union CValue { /* value on stack */ typedef struct SValue { CType type; /* type */ - unsigned short r; /* register + flags */ - unsigned short r2; /* second register, used for 'long long' + unsigned int r; /* register + flags */ + unsigned int r2; /* second register, used for 'long long' type. If not used, set to VT_CONST */ CValue c; /* constant, if 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_DEFSIGN 0x2000 /* signed type */ #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 */ #define VT_EXTERN 0x00000080 /* extern definition */ @@ -791,14 +793,14 @@ struct TCCState { #define VT_EXPORT 0x00008000 /* win32: data exported from dll */ #define VT_WEAK 0x00010000 /* weak symbol */ #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 have linkage and hence never have visibility. */ #define VT_VIS_SIZE 2 /* We have four visibilities. */ #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) */ @@ -1185,7 +1187,7 @@ ST_DATA Sym *define_stack; 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; #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 nocode_wanted; /* true if no code generation wanted for an expression */ diff --git a/tccgen.c b/tccgen.c index 33240cf..daf5f48 100644 --- a/tccgen.c +++ b/tccgen.c @@ -28,7 +28,7 @@ rsym: return symbol 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 *cur_text_section; /* current section where function code is generated */ @@ -525,41 +525,6 @@ static void vdup(void) 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 */ ST_FUNC void save_reg(int r) { @@ -762,25 +727,28 @@ static void gbound(void) register value (such as structures). */ 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; + ft = vtop->type.t; + sbt = ft & VT_BTYPE; /* NOTE: get_reg can modify vstack[] */ - if (vtop->type.t & VT_BITFIELD) { + if (ft & VT_BITFIELD) { CType type; - int bits = 32; - bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f; - bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f; + int bits; + bit_pos = (ft >> VT_STRUCT_SHIFT) & 0x3f; + bit_size = (ft >> (VT_STRUCT_SHIFT + 6)) & 0x3f; /* 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 */ - if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { + if (sbt == VT_LLONG) { type.t = VT_LLONG; bits = 64; - } else + } else{ type.t = VT_INT; - if((vtop->type.t & VT_UNSIGNED) || - (vtop->type.t & VT_BTYPE) == VT_BOOL) + bits = 32; + } + if((ft & VT_UNSIGNED) || sbt == VT_BOOL) type.t |= VT_UNSIGNED; gen_cast(&type); /* generate shifts */ @@ -837,41 +805,39 @@ ST_FUNC int gv(int rc) gbound(); #endif - r = vtop->r & VT_VALMASK; - rc2 = (rc & RC_FLOAT) ? RC_FLOAT : RC_INT; - if (rc == RC_IRET) - rc2 = RC_LRET; -#ifdef TCC_TARGET_X86_64 - else if (rc == RC_FRET) - rc2 = RC_QRET; -#endif + r = vtop->r & VT_VALMASK; + if((rc & ~RC_MASK) && (rc != RC_ST0)) + rc2 = ex_rc; + else + rc2 = (rc & RC_FLOAT) ? RC_FLOAT : RC_INT; /* 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) + if (r >= VT_CONST || (vtop->r & VT_LVAL) || !(reg_classes[r] & rc) #ifdef TCC_TARGET_X86_64 - || ((vtop->type.t & VT_BTYPE) == VT_QLONG && !(reg_classes[vtop->r2] & rc2)) - || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT && !(reg_classes[vtop->r2] & rc2)) + || (sbt == VT_QLONG && !(reg_classes[vtop->r2] & rc2)) + || (sbt == VT_QFLOAT && !(reg_classes[vtop->r2] & rc2)) #else - || ((vtop->type.t & VT_BTYPE) == VT_LLONG && !(reg_classes[vtop->r2] & rc2)) + || (sbt == VT_LLONG && !(reg_classes[vtop->r2] & rc2)) #endif - ) + || vtop->c.i) { r = get_reg(rc); #ifdef TCC_TARGET_X86_64 - 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; + if ((sbt == VT_QLONG) || (sbt == VT_QFLOAT)) #else - if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { - int addr_type = VT_INT, load_size = 4, load_type = VT_INT; + if (sbt == VT_LLONG) +#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; #endif - int r2, original_type; - original_type = vtop->type.t; + int r2; /* two register type load : expand to two words temporarily */ #ifndef TCC_TARGET_X86_64 @@ -884,20 +850,19 @@ ST_FUNC int gv(int rc) vpushi(ll >> 32); /* second word */ } else #endif - if (r >= VT_CONST || /* XXX: test to VT_CONST incorrect ? */ - (vtop->r & VT_LVAL)) { + /* XXX: test to VT_CONST incorrect ? */ + if (r >= VT_CONST || (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. */ - save_regs(1); + in the regs. use VT_TMP XXX: totally inefficient. */ /* load from memory */ vtop->type.t = load_type; load(r, vtop); vdup(); - vtop[-1].r = r; /* save register value */ + vtop[-1].r = r | VT_TMP; /* lock register value */ /* increment pointer to get second word */ - vtop->type.t = addr_type; + vtop->type = char_pointer_type; gaddrof(); vpushi(load_size); gen_op('+'); @@ -907,23 +872,23 @@ ST_FUNC int gv(int rc) /* move registers */ load(r, vtop); vdup(); - vtop[-1].r = r; /* save register value */ + vtop[-1].r = r | VT_TMP; /* lock register value */ vtop->r = vtop[-1].r2; } /* Allocate second register. Here we rely on the fact that get_reg() tries first to free r2 of an SValue. */ r2 = get_reg(rc2); load(r2, vtop); - vpop(); + vtop--; /* write second register */ vtop->r2 = r2; - vtop->type.t = original_type; - } else if ((vtop->r & VT_LVAL) && !is_float(vtop->type.t)) { - int t1, t; + vtop->r &= ~VT_TMP; + vtop->type.t = ft; + } else if ((vtop->r & VT_LVAL) && !is_float(ft)) { + int t; /* lvalue of scalar type : need to use lvalue type because of possible cast */ - t = vtop->type.t; - t1 = t; + t = ft; /* compute memory access type */ if (vtop->r & VT_REF) #ifdef TCC_TARGET_X86_64 @@ -940,7 +905,7 @@ ST_FUNC int gv(int rc) vtop->type.t = t; load(r, vtop); /* restore wanted type */ - vtop->type.t = t1; + vtop->type.t = ft; } else { /* one register type load */ load(r, vtop); @@ -994,6 +959,7 @@ static int rc_fret(int t) return RC_ST0; } #endif + ex_rc = RC_QRET; return RC_FRET; } @@ -2116,31 +2082,30 @@ ST_FUNC int type_size(CType *type, int *a) { Sym *s; int bt; + size_t size; bt = type->t & VT_BTYPE; if (bt == VT_STRUCT) { + assert(!(type->t & VT_VLS)); /* struct/union */ s = type->ref; *a = s->r; - return s->c; + size = s->c; } else if (bt == VT_PTR) { if (type->t & VT_ARRAY) { int ts; - s = type->ref; ts = type_size(&s->type, a); - if (ts < 0 && s->c < 0) ts = -ts; - - return ts * s->c; + size = (size_t)ts * s->c; } else { *a = PTR_SIZE; - return PTR_SIZE; + size = PTR_SIZE; } } else if (bt == VT_LDOUBLE) { *a = LDOUBLE_ALIGN; - return LDOUBLE_SIZE; + size = LDOUBLE_SIZE; } else if (bt == VT_DOUBLE || bt == VT_LLONG) { #ifdef TCC_TARGET_I386 #ifdef TCC_TARGET_PE @@ -2157,21 +2122,23 @@ ST_FUNC int type_size(CType *type, int *a) #else *a = 8; #endif - return 8; + size = 8; } else if (bt == VT_INT || bt == VT_ENUM || bt == VT_FLOAT) { *a = 4; - return 4; + size = 4; } else if (bt == VT_SHORT) { *a = 2; - return 2; - } else if (bt == VT_QLONG || bt == VT_QFLOAT) { + size = 2; + } else if (bt == VT_QLONG || bt == VT_QFLOAT) { *a = 8; - return 16; + size = 16; } else { /* char, void, function, _Bool */ *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 @@ -2600,24 +2567,19 @@ ST_FUNC void vstore(void) bit_size = (ft >> (VT_STRUCT_SHIFT + 6)) & 0x3f; /* remove bit field info to avoid loops */ vtop[-1].type.t = ft & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); - /* duplicate source into other register */ - 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); } - /* duplicate destination */ - vdup(); - vtop[-1] = vtop[-2]; - /* duplicate destination */ vdup(); vtop[-1] = vtop[-2]; /* mask and shift source */ - if((ft & VT_BTYPE) != VT_BOOL) { - if((ft & VT_BTYPE) == VT_LLONG) { + if(dbt != VT_BOOL) { + if(dbt == VT_LLONG) { vpushll((1ULL << bit_size) - 1ULL); } else { vpushi((1 << bit_size) - 1); @@ -2628,7 +2590,7 @@ ST_FUNC void vstore(void) gen_op(TOK_SHL); /* load destination, mask and or with source */ vswap(); - if((ft & VT_BTYPE) == VT_LLONG) { + if(dbt == VT_LLONG) { vpushll(~(((1ULL << bit_size) - 1ULL) << bit_pos)); } else { vpushi(~(((1 << bit_size) - 1) << bit_pos)); @@ -2637,10 +2599,6 @@ ST_FUNC void vstore(void) gen_op('|'); /* store result */ vstore(); - - /* pop off shifted source from "duplicate source..." above */ - vpop(); - } else { #ifdef CONFIG_TCC_BCHECK /* bound check case */ @@ -4772,7 +4730,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, vstore(); } else { /* returning structure packed into registers */ - int r, size, addr, align; + int rc, size, addr, align; size = type_size(&func_vt,&align); if ((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & (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; if (is_float(ret_type.t)) - r = rc_fret(ret_type.t); - else - r = RC_IRET; + rc = rc_fret(ret_type.t); + else{ + rc = RC_IRET; + ex_rc = RC_LRET; + } for (;;) { - gv(r); + gv(rc); 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; /* XXX: compatible with arm only: ret_align == register_size */ vtop->c.i += ret_align; vtop->r = VT_LOCAL | VT_LVAL; diff --git a/x86_64-gen.c b/x86_64-gen.c index 484da3f..f310815 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -487,31 +487,24 @@ void load(int r, SValue *sv) orex(0,r,0,0); oad(0xb8 + REG_VALUE(r), t ^ 1); /* mov $0, r */ } else if (v != r) { - if ((r >= TREG_XMM0) && (r <= TREG_XMM7)) { - if (v == TREG_ST0) { - /* gen_cvt_ftof(VT_DOUBLE); */ - o(0xf0245cdd); /* fstpl -0x10(%rsp) */ - /* movsd -0x10(%rsp),%xmmN */ - o(0x100ff2); - o(0x44 + REG_VALUE(r)*8); /* %xmmN */ - o(0xf024); - } else { - assert((v >= TREG_XMM0) && (v <= TREG_XMM7)); - if ((ft & VT_BTYPE) == VT_FLOAT) { - o(0x100ff3); - } else { - assert((ft & VT_BTYPE) == VT_DOUBLE); - o(0x100ff2); - } - o(0xc0 + REG_VALUE(v) + REG_VALUE(r)*8); - } + if (reg_classes[r] & RC_FLOAT) { + if(v == TREG_ST0){ + /* gen_cvt_ftof(VT_DOUBLE); */ + o(0xf0245cdd); /* fstpl -0x10(%rsp) */ + /* movsd -0x10(%rsp),%xmm0 */ + o(0x100ff2); + o(0xf02444 + REG_VALUE(r)*8); + }else if(reg_classes[v] & RC_FLOAT){ + o(0x7e0ff3); + o(0xc0 + REG_VALUE(v) + REG_VALUE(r)*8); + }else + assert(0); } else if (r == TREG_ST0) { - assert((v >= TREG_XMM0) && (v <= TREG_XMM7)); + assert(reg_classes[v] & RC_FLOAT); /* gen_cvt_ftof(VT_LDOUBLE); */ - /* movsd %xmmN,-0x10(%rsp) */ - o(0x110ff2); - o(0x44 + REG_VALUE(r)*8); /* %xmmN */ - o(0xf024); + /* movsd %xmm0,-0x10(%rsp) */ + o(0x110ff2); + o(0xf02444 + REG_VALUE(v)*8); o(0xf02444dd); /* fldl -0x10(%rsp) */ } else { orex(1,r,v, 0x89); @@ -522,82 +515,56 @@ void load(int r, SValue *sv) } /* store register 'r' in lvalue 'v' */ -void store(int r, SValue *v) +void store(int r, SValue *sv) { - int fr, bt, ft, fc; - int op64 = 0; - /* store the REX prefix in this variable when PIC is enabled */ - int pic = 0; + int fr, bt, ft, fc, ll, v; #ifdef TCC_TARGET_PE SValue v2; - v = pe_getimport(v, &v2); + sv = pe_getimport(sv, &v2); #endif - - ft = v->type.t; - fc = v->c.ul; - fr = v->r & VT_VALMASK; + ft = sv->type.t & ~VT_DEFSIGN; + fc = sv->c.ul; + fr = sv->r; 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 */ - if (fr == VT_CONST && (v->r & VT_SYM)) { + // if (fr == VT_CONST && (v->r & VT_SYM)) { /* mov xx(%rip), %r11 */ - o(0x1d8b4c); - gen_gotpcrel(TREG_R11, v->sym, v->c.ul); - pic = is64_type(bt) ? 0x49 : 0x41; - } -#endif + // o(0x1d8b4c); + // gen_gotpcrel(TREG_R11, v->sym, v->c.ul); + //pic = is64_type(bt) ? 0x49 : 0x41; + // } +//#endif /* XXX: incorrect if float reg to reg */ if (bt == VT_FLOAT) { - o(0x66); - o(pic); - o(0x7e0f); /* movd */ - r = REG_VALUE(r); + orex(0, fr, r, 0x110ff3); /* movss */ } else if (bt == VT_DOUBLE) { - o(0x66); - o(pic); - o(0xd60f); /* movq */ - r = REG_VALUE(r); + orex(0, fr, r, 0x110ff2);/* movds */ } else if (bt == VT_LDOUBLE) { o(0xc0d9); /* fld %st(0) */ - o(pic); - o(0xdb); /* fstpt */ + orex(0, fr, r, 0xdb);/* fstpt */ r = 7; } else { if (bt == VT_SHORT) o(0x66); - o(pic); - if (bt == VT_BYTE || bt == VT_BOOL) - orex(0, 0, r, 0x88); - else if (is64_type(bt)) - 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 (bt == VT_BYTE || bt == VT_BOOL) + orex(ll, fr, r, 0x88); + else{ + orex(ll, fr, r, 0x89); + } } + 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 */ @@ -618,10 +585,9 @@ static void gcall_or_jmp(int is_jmp) oad(0xe8 + is_jmp, vtop->c.ul - 4); /* call/jmp im */ } else { /* otherwise, indirect call */ - r = TREG_R11; + r = get_reg(RC_INT1); load(r, vtop); - o(0x41); /* REX */ - o(0xff); /* call/jmp *r */ + orex(0, r, 0, 0xff); /* REX call/jmp *r */ o(0xd0 + REG_VALUE(r) + (is_jmp << 4)); } } @@ -997,7 +963,7 @@ static X86_64_Mode classify_x86_64_inner(CType *ty) 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; int size, align, ret_t = 0; From 87a850f5537cccabc56d2f9b76faefe1454e4b19 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Thu, 1 May 2014 15:15:01 +0800 Subject: [PATCH 13/52] fix its own making bug. Improved init_putz (). Modify the tests / Makefile to make the test more secure --- tcc.h | 2 ++ tccgen.c | 11 +++--- tests/Makefile | 10 ++++-- x86_64-gen.c | 97 +++++++++++++++++++++++++++----------------------- 4 files changed, 68 insertions(+), 52 deletions(-) diff --git a/tcc.h b/tcc.h index d904363..e01643f 100644 --- a/tcc.h +++ b/tcc.h @@ -1338,6 +1338,8 @@ ST_FUNC void gen_le16(int c); ST_FUNC void gen_le32(int c); ST_FUNC void gen_addr32(int r, Sym *sym, int c); ST_FUNC void gen_addrpc32(int r, Sym *sym, int c); +ST_FUNC void struct_copy(SValue *d, SValue *s, SValue *c); +ST_FUNC void gen_putz(SValue *d, int size); #endif #ifdef CONFIG_TCC_BCHECK diff --git a/tccgen.c b/tccgen.c index daf5f48..20011a0 100644 --- a/tccgen.c +++ b/tccgen.c @@ -5224,16 +5224,17 @@ static void init_putz(CType *t, Section *sec, unsigned long c, int size) if (sec) { /* nothing to do because globals are already set to zero */ } else { +#ifdef TCC_TARGET_ARM vpush_global_sym(&func_old_type, TOK_memset); vseti(VT_LOCAL, c); -#ifdef TCC_TARGET_ARM vpushs(size); vpushi(0); -#else - vpushi(0); - vpushs(size); -#endif gfunc_call(3); +#else + vseti(VT_LOCAL, c); + gen_putz(vtop, size); + vtop--; +#endif } } diff --git a/tests/Makefile b/tests/Makefile index a8b41f9..4c728eb 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -70,7 +70,7 @@ ifdef LIBCRT LIBCRT:=$(TOP)/$(LIBCRT) endif -all test : $(TESTS) +all test : clean $(TESTS) hello-exe: ../examples/ex1.c @echo ------------ $@ ------------ @@ -210,10 +210,14 @@ abitest-cc$(EXESUF): abitest.c $(top_builddir)/$(LIBTCC) abitest-tcc$(EXESUF): abitest.c libtcc.c $(TCC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(NATIVE_DEFINES) -DONE_SOURCE $(LIBS) $(LDFLAGS) -I$(top_srcdir) -abitest: abitest-cc$(EXESUF) abitest-tcc$(EXESUF) +abitest-tcc1$(EXESUF): abitest.c $(top_builddir)/$(LIBTCC) + $(CC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(NATIVE_DEFINES) $(LIBS) $(LINK_LIBTCC) $(LDFLAGS) -I$(top_srcdir) + +abitest: abitest-cc$(EXESUF) abitest-tcc$(EXESUF) abitest-tcc1$(EXESUF) @echo ------------ $@ ------------ ./abitest-cc$(EXESUF) lib_path=.. include="$(top_srcdir)/include" ./abitest-tcc$(EXESUF) lib_path=.. include="$(top_srcdir)/include" + ./abitest-tcc1$(EXESUF) lib_path=.. include="$(top_srcdir)/include" vla_test$(EXESUF): vla_test.c $(TCC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) @@ -240,6 +244,6 @@ cache: tcc_g clean: $(MAKE) -C tests2 $@ rm -vf *~ *.o *.a *.bin *.i *.ref *.out *.out? *.out?b *.cc \ - *-cc *-tcc *.exe \ + *-cc *-tcc *.exe *-tcc1\ hello libtcc_test vla_test tcctest[1234] ex? tcc_g tcclib.h \ ../lib/libcrt.a diff --git a/x86_64-gen.c b/x86_64-gen.c index f310815..1f838e3 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -592,6 +592,31 @@ static void gcall_or_jmp(int is_jmp) } } +void struct_copy(SValue *d, SValue *s, SValue *c) +{ + if(!c->c.i) + return; + save_reg(TREG_RCX); + load(TREG_RCX, c); + load(TREG_RDI, d); + load(TREG_RSI, s); + o(0xa4f3);// rep movsb +} + +void gen_putz(SValue *d, int size) +{ + if(!size) + return; + save_reg(TREG_RAX); + o(0xb0); + g(0x00); + save_reg(TREG_RCX); + o(0xb8 + REG_VALUE(TREG_RCX)); /* mov $xx, r */ + gen_le32(size); + load(TREG_RDI, d); + o(0xaaf3);//rep stos +} + #ifdef TCC_TARGET_PE #define REGN 4 @@ -1060,14 +1085,6 @@ static const uint8_t arg_regs[REGN] = { TREG_RDI, TREG_RSI, TREG_RDX, TREG_RCX, TREG_R8, TREG_R9 }; -static int arg_prepare_reg(int idx) { - if (idx == 2 || idx == 3) - /* idx=2: r10, idx=3: r11 */ - return idx + 8; - else - return arg_regs[idx]; -} - /* Generate function call. The function address is pushed first, then all the parameters in call order. This functions pops all the parameters and the function address. */ @@ -1080,6 +1097,9 @@ void gfunc_call(int nb_args) int nb_sse_args = 0; int sse_reg, gen_reg; + /* fetch cpu flag before the following sub will change the value */ + if (vtop >= vstack && (vtop->r & VT_VALMASK) == VT_CMP) + gv(RC_INT); /* calculate the number of integer/float register arguments */ for(i = 0; i < nb_args; i++) { mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); @@ -1276,7 +1296,7 @@ void gfunc_call(int nb_args) } /* XXX This should be superfluous. */ - save_regs(0); /* save used temporary registers */ + // save_regs(0); /* save used temporary registers */ /* then, we prepare register passing arguments. Note that we cannot set RDX and RCX in this loop because gv() @@ -1289,36 +1309,34 @@ void gfunc_call(int nb_args) /* Alter stack entry type so that gv() knows how to treat it */ vtop->type = type; if (mode == x86_64_mode_sse) { - if (reg_count == 2) { - sse_reg -= 2; - gv(RC_FRET); /* Use pair load into xmm0 & xmm1 */ - if (sse_reg) { /* avoid redundant movaps %xmm0, %xmm0 */ - /* movaps %xmm0, %xmmN */ - o(0x280f); - o(0xc0 + (sse_reg << 3)); - /* movaps %xmm1, %xmmN */ - o(0x280f); - o(0xc1 + ((sse_reg+1) << 3)); - } - } else { - assert(reg_count == 1); - --sse_reg; - /* Load directly to register */ - gv(RC_XMM0 << sse_reg); - } + sse_reg -= reg_count; + if (sse_reg + reg_count <= 8) { + if (reg_count == 2) { + ex_rc = RC_XMM0 << (sse_reg + 1); + gv(RC_XMM0 << sse_reg); + }else{ + assert(reg_count == 1); + /* Load directly to register */ + gv(RC_XMM0 << sse_reg); + } + } } else if (mode == x86_64_mode_integer) { /* simple type */ /* XXX: implicit cast ? */ + int d; gen_reg -= reg_count; - r = gv(RC_INT); - int d = arg_prepare_reg(gen_reg); - orex(1,d,r,0x89); /* mov */ - o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d)); - if (reg_count == 2) { - d = arg_prepare_reg(gen_reg+1); - orex(1,d,vtop->r2,0x89); /* mov */ - o(0xc0 + REG_VALUE(vtop->r2) * 8 + REG_VALUE(d)); - } + if (gen_reg + reg_count <= REGN) { + if (reg_count == 2) { + d = arg_regs[gen_reg+1]; + ex_rc = reg_classes[d] & ~RC_MASK; + d = arg_regs[gen_reg]; + gv(reg_classes[d] & ~RC_MASK); + }else{ + assert(reg_count == 1); + d = arg_regs[gen_reg]; + gv(reg_classes[d] & ~RC_MASK); + } + } } vtop--; } @@ -1330,15 +1348,6 @@ void gfunc_call(int nb_args) (or edx/ecx) currently, which the below writes would clobber. So evict all remaining operands here. */ save_regs(0); - - /* Copy R10 and R11 into RDX and RCX, respectively */ - if (nb_reg_args > 2) { - o(0xd2894c); /* mov %r10, %rdx */ - if (nb_reg_args > 3) { - o(0xd9894c); /* mov %r11, %rcx */ - } - } - oad(0xb8, nb_sse_args < 8 ? nb_sse_args : 8); /* mov nb_sse_args, %eax */ gcall_or_jmp(0); if (args_size) From 2742fbcf95c25a36af23fcfa63ba6c78bc20abcc Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Thu, 1 May 2014 15:19:03 +0800 Subject: [PATCH 14/52] clean --- tccgen.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tccgen.c b/tccgen.c index 20011a0..a4881e0 100644 --- a/tccgen.c +++ b/tccgen.c @@ -4627,7 +4627,6 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, gsym_addr(b, d); } else if (tok == '{') { Sym *llabel; - int saved_loc, saved_pop_stack, size; int block_vla_sp_loc, *saved_vla_sp_loc, saved_vla_flags; next(); @@ -4638,9 +4637,6 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, scope_stack_bottom = frame_bottom; llabel = local_label_stack; - saved_loc = loc; - saved_pop_stack = pop_stack; - /* save VLA state */ block_vla_sp_loc = *(saved_vla_sp_loc = vla_sp_loc); if (saved_vla_sp_loc != &vla_sp_root_loc) @@ -4693,11 +4689,6 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, scope_stack_bottom = scope_stack_bottom->next; sym_pop(&local_stack, s); - size = -(loc - saved_loc); - pop_stack = saved_pop_stack; - if(size) - pop_stack += size; - /* Pop VLA frames and restore stack pointer if required */ if (saved_vla_sp_loc != &vla_sp_root_loc) *saved_vla_sp_loc = block_vla_sp_loc; From 59a22d59a20a472af772fce62c606209e99a5af0 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Thu, 1 May 2014 20:58:43 +0800 Subject: [PATCH 15/52] update for x86_64-gen.c --- tcc.h | 2 + tccelf.c | 4 +- tccgen.c | 74 ++++--- x86_64-gen.c | 562 +++++++++++++++++++++++---------------------------- 4 files changed, 310 insertions(+), 332 deletions(-) diff --git a/tcc.h b/tcc.h index e01643f..7bbd246 100644 --- a/tcc.h +++ b/tcc.h @@ -1237,6 +1237,8 @@ ST_FUNC void gexpr(void); ST_FUNC int expr_const(void); ST_FUNC void gen_inline_functions(void); ST_FUNC void decl(int l); +ST_FUNC void vdup(void); +ST_FUNC void gaddrof(void); #if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_C67 ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size); #endif diff --git a/tccelf.c b/tccelf.c index 5a5d4af..9faf27f 100644 --- a/tccelf.c +++ b/tccelf.c @@ -1596,7 +1596,7 @@ ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel) put32(s1->got->data + offset, sym->st_value & 0xffffffff); } -/* Perform relocation to GOT or PLT entries */ +/* Perform relocation to GOT or PLT entries */ ST_FUNC void fill_got(TCCState *s1) { Section *s; @@ -2469,7 +2469,7 @@ static int elf_output_file(TCCState *s1, const char *filename) goto the_end; } - /* Perform relocation to GOT or PLT entries */ + /* Perform relocation to GOT or PLT entries */ if (file_type == TCC_OUTPUT_EXE && s1->static_link) fill_got(s1); diff --git a/tccgen.c b/tccgen.c index a4881e0..0844d40 100644 --- a/tccgen.c +++ b/tccgen.c @@ -520,7 +520,7 @@ ST_FUNC void vpushv(SValue *v) *vtop = *v; } -static void vdup(void) +ST_FUNC void vdup(void) { vpushv(vtop); } @@ -682,7 +682,7 @@ static void move_reg(int r, int s, int t) } /* get address of vtop (vtop MUST BE an lvalue) */ -static void gaddrof(void) +ST_FUNC void gaddrof(void) { if (vtop->r & VT_REF) gv(RC_INT); @@ -2531,31 +2531,55 @@ ST_FUNC void vstore(void) /* structure assignment : generate memcpy */ /* XXX: optimize if small size */ if (!nocode_wanted) { - size = type_size(&vtop->type, &align); - - /* destination */ - vswap(); - vtop->type.t = VT_PTR; - gaddrof(); - - /* address of memcpy() */ + SValue ret; + int ret_nregs, ret_align; + ret_nregs = gfunc_sret(&vtop->type, func_var, &ret.type, &ret_align); + if(0){ + vswap(); + vpushv(vtop - 1); + vtop[0].type = ret.type; + vtop[-1].type = ret.type; + vstore_im(); + vtop -=2; + }else{ + size = type_size(&vtop->type, &align); #ifdef TCC_ARM_EABI - if(!(align & 7)) - vpush_global_sym(&func_old_type, TOK_memcpy8); - else if(!(align & 3)) - vpush_global_sym(&func_old_type, TOK_memcpy4); - else -#endif - vpush_global_sym(&func_old_type, TOK_memcpy); + /* destination */ + vswap(); + vtop->type.t = VT_PTR; + gaddrof(); - vswap(); - /* source */ - vpushv(vtop - 2); - vtop->type.t = VT_PTR; - gaddrof(); - /* type size */ - vpushi(size); - gfunc_call(3); + /* address of memcpy() */ + if(!(align & 7)) + vpush_global_sym(&func_old_type, TOK_memcpy8); + else if(!(align & 3)) + vpush_global_sym(&func_old_type, TOK_memcpy4); + else + vpush_global_sym(&func_old_type, TOK_memcpy); + + vswap(); + /* source */ + vpushv(vtop - 2); + vtop->type.t = VT_PTR; + gaddrof(); + /* type size */ + vpushi(size); + gfunc_call(3); +#else + /* destination */ + vswap(); + vtop->type.t = VT_PTR; + gaddrof(); + /* source */ + vpushv(vtop - 1); + vtop->type.t = VT_PTR; + gaddrof(); + /* size */ + vpushi(size); + struct_copy(&vtop[-2], &vtop[-1], &vtop[0]); + vtop -=3; +#endif + } } else { vswap(); vpop(); diff --git a/x86_64-gen.c b/x86_64-gen.c index 1f838e3..a671e8e 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -309,18 +309,19 @@ static void gen_gotpcrel(int r, Sym *sym, int c) } } -static void gen_modrm_impl(int op_reg, int r, Sym *sym, int c, int is_got) +static void gen_modrm_impl(int op_reg, int fr, Sym *sym, int c, int flag) { + int r = fr & VT_VALMASK; op_reg = REG_VALUE(op_reg) << 3; - if ((r & VT_VALMASK) == VT_CONST) { + if (r == VT_CONST) { /* constant memory reference */ o(0x05 | op_reg); - if (is_got) { - gen_gotpcrel(r, sym, c); + if (flag & FLAG_GOT) { + gen_gotpcrel(fr, sym, c); } else { - gen_addrpc32(r, sym, c); + gen_addrpc32(fr, sym, c); } - } else if ((r & VT_VALMASK) == VT_LOCAL) { + } else if (r == VT_LOCAL) { /* currently, we use only ebp as base */ if (c == (char)c) { /* short reference */ @@ -329,15 +330,23 @@ static void gen_modrm_impl(int op_reg, int r, Sym *sym, int c, int is_got) } else { oad(0x85 | op_reg, c); } - } else if (r & TREG_MEM) { - if (c) { - g(0x80 | op_reg | REG_VALUE(r)); - gen_le32(c); + } else if (c) { + if (c == (char)c) { + /* short reference */ + g(0x40 | op_reg | REG_VALUE(fr)); + if(r == TREG_RSP) + g(0x24); + g(c); } else { - g(0x00 | op_reg | REG_VALUE(r)); + g(0x80 | op_reg | REG_VALUE(fr)); + if(r == TREG_RSP) + g(0x24); + gen_le32(c); } } else { - g(0x00 | op_reg | REG_VALUE(r)); + g(0x00 | op_reg | REG_VALUE(fr)); + if(r == TREG_RSP) + g(0x24); } } @@ -352,17 +361,18 @@ static void gen_modrm(int op_reg, int r, Sym *sym, int c) opcode bits */ static void gen_modrm64(int opcode, int op_reg, int r, Sym *sym, int c) { - int is_got; - is_got = (op_reg & TREG_MEM) && !(sym->type.t & VT_STATIC); + int flag; + if((op_reg & TREG_MEM) && !(sym->type.t & VT_STATIC)) + flag = FLAG_GOT; orex(1, r, op_reg, opcode); - gen_modrm_impl(op_reg, r, sym, c, is_got); + gen_modrm_impl(op_reg, r, sym, c, flag); } /* load 'r' from value 'sv' */ void load(int r, SValue *sv) { - int v, t, ft, fc, fr; + int v, t, ft, fc, fr, ll; SValue v1; #ifdef TCC_TARGET_PE @@ -373,19 +383,21 @@ void load(int r, SValue *sv) fr = sv->r; ft = sv->type.t & ~VT_DEFSIGN; fc = sv->c.ul; + ll = is64_type(ft); #ifndef TCC_TARGET_PE /* we use indirect access via got */ if ((fr & VT_VALMASK) == VT_CONST && (fr & VT_SYM) && (fr & VT_LVAL) && !(sv->sym->type.t & VT_STATIC)) { /* use the result register as a temporal register */ - int tr = r | TREG_MEM; + int tr; if (is_float(ft)) { /* we cannot use float registers as a temporal register */ tr = get_reg(RC_INT) | TREG_MEM; - } + }else{ + tr = r | TREG_MEM; + } gen_modrm64(0x8b, tr, fr, sv->sym, 0); - /* load from the temporal register */ fr = tr | VT_LVAL; } @@ -393,7 +405,6 @@ void load(int r, SValue *sv) v = fr & VT_VALMASK; if (fr & VT_LVAL) { - int b, ll; if (v == VT_LLOCAL) { v1.type.t = VT_PTR; v1.r = VT_LOCAL | VT_LVAL; @@ -402,14 +413,13 @@ void load(int r, SValue *sv) if (!(reg_classes[fr] & RC_INT)) fr = get_reg(RC_INT); load(fr, &v1); + fc = 0; } - ll = 0; + int b; if ((ft & VT_BTYPE) == VT_FLOAT) { - b = 0x6e0f66; - r = REG_VALUE(r); /* movd */ + b = 0x100ff3; /* movss */ } else if ((ft & VT_BTYPE) == VT_DOUBLE) { - b = 0x7e0ff3; /* movq */ - r = REG_VALUE(r); + b = 0x100ff2; /* movds */ } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { b = 0xdb, r = 5; /* fldt */ } else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) { @@ -421,18 +431,13 @@ void load(int r, SValue *sv) } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) { b = 0xb70f; /* movzwl */ } else { - assert(((ft & VT_BTYPE) == VT_INT) || ((ft & VT_BTYPE) == VT_LLONG) + assert(((ft & VT_BTYPE) == VT_INT) || ((ft & VT_BTYPE) == VT_LLONG) || ((ft & VT_BTYPE) == VT_PTR) || ((ft & VT_BTYPE) == VT_ENUM) || ((ft & VT_BTYPE) == VT_FUNC)); - ll = is64_type(ft); b = 0x8b; } - if (ll) { - gen_modrm64(b, r, fr, sv->sym, fc); - } else { - orex(ll, fr, r, b); - gen_modrm(r, fr, sv->sym, fc); - } + orex(ll, fr, r, b); + gen_modrm(r, fr, sv->sym, fc); } else { if (v == VT_CONST) { if (fr & VT_SYM) { @@ -451,33 +456,33 @@ void load(int r, SValue *sv) gen_gotpcrel(r, sv->sym, fc); } #endif - } else if (is64_type(ft)) { - orex(1,r,0, 0xb8 + REG_VALUE(r)); /* mov $xx, r */ - gen_le64(sv->c.ull); } else { - orex(0,r,0, 0xb8 + REG_VALUE(r)); /* mov $xx, r */ - gen_le32(fc); - } + orex(ll,r,0, 0xb8 + REG_VALUE(r)); /* mov $xx, r */ + if (ll) + gen_le64(sv->c.ull); + else + gen_le32(fc); + } } else if (v == VT_LOCAL) { orex(1,0,r,0x8d); /* lea xxx(%ebp), r */ gen_modrm(r, VT_LOCAL, sv->sym, fc); } else if (v == VT_CMP) { - orex(0,r,0,0); - if ((fc & ~0x100) != TOK_NE) - oad(0xb8 + REG_VALUE(r), 0); /* mov $0, r */ - else - oad(0xb8 + REG_VALUE(r), 1); /* mov $1, r */ - if (fc & 0x100) - { - /* This was a float compare. If the parity bit is - set the result was unordered, meaning false for everything - except TOK_NE, and true for TOK_NE. */ - fc &= ~0x100; - o(0x037a + (REX_BASE(r) << 8)); - } - orex(0,r,0, 0x0f); /* setxx %br */ - o(fc); - o(0xc0 + REG_VALUE(r)); + orex(0, r, 0, 0xb8 + REG_VALUE(r)); + if ((fc & ~0x100) == TOK_NE){ + gen_le32(1);/* mov $0, r */ + }else{ + gen_le32(0);/* mov $1, r */ + } + if (fc & 0x100){ + fc &= ~0x100; + /* This was a float compare. If the parity bit is + set the result was unordered, meaning false for everything + except TOK_NE, and true for TOK_NE. */ + o(0x037a + (REX_BASE(r) << 8));/* jp 3*/ + } + orex(0,r,0, 0x0f); /* setxx %br */ + o(fc); + o(0xc0 + REG_VALUE(r)); } else if (v == VT_JMP || v == VT_JMPI) { t = v & 1; orex(0,r,0,0); @@ -507,8 +512,13 @@ void load(int r, SValue *sv) o(0xf02444 + REG_VALUE(v)*8); o(0xf02444dd); /* fldl -0x10(%rsp) */ } else { - orex(1,r,v, 0x89); - o(0xc0 + REG_VALUE(r) + REG_VALUE(v) * 8); /* mov v, r */ + if(fc){ + orex(1,fr,r,0x8d); /* lea xxx(%ebp), r */ + gen_modrm(r, fr, sv->sym, fc); + }else{ + orex(ll,v,r, 0x8b); + o(0xc0 + REG_VALUE(v) + REG_VALUE(r) * 8); /* mov v, r */ + } } } } @@ -617,6 +627,29 @@ void gen_putz(SValue *d, int size) o(0xaaf3);//rep stos } +/* Generate function call. The function address is pushed first, then + all the parameters in call order. This functions pops all the + parameters and the function address. */ +void gen_offs_sp(int b, int r, int off) +{ + if(r & 0x100) + o(b); + else + orex(1, 0, r, b); + if(!off){ + o(0x2404 | (REG_VALUE(r) << 3)); + }else if (off == (char)off) { + o(0x2444 | (REG_VALUE(r) << 3)); + g(off); + } else { + o(0x2484 | (REG_VALUE(r) << 3)); + gen_le32(off); + } +} + +static int func_scratch; +static int r_loc; + #ifdef TCC_TARGET_PE #define REGN 4 @@ -634,24 +667,6 @@ static int arg_prepare_reg(int idx) { return arg_regs[idx]; } -static int func_scratch; - -/* Generate function call. The function address is pushed first, then - all the parameters in call order. This functions pops all the - parameters and the function address. */ - -void gen_offs_sp(int b, int r, int d) -{ - orex(1,0,r & 0x100 ? 0 : r, b); - if (d == (char)d) { - o(0x2444 | (REG_VALUE(r) << 3)); - g(d); - } else { - o(0x2484 | (REG_VALUE(r) << 3)); - gen_le32(d); - } -} - /* Return the number of registers needed to return the struct, or 0 if returning via struct pointer. */ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align) @@ -815,8 +830,7 @@ void gfunc_prolog(CType *func_type) Sym *sym; CType *type; - func_ret_sub = 0; - func_scratch = 0; + func_ret_sub = func_scratch = r_loc = 0; pop_stack = loc = 0; addr = PTR_SIZE * 2; @@ -911,16 +925,6 @@ void gfunc_epilog(void) #else -static void gadd_sp(int val) -{ - if (val == (char)val) { - o(0xc48348); - g(val); - } else { - oad(0xc48148, val); /* add $xxx, %rsp */ - } -} - typedef enum X86_64_Mode { x86_64_mode_none, x86_64_mode_memory, @@ -1090,12 +1094,12 @@ static const uint8_t arg_regs[REGN] = { parameters and the function address. */ void gfunc_call(int nb_args) { - X86_64_Mode mode; - CType type; - int size, align, r, args_size, stack_adjust, run_start, run_end, i, reg_count; + X86_64_Mode mode; + int size, align, args_size, s, e, i, reg_count; int nb_reg_args = 0; int nb_sse_args = 0; - int sse_reg, gen_reg; + int gen_reg, sse_reg; + CType type; /* fetch cpu flag before the following sub will change the value */ if (vtop >= vstack && (vtop->r & VT_VALMASK) == VT_CMP) @@ -1109,207 +1113,166 @@ void gfunc_call(int nb_args) nb_reg_args += reg_count; } - /* arguments are collected in runs. Each run is a collection of 8-byte aligned arguments - and ended by a 16-byte aligned argument. This is because, from the point of view of - the callee, argument alignment is computed from the bottom up. */ - /* for struct arguments, we need to call memcpy and the function - call breaks register passing arguments we are preparing. - So, we process arguments which will be passed by stack first. */ - gen_reg = nb_reg_args; - sse_reg = nb_sse_args; - run_start = 0; args_size = 0; - while (run_start != nb_args) { - int run_gen_reg = gen_reg, run_sse_reg = sse_reg; - - run_end = nb_args; - stack_adjust = 0; - for(i = run_start; (i < nb_args) && (run_end == nb_args); i++) { - mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); - switch (mode) { - case x86_64_mode_memory: - case x86_64_mode_x87: - stack_arg: - if (align == 16) - run_end = i; - else - stack_adjust += size; - break; - - case x86_64_mode_sse: - sse_reg -= reg_count; - if (sse_reg + reg_count > 8) goto stack_arg; - break; - - case x86_64_mode_integer: - gen_reg -= reg_count; - if (gen_reg + reg_count > REGN) goto stack_arg; - break; - default: break; /* nothing to be done for x86_64_mode_none */ - } - } - - gen_reg = run_gen_reg; - sse_reg = run_sse_reg; - - /* adjust stack to align SSE boundary */ - if (stack_adjust &= 15) { - /* fetch cpu flag before the following sub will change the value */ - if (vtop >= vstack && (vtop->r & VT_VALMASK) == VT_CMP) - gv(RC_INT); - - stack_adjust = 16 - stack_adjust; - o(0x48); - oad(0xec81, stack_adjust); /* sub $xxx, %rsp */ - args_size += stack_adjust; - } - - for(i = run_start; i < run_end;) { - /* Swap argument to top, it will possibly be changed here, - and might use more temps. At the end of the loop we keep - in on the stack and swap it back to its original position - if it is a register. */ - SValue tmp = vtop[0]; - vtop[0] = vtop[-i]; - vtop[-i] = tmp; - - mode = classify_x86_64_arg(&vtop->type, NULL, &size, &align, ®_count); - - int arg_stored = 1; - switch (vtop->type.t & VT_BTYPE) { - case VT_STRUCT: - if (mode == x86_64_mode_sse) { - if (sse_reg > 8) - sse_reg -= reg_count; - else - arg_stored = 0; - } else if (mode == x86_64_mode_integer) { - if (gen_reg > REGN) - gen_reg -= reg_count; - else - arg_stored = 0; - } - - if (arg_stored) { - /* allocate the necessary size on stack */ - o(0x48); - oad(0xec81, size); /* sub $xxx, %rsp */ - /* generate structure store */ - r = get_reg(RC_INT); - orex(1, r, 0, 0x89); /* mov %rsp, r */ - o(0xe0 + REG_VALUE(r)); - vset(&vtop->type, r | VT_LVAL, 0); - vswap(); - vstore(); - args_size += size; - } - break; - - case VT_LDOUBLE: - assert(0); - break; - - case VT_FLOAT: - case VT_DOUBLE: - assert(mode == x86_64_mode_sse); - if (sse_reg > 8) { - --sse_reg; - r = gv(RC_FLOAT); - o(0x50); /* push $rax */ - /* movq %xmmN, (%rsp) */ - o(0xd60f66); - o(0x04 + REG_VALUE(r)*8); - o(0x24); - args_size += size; - } else { - arg_stored = 0; - } - break; - - default: - assert(mode == x86_64_mode_integer); - /* simple type */ - /* XXX: implicit cast ? */ - if (gen_reg > REGN) { - --gen_reg; - r = gv(RC_INT); - orex(0,r,0,0x50 + REG_VALUE(r)); /* push r */ - args_size += size; - } else { - arg_stored = 0; - } - break; - } - - /* And swap the argument back to it's original position. */ - tmp = vtop[0]; - vtop[0] = vtop[-i]; - vtop[-i] = tmp; - - if (arg_stored) { - vrotb(i+1); - assert((vtop->type.t == tmp.type.t) && (vtop->r == tmp.r)); - vpop(); - --nb_args; - --run_end; - } else { - ++i; - } - } - - /* handle 16 byte aligned arguments at end of run */ - run_start = i = run_end; - while (i < nb_args) { - /* Rotate argument to top since it will always be popped */ - mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); - if (align != 16) - break; - - vrotb(i+1); - - if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { - gv(RC_ST0); - oad(0xec8148, size); /* sub $xxx, %rsp */ - o(0x7cdb); /* fstpt 0(%rsp) */ - g(0x24); - g(0x00); - args_size += size; - } else { - //assert(mode == x86_64_mode_memory); - - /* allocate the necessary size on stack */ - o(0x48); - oad(0xec81, size); /* sub $xxx, %rsp */ - /* generate structure store */ - r = get_reg(RC_INT); - orex(1, r, 0, 0x89); /* mov %rsp, r */ - o(0xe0 + REG_VALUE(r)); - vset(&vtop->type, r | VT_LVAL, 0); - vswap(); - vstore(); - args_size += size; - } - - vpop(); - --nb_args; - } - } - - /* XXX This should be superfluous. */ - // save_regs(0); /* save used temporary registers */ - - /* then, we prepare register passing arguments. - Note that we cannot set RDX and RCX in this loop because gv() - may break these temporary registers. Let's use R10 and R11 - instead of them */ - assert(gen_reg <= REGN); - assert(sse_reg <= 8); + gen_reg = nb_reg_args; + sse_reg = nb_sse_args; + /* for struct arguments, we need to call memcpy and the function + call breaks register passing arguments we are preparing. + So, we process arguments which will be passed by stack first. */ for(i = 0; i < nb_args; i++) { - mode = classify_x86_64_arg(&vtop->type, &type, &size, &align, ®_count); + mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); + switch (mode) { + case x86_64_mode_x87: + if((vtop[-i].type.t & VT_BTYPE) == VT_STRUCT) + goto stack_arg1; + else + args_size = (args_size + 15) & ~15; + case x86_64_mode_memory: + stack_arg1: + args_size += size; + break; + case x86_64_mode_sse: + sse_reg -= reg_count; + if (sse_reg + reg_count > 8) + goto stack_arg1; + break; + case x86_64_mode_integer: + gen_reg -= reg_count; + if (gen_reg + reg_count > REGN) + goto stack_arg1; + break; + default: break; /* nothing to be done for x86_64_mode_none */ + } + } + + args_size = (args_size + 15) & ~15; + if (func_scratch < args_size) + func_scratch = args_size; + + gen_reg = nb_reg_args; + sse_reg = nb_sse_args; + for(s = e = 0; s < nb_args; s = e){ + int run_gen, run_sse, st_size; + run_gen = gen_reg; + run_sse = sse_reg; + st_size = 0; + for(i = s; i < nb_args; i++) { + mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); + switch (mode) { + case x86_64_mode_x87: + if((vtop[-i].type.t & VT_BTYPE) == VT_STRUCT){ + goto stack_arg2; + }else{ + ++i; + goto doing; + } + case x86_64_mode_memory: + stack_arg2: + st_size += size; + break; + case x86_64_mode_sse: + sse_reg -= reg_count; + if (sse_reg + reg_count > 8) + goto stack_arg2; + break; + case x86_64_mode_integer: + gen_reg -= reg_count; + if (gen_reg + reg_count > REGN) + goto stack_arg2; + break; + default: break; /* nothing to be done for x86_64_mode_none */ + } + } +doing: + e = i; + st_size = -st_size & 15;// 16 - (size & 15) + if(st_size) + args_size -= st_size; + + gen_reg = run_gen; + sse_reg = run_sse; + for(i = s; i < e; i++) { + SValue tmp; + /* Swap argument to top, it will possibly be changed here, + and might use more temps. All arguments must remain on the + stack, so that get_reg can correctly evict some of them onto + stack. We could use also use a vrott(nb_args) at the end + of this loop, but this seems faster. */ + if(i != 0){ + tmp = vtop[0]; + vtop[0] = vtop[-i]; + vtop[-i] = tmp; + } + + mode = classify_x86_64_arg(&vtop->type, &type, &size, &align, ®_count); + switch (mode) { + case x86_64_mode_x87: + /* ±ØÐë±£Ö¤ TREG_ST0 µÄΨһ */ + if((vtop->type.t & VT_BTYPE) == VT_STRUCT){ + vdup(); + vtop->type = type; + gv(RC_ST0); + args_size -= size; + gen_offs_sp(0xdb, 0x107, args_size); + vtop--;//ÊÍ·Å TREG_ST0 + }else{ + gv(RC_ST0); + args_size -= size; + gen_offs_sp(0xdb, 0x107, args_size); + vtop->r = VT_CONST;//ÊÍ·Å TREG_ST0 + } + break; + case x86_64_mode_memory: + args_size -= size; + vset(&char_pointer_type, TREG_RSP, args_size);/* generate memcpy RSP */ + vpushv(&vtop[-1]); + vtop->type = char_pointer_type; + gaddrof(); + vpushi(size); + struct_copy(&vtop[-2], &vtop[-1], &vtop[0]); + vtop -= 3; + break; + case x86_64_mode_sse: + sse_reg -= reg_count; + if (sse_reg + reg_count > 8){ + args_size -= size; + goto gen_code; + } + break; + case x86_64_mode_integer: + gen_reg -= reg_count; + if (gen_reg + reg_count > REGN){ + args_size -= size; + gen_code: + vset(&type, TREG_RSP | VT_LVAL, args_size); + vpushv(&vtop[-1]); + vtop->type = type; + vstore(); + vtop--; + } + break; + default: break; /* nothing to be done for x86_64_mode_none */ + } + if(i != 0){ + tmp = vtop[0]; + vtop[0] = vtop[-i]; + vtop[-i] = tmp; + } + } + run_gen = gen_reg; + run_sse = sse_reg; + } + + gen_reg = nb_reg_args; + sse_reg = nb_sse_args; + for(i = 0; i < nb_args; i++) { + int d; + mode = classify_x86_64_arg(&vtop->type, &type, &size, &align, ®_count); /* Alter stack entry type so that gv() knows how to treat it */ vtop->type = type; + /* Alter stack entry type so that gv() knows how to treat it */ if (mode == x86_64_mode_sse) { - sse_reg -= reg_count; + sse_reg -= reg_count; if (sse_reg + reg_count <= 8) { if (reg_count == 2) { ex_rc = RC_XMM0 << (sse_reg + 1); @@ -1321,11 +1284,8 @@ void gfunc_call(int nb_args) } } } else if (mode == x86_64_mode_integer) { - /* simple type */ - /* XXX: implicit cast ? */ - int d; - gen_reg -= reg_count; - if (gen_reg + reg_count <= REGN) { + gen_reg -= reg_count; + if (gen_reg + reg_count <= REGN) { if (reg_count == 2) { d = arg_regs[gen_reg+1]; ex_rc = reg_classes[d] & ~RC_MASK; @@ -1338,20 +1298,11 @@ void gfunc_call(int nb_args) } } } - vtop--; + vpop(); } - assert(gen_reg == 0); - assert(sse_reg == 0); - - /* We shouldn't have many operands on the stack anymore, but the - call address itself is still there, and it might be in %eax - (or edx/ecx) currently, which the below writes would clobber. - So evict all remaining operands here. */ - save_regs(0); + save_regs(0); oad(0xb8, nb_sse_args < 8 ? nb_sse_args : 8); /* mov nb_sse_args, %eax */ gcall_or_jmp(0); - if (args_size) - gadd_sp(args_size); vtop--; } @@ -1375,6 +1326,7 @@ void gfunc_prolog(CType *func_type) sym = func_type->ref; addr = PTR_SIZE * 2; pop_stack = loc = 0; + func_scratch = r_loc = 0; ind += FUNC_PROLOG_SIZE; func_sub_sp_offset = ind; func_ret_sub = 0; @@ -1395,7 +1347,7 @@ void gfunc_prolog(CType *func_type) break; case x86_64_mode_integer: - if (seen_reg_num + reg_count <= 8) { + if (seen_reg_num + reg_count <= REGN) { seen_reg_num += reg_count; } else { seen_reg_num = 8; @@ -1521,7 +1473,7 @@ void gfunc_epilog(void) g(func_ret_sub >> 8); } /* align local size to word & save local variables */ - v = (-loc + 15) & -16; + v = (func_scratch -loc + 15) & -16; saved_ind = ind; ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; o(0xe5894855); /* push %rbp, mov %rsp, %rbp */ From 504d40a328c496a738e459fae4339fd78c59426f Mon Sep 17 00:00:00 2001 From: grischka Date: Thu, 1 May 2014 15:33:29 +0200 Subject: [PATCH 16/52] Attention: never use hard tabs other than 8 (eight) wide The attached fix (libcrt.c) is just one example. There seem many more such introduced from latest commits that look badly formatted in anyone else's editors and should be fixed. General recommended policy: - if possible, do not add new hard tabs ('\t') at all. Use spaces (soft tabs) instead - in any case, configure your editor to read/write hard tabs with width of 8 (eight) Also: - Avoid merge commits (unless for very good reason). Instead use "git cherry-pick" or "git rebase" to put your commits on top of the public branch. ref: 2a8905c93b4f67a21e3dbf297c3e93c598831528 Also: - jiang: please explain what you are doing, in the commit message and on the list. Subscribe to the mailing list to receive feedback from people for your work. For example, what was wrong with 'parse_number'? Show a test case and how your version fixes it (it is slower btw). --- lib/libcrt.c | 112 +++++++++++++++++++++++++-------------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/lib/libcrt.c b/lib/libcrt.c index d7d895a..642927a 100644 --- a/lib/libcrt.c +++ b/lib/libcrt.c @@ -530,77 +530,77 @@ long double __floatundixf(unsigned long long a) unsigned long long __fixunssfdi (float a1) { - register union float_long fl1; - register int exp; - register unsigned long l; - int s; - fl1.f = a1; + register union float_long fl1; + register int exp; + register unsigned long l; + int s; + fl1.f = a1; - if (fl1.l == 0) - return 0; + if (fl1.l == 0) + return 0; - exp = EXP (fl1.l) - EXCESS - 24; + exp = EXP (fl1.l) - EXCESS - 24; - l = MANT(fl1.l); - s = SIGN(fl1.l)? -1: 1; - if (exp >= 64) - return (unsigned long long)-1; - else if (exp >= 0) - return ((unsigned long long)l << exp)*s; - else if (exp >= -23) - return (l >> -exp)*s; - else - return 0; + l = MANT(fl1.l); + s = SIGN(fl1.l)? -1: 1; + if (exp >= 64) + return (unsigned long long)-1; + else if (exp >= 0) + return ((unsigned long long)l << exp)*s; + else if (exp >= -23) + return (l >> -exp)*s; + else + return 0; } unsigned long long __fixunsdfdi (double a1) { - register union double_long dl1; - register int exp; - register unsigned long long l; - int s; - dl1.d = a1; + register union double_long dl1; + register int exp; + register unsigned long long l; + int s; + dl1.d = a1; - if (dl1.ll == 0) - return (0); + if (dl1.ll == 0) + return (0); - exp = EXPD (dl1) - EXCESSD - 53; + exp = EXPD (dl1) - EXCESSD - 53; - l = MANTD_LL(dl1); - s = SIGND(dl1)? -1: 1; - if (exp >= 64) - return (unsigned long long)-1; - else if (exp >= 0) - return (l << exp)*s; - else if (exp >= -52) - return (l >> -exp)*s; - else - return 0; + l = MANTD_LL(dl1); + s = SIGND(dl1)? -1: 1; + if (exp >= 64) + return (unsigned long long)-1; + else if (exp >= 0) + return (l << exp)*s; + else if (exp >= -52) + return (l >> -exp)*s; + else + return 0; } unsigned long long __fixunsxfdi (long double a1) { - register union ldouble_long dl1; - register int exp; - register unsigned long long l; - int s; - dl1.ld = a1; + register union ldouble_long dl1; + register int exp; + register unsigned long long l; + int s; + dl1.ld = a1; - if (dl1.l.lower == 0 && dl1.l.upper == 0) - return (0); + if (dl1.l.lower == 0 && dl1.l.upper == 0) + return (0); - exp = EXPLD (dl1) - EXCESSLD - 64; - s = SIGNLD(dl1)? -1: 1; - l = dl1.l.lower; + exp = EXPLD (dl1) - EXCESSLD - 64; + s = SIGNLD(dl1)? -1: 1; + l = dl1.l.lower; - if (exp >= 64) - return (unsigned long long)-1; - else if (exp >= 0) - return ((unsigned long long)l << exp)*s; - else if (exp >= -64) - return (l >> -exp)*s; - else - return 0; + if (exp >= 64) + return (unsigned long long)-1; + else if (exp >= 0) + return ((unsigned long long)l << exp)*s; + else if (exp >= -64) + return (l >> -exp)*s; + else + return 0; } long long __fixsfdi (float a1) @@ -640,7 +640,7 @@ extern void abort(void); #endif enum __va_arg_type { - __va_gen_reg, __va_float_reg, __va_ld_reg, __va_stack + __va_gen_reg, __va_float_reg, __va_ld_reg, __va_stack }; //This should be in sync with the declaration on our include/stdarg.h @@ -691,7 +691,7 @@ void *__va_arg(__va_list_struct *ap, size = 8; goto use_overflow_area; - case __va_ld_reg: + case __va_ld_reg: ap->overflow_arg_area = (char*)((intptr_t)(ap->overflow_arg_area + align - 1) & -(intptr_t)align); case __va_stack: use_overflow_area: From ee99fd45abadf5eb8e10d76715a5c29500cf720d Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Fri, 2 May 2014 00:39:50 +0800 Subject: [PATCH 17/52] Add a comment. ref: 2a8905c93b4f67a21e3dbf297c3e93c598831528 Sorry, I used the wrong command, I did not mean it. Thank grischka --- x86_64-gen.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x86_64-gen.c b/x86_64-gen.c index a671e8e..0307792 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -1207,19 +1207,19 @@ doing: mode = classify_x86_64_arg(&vtop->type, &type, &size, &align, ®_count); switch (mode) { case x86_64_mode_x87: - /* ±ØÐë±£Ö¤ TREG_ST0 µÄΨһ */ + /* Must ensure TREG_ST0 only */ if((vtop->type.t & VT_BTYPE) == VT_STRUCT){ vdup(); vtop->type = type; gv(RC_ST0); args_size -= size; gen_offs_sp(0xdb, 0x107, args_size); - vtop--;//ÊÍ·Å TREG_ST0 + vtop--;//Release TREG_ST0 }else{ gv(RC_ST0); args_size -= size; gen_offs_sp(0xdb, 0x107, args_size); - vtop->r = VT_CONST;//ÊÍ·Å TREG_ST0 + vtop->r = VT_CONST;//Release TREG_ST0 } break; case x86_64_mode_memory: From 5b52a44b524916bf564a9c399ce536a7ea5b5201 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Fri, 2 May 2014 09:42:33 +0800 Subject: [PATCH 18/52] gen_putz () and struct_copy (), is to reduce the third-party call that generates faster code tcc Now only for x86-64 parse_number also to reduce the reliance on third-party libraries, allowing faster analysis tcc --- tccgen.c | 53 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/tccgen.c b/tccgen.c index 0844d40..b8721b1 100644 --- a/tccgen.c +++ b/tccgen.c @@ -2543,30 +2543,32 @@ ST_FUNC void vstore(void) vtop -=2; }else{ size = type_size(&vtop->type, &align); -#ifdef TCC_ARM_EABI - /* destination */ - vswap(); - vtop->type.t = VT_PTR; - gaddrof(); +#ifndef TCC_TARGET_X86_64 + /* destination */ + vswap(); + vtop->type.t = VT_PTR; + gaddrof(); - /* address of memcpy() */ - if(!(align & 7)) - vpush_global_sym(&func_old_type, TOK_memcpy8); - else if(!(align & 3)) - vpush_global_sym(&func_old_type, TOK_memcpy4); - else - vpush_global_sym(&func_old_type, TOK_memcpy); + /* address of memcpy() */ +# ifdef TCC_ARM_EABI + if(!(align & 7)) + vpush_global_sym(&func_old_type, TOK_memcpy8); + else if(!(align & 3)) + vpush_global_sym(&func_old_type, TOK_memcpy4); + else +# endif + vpush_global_sym(&func_old_type, TOK_memcpy); - vswap(); - /* source */ - vpushv(vtop - 2); - vtop->type.t = VT_PTR; - gaddrof(); - /* type size */ - vpushi(size); - gfunc_call(3); + vswap(); + /* source */ + vpushv(vtop - 2); + vtop->type.t = VT_PTR; + gaddrof(); + /* type size */ + vpushi(size); + gfunc_call(3); #else - /* destination */ + /* destination */ vswap(); vtop->type.t = VT_PTR; gaddrof(); @@ -5239,14 +5241,19 @@ static void init_putz(CType *t, Section *sec, unsigned long c, int size) if (sec) { /* nothing to do because globals are already set to zero */ } else { -#ifdef TCC_TARGET_ARM +#ifndef TCC_TARGET_X86_64 vpush_global_sym(&func_old_type, TOK_memset); vseti(VT_LOCAL, c); +#ifdef TCC_TARGET_ARM vpushs(size); vpushi(0); +#else + vpushi(0); + vpushs(size); +#endif gfunc_call(3); #else - vseti(VT_LOCAL, c); + vseti(VT_LOCAL, c); gen_putz(vtop, size); vtop--; #endif From 6c8207633fd42e420e32bdf4912be9fbf307f5ad Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Fri, 2 May 2014 11:23:54 +0800 Subject: [PATCH 19/52] Fixes include the double quotes bug Added push_macro, pop_macro support Fix pack bug, when output with-E will pack the bug --- libtcc.c | 6 +- tcc.h | 12 +- tccgen.c | 6 +- tccpp.c | 302 ++++++++++++++++++++++++++++++++---------------- tcctok.h | 2 + tests/tcctest.c | 31 ++++- 6 files changed, 248 insertions(+), 111 deletions(-) diff --git a/libtcc.c b/libtcc.c index b9f5952..28b6407 100644 --- a/libtcc.c +++ b/libtcc.c @@ -868,6 +868,7 @@ LIBTCCAPI void tcc_undefine_symbol(TCCState *s1, const char *sym) static void tcc_cleanup(void) { int i, n; + CSym *def; if (NULL == tcc_state) return; tcc_state = NULL; @@ -877,8 +878,11 @@ static void tcc_cleanup(void) /* free tokens */ n = tok_ident - TOK_IDENT; - for(i = 0; i < n; i++) + for(i = 0; i < n; i++){ + def = &table_ident[i]->sym_define; + tcc_free(def->data); tcc_free(table_ident[i]); + } tcc_free(table_ident); /* free sym_pools */ diff --git a/tcc.h b/tcc.h index 7bbd246..266b43a 100644 --- a/tcc.h +++ b/tcc.h @@ -305,15 +305,22 @@ #define VSTACK_SIZE 256 #define STRING_MAX_SIZE 1024 #define PACK_STACK_SIZE 8 +#define MACRO_STACK_SIZE 4 #define TOK_HASH_SIZE 8192 /* must be a power of two */ #define TOK_ALLOC_INCR 512 /* must be a power of two */ #define TOK_MAX_SIZE 4 /* token max size in int unit when stored in string */ +typedef struct CSym { + int off; + int size;/* size in *sym */ + struct Sym **data; /* if non NULL, data has been malloced */ +} CSym; + /* token symbol management */ typedef struct TokenSym { struct TokenSym *hash_next; - struct Sym *sym_define; /* direct pointer to define */ + struct CSym sym_define; /* direct pointer to define */ struct Sym *sym_label; /* direct pointer to label */ struct Sym *sym_struct; /* direct pointer to structure */ struct Sym *sym_identifier; /* direct pointer to identifier */ @@ -1129,7 +1136,8 @@ ST_DATA TokenSym **table_ident; token. line feed is also returned at eof */ #define PARSE_FLAG_ASM_COMMENTS 0x0008 /* '#' can be used for line comment */ -#define PARSE_FLAG_SPACES 0x0010 /* next() returns space tokens (for -E) */ +#define PARSE_FLAG_SPACES 0x0010 /* next() returns space tokens (for -E) */ +#define PARSE_FLAG_PACK 0x0020 /* #pragma pack */ ST_FUNC TokenSym *tok_alloc(const char *str, int len); ST_FUNC char *get_tok_str(int v, CValue *cv); diff --git a/tccgen.c b/tccgen.c index b8721b1..456005e 100644 --- a/tccgen.c +++ b/tccgen.c @@ -5244,13 +5244,13 @@ static void init_putz(CType *t, Section *sec, unsigned long c, int size) #ifndef TCC_TARGET_X86_64 vpush_global_sym(&func_old_type, TOK_memset); vseti(VT_LOCAL, c); -#ifdef TCC_TARGET_ARM +# ifdef TCC_TARGET_ARM vpushs(size); vpushi(0); -#else +# else vpushi(0); vpushs(size); -#endif +# endif gfunc_call(3); #else vseti(VT_LOCAL, c); diff --git a/tccpp.c b/tccpp.c index 732c5ea..538f671 100644 --- a/tccpp.c +++ b/tccpp.c @@ -233,7 +233,10 @@ static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len) ts = tcc_malloc(sizeof(TokenSym) + len); table_ident[i] = ts; ts->tok = tok_ident++; - ts->sym_define = NULL; + ts->sym_define.data = tcc_malloc(sizeof(Sym**)); + ts->sym_define.off = 0; + ts->sym_define.data[0] = NULL; + ts->sym_define.size = 1; ts->sym_label = NULL; ts->sym_struct = NULL; ts->sym_identifier = NULL; @@ -1052,52 +1055,62 @@ static int macro_is_equal(const int *a, const int *b) ST_INLN void define_push(int v, int macro_type, int *str, Sym *first_arg) { Sym *s; - + CSym *def; s = define_find(v); if (s && !macro_is_equal(s->d, str)) tcc_warning("%s redefined", get_tok_str(v, NULL)); - s = sym_push2(&define_stack, v, macro_type, 0); s->d = str; s->next = first_arg; - table_ident[v - TOK_IDENT]->sym_define = s; + def = &table_ident[v - TOK_IDENT]->sym_define; + def->data[def->off] = s; } /* undefined a define symbol. Its name is just set to zero */ ST_FUNC void define_undef(Sym *s) { int v; - v = s->v; - if (v >= TOK_IDENT && v < tok_ident) - table_ident[v - TOK_IDENT]->sym_define = NULL; - s->v = 0; + CSym *def; + v = s->v - TOK_IDENT; + if ((unsigned)v < (unsigned)(tok_ident - TOK_IDENT)){ + def = &table_ident[v]->sym_define; + def->data[def->off] = NULL; + } } ST_INLN Sym *define_find(int v) { + CSym *def; v -= TOK_IDENT; if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) return NULL; - return table_ident[v]->sym_define; + def = &table_ident[v]->sym_define; + return def->data[def->off]; } /* free define stack until top reaches 'b' */ ST_FUNC void free_defines(Sym *b) { - Sym *top, *top1; + Sym *top, *tmp; int v; + CSym *def; top = define_stack; while (top != b) { - top1 = top->prev; + tmp = top->prev; /* do not free args or predefined defines */ if (top->d) tok_str_free(top->d); - v = top->v; - if (v >= TOK_IDENT && v < tok_ident) - table_ident[v - TOK_IDENT]->sym_define = NULL; + v = top->v - TOK_IDENT; + if ((unsigned)v < (unsigned)(tok_ident - TOK_IDENT)){ + def = &table_ident[v]->sym_define; + if(def->off) + def->off = 0; + if(def->data[0]) + def->data[0] = NULL; + } sym_free(top); - top = top1; + top = tmp; } define_stack = b; } @@ -1338,66 +1351,18 @@ static inline void add_cached_include(TCCState *s1, const char *filename, int if s1->cached_includes_hash[h] = s1->nb_cached_includes; } -static void pragma_parse(TCCState *s1) -{ - int val; - - next(); - if (tok == TOK_pack) { - /* - This may be: - #pragma pack(1) // set - #pragma pack() // reset to default - #pragma pack(push,1) // push & set - #pragma pack(pop) // restore previous - */ - next(); - skip('('); - if (tok == TOK_ASM_pop) { - next(); - if (s1->pack_stack_ptr <= s1->pack_stack) { - stk_error: - tcc_error("out of pack stack"); - } - s1->pack_stack_ptr--; - } else { - val = 0; - if (tok != ')') { - if (tok == TOK_ASM_push) { - next(); - if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE - 1) - goto stk_error; - s1->pack_stack_ptr++; - skip(','); - } - if (tok != TOK_CINT) { - pack_error: - tcc_error("invalid pack pragma"); - } - val = tokc.i; - if (val < 1 || val > 16 || (val & (val - 1)) != 0) - goto pack_error; - next(); - } - *s1->pack_stack_ptr = val; - skip(')'); - } - } -} - /* is_bof is true if first non space token at beginning of file */ ST_FUNC void preprocess(int is_bof) { TCCState *s1 = tcc_state; int i, c, n, saved_parse_flags; - char buf[1024], *q; + uint8_t buf[1024], *p; Sym *s; saved_parse_flags = parse_flags; - parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | - PARSE_FLAG_LINEFEED; + parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | PARSE_FLAG_LINEFEED; next_nomacro(); - redo: +redo: switch(tok) { case TOK_DEFINE: next_nomacro(); @@ -1420,19 +1385,21 @@ ST_FUNC void preprocess(int is_bof) goto read_name; } else if (ch == '\"') { c = ch; - read_name: +read_name: inp(); - q = buf; + p = buf; while (ch != c && ch != '\n' && ch != CH_EOF) { - if ((q - buf) < sizeof(buf) - 1) - *q++ = ch; + if ((p - buf) < sizeof(buf) - 1) + *p++ = ch; if (ch == '\\') { if (handle_stray_noerror() == 0) - --q; + --p; } else inp(); } - *q = '\0'; + if (ch != c) + goto include_syntax; + *p = '\0'; minp(); #if 0 /* eat all spaces and comments after include */ @@ -1470,6 +1437,8 @@ ST_FUNC void preprocess(int is_bof) c = '>'; } } + if(!buf[0]) + tcc_error(" empty filename in #include"); if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE) tcc_error("#include recursion too deep"); @@ -1536,8 +1505,7 @@ include_trynext: printf("%s: including %s\n", file->prev->filename, file->filename); #endif /* update target deps */ - dynarray_add((void ***)&s1->target_deps, &s1->nb_target_deps, - tcc_strdup(buf1)); + dynarray_add((void ***)&s1->target_deps, &s1->nb_target_deps, tcc_strdup(buf1)); /* push current file in stack */ ++s1->include_stack_ptr; /* add include file debug info */ @@ -1570,7 +1538,7 @@ include_done: file->ifndef_macro = tok; } } - c = (define_find(tok) != 0) ^ c; + c = !!define_find(tok) ^ c; do_if: if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE) tcc_error("memory full (ifdef)"); @@ -1594,12 +1562,12 @@ include_done: goto skip; c = expr_preprocess(); s1->ifdef_stack_ptr[-1] = c; - test_else: +test_else: if (s1->ifdef_stack_ptr == file->ifdef_stack_ptr + 1) file->ifndef_macro = 0; - test_skip: +test_skip: if (!(c & 1)) { - skip: +skip: preprocess_skip(); is_bof = 0; goto redo; @@ -1617,11 +1585,11 @@ include_done: /* need to set to zero to avoid false matches if another #ifndef at middle of file */ file->ifndef_macro = 0; - while (tok != TOK_LINEFEED) - next_nomacro(); tok_flags |= TOK_FLAG_ENDIF; - goto the_end; } + next_nomacro(); + if (tok != TOK_LINEFEED) + tcc_warning("Ignoring: %s", get_tok_str(tok, &tokc)); break; case TOK_LINE: next(); @@ -1632,8 +1600,7 @@ include_done: if (tok != TOK_LINEFEED) { if (tok != TOK_STR) tcc_error("#line"); - pstrcpy(file->filename, sizeof(file->filename), - (char *)tokc.cstr->data); + pstrcpy(file->filename, sizeof(file->filename), (char *)tokc.cstr->data); } break; case TOK_ERROR: @@ -1641,24 +1608,161 @@ include_done: c = tok; ch = file->buf_ptr[0]; skip_spaces(); - q = buf; + p = buf; while (ch != '\n' && ch != CH_EOF) { - if ((q - buf) < sizeof(buf) - 1) - *q++ = ch; + if ((p - buf) < sizeof(buf) - 1) + *p++ = ch; if (ch == '\\') { if (handle_stray_noerror() == 0) - --q; + --p; } else inp(); } - *q = '\0'; + *p = '\0'; if (c == TOK_ERROR) tcc_error("#error %s", buf); else tcc_warning("#warning %s", buf); break; case TOK_PRAGMA: - pragma_parse(s1); + next(); + if (tok == TOK_pack && parse_flags & PARSE_FLAG_PACK) { + /* + This may be: + #pragma pack(1) // set + #pragma pack() // reset to default + #pragma pack(push,1) // push & set + #pragma pack(pop) // restore previous + */ + next(); + skip('('); + if (tok == TOK_ASM_pop) { + next(); + if (s1->pack_stack_ptr <= s1->pack_stack) { +stk_error: + tcc_error("out of pack stack"); + } + s1->pack_stack_ptr--; + } else { + int val = 0; + if (tok != ')') { + if (tok == TOK_ASM_push) { + next(); + s1->pack_stack_ptr++; + if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE) + goto stk_error; + skip(','); + } + if (tok != TOK_CINT) { +pack_error: + tcc_error("invalid pack pragma"); + } + val = tokc.i; + if (val < 1 || val > 16) + goto pack_error; + if (val < 1 || val > 16) + tcc_error("Value must be greater than 1 is less than or equal to 16"); + if ((val & (val - 1)) != 0) + tcc_error("Value must be a power of 2 curtain"); + next(); + } + *s1->pack_stack_ptr = val; + skip(')'); + } + }else if (tok == TOK_PUSH_MACRO || tok == TOK_POP_MACRO) { + TokenSym *ts; + CSym *def; + uint8_t *p1; + int len, t; + t = tok; + ch = file->buf_ptr[0]; + skip_spaces(); + if (ch != '(') + goto macro_xxx_syntax; + /* XXX: incorrect if comments : use next_nomacro with a special mode */ + inp(); + skip_spaces(); + if (ch == '\"'){ + inp(); + p = buf; + while (ch != '\"' && ch != '\n' && ch != CH_EOF) { + if ((p - buf) < sizeof(buf) - 1) + *p++ = ch; + if (ch == CH_EOB) { + --p; + handle_stray(); + }else + inp(); + } + if(ch != '\"') + goto macro_xxx_syntax; + *p = '\0'; + minp(); + next(); + }else{ + /* computed #pragma macro_xxx for #define xxx */ + next(); + buf[0] = '\0'; + while (tok != ')') { + if (tok != TOK_STR) { + macro_xxx_syntax: + tcc_error("'macro_xxx' expects (\"NAME\")"); + } + pstrcat(buf, sizeof(buf), (char *)tokc.cstr->data); + next(); + } + } + skip (')'); + if(!buf[0]) + tcc_error(" empty string in #pragma"); + /* find TokenSym */ + p = buf; + while (is_space(*p)) + p++; + p1 = p; + for(;;){ + if (!isidnum_table[p[0] - CH_EOF]) + break; + ++p; + } + len = p - p1; + while (is_space(*p)) + p++; + if(!p) //'\0' + tcc_error("unrecognized string: %s", buf); + ts = tok_alloc(p1, len); + if(ts){ + def = &ts->sym_define; + if(t == TOK_PUSH_MACRO){ + void *tmp = def->data[def->off]; + if(tmp){ + def->off++; + if(def->off >= def->size){ + int size = def->size; + size *= 2; + if (size >= MACRO_STACK_SIZE) + tcc_error("stack full"); + def->data = tcc_realloc(def->data, size*sizeof(Sym**)); + def->size = size; + } + def->data[def->off] = tmp; + } + }else{ + if(def->off){ + --def->off; + }else{ + tcc_warning("stack empty"); + } + } + } + }else{ + fputs("#pragma ", s1->ppfp); + while (tok != TOK_LINEFEED){ + fputs(get_tok_str(tok, &tokc), s1->ppfp); + next(); + } + goto the_end; + } break; default: if (tok == TOK_LINEFEED || tok == '!' || tok == TOK_PPNUM) { @@ -1678,7 +1782,7 @@ include_done: /* ignore other preprocess commands or #! for C scripts */ while (tok != TOK_LINEFEED) next_nomacro(); - the_end: +the_end: parse_flags = saved_parse_flags; } @@ -3030,12 +3134,13 @@ ST_FUNC int tcc_preprocess(TCCState *s1) ch = file->buf_ptr[0]; tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; parse_flags = PARSE_FLAG_ASM_COMMENTS | PARSE_FLAG_PREPROCESS | - PARSE_FLAG_LINEFEED | PARSE_FLAG_SPACES; + PARSE_FLAG_LINEFEED | PARSE_FLAG_SPACES; token_seen = 0; line_ref = 0; file_ref = NULL; iptr = s1->include_stack_ptr; - + tok = TOK_LINEFEED; /* print line */ + goto print_line; for (;;) { next(); if (tok == TOK_EOF) { @@ -3043,11 +3148,11 @@ ST_FUNC int tcc_preprocess(TCCState *s1) } else if (file != file_ref) { goto print_line; } else if (tok == TOK_LINEFEED) { - if (!token_seen) + if (token_seen) continue; ++line_ref; - token_seen = 0; - } else if (!token_seen) { + token_seen = 1; + } else if (token_seen) { d = file->line_num - line_ref; if (file != file_ref || d < 0 || d >= 8) { print_line: @@ -3055,8 +3160,7 @@ print_line: s = iptr_new > iptr ? " 1" : iptr_new < iptr ? " 2" : iptr_new > s1->include_stack ? " 3" - : "" - ; + : ""; iptr = iptr_new; fprintf(s1->ppfp, "# %d \"%s\"%s\n", file->line_num, file->filename, s); } else { @@ -3064,8 +3168,8 @@ print_line: fputs("\n", s1->ppfp), --d; } line_ref = (file_ref = file)->line_num; - token_seen = tok != TOK_LINEFEED; - if (!token_seen) + token_seen = tok == TOK_LINEFEED; + if (token_seen) continue; } fputs(get_tok_str(tok, &tokc), s1->ppfp); diff --git a/tcctok.h b/tcctok.h index 6fc8308..c2aa040 100644 --- a/tcctok.h +++ b/tcctok.h @@ -138,6 +138,8 @@ /* pragma */ DEF(TOK_pack, "pack") + DEF(TOK_PUSH_MACRO, "push_macro") + DEF(TOK_POP_MACRO, "pop_macro") #if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64) /* already defined for assembler */ DEF(TOK_ASM_push, "push") diff --git a/tests/tcctest.c b/tests/tcctest.c index ca2ad0b..5fac82e 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -235,7 +235,7 @@ void intdiv_test(void) void macro_test(void) { - printf("macro:\n"); + printf("macro:\n"); pf("N=%d\n", N); printf("aaa=%d\n", AAA); @@ -379,6 +379,23 @@ comment /* And again when the name and parenthes are separated by a comment. */ TEST2 /* the comment */ (); + /* macro_push and macro_pop test */ + #define MACRO_TEST "macro_test1\n" + #pragma push_macro("MACRO_TEST") + #undef MACRO_TEST + #define MACRO_TEST "macro_test2\n" + printf(MACRO_TEST); + #pragma pop_macro("MACRO_TEST") + printf(MACRO_TEST); +/* gcc does not support + #define MACRO_TEST_MACRO "MACRO_TEST" + #pragma push_macro(MACRO_TEST_MACRO) + #undef MACRO_TEST + #define MACRO_TEST "macro_test3\n" + printf(MACRO_TEST); + #pragma pop_macro(MACRO_TEST_MACRO) + printf(MACRO_TEST); +*/ } @@ -2167,14 +2184,15 @@ void whitespace_test(void) { char *str; - #if 1 + +#if 1 pri\ -ntf("whitspace:\n"); +ntf("whitspace:\n"); #endif pf("N=%d\n", 2); #ifdef CORRECT_CR_HANDLING - pri\ + pri\ ntf("aaa=%d\n", 3); #endif @@ -2186,11 +2204,12 @@ ntf("min=%d\n", 4); printf("len1=%d\n", strlen(" ")); #ifdef CORRECT_CR_HANDLING - str = " + str = " "; printf("len1=%d str[0]=%d\n", strlen(str), str[0]); #endif - printf("len1=%d\n", strlen(" a + printf("len1=%d\n", strlen(" +a ")); #endif /* ACCEPT_CR_IN_STRINGS */ } From e647c3137d91f5daa1096b21e09d689ddf71335b Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Fri, 2 May 2014 23:45:48 +0800 Subject: [PATCH 20/52] Fix x86-64 vla For example, it should look like this High stack ------------- ----- Func_ret_sub ------------ ---- Vla stack ------------- ---- Known loc -------------- Low Increased loc_stack () function is used for temporary stack management, call save_reg (), released by load () Like this Before use High ----- Known loc ---- --- ---- ---- Pop_stack Low loc_stack (size, 1) After use High ----- Known loc ---- Pop_stack --- ---- ---- Low --- tcc.h | 4 +- tccgen.c | 458 ++++++++++++++++++++++++++++++++------------------- x86_64-gen.c | 51 ++++-- 3 files changed, 322 insertions(+), 191 deletions(-) diff --git a/tcc.h b/tcc.h index 266b43a..f56273f 100644 --- a/tcc.h +++ b/tcc.h @@ -761,7 +761,7 @@ struct TCCState { #define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED) #define VT_BOUNDED 0x8000 /* value is bounded. The address of the bounding function call point is in vc */ -#define VT_TMP 0x10000 +#define VT_TMP 0x10000 /* luck or tmp stack */ /* types */ #define VT_BTYPE 0x000f /* mask for basic type */ @@ -1212,6 +1212,7 @@ ST_FUNC int ieee_finite(double d); ST_FUNC void test_lvalue(void); ST_FUNC void swap(int *p, int *q); ST_FUNC void vpushi(int v); +ST_FUNC void vpushs(addr_t v); ST_FUNC Sym *external_global_sym(int v, CType *type, int r); ST_FUNC void vset(CType *type, int r, int v); ST_FUNC void vswap(void); @@ -1247,6 +1248,7 @@ ST_FUNC void gen_inline_functions(void); ST_FUNC void decl(int l); ST_FUNC void vdup(void); ST_FUNC void gaddrof(void); +ST_FUNC int loc_stack(int size, int is_sub); #if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_C67 ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size); #endif diff --git a/tccgen.c b/tccgen.c index 456005e..9e6275e 100644 --- a/tccgen.c +++ b/tccgen.c @@ -370,7 +370,7 @@ ST_FUNC void vpushi(int v) } /* push a pointer sized constant */ -static void vpushs(addr_t v) +ST_FUNC void vpushs(addr_t v) { CValue cval; cval.ptr_offset = v; @@ -525,6 +525,41 @@ ST_FUNC void vdup(void) 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 */ ST_FUNC void save_reg(int r) { @@ -533,57 +568,76 @@ ST_FUNC void save_reg(int r) CType *type; /* modify all stack values */ - saved = 0; - l = 0; - for(p=vstack;p<=vtop;p++) { - if ((p->r & VT_VALMASK) == r || - ((p->type.t & VT_BTYPE) == VT_LLONG && (p->r2 & VT_VALMASK) == r)) { + l = saved = 0; + for(p = vstack; p <= vtop; p++) { +#ifdef TCC_TARGET_X86_64 + if ((p->r & VT_VALMASK) == r || + ((((p->type.t & VT_BTYPE) == VT_QLONG) || ((p->type.t & VT_BTYPE) == VT_QFLOAT)) && + ((p->r2 & VT_VALMASK) == r))) +#else + if ((p->r & VT_VALMASK) == r || ((p->type.t & VT_BTYPE) == VT_LLONG && (p->r2 & VT_VALMASK) == r)) +#endif + { /* must save value on stack if not already done */ if (!saved) { /* NOTE: must reload 'r' because r might be equal to r2 */ r = p->r & VT_VALMASK; /* store register in the stack */ type = &p->type; - if ((p->r & VT_LVAL) || - (!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG)) + if((type->t & VT_BTYPE) == VT_STRUCT){ + int ret_align; + SValue ret; + gfunc_sret(type, func_var, &ret.type, &ret_align); + type = &ret.type; + } + if ((p->r & VT_LVAL) || ((type->t & VT_BTYPE) == VT_FUNC)) #ifdef TCC_TARGET_X86_64 type = &char_pointer_type; #else type = &int_type; #endif - size = type_size(type, &align); - loc = (loc - size) & -align; - sv.type.t = type->t; + size = type_size(type, &align); + l = loc_stack(size, 1); sv.r = VT_LOCAL | VT_LVAL; - sv.c.ul = loc; - store(r, &sv); + sv.c.ul = l; +#ifdef TCC_TARGET_X86_64 + if (((type->t & VT_BTYPE) == VT_QLONG) || ((type->t & VT_BTYPE) == VT_QFLOAT)) +#else + if ((type->t & VT_BTYPE) == VT_LLONG) +#endif + { +#ifdef TCC_TARGET_X86_64 + int load_size = 8, load_type = ((type->t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE; +#else + int load_size = 4, load_type = VT_INT; +#endif + sv.type.t = load_type; + store(r, &sv); + sv.c.ul += load_size; + store(p->r2, &sv); + }else{ + sv.type.t = type->t; + store(r, &sv); + } #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) /* x86 specific: need to pop fp register ST0 if saved */ if (r == TREG_ST0) { o(0xd8dd); /* fstp %st(0) */ } #endif -#ifndef TCC_TARGET_X86_64 - /* special long long case */ - if ((type->t & VT_BTYPE) == VT_LLONG) { - sv.c.ul += 4; - store(p->r2, &sv); - } -#endif - l = loc; - saved = 1; + saved = 1; } - /* mark that stack entry as being saved on the stack */ - if (p->r & VT_LVAL) { - /* also clear the bounded flag because the - relocation address of the function was stored in - p->c.ul */ - p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL; - } else { - p->r = lvalue_type(p->type.t) | VT_LOCAL; - } - p->r2 = VT_CONST; - p->c.ul = l; + /* mark that stack entry as being saved on the stack */ + if (p->r & VT_LVAL) { + /* also clear the bounded flag because the + relocation address of the function was stored in + p->c.ul */ + p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL; + } else { + p->r = lvalue_type(p->type.t) | VT_LOCAL | VT_TMP; + } + p->r2 = VT_CONST; + p->c.ul = l; } } } @@ -613,42 +667,57 @@ ST_FUNC int get_reg_ex(int rc, int rc2) } #endif -/* find a free register of class 'rc'. If none, save one register */ -ST_FUNC int get_reg(int rc) +static int for_reg(int rc) { - int r; + int r; + SValue *p; + if(rc){ + for(r = 0; r < NB_REGS; r++) { + if (reg_classes[r] & rc) { + for(p = vstack; p <= vtop; p++) { + if ((p->r & VT_VALMASK) == r || (p->r2 & VT_VALMASK) == r) + goto notfound; + } + goto found; + } + notfound:; + } + } + r = -1; +found: + return r; +} + +/* find a free register of class 'rc'. If none, save one register */ +int get_reg(int rc) +{ + int r; SValue *p; /* find a free register */ - for(r=0;rr & VT_VALMASK) == r || - (p->r2 & VT_VALMASK) == r) - goto notfound; - } - return r; - } - notfound: ; - } - + r = for_reg(rc); + if (r != -1) + return r; /* no register left : free the first one on the stack (VERY IMPORTANT to start from the bottom to ensure that we don't spill registers used in gen_opi()) */ - for(p=vstack;p<=vtop;p++) { + for(p = vstack; p <= vtop; p++) { /* look at second register (if long long) */ + if(p->r & VT_TMP) + continue; r = p->r2 & VT_VALMASK; if (r < VT_CONST && (reg_classes[r] & rc)) goto save_found; r = p->r & VT_VALMASK; if (r < VT_CONST && (reg_classes[r] & rc)) { - save_found: - save_reg(r); +save_found: + save_reg(r); return r; } } /* Should never comes here */ - return -1; + assert(0); + return -1; } /* save registers up to (vtop - n) stack entry */ @@ -689,9 +758,7 @@ ST_FUNC void gaddrof(void) vtop->r &= ~VT_LVAL; /* tricky: if saved lvalue, then we can go back to lvalue */ if ((vtop->r & VT_VALMASK) == VT_LLOCAL) - vtop->r = (vtop->r & ~(VT_VALMASK | VT_LVAL_TYPE)) | VT_LOCAL | VT_LVAL; - - + vtop->r = (vtop->r & ~(VT_VALMASK | VT_LVAL_TYPE)) | VT_LOCAL | VT_LVAL| VT_TMP; } #ifdef CONFIG_TCC_BCHECK @@ -1067,8 +1134,9 @@ ST_FUNC void vrott(int n) /* pop stack value */ ST_FUNC void vpop(void) { - int v; - v = vtop->r & VT_VALMASK; + int v, fr; + fr = vtop->r; + v = fr & VT_VALMASK; #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) /* for x86, we need to pop the FP stack */ if (v == TREG_ST0 && !nocode_wanted) { @@ -1079,6 +1147,17 @@ ST_FUNC void vpop(void) /* need to put correct jump if && or || without test */ gsym(vtop->c.ul); } + if(fr & VT_TMP){ + int size, align; + SValue ret; + if((vtop->type.t & VT_BTYPE) == VT_FUNC) + size = 8; + else{ + gfunc_sret(&vtop->type, func_var, &ret.type, &align); + size = type_size(&ret.type, &align); + } + loc_stack(size, 0); + } vtop--; } @@ -2154,7 +2233,7 @@ ST_FUNC void vla_runtime_type_size(CType *type, int *a) static void vla_sp_save(void) { if (!(vla_flags & VLA_SP_LOC_SET)) { - *vla_sp_loc = (loc -= PTR_SIZE); + *vla_sp_loc = loc_stack(PTR_SIZE, 1); vla_flags |= VLA_SP_LOC_SET; } if (!(vla_flags & VLA_SP_SAVED)) { @@ -2423,6 +2502,8 @@ static void gen_assign_cast(CType *dt) if (sbt == VT_PTR || sbt == VT_FUNC) { tcc_warning("assignment makes integer from pointer without a cast"); } + if (sbt == VT_STRUCT) + goto error; /* XXX: more tests */ break; case VT_STRUCT: @@ -2466,7 +2547,7 @@ static void vstore_im(){ #else sv.type.t = VT_INT; #endif - sv.r = VT_LOCAL | VT_LVAL; + sv.r = VT_LOCAL | VT_LVAL | VT_TMP; sv.c.ul = vtop[-1].c.ul; load(t, &sv); vtop[-1].r = t | VT_LVAL; @@ -2534,7 +2615,7 @@ ST_FUNC void vstore(void) SValue ret; int ret_nregs, ret_align; ret_nregs = gfunc_sret(&vtop->type, func_var, &ret.type, &ret_align); - if(0){ + if(ret_nregs){ vswap(); vpushv(vtop - 1); vtop[0].type = ret.type; @@ -2565,7 +2646,7 @@ ST_FUNC void vstore(void) vtop->type.t = VT_PTR; gaddrof(); /* type size */ - vpushi(size); + vpushs(size); gfunc_call(3); #else /* destination */ @@ -2577,7 +2658,7 @@ ST_FUNC void vstore(void) vtop->type.t = VT_PTR; gaddrof(); /* size */ - vpushi(size); + vpushs(size); struct_copy(&vtop[-2], &vtop[-1], &vtop[0]); vtop -=3; #endif @@ -3298,7 +3379,7 @@ static void asm_label_instr(CString *astr) static void post_type(CType *type, AttributeDef *ad) { - int n, l, t1, arg_size, align; + int n, l, t1, arg_size, size, align; Sym **plast, *s, *first; AttributeDef ad1; CType pt; @@ -3402,13 +3483,12 @@ static void post_type(CType *type, AttributeDef *ad) t1 |= type->t & VT_VLA; if (t1 & VT_VLA) { - loc -= type_size(&int_type, &align); - loc &= -align; - n = loc; + size = type_size(&int_type, &align); + n = loc_stack(size, 1); vla_runtime_type_size(type, &align); gen_op('*'); - vset(&int_type, VT_LOCAL|VT_LVAL, loc); + vset(&int_type, VT_LOCAL|VT_LVAL, n); vswap(); vstore(); } @@ -4004,47 +4084,94 @@ ST_FUNC void unary(void) /* post operations */ while (1) { + SValue ret; + int ret_nregs, ret_align; if (tok == TOK_INC || tok == TOK_DEC) { inc(1, tok); next(); } else if (tok == '.' || tok == TOK_ARROW) { - int qualifiers; + int qualifiers, add, is_lval; /* field */ - if (tok == TOK_ARROW) - indir(); - qualifiers = vtop->type.t & (VT_CONSTANT | VT_VOLATILE); - test_lvalue(); - gaddrof(); - next(); - /* expect pointer on structure */ - if ((vtop->type.t & VT_BTYPE) != VT_STRUCT) - expect("struct or union"); - s = vtop->type.ref; - /* find field */ - tok |= SYM_FIELD; - while ((s = s->next) != NULL) { - if (s->v == tok) - break; - } - if (!s) - tcc_error("field not found: %s", get_tok_str(tok & ~SYM_FIELD, NULL)); - /* add field offset to pointer */ - vtop->type = char_pointer_type; /* change type to 'char *' */ - vpushi(s->c); - gen_op('+'); - /* change type to field type, and set to lvalue */ - vtop->type = s->type; - vtop->type.t |= qualifiers; - /* an array is never an lvalue */ - if (!(vtop->type.t & VT_ARRAY)) { - vtop->r |= lvalue_type(vtop->type.t); -#ifdef CONFIG_TCC_BCHECK - /* if bound checking, the referenced pointer must be checked */ - if (tcc_state->do_bounds_check) - vtop->r |= VT_MUSTBOUND; + qualifiers = vtop->type.t & (VT_CONSTANT | VT_VOLATILE); + add = 0; + if (tok == TOK_ARROW) + indir(); + + type = vtop->type; + is_lval = (vtop->r & (VT_VALMASK | VT_LVAL)) >= VT_CONST; + if(is_lval){ + test_lvalue(); + gaddrof(); + vtop->type = char_pointer_type; /* change type to 'char *' */ + }else + gfunc_sret(&vtop->type, func_var, &ret.type, &ret_align); + do{ + next(); + /* expect pointer on structure */ + if ((type.t & VT_BTYPE) != VT_STRUCT) + expect("struct or union"); + s = type.ref; + /* find field */ + tok |= SYM_FIELD; + while ((s = s->next) != NULL) { + if (s->v == tok) + break; + } + if (!s) + tcc_error("field not found: %s", get_tok_str(tok & ~SYM_FIELD, NULL)); + /* add bit */ + add += s->c; + /* change type to field type, and set to lvalue */ + type = s->type; + next(); + }while(tok == '.'); + + type.t |= qualifiers; + if (is_lval){ + p_lval: + vpushi(add); + gen_op('+'); + /* an array is never an lvalue */ + if (!(type.t & VT_ARRAY)) { + vtop->r |= lvalue_type(type.t); + #ifdef CONFIG_TCC_BCHECK + /* if bound checking, the referenced pointer must be checked */ + if (tcc_state->do_bounds_check) + vtop->r |= VT_MUSTBOUND; + #endif + } + }else{ + gfunc_sret(&vtop->type, func_var, &ret.type, &ret_align); + if(is_float(ret.type.t) || (type.t & VT_ARRAY)){ +#ifdef TCC_TARGET_X86_64 + if((ret.type.t & VT_BTYPE) != VT_LDOUBLE) #endif - } - next(); + { + save_reg(vtop->r); + vtop->r &= ~VT_TMP; + gaddrof(); + vtop->type = char_pointer_type; /* change type to 'char *' */ + goto p_lval; + } + }else{ +#ifdef TCC_TARGET_X86_64 + int load_size = 8; +#else + int load_size = 4; +#endif + if(add & load_size){ + add -= load_size; + vtop->r = vtop->r2; + vtop->r2 = VT_CONST; + } + if(add){ + vtop->type.t = VT_LLONG; + vpushi(add*8); + gen_op(TOK_SAR); + } + } + } + vtop->type = type; } else if (tok == '[') { next(); gexpr(); @@ -4052,9 +4179,8 @@ ST_FUNC void unary(void) indir(); skip(']'); } else if (tok == '(') { - SValue ret; Sym *sa; - int nb_args, ret_nregs, ret_align, variadic; + int nb_args, variadic, addr; /* function call */ if ((vtop->type.t & VT_BTYPE) != VT_FUNC) { @@ -4072,7 +4198,6 @@ ST_FUNC void unary(void) } /* get return type */ s = vtop->type.ref; - next(); sa = s->next; /* first parameter */ nb_args = 0; ret.r2 = VT_CONST; @@ -4084,12 +4209,12 @@ ST_FUNC void unary(void) if (!ret_nregs) { /* get some space for the returned structure */ size = type_size(&s->type, &align); - loc = (loc - size) & -align; + addr = loc_stack(size, 1); ret.type = s->type; ret.r = VT_LOCAL | VT_LVAL; /* pass it as 'int' to avoid structure arg passing problems */ - vseti(VT_LOCAL, loc); + vseti(VT_LOCAL, addr); ret.c = vtop->c; nb_args++; } @@ -4117,6 +4242,7 @@ ST_FUNC void unary(void) } ret.c.i = 0; } + next(); if (tok != ')') { for(;;) { expr_eq(); @@ -4145,25 +4271,8 @@ ST_FUNC void unary(void) } /* handle packed struct return */ - if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) { - int addr, offset; - - size = type_size(&s->type, &align); - loc = (loc - size) & -align; - addr = loc; - offset = 0; - for (;;) { - vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset); - vswap(); - vstore(); - vtop--; - if (--ret_nregs == 0) - break; - /* XXX: compatible with arm only: ret_align == register_size */ - offset += ret_align; - } - vset(&s->type, VT_LOCAL | VT_LVAL, addr); - } + if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) + vtop->type = s->type; } else { break; } @@ -4332,8 +4441,8 @@ static void expr_lor(void) /* XXX: better constant handling */ static void expr_cond(void) { - int tt, u, r1, r2, rc, t1, t2, bt1, bt2; - SValue sv; + int tt, u, r, rc, t1, t2, bt1, bt2, ret_nregs, ret_align; + SValue sv, ret; CType type, type1, type2; if (const_wanted) { @@ -4375,8 +4484,7 @@ static void expr_cond(void) } else rc = RC_INT; - gv(rc); - save_regs(1); + save_regs(1); } if (tok == ':' && gnu_ext) { gv_dup(); @@ -4415,16 +4523,14 @@ static void expr_cond(void) (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED)) type.t |= VT_UNSIGNED; } else if (bt1 == VT_PTR || bt2 == VT_PTR) { - /* If one is a null ptr constant the result type - is the other. */ - if (is_null_pointer (vtop)) - type = type1; - else if (is_null_pointer (&sv)) - type = type2; - /* XXX: test pointer compatibility, C99 has more elaborate - rules here. */ - else - type = type1; + /* If one is a null ptr constant the result type is the other. */ + if (is_null_pointer (vtop)) + type = type1; + else if (is_null_pointer (&sv)) + type = type2; + /* XXX: test pointer compatibility, C99 has more elaborate rules here. */ + else + type = type1; } else if (bt1 == VT_FUNC || bt2 == VT_FUNC) { /* XXX: test function pointer compatibility */ type = bt1 == VT_FUNC ? type1 : type2; @@ -4442,26 +4548,35 @@ static void expr_cond(void) (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) type.t |= VT_UNSIGNED; } - + /* now we convert second operand */ gen_cast(&type); - if (VT_STRUCT == (vtop->type.t & VT_BTYPE)) - gaddrof(); - rc = RC_INT; - if (is_float(type.t)) { + ret_nregs = 0; + if (VT_STRUCT == (type.t & VT_BTYPE)){ + ret_nregs = gfunc_sret(&type, func_var, &ret.type, &ret_align); + if(ret_nregs) + vtop->type = ret.type; + else + gaddrof(); + } + + if (is_float(vtop->type.t)) { rc = RC_FLOAT; #ifdef TCC_TARGET_X86_64 if ((type.t & VT_BTYPE) == VT_LDOUBLE) { rc = RC_ST0; } #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; - } - - r2 = gv(rc); + } else + rc = RC_INT; + r = gv(rc); + rc = reg_classes[r] & ~RC_MASK; +#ifdef TCC_TARGET_X86_64 + if (((vtop->type.t & VT_BTYPE) == VT_QLONG) || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT)) +#else + if ((vtop->type.t & VT_BTYPE) == VT_LLONG) +#endif + ex_rc = reg_classes[vtop->r2] & ~RC_MASK; /* this is horrible, but we must also convert first operand */ tt = gjmp(0); @@ -4469,12 +4584,21 @@ static void expr_cond(void) /* put again first value and cast it */ *vtop = sv; gen_cast(&type); - if (VT_STRUCT == (vtop->type.t & VT_BTYPE)) - gaddrof(); - r1 = gv(rc); - move_reg(r2, r1, type.t); - vtop->r = r2; + if (VT_STRUCT == (type.t & VT_BTYPE)){ + if(ret_nregs) + vtop->type = ret.type; + else + gaddrof(); + } + gv(rc); gsym(tt); + + if (VT_STRUCT == (type.t & VT_BTYPE)){ + if(ret_nregs) + vtop->type = type; + else + vtop->r |= VT_LVAL; + } } } } @@ -4747,18 +4871,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, vstore(); } else { /* returning structure packed into registers */ - int rc, size, addr, align; - size = type_size(&func_vt,&align); - if ((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & (ret_align-1))) - && (align & (ret_align-1))) { - loc = (loc - size) & -align; - addr = loc; - type = func_vt; - vset(&type, VT_LOCAL | VT_LVAL, addr); - vswap(); - vstore(); - vset(&ret_type, VT_LOCAL | VT_LVAL, addr); - } + int rc; vtop->type = ret_type; if (is_float(ret_type.t)) rc = rc_fret(ret_type.t); @@ -5606,11 +5719,10 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, sec = NULL; #ifdef CONFIG_TCC_BCHECK if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) { - loc--; + loc_stack(1, 1); } #endif - loc = (loc - size) & -align; - addr = loc; + addr = loc_stack(size, 1); #ifdef CONFIG_TCC_BCHECK /* handles bounds */ /* XXX: currently, since we do only one pass, we cannot track @@ -5618,7 +5730,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) { unsigned long *bounds_ptr; /* add padding between regions */ - loc--; + loc_stack(1, 1); /* then add local bound info */ bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(unsigned long)); bounds_ptr[0] = addr; diff --git a/x86_64-gen.c b/x86_64-gen.c index 0307792..7a79278 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -405,6 +405,14 @@ void load(int r, SValue *sv) v = fr & VT_VALMASK; if (fr & VT_LVAL) { + if(fr & VT_TMP){ + int size, align; + if((ft & VT_BTYPE) == VT_FUNC) + size = 8; + else + size = type_size(&sv->type, &align); + loc_stack(size, 0); + } if (v == VT_LLOCAL) { v1.type.t = VT_PTR; v1.r = VT_LOCAL | VT_LVAL; @@ -602,6 +610,24 @@ static void gcall_or_jmp(int is_jmp) } } +static int func_scratch; +static int r_loc; + +int reloc_add(int inds) +{ + return psym(0, inds); +} + +void reloc_use(int t, int data) +{ + int *ptr; + while (t) { + ptr = (int *)(cur_text_section->data + t); + t = *ptr; /* next value */ + *ptr = data; + } +} + void struct_copy(SValue *d, SValue *s, SValue *c) { if(!c->c.i) @@ -647,9 +673,6 @@ void gen_offs_sp(int b, int r, int off) } } -static int func_scratch; -static int r_loc; - #ifdef TCC_TARGET_PE #define REGN 4 @@ -905,7 +928,7 @@ void gfunc_epilog(void) ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; /* align local size to word & save local variables */ v = (func_scratch + -loc + 15) & -16; - + reloc_use(r_loc, func_scratch); if (v >= 4096) { Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0); oad(0xb8, v); /* mov stacksize, %eax */ @@ -1210,6 +1233,7 @@ doing: /* Must ensure TREG_ST0 only */ if((vtop->type.t & VT_BTYPE) == VT_STRUCT){ vdup(); + vtop[-1].r = VT_CONST; vtop->type = type; gv(RC_ST0); args_size -= size; @@ -1228,7 +1252,7 @@ doing: vpushv(&vtop[-1]); vtop->type = char_pointer_type; gaddrof(); - vpushi(size); + vpushs(size); struct_copy(&vtop[-2], &vtop[-1], &vtop[0]); vtop -= 3; break; @@ -1474,6 +1498,7 @@ void gfunc_epilog(void) } /* align local size to word & save local variables */ v = (func_scratch -loc + 15) & -16; + reloc_use(r_loc, func_scratch); saved_ind = ind; ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; o(0xe5894855); /* push %rbp, mov %rsp, %rbp */ @@ -2043,27 +2068,19 @@ ST_FUNC void gen_vla_sp_restore(int addr) { /* Subtract from the stack pointer, and push the resulting value onto the stack */ ST_FUNC void gen_vla_alloc(CType *type, int align) { -#ifdef TCC_TARGET_PE - /* alloca does more than just adjust %rsp on Windows */ - vpush_global_sym(&func_old_type, TOK_alloca); - vswap(); /* Move alloca ref past allocation size */ - gfunc_call(1); - vset(type, REG_IRET, 0); -#else int r; r = gv(RC_INT); /* allocation size */ /* sub r,%rsp */ o(0x2b48); o(0xe0 | REG_VALUE(r)); - /* We align to 16 bytes rather than align */ - /* and ~15, %rsp */ + /* and ~15, %rsp */ o(0xf0e48348); /* mov %rsp, r */ - o(0x8948); - o(0xe0 | REG_VALUE(r)); + orex(1, 0, r, 0x8d); + o(0x2484 | (REG_VALUE(r)*8)); + r_loc = reloc_add(r_loc); vpop(); vset(type, r, 0); -#endif } From 6755b4a3defec21593c08ac429b214ab908d1dd1 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Sat, 3 May 2014 00:33:19 +0800 Subject: [PATCH 21/52] Modify i386-gen.c, Thank Roy Tam reported problems --- i386-gen.c | 167 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 113 insertions(+), 54 deletions(-) diff --git a/i386-gen.c b/i386-gen.c index b9811f5..018307a 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -33,17 +33,25 @@ #define RC_ST0 0x0008 #define RC_ECX 0x0010 #define RC_EDX 0x0020 +#define RC_EBX 0x0040 +#define RC_ESI 0x0080 +#define RC_EDI 0x0100 +#define RC_INT2 0x0200 #define RC_IRET RC_EAX /* function return: integer register */ #define RC_LRET RC_EDX /* function return: second integer register */ #define RC_FRET RC_ST0 /* function return: float register */ +#define RC_MASK (RC_INT|RC_INT2|RC_FLOAT) /* pretty names for the registers */ enum { TREG_EAX = 0, TREG_ECX, TREG_EDX, + TREG_EBX, + TREG_ESP, TREG_ST0, - TREG_ESP = 4 + TREG_ESI, + TREG_EDI, }; /* return registers for function */ @@ -90,10 +98,14 @@ enum { #include "tcc.h" ST_DATA const int reg_classes[NB_REGS] = { - /* eax */ RC_INT | RC_EAX, - /* ecx */ RC_INT | RC_ECX, + /* eax */ RC_INT | RC_EAX | RC_INT2, + /* ecx */ RC_INT | RC_ECX | RC_INT2, /* edx */ RC_INT | RC_EDX, + RC_INT|RC_INT2|RC_EBX, + 0, /* st0 */ RC_FLOAT | RC_ST0, + RC_RSI|RC_INT2, + RC_RDI|RC_INT2, }; static unsigned long func_sub_sp_offset; @@ -226,6 +238,14 @@ ST_FUNC void load(int r, SValue *sv) v = fr & VT_VALMASK; if (fr & VT_LVAL) { + if(fr & VT_TMP){ + int size, align; + if((ft & VT_BTYPE) == VT_FUNC) + size = 4; + else + size = type_size(&sv->type, &align); + loc_stack(size, 0); + } if (v == VT_LLOCAL) { v1.type.t = VT_INT; v1.r = VT_LOCAL | VT_LVAL; @@ -715,40 +735,48 @@ ST_FUNC int gtst(int inv, int t) /* generate an integer binary operation */ ST_FUNC void gen_opi(int op) { - int r, fr, opc, c; + int r, fr, opc, fc, c; + int cc, uu, tt2; + + fr = vtop[0].r; + fc = vtop->c.ul; + cc = (fr & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; + tt2 = (fr & (VT_LVAL | VT_LVAL_TYPE)) == VT_LVAL; switch(op) { case '+': case TOK_ADDC1: /* add with carry generation */ opc = 0; gen_op8: - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { + vswap(); + r = gv(RC_INT); + vswap(); + if (cc) { /* constant case */ - vswap(); - r = gv(RC_INT); - vswap(); c = vtop->c.i; if (c == (char)c) { /* generate inc and dec for smaller code */ - if (c==1 && opc==0) { + if (c == 1 && opc == 0) { o (0x40 | r); // inc - } else if (c==1 && opc==5) { + } else if (c == 1 && opc == 5) { o (0x48 | r); // dec } else { o(0x83); - o(0xc0 | (opc << 3) | r); + o(0xc0 + r + opc*8); g(c); } } else { o(0x81); - oad(0xc0 | (opc << 3) | r, c); + oad(0xc0 + r+ opc*8, c); } } else { - gv2(RC_INT, RC_INT); - r = vtop[-1].r; - fr = vtop[0].r; - o((opc << 3) | 0x01); - o(0xc0 + r + fr * 8); + if(!tt2) + fr = gv(RC_INT); + o(0x03 + opc*8); + if(fr >= VT_CONST) + gen_modrm(r, fr, vtop->sym, fc); + else + o(0xc0 + fr + r*8); } vtop--; if (op >= TOK_ULT && op <= TOK_GT) { @@ -776,12 +804,28 @@ ST_FUNC void gen_opi(int op) opc = 1; goto gen_op8; case '*': - gv2(RC_INT, RC_INT); - r = vtop[-1].r; - fr = vtop[0].r; + opc = 5; + vswap(); + r = gv(RC_INT); + vswap(); + if(!tt2) + fr = gv(RC_INT); + if(r == TREG_EAX){ + if(fr != TREG_EDX) + save_reg(TREG_EDX); + o(0xf7); + if(fr >= VT_CONST) + gen_modrm(opc, fr, vtop->sym, fc); + else + o(0xc0 + fr + opc*8); + }else{ + o(0xaf0f); /* imul fr, r */ + if(fr >= VT_CONST) + gen_modrm(r, fr, vtop->sym, fc); + else + o(0xc0 + fr + r*8); + } vtop--; - o(0xaf0f); /* imul fr, r */ - o(0xc0 + fr + r * 8); break; case TOK_SHL: opc = 4; @@ -792,56 +836,71 @@ ST_FUNC void gen_opi(int op) case TOK_SAR: opc = 7; gen_shift: - opc = 0xc0 | (opc << 3); - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { + if (cc) { /* constant case */ vswap(); r = gv(RC_INT); vswap(); - c = vtop->c.i & 0x1f; - o(0xc1); /* shl/shr/sar $xxx, r */ - o(opc | r); - g(c); + c = vtop->c.i; + if(c == 1){ + o(0xd1); + o(0xc0 + r + opc*8); + }else{ + o(0xc1); /* shl/shr/sar $xxx, r */ + o(0xc0 + r + opc*8); + g(c & 0x1f); + } } else { /* we generate the shift in ecx */ gv2(RC_INT, RC_ECX); r = vtop[-1].r; o(0xd3); /* shl/shr/sar %cl, r */ - o(opc | r); + o(0xc0 + r + opc*8); } vtop--; break; - case '/': - case TOK_UDIV: - case TOK_PDIV: - case '%': case TOK_UMOD: + opc = 4; + uu = 1; + goto divmod; + case TOK_UDIV: case TOK_UMULL: + opc = 6; + uu = 1; + goto divmod; + case '/': + case '%': + case TOK_PDIV: + opc = 7; + uu = 0; + divmod: /* first operand must be in eax */ /* XXX: need better constraint for second operand */ - gv2(RC_EAX, RC_ECX); - r = vtop[-1].r; - fr = vtop[0].r; - vtop--; - save_reg(TREG_EDX); - if (op == TOK_UMULL) { + if(!tt2){ + gv2(RC_EAX, RC_INT2); + fr = vtop[0].r; + }else{ + vswap(); + gv(RC_EAX); + vswap(); + } + save_reg(TREG_EDX); + if (op == TOK_UMULL) { o(0xf7); /* mul fr */ - o(0xe0 + fr); - vtop->r2 = TREG_EDX; + vtop->r2 = TREG_EDX; + }else{ + o(uu ? 0xd231 : 0x99); /* xor %edx,%edx : cdq RDX:RAX <- sign-extend of RAX. */ + o(0xf7); /* div fr, %eax */ + } + if(fr >= VT_CONST) + gen_modrm(opc, fr, vtop->sym, fc); + else + o(0xc0 + fr + opc*8); + if (op == '%' || op == TOK_UMOD) + r = TREG_EDX; + else r = TREG_EAX; - } else { - if (op == TOK_UDIV || op == TOK_UMOD) { - o(0xf7d231); /* xor %edx, %edx, div fr, %eax */ - o(0xf0 + fr); - } else { - o(0xf799); /* cltd, idiv fr, %eax */ - o(0xf8 + fr); - } - if (op == '%' || op == TOK_UMOD) - r = TREG_EDX; - else - r = TREG_EAX; - } + vtop--; vtop->r = r; break; default: From a0d45c1bcd87d2388817076ac9b62343d8ae04c3 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Sat, 3 May 2014 00:39:40 +0800 Subject: [PATCH 22/52] forget commit tccge.c for i386 --- tccgen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tccgen.c b/tccgen.c index 9e6275e..d504572 100644 --- a/tccgen.c +++ b/tccgen.c @@ -1025,8 +1025,8 @@ static int rc_fret(int t) if (t == VT_LDOUBLE) { return RC_ST0; } -#endif ex_rc = RC_QRET; +#endif return RC_FRET; } From 089dea355a28da44376ce4f5195baa4b4e0b217d Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Sat, 3 May 2014 23:51:09 +0800 Subject: [PATCH 23/52] tcc on i386 are still having problems at work.Thank Roy report again. Struck on several variables can be connected to commit in the register. I am worried whether tcc can run the os. Since my machine is ubuntu 64 bits I can test my machine. --- arm-gen.c | 10 +++++++++- c67-gen.c | 11 ++++++++++- i386-gen.c | 10 +++++----- tcc.h | 2 -- tccgen.c | 37 ++++++++----------------------------- x86_64-gen.c | 2 +- 6 files changed, 33 insertions(+), 39 deletions(-) diff --git a/arm-gen.c b/arm-gen.c index 6da1706..567c868 100644 --- a/arm-gen.c +++ b/arm-gen.c @@ -61,7 +61,7 @@ #define RC_IRET RC_R0 /* function return: integer register */ #define RC_LRET RC_R1 /* function return: second integer register */ #define RC_FRET RC_F0 /* function return: float register */ - +#define RC_MASK (RC_INT|RC_FLOAT) /* pretty names for the registers */ enum { TREG_R0 = 0, @@ -540,6 +540,14 @@ void load(int r, SValue *sv) v = fr & VT_VALMASK; if (fr & VT_LVAL) { uint32_t base = 0xB; // fp + if(fr & VT_TMP){ + int size, align; + if((ft & VT_BTYPE) == VT_FUNC) + size = PTR_SIZE; + else + size = type_size(&sv->type, &align); + loc_stack(size, 0); + } if(v == VT_LLOCAL) { v1.type.t = VT_PTR; v1.r = VT_LOCAL | VT_LVAL; diff --git a/c67-gen.c b/c67-gen.c index 209fa7f..07ae259 100644 --- a/c67-gen.c +++ b/c67-gen.c @@ -58,7 +58,7 @@ #define RC_IRET RC_C67_A4 /* function return: integer register */ #define RC_LRET RC_C67_A5 /* function return: second integer register */ #define RC_FRET RC_C67_A4 /* function return: float register */ - +#define RC_MASK (RC_INT|RC_FLOAT) /* pretty names for the registers */ enum { TREG_EAX = 0, // really A2 @@ -1571,12 +1571,21 @@ void load(int r, SValue * sv) v = fr & VT_VALMASK; if (fr & VT_LVAL) { + if(fr & VT_TMP){ + int size, align; + if((ft & VT_BTYPE) == VT_FUNC) + size = PTR_SIZE; + else + size = type_size(&sv->type, &align); + loc_stack(size, 0); + } if (v == VT_LLOCAL) { v1.type.t = VT_INT; v1.r = VT_LOCAL | VT_LVAL; v1.c.ul = fc; load(r, &v1); fr = r; + fc = 0; } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { tcc_error("long double not supported"); } else if ((ft & VT_TYPE) == VT_BYTE) { diff --git a/i386-gen.c b/i386-gen.c index 018307a..cfa9cc6 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -21,7 +21,7 @@ #ifdef TARGET_DEFS_ONLY /* number of available registers */ -#define NB_REGS 4 +#define NB_REGS 8 #define NB_ASM_REGS 8 /* a register can belong to several classes. The classes must be @@ -41,7 +41,6 @@ #define RC_LRET RC_EDX /* function return: second integer register */ #define RC_FRET RC_ST0 /* function return: float register */ #define RC_MASK (RC_INT|RC_INT2|RC_FLOAT) - /* pretty names for the registers */ enum { TREG_EAX = 0, @@ -104,8 +103,8 @@ ST_DATA const int reg_classes[NB_REGS] = { RC_INT|RC_INT2|RC_EBX, 0, /* st0 */ RC_FLOAT | RC_ST0, - RC_RSI|RC_INT2, - RC_RDI|RC_INT2, + RC_ESI|RC_INT2, + RC_EDI|RC_INT2, }; static unsigned long func_sub_sp_offset; @@ -241,7 +240,7 @@ ST_FUNC void load(int r, SValue *sv) if(fr & VT_TMP){ int size, align; if((ft & VT_BTYPE) == VT_FUNC) - size = 4; + size = PTR_SIZE; else size = type_size(&sv->type, &align); loc_stack(size, 0); @@ -254,6 +253,7 @@ ST_FUNC void load(int r, SValue *sv) if (!(reg_classes[fr] & RC_INT)) fr = get_reg(RC_INT); load(fr, &v1); + fc = 0; } if ((ft & VT_BTYPE) == VT_FLOAT) { o(0xd9); /* flds */ diff --git a/tcc.h b/tcc.h index f56273f..1cead42 100644 --- a/tcc.h +++ b/tcc.h @@ -1350,8 +1350,6 @@ ST_FUNC void gen_le16(int c); ST_FUNC void gen_le32(int c); ST_FUNC void gen_addr32(int r, Sym *sym, int c); ST_FUNC void gen_addrpc32(int r, Sym *sym, int c); -ST_FUNC void struct_copy(SValue *d, SValue *s, SValue *c); -ST_FUNC void gen_putz(SValue *d, int size); #endif #ifdef CONFIG_TCC_BCHECK diff --git a/tccgen.c b/tccgen.c index d504572..c2481b0 100644 --- a/tccgen.c +++ b/tccgen.c @@ -873,7 +873,7 @@ ST_FUNC int gv(int rc) #endif r = vtop->r & VT_VALMASK; - if((rc & ~RC_MASK) && (rc != RC_ST0)) + if(rc & ~RC_MASK) rc2 = ex_rc; else rc2 = (rc & RC_FLOAT) ? RC_FLOAT : RC_INT; @@ -2624,20 +2624,19 @@ ST_FUNC void vstore(void) vtop -=2; }else{ size = type_size(&vtop->type, &align); -#ifndef TCC_TARGET_X86_64 /* destination */ vswap(); vtop->type.t = VT_PTR; gaddrof(); /* address of memcpy() */ -# ifdef TCC_ARM_EABI +#ifdef TCC_ARM_EABI if(!(align & 7)) vpush_global_sym(&func_old_type, TOK_memcpy8); else if(!(align & 3)) vpush_global_sym(&func_old_type, TOK_memcpy4); else -# endif +#endif vpush_global_sym(&func_old_type, TOK_memcpy); vswap(); @@ -2646,22 +2645,8 @@ ST_FUNC void vstore(void) vtop->type.t = VT_PTR; gaddrof(); /* type size */ - vpushs(size); + vpushi(size); gfunc_call(3); -#else - /* destination */ - vswap(); - vtop->type.t = VT_PTR; - gaddrof(); - /* source */ - vpushv(vtop - 1); - vtop->type.t = VT_PTR; - gaddrof(); - /* size */ - vpushs(size); - struct_copy(&vtop[-2], &vtop[-1], &vtop[0]); - vtop -=3; -#endif } } else { vswap(); @@ -5354,22 +5339,16 @@ static void init_putz(CType *t, Section *sec, unsigned long c, int size) if (sec) { /* nothing to do because globals are already set to zero */ } else { -#ifndef TCC_TARGET_X86_64 vpush_global_sym(&func_old_type, TOK_memset); vseti(VT_LOCAL, c); -# ifdef TCC_TARGET_ARM +#ifdef TCC_TARGET_ARM vpushs(size); vpushi(0); -# else - vpushi(0); - vpushs(size); -# endif - gfunc_call(3); #else - vseti(VT_LOCAL, c); - gen_putz(vtop, size); - vtop--; + vpushi(0); + vpushs(size); #endif + gfunc_call(3); } } diff --git a/x86_64-gen.c b/x86_64-gen.c index 7a79278..2b52bb1 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -408,7 +408,7 @@ void load(int r, SValue *sv) if(fr & VT_TMP){ int size, align; if((ft & VT_BTYPE) == VT_FUNC) - size = 8; + size = PTR_SIZE; else size = type_size(&sv->type, &align); loc_stack(size, 0); From 5e56fb635a23484d8fda8b54a40900d0a54b0ba1 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Sun, 4 May 2014 13:18:31 +0800 Subject: [PATCH 24/52] Return to: e20c1eb99e1003c1e59522c136dbb15c52d7cc7c 1: The new patch for the other machines still have the problem. 2: libcrt Rename (what if gcc had libcrt as well) 3: parse_number exact problem 4: VT_VLS is to allow tcc Compile the following int b = 9; struct st { int a; int b [b] }; struct st st1; st1.b [8] = 9; printf ("% d \ n", st1.b [8]); tcc a problem. Due to problems in front, and now can not be improved 5: they commit much, bug difficult to lock, you can not let other people help develop. 6: ('\ t') too Thanks to Michael and Ray Their criticism I have benefited! --- Makefile | 58 +- arm-gen.c | 93 +-- c67-gen.c | 44 +- asmx86.c => i386-asm.c | 41 +- i386-gen.c | 190 ++--- asmx86-tok.h => i386-tok.h | 0 il-gen.c | 15 +- lib/Makefile | 16 +- lib/{libcrt.c => libtcc1.c} | 44 +- libtcc.c | 12 +- tcc.h | 40 +- tccasm.c | 49 +- tccelf.c | 12 +- tccgen.c | 850 ++++++++++----------- tccpe.c | 2 +- tccpp.c | 302 +++----- tcctok.h | 4 +- tests/Makefile | 20 +- tests/abitest.c | 2 +- tests/libtcc_test.c | 2 +- tests/tcctest.c | 54 +- win32/tools/tiny_libmaker.c | 2 +- x86_64-gen.c | 1378 ++++++++++++++++++----------------- 23 files changed, 1416 insertions(+), 1814 deletions(-) rename asmx86.c => i386-asm.c (98%) rename asmx86-tok.h => i386-tok.h (100%) rename lib/{libcrt.c => libtcc1.c} (96%) diff --git a/Makefile b/Makefile index 0f3002b..4f18567 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ endif endif else # not GCC ifeq (-$(findstring clang,$(CC))-,-clang-) -# make clang accept gnuisms in libcrt.c +# make clang accept gnuisms in libtcc1.c CFLAGS+=-fheinous-gnu-extensions endif endif @@ -101,11 +101,11 @@ $(ARM_EABI_CROSS)_LINK = arm-eabi-tcc$(EXESUF) CORE_FILES = tcc.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c tccrun.c CORE_FILES += tcc.h config.h libtcc.h tcctok.h -I386_FILES = $(CORE_FILES) i386-gen.c asmx86.c i386-asm.h asmx86-tok.h -WIN32_FILES = $(CORE_FILES) i386-gen.c asmx86.c i386-asm.h asmx86-tok.h tccpe.c -WIN64_FILES = $(CORE_FILES) x86_64-gen.c asmx86.c x86_64-asm.h tccpe.c +I386_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h +WIN32_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h tccpe.c +WIN64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h tccpe.c WINCE_FILES = $(CORE_FILES) arm-gen.c tccpe.c -X86_64_FILES = $(CORE_FILES) x86_64-gen.c asmx86.c x86_64-asm.h +X86_64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h ARM_FILES = $(CORE_FILES) arm-gen.c C67_FILES = $(CORE_FILES) c67-gen.c tcccoff.c @@ -113,29 +113,29 @@ ifdef CONFIG_WIN64 PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF) NATIVE_FILES=$(WIN64_FILES) PROGS_CROSS=$(WIN32_CROSS) $(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(C67_CROSS) -LIBTCC1_CROSS=lib/i386-win32/libcrt.a -LIBCRT=libcrt.a +LIBTCC1_CROSS=lib/i386-win32/libtcc1.a +LIBTCC1=libtcc1.a else ifdef CONFIG_WIN32 PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF) NATIVE_FILES=$(WIN32_FILES) PROGS_CROSS=$(WIN64_CROSS) $(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(C67_CROSS) -LIBTCC1_CROSS=lib/x86_64-win32/libcrt.a -LIBCRT=libcrt.a +LIBTCC1_CROSS=lib/x86_64-win32/libtcc1.a +LIBTCC1=libtcc1.a else ifeq ($(ARCH),i386) NATIVE_FILES=$(I386_FILES) PROGS_CROSS=$(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(C67_CROSS) -LIBTCC1_CROSS=lib/i386-win32/libcrt.a lib/x86_64-win32/libcrt.a -LIBCRT=libcrt.a +LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a +LIBTCC1=libtcc1.a else ifeq ($(ARCH),x86-64) NATIVE_FILES=$(X86_64_FILES) PROGS_CROSS=$(I386_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(C67_CROSS) -LIBTCC1_CROSS=lib/i386-win32/libcrt.a lib/x86_64-win32/libcrt.a lib/i386/libcrt.a -LIBCRT=libcrt.a +LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a lib/i386/libtcc1.a +LIBTCC1=libtcc1.a else ifeq ($(ARCH),arm) NATIVE_FILES=$(ARM_FILES) PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(C67_CROSS) -LIBCRT=libcrt.a -LIBTCC1_CROSS=lib/i386-win32/libcrt.a lib/x86_64-win32/libcrt.a lib/i386/libcrt.a +LIBTCC1=libtcc1.a +LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a lib/i386/libtcc1.a endif PROGS_CROSS_LINK=$(foreach PROG_CROSS,$(PROGS_CROSS),$($(PROG_CROSS)_LINK)) @@ -143,7 +143,7 @@ ifeq ($(TARGETOS),Darwin) PROGS+=tiny_libmaker$(EXESUF) endif -TCCLIBS = $(LIBCRT) $(LIBTCC) $(LIBTCC_EXTRA) +TCCLIBS = $(LIBTCC1) $(LIBTCC) $(LIBTCC_EXTRA) TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info ifdef CONFIG_CROSS @@ -225,9 +225,9 @@ tiny_libmaker$(EXESUF): win32/tools/tiny_libmaker.c $(CC) -o $@ $< $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) # TinyCC runtime libraries -libcrt.a : FORCE +libtcc1.a : FORCE $(MAKE) -C lib native -lib/%/libcrt.a : FORCE $(PROGS_CROSS) +lib/%/libtcc1.a : FORCE $(PROGS_CROSS) $(MAKE) -C lib cross TARGET=$* FORCE: @@ -258,8 +258,8 @@ endif -$(INSTALL) -m644 tcc-doc.info "$(infodir)" mkdir -p "$(tccdir)" mkdir -p "$(tccdir)/include" -ifneq ($(LIBCRT),) - $(INSTALL) -m644 $(LIBCRT) "$(tccdir)" +ifneq ($(LIBTCC1),) + $(INSTALL) -m644 $(LIBTCC1) "$(tccdir)" endif $(INSTALL) -m644 $(addprefix $(top_srcdir)/include/,$(TCC_INCLUDES)) $(top_srcdir)/tcclib.h "$(tccdir)/include" mkdir -p "$(libdir)" @@ -277,19 +277,19 @@ ifdef CONFIG_CROSS mkdir -p "$(tccdir)/win32/lib/64" ifneq ($(ARCH),i386) mkdir -p "$(tccdir)/i386" - $(INSTALL) -m644 lib/i386/libcrt.a "$(tccdir)/i386" + $(INSTALL) -m644 lib/i386/libtcc1.a "$(tccdir)/i386" cp -r "$(tccdir)/include" "$(tccdir)/i386" endif $(INSTALL) -m644 $(top_srcdir)/win32/lib/*.def "$(tccdir)/win32/lib" - $(INSTALL) -m644 lib/i386-win32/libcrt.a "$(tccdir)/win32/lib/32" - $(INSTALL) -m644 lib/x86_64-win32/libcrt.a "$(tccdir)/win32/lib/64" + $(INSTALL) -m644 lib/i386-win32/libtcc1.a "$(tccdir)/win32/lib/32" + $(INSTALL) -m644 lib/x86_64-win32/libtcc1.a "$(tccdir)/win32/lib/64" cp -r $(top_srcdir)/win32/include/. "$(tccdir)/win32/include" cp -r "$(tccdir)/include" "$(tccdir)/win32" endif uninstall: rm -fv $(foreach P,$(PROGS),"$(bindir)/$P") - rm -fv $(foreach P,$(LIBCRT),"$(tccdir)/$P") + rm -fv $(foreach P,$(LIBTCC1),"$(tccdir)/$P") rm -fv $(foreach P,$(TCC_INCLUDES),"$(tccdir)/include/$P") rm -fv "$(tccdir)/include/tcclib.h" rm -fv "$(docdir)/tcc-doc.html" "$(mandir)/man1/tcc.1" "$(infodir)/tcc-doc.info" @@ -310,7 +310,7 @@ install: $(PROGS) $(TCCLIBS) $(TCCDOCS) mkdir -p "$(tccdir)/doc" mkdir -p "$(tccdir)/libtcc" $(INSTALLBIN) -m755 $(PROGS) "$(tccdir)" - $(INSTALL) -m644 $(LIBCRT) $(top_srcdir)/win32/lib/*.def "$(tccdir)/lib" + $(INSTALL) -m644 $(LIBTCC1) $(top_srcdir)/win32/lib/*.def "$(tccdir)/lib" cp -r $(top_srcdir)/win32/include/. "$(tccdir)/include" cp -r $(top_srcdir)/win32/examples/. "$(tccdir)/examples" $(INSTALL) -m644 $(addprefix $(top_srcdir)/include/,$(TCC_INCLUDES)) $(top_srcdir)/tcclib.h "$(tccdir)/include" @@ -320,8 +320,8 @@ install: $(PROGS) $(TCCLIBS) $(TCCDOCS) ifdef CONFIG_CROSS mkdir -p "$(tccdir)/lib/32" mkdir -p "$(tccdir)/lib/64" - -$(INSTALL) -m644 lib/i386-win32/libcrt.a "$(tccdir)/lib/32" - -$(INSTALL) -m644 lib/x86_64-win32/libcrt.a "$(tccdir)/lib/64" + -$(INSTALL) -m644 lib/i386-win32/libtcc1.a "$(tccdir)/lib/32" + -$(INSTALL) -m644 lib/x86_64-win32/libtcc1.a "$(tccdir)/lib/64" endif uninstall: @@ -340,7 +340,7 @@ tcc-doc.info: tcc-doc.texi -makeinfo $< # in tests subdir -export LIBCRT +export LIBTCC1 %est: $(MAKE) -C tests $@ 'PROGS_CROSS=$(PROGS_CROSS)' @@ -348,7 +348,7 @@ export LIBCRT clean: rm -vf $(PROGS) tcc_p$(EXESUF) tcc.pod *~ *.o *.a *.so* *.out *.exe libtcc_test$(EXESUF) $(MAKE) -C tests $@ -ifneq ($(LIBCRT),) +ifneq ($(LIBTCC1),) $(MAKE) -C lib $@ endif diff --git a/arm-gen.c b/arm-gen.c index 567c868..680a490 100644 --- a/arm-gen.c +++ b/arm-gen.c @@ -61,7 +61,7 @@ #define RC_IRET RC_R0 /* function return: integer register */ #define RC_LRET RC_R1 /* function return: second integer register */ #define RC_FRET RC_F0 /* function return: float register */ -#define RC_MASK (RC_INT|RC_FLOAT) + /* pretty names for the registers */ enum { TREG_R0 = 0, @@ -540,14 +540,6 @@ void load(int r, SValue *sv) v = fr & VT_VALMASK; if (fr & VT_LVAL) { uint32_t base = 0xB; // fp - if(fr & VT_TMP){ - int size, align; - if((ft & VT_BTYPE) == VT_FUNC) - size = PTR_SIZE; - else - size = type_size(&sv->type, &align); - loc_stack(size, 0); - } if(v == VT_LLOCAL) { v1.type.t = VT_PTR; v1.r = VT_LOCAL | VT_LVAL; @@ -1417,60 +1409,37 @@ void gjmp_addr(int a) /* generate a test. set 'inv' to invert test. Stack entry is popped */ int gtst(int inv, int t) { - int v, r; - uint32_t op; - v = vtop->r & VT_VALMASK; - r=ind; - if (v == VT_CMP) { - op=mapcc(inv?negcc(vtop->c.i):vtop->c.i); - op|=encbranch(r,t,1); - o(op); - t=r; - } else if (v == VT_JMP || v == VT_JMPI) { - if ((v & 1) == inv) { - if(!vtop->c.i) - vtop->c.i=t; - else { - uint32_t *x; - int p,lp; - if(t) { - p = vtop->c.i; - do { - p = decbranch(lp=p); - } while(p); - x = (uint32_t *)(cur_text_section->data + lp); - *x &= 0xff000000; - *x |= encbranch(lp,t,1); - } - t = vtop->c.i; - } - } else { - t = gjmp(t); - gsym(vtop->c.i); + int v, r; + uint32_t op; + v = vtop->r & VT_VALMASK; + r=ind; + if (v == VT_CMP) { + op=mapcc(inv?negcc(vtop->c.i):vtop->c.i); + op|=encbranch(r,t,1); + o(op); + t=r; + } else { /* VT_JMP || VT_JMPI */ + if ((v & 1) == inv) { + if(!vtop->c.i) + vtop->c.i=t; + else { + uint32_t *x; + int p,lp; + if(t) { + p = vtop->c.i; + do { + p = decbranch(lp=p); + } while(p); + x = (uint32_t *)(cur_text_section->data + lp); + *x &= 0xff000000; + *x |= encbranch(lp,t,1); + } + t = vtop->c.i; + } + } else { + t = gjmp(t); + gsym(vtop->c.i); } - } else { - if (is_float(vtop->type.t)) { - r=gv(RC_FLOAT); -#ifdef TCC_ARM_VFP - o(0xEEB50A40|(vfpr(r)<<12)|T2CPR(vtop->type.t)); /* fcmpzX */ - o(0xEEF1FA10); /* fmstat */ -#else - o(0xEE90F118|(fpr(r)<<16)); -#endif - vtop->r = VT_CMP; - vtop->c.i = TOK_NE; - return gtst(inv, t); - } else if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { - /* constant jmp optimization */ - if ((vtop->c.i != 0) != inv) - t = gjmp(t); - } else { - v = gv(RC_INT); - o(0xE3300000|(intr(v)<<16)); - vtop->r = VT_CMP; - vtop->c.i = TOK_NE; - return gtst(inv, t); - } } vtop--; return t; diff --git a/c67-gen.c b/c67-gen.c index 07ae259..a26dfaa 100644 --- a/c67-gen.c +++ b/c67-gen.c @@ -58,7 +58,7 @@ #define RC_IRET RC_C67_A4 /* function return: integer register */ #define RC_LRET RC_C67_A5 /* function return: second integer register */ #define RC_FRET RC_C67_A4 /* function return: float register */ -#define RC_MASK (RC_INT|RC_FLOAT) + /* pretty names for the registers */ enum { TREG_EAX = 0, // really A2 @@ -1571,21 +1571,12 @@ void load(int r, SValue * sv) v = fr & VT_VALMASK; if (fr & VT_LVAL) { - if(fr & VT_TMP){ - int size, align; - if((ft & VT_BTYPE) == VT_FUNC) - size = PTR_SIZE; - else - size = type_size(&sv->type, &align); - loc_stack(size, 0); - } if (v == VT_LLOCAL) { v1.type.t = VT_INT; v1.r = VT_LOCAL | VT_LVAL; v1.c.ul = fc; load(r, &v1); fr = r; - fc = 0; } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { tcc_error("long double not supported"); } else if ((ft & VT_TYPE) == VT_BYTE) { @@ -2111,7 +2102,7 @@ int gtst(int inv, int t) C67_NOP(5); t = ind1; //return where we need to patch - } else if (v == VT_JMP || v == VT_JMPI) { + } else { /* VT_JMP || VT_JMPI */ /* && or || optimization */ if ((v & 1) == inv) { /* insert vtop->c jump list in t */ @@ -2137,37 +2128,6 @@ int gtst(int inv, int t) t = gjmp(t); gsym(vtop->c.i); } - } else { - if (is_float(vtop->type.t)) { - vpushi(0); - gen_op(TOK_NE); - } - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { - /* constant jmp optimization */ - if ((vtop->c.i != 0) != inv) - t = gjmp(t); - } else { - // I think we need to get the value on the stack - // into a register, test it, and generate a branch - // return the address of the branch, so it can be - // later patched - - v = gv(RC_INT); // get value into a reg - ind1 = ind; - C67_MVKL(C67_A0, t); //r=reg to load, constant - C67_MVKH(C67_A0, t); //r=reg to load, constant - - if (v != TREG_EAX && // check if not already in a conditional test reg - v != TREG_EDX && v != TREG_ST0 && v != C67_B2) { - C67_MV(v, C67_B2); - v = C67_B2; - } - - C67_IREG_B_REG(inv, v, C67_A0); // [!R] B.S2x A0 - C67_NOP(5); - t = ind1; //return where we need to patch - ind1 = ind; - } } vtop--; return t; diff --git a/asmx86.c b/i386-asm.c similarity index 98% rename from asmx86.c rename to i386-asm.c index 9010c03..a524658 100644 --- a/asmx86.c +++ b/i386-asm.c @@ -239,36 +239,6 @@ static const uint16_t op0_codes[] = { #endif }; -#ifdef PRINTF_ASM_CODE -void printf_asm_opcode(){ - const ASMInstr *pa; - int freq[4]; - int op_vals[500]; - int nb_op_vals, i, j; - nb_op_vals = 0; - memset(freq, 0, sizeof(freq)); - for(pa = asm_instrs; pa->sym != 0; pa++) { - freq[pa->nb_ops]++; - for(i=0;inb_ops;i++) { - for(j=0;jop_type[i] == op_vals[j]) - goto found; - } - op_vals[nb_op_vals++] = pa->op_type[i]; - found: ; - } - } - for(i=0;i> 8); g(b); return; - } else if (opcode <= TOK_ASM_alllast) { - tcc_error("bad operand with opcode '%s'", get_tok_str(opcode, NULL)); + } else if (opcode <= TOK_ASM_alllast) { + tcc_error("bad operand with opcode '%s'", + get_tok_str(opcode, NULL)); } else { tcc_error("unknown opcode '%s'", get_tok_str(opcode, NULL)); @@ -1098,7 +1069,7 @@ ST_FUNC void asm_compute_constraints(ASMOperand *operands, uint8_t regs_allocated[NB_ASM_REGS]; /* init fields */ - for(i=0; iinput_index = -1; op->ref_index = -1; @@ -1108,7 +1079,7 @@ ST_FUNC void asm_compute_constraints(ASMOperand *operands, } /* compute constraint priority and evaluate references to output constraints if input constraints */ - for(i=0; iconstraint; str = skip_constraint_modifiers(str); @@ -1528,4 +1499,4 @@ ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str) tcc_error("invalid clobber register '%s'", str); } clobber_regs[reg] = 1; -} \ No newline at end of file +} diff --git a/i386-gen.c b/i386-gen.c index cfa9cc6..ece054b 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -21,7 +21,7 @@ #ifdef TARGET_DEFS_ONLY /* number of available registers */ -#define NB_REGS 8 +#define NB_REGS 4 #define NB_ASM_REGS 8 /* a register can belong to several classes. The classes must be @@ -33,24 +33,17 @@ #define RC_ST0 0x0008 #define RC_ECX 0x0010 #define RC_EDX 0x0020 -#define RC_EBX 0x0040 -#define RC_ESI 0x0080 -#define RC_EDI 0x0100 -#define RC_INT2 0x0200 #define RC_IRET RC_EAX /* function return: integer register */ #define RC_LRET RC_EDX /* function return: second integer register */ #define RC_FRET RC_ST0 /* function return: float register */ -#define RC_MASK (RC_INT|RC_INT2|RC_FLOAT) + /* pretty names for the registers */ enum { TREG_EAX = 0, TREG_ECX, TREG_EDX, - TREG_EBX, - TREG_ESP, TREG_ST0, - TREG_ESI, - TREG_EDI, + TREG_ESP = 4 }; /* return registers for function */ @@ -97,14 +90,10 @@ enum { #include "tcc.h" ST_DATA const int reg_classes[NB_REGS] = { - /* eax */ RC_INT | RC_EAX | RC_INT2, - /* ecx */ RC_INT | RC_ECX | RC_INT2, + /* eax */ RC_INT | RC_EAX, + /* ecx */ RC_INT | RC_ECX, /* edx */ RC_INT | RC_EDX, - RC_INT|RC_INT2|RC_EBX, - 0, /* st0 */ RC_FLOAT | RC_ST0, - RC_ESI|RC_INT2, - RC_EDI|RC_INT2, }; static unsigned long func_sub_sp_offset; @@ -237,14 +226,6 @@ ST_FUNC void load(int r, SValue *sv) v = fr & VT_VALMASK; if (fr & VT_LVAL) { - if(fr & VT_TMP){ - int size, align; - if((ft & VT_BTYPE) == VT_FUNC) - size = PTR_SIZE; - else - size = type_size(&sv->type, &align); - loc_stack(size, 0); - } if (v == VT_LLOCAL) { v1.type.t = VT_INT; v1.r = VT_LOCAL | VT_LVAL; @@ -253,7 +234,6 @@ ST_FUNC void load(int r, SValue *sv) if (!(reg_classes[fr] & RC_INT)) fr = get_reg(RC_INT); load(fr, &v1); - fc = 0; } if ((ft & VT_BTYPE) == VT_FLOAT) { o(0xd9); /* flds */ @@ -697,7 +677,7 @@ ST_FUNC int gtst(int inv, int t) /* fast case : can jump directly since flags are set */ g(0x0f); t = psym((vtop->c.i - 16) ^ inv, t); - } else if (v == VT_JMP || v == VT_JMPI) { + } else { /* VT_JMP || VT_JMPI */ /* && or || optimization */ if ((v & 1) == inv) { /* insert vtop->c jump list in t */ @@ -710,23 +690,6 @@ ST_FUNC int gtst(int inv, int t) t = gjmp(t); gsym(vtop->c.i); } - } else { - if (is_float(vtop->type.t) || - (vtop->type.t & VT_BTYPE) == VT_LLONG) { - vpushi(0); - gen_op(TOK_NE); - } - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { - /* constant jmp optimization */ - if ((vtop->c.i != 0) != inv) - t = gjmp(t); - } else { - v = gv(RC_INT); - o(0x85); - o(0xc0 + v * 9); - g(0x0f); - t = psym(0x85 ^ inv, t); - } } vtop--; return t; @@ -735,48 +698,40 @@ ST_FUNC int gtst(int inv, int t) /* generate an integer binary operation */ ST_FUNC void gen_opi(int op) { - int r, fr, opc, fc, c; - int cc, uu, tt2; - - fr = vtop[0].r; - fc = vtop->c.ul; - cc = (fr & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; - tt2 = (fr & (VT_LVAL | VT_LVAL_TYPE)) == VT_LVAL; + int r, fr, opc, c; switch(op) { case '+': case TOK_ADDC1: /* add with carry generation */ opc = 0; gen_op8: - vswap(); - r = gv(RC_INT); - vswap(); - if (cc) { + if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { /* constant case */ + vswap(); + r = gv(RC_INT); + vswap(); c = vtop->c.i; if (c == (char)c) { /* generate inc and dec for smaller code */ - if (c == 1 && opc == 0) { + if (c==1 && opc==0) { o (0x40 | r); // inc - } else if (c == 1 && opc == 5) { + } else if (c==1 && opc==5) { o (0x48 | r); // dec } else { o(0x83); - o(0xc0 + r + opc*8); + o(0xc0 | (opc << 3) | r); g(c); } } else { o(0x81); - oad(0xc0 + r+ opc*8, c); + oad(0xc0 | (opc << 3) | r, c); } } else { - if(!tt2) - fr = gv(RC_INT); - o(0x03 + opc*8); - if(fr >= VT_CONST) - gen_modrm(r, fr, vtop->sym, fc); - else - o(0xc0 + fr + r*8); + gv2(RC_INT, RC_INT); + r = vtop[-1].r; + fr = vtop[0].r; + o((opc << 3) | 0x01); + o(0xc0 + r + fr * 8); } vtop--; if (op >= TOK_ULT && op <= TOK_GT) { @@ -804,28 +759,12 @@ ST_FUNC void gen_opi(int op) opc = 1; goto gen_op8; case '*': - opc = 5; - vswap(); - r = gv(RC_INT); - vswap(); - if(!tt2) - fr = gv(RC_INT); - if(r == TREG_EAX){ - if(fr != TREG_EDX) - save_reg(TREG_EDX); - o(0xf7); - if(fr >= VT_CONST) - gen_modrm(opc, fr, vtop->sym, fc); - else - o(0xc0 + fr + opc*8); - }else{ - o(0xaf0f); /* imul fr, r */ - if(fr >= VT_CONST) - gen_modrm(r, fr, vtop->sym, fc); - else - o(0xc0 + fr + r*8); - } + gv2(RC_INT, RC_INT); + r = vtop[-1].r; + fr = vtop[0].r; vtop--; + o(0xaf0f); /* imul fr, r */ + o(0xc0 + fr + r * 8); break; case TOK_SHL: opc = 4; @@ -836,71 +775,56 @@ ST_FUNC void gen_opi(int op) case TOK_SAR: opc = 7; gen_shift: - if (cc) { + opc = 0xc0 | (opc << 3); + if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { /* constant case */ vswap(); r = gv(RC_INT); vswap(); - c = vtop->c.i; - if(c == 1){ - o(0xd1); - o(0xc0 + r + opc*8); - }else{ - o(0xc1); /* shl/shr/sar $xxx, r */ - o(0xc0 + r + opc*8); - g(c & 0x1f); - } + c = vtop->c.i & 0x1f; + o(0xc1); /* shl/shr/sar $xxx, r */ + o(opc | r); + g(c); } else { /* we generate the shift in ecx */ gv2(RC_INT, RC_ECX); r = vtop[-1].r; o(0xd3); /* shl/shr/sar %cl, r */ - o(0xc0 + r + opc*8); + o(opc | r); } vtop--; break; - case TOK_UMOD: - opc = 4; - uu = 1; - goto divmod; - case TOK_UDIV: - case TOK_UMULL: - opc = 6; - uu = 1; - goto divmod; case '/': - case '%': + case TOK_UDIV: case TOK_PDIV: - opc = 7; - uu = 0; - divmod: + case '%': + case TOK_UMOD: + case TOK_UMULL: /* first operand must be in eax */ /* XXX: need better constraint for second operand */ - if(!tt2){ - gv2(RC_EAX, RC_INT2); - fr = vtop[0].r; - }else{ - vswap(); - gv(RC_EAX); - vswap(); - } - save_reg(TREG_EDX); - if (op == TOK_UMULL) { + gv2(RC_EAX, RC_ECX); + r = vtop[-1].r; + fr = vtop[0].r; + vtop--; + save_reg(TREG_EDX); + if (op == TOK_UMULL) { o(0xf7); /* mul fr */ - vtop->r2 = TREG_EDX; - }else{ - o(uu ? 0xd231 : 0x99); /* xor %edx,%edx : cdq RDX:RAX <- sign-extend of RAX. */ - o(0xf7); /* div fr, %eax */ - } - if(fr >= VT_CONST) - gen_modrm(opc, fr, vtop->sym, fc); - else - o(0xc0 + fr + opc*8); - if (op == '%' || op == TOK_UMOD) - r = TREG_EDX; - else + o(0xe0 + fr); + vtop->r2 = TREG_EDX; r = TREG_EAX; - vtop--; + } else { + if (op == TOK_UDIV || op == TOK_UMOD) { + o(0xf7d231); /* xor %edx, %edx, div fr, %eax */ + o(0xf0 + fr); + } else { + o(0xf799); /* cltd, idiv fr, %eax */ + o(0xf8 + fr); + } + if (op == '%' || op == TOK_UMOD) + r = TREG_EDX; + else + r = TREG_EAX; + } vtop->r = r; break; default: diff --git a/asmx86-tok.h b/i386-tok.h similarity index 100% rename from asmx86-tok.h rename to i386-tok.h diff --git a/il-gen.c b/il-gen.c index 9dafbbf..9e1ec64 100644 --- a/il-gen.c +++ b/il-gen.c @@ -516,7 +516,7 @@ int gtst(int inv, int t) break; } t = out_opj(c, t); - } else if (v == VT_JMP || v == VT_JMPI) { + } else { /* VT_JMP || VT_JMPI */ /* && or || optimization */ if ((v & 1) == inv) { /* insert vtop->c jump list in t */ @@ -529,19 +529,6 @@ int gtst(int inv, int t) t = gjmp(t); gsym(vtop->c.i); } - } else { - if (is_float(vtop->t)) { - vpushi(0); - gen_op(TOK_NE); - } - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_FORWARD)) == VT_CONST) { - /* constant jmp optimization */ - if ((vtop->c.i != 0) != inv) - t = gjmp(t); - } else { - v = gv(RC_INT); - t = out_opj(IL_OP_BRTRUE - inv, t); - } } vtop--; return t; diff --git a/lib/Makefile b/lib/Makefile index 4bf2c7e..e9e12f1 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,5 +1,5 @@ # -# Tiny C Compiler Makefile for libcrt.a +# Tiny C Compiler Makefile for libtcc1.a # TOP = .. @@ -38,15 +38,15 @@ endif DIR = $(TARGET) -native : ../libcrt.a -cross : $(DIR)/libcrt.a +native : ../libtcc1.a +cross : $(DIR)/libtcc1.a native : TCC = $(TOP)/tcc$(EXESUF) cross : TCC = $(TOP)/$(TARGET)-tcc$(EXESUF) -I386_O = libcrt.o alloca86.o alloca86-bt.o $(BCHECK_O) -X86_64_O = libcrt.o alloca86_64.o -ARM_O = libcrt.o armeabi.o alloca-arm.o +I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BCHECK_O) +X86_64_O = libtcc1.o alloca86_64.o +ARM_O = libtcc1.o armeabi.o alloca-arm.o WIN32_O = $(I386_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o WIN64_O = $(X86_64_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o @@ -83,7 +83,7 @@ ifeq "$(TARGET)" "arm" TGT = -DTCC_TARGET_ARM XCC ?= $(TCC) -B$(TOP) else - $(error libcrt.a not supported on target '$(TARGET)') + $(error libtcc1.a not supported on target '$(TARGET)') endif endif endif @@ -102,7 +102,7 @@ ifdef XAR AR = $(XAR) endif -$(DIR)/libcrt.a ../libcrt.a : $(OBJ) $(XAR) +$(DIR)/libtcc1.a ../libtcc1.a : $(OBJ) $(XAR) $(AR) rcs $@ $(OBJ) $(DIR)/%.o : %.c $(XCC) -c $< -o $@ $(XFLAGS) diff --git a/lib/libcrt.c b/lib/libtcc1.c similarity index 96% rename from lib/libcrt.c rename to lib/libtcc1.c index 642927a..284965e 100644 --- a/lib/libcrt.c +++ b/lib/libtcc1.c @@ -533,24 +533,23 @@ unsigned long long __fixunssfdi (float a1) register union float_long fl1; register int exp; register unsigned long l; - int s; + fl1.f = a1; if (fl1.l == 0) - return 0; + return (0); exp = EXP (fl1.l) - EXCESS - 24; l = MANT(fl1.l); - s = SIGN(fl1.l)? -1: 1; - if (exp >= 64) + if (exp >= 41) return (unsigned long long)-1; else if (exp >= 0) - return ((unsigned long long)l << exp)*s; + return (unsigned long long)l << exp; else if (exp >= -23) - return (l >> -exp)*s; + return l >> -exp; else - return 0; + return 0; } unsigned long long __fixunsdfdi (double a1) @@ -558,7 +557,7 @@ unsigned long long __fixunsdfdi (double a1) register union double_long dl1; register int exp; register unsigned long long l; - int s; + dl1.d = a1; if (dl1.ll == 0) @@ -567,15 +566,15 @@ unsigned long long __fixunsdfdi (double a1) exp = EXPD (dl1) - EXCESSD - 53; l = MANTD_LL(dl1); - s = SIGND(dl1)? -1: 1; - if (exp >= 64) + + if (exp >= 12) return (unsigned long long)-1; else if (exp >= 0) - return (l << exp)*s; + return l << exp; else if (exp >= -52) - return (l >> -exp)*s; + return l >> -exp; else - return 0; + return 0; } unsigned long long __fixunsxfdi (long double a1) @@ -583,24 +582,22 @@ unsigned long long __fixunsxfdi (long double a1) register union ldouble_long dl1; register int exp; register unsigned long long l; - int s; + dl1.ld = a1; if (dl1.l.lower == 0 && dl1.l.upper == 0) return (0); exp = EXPLD (dl1) - EXCESSLD - 64; - s = SIGNLD(dl1)? -1: 1; + l = dl1.l.lower; - if (exp >= 64) + if (exp > 0) return (unsigned long long)-1; - else if (exp >= 0) - return ((unsigned long long)l << exp)*s; - else if (exp >= -64) - return (l >> -exp)*s; + else if (exp >= -63) + return l >> -exp; else - return 0; + return 0; } long long __fixsfdi (float a1) @@ -640,7 +637,7 @@ extern void abort(void); #endif enum __va_arg_type { - __va_gen_reg, __va_float_reg, __va_ld_reg, __va_stack + __va_gen_reg, __va_float_reg, __va_stack }; //This should be in sync with the declaration on our include/stdarg.h @@ -691,11 +688,10 @@ void *__va_arg(__va_list_struct *ap, size = 8; goto use_overflow_area; - case __va_ld_reg: - ap->overflow_arg_area = (char*)((intptr_t)(ap->overflow_arg_area + align - 1) & -(intptr_t)align); case __va_stack: use_overflow_area: ap->overflow_arg_area += size; + ap->overflow_arg_area = (char*)((intptr_t)(ap->overflow_arg_area + align - 1) & -(intptr_t)align); return ap->overflow_arg_area - size; default: diff --git a/libtcc.c b/libtcc.c index 28b6407..deda7e6 100644 --- a/libtcc.c +++ b/libtcc.c @@ -52,10 +52,10 @@ ST_DATA struct TCCState *tcc_state; #include "x86_64-gen.c" #endif #ifdef CONFIG_TCC_ASM -#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 -#include "asmx86.c" -#endif #include "tccasm.c" +#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 +#include "i386-asm.c" +#endif #endif #ifdef TCC_TARGET_COFF #include "tcccoff.c" @@ -868,7 +868,6 @@ LIBTCCAPI void tcc_undefine_symbol(TCCState *s1, const char *sym) static void tcc_cleanup(void) { int i, n; - CSym *def; if (NULL == tcc_state) return; tcc_state = NULL; @@ -878,11 +877,8 @@ static void tcc_cleanup(void) /* free tokens */ n = tok_ident - TOK_IDENT; - for(i = 0; i < n; i++){ - def = &table_ident[i]->sym_define; - tcc_free(def->data); + for(i = 0; i < n; i++) tcc_free(table_ident[i]); - } tcc_free(table_ident); /* free sym_pools */ diff --git a/tcc.h b/tcc.h index 1cead42..c93cedf 100644 --- a/tcc.h +++ b/tcc.h @@ -39,7 +39,6 @@ #include #include #include -#include #ifdef CONFIG_TCCASSERT #include @@ -148,7 +147,6 @@ /* #define MEM_DEBUG */ /* assembler debug */ /* #define ASM_DEBUG */ -/* #define PRINTF_ASM_CODE */ /* target selection */ /* #define TCC_TARGET_I386 *//* i386 code generator */ @@ -276,7 +274,7 @@ # define DEFAULT_ELFINTERP(s) default_elfinterp(s) #endif -/* library to use with CONFIG_USE_LIBGCC instead of libcrt.a */ +/* library to use with CONFIG_USE_LIBGCC instead of libtcc1.a */ #define TCC_LIBGCC USE_MUADIR(CONFIG_SYSROOT "/" CONFIG_LDDIR) "/libgcc_s.so.1" /* -------------------------------------------- */ @@ -305,22 +303,15 @@ #define VSTACK_SIZE 256 #define STRING_MAX_SIZE 1024 #define PACK_STACK_SIZE 8 -#define MACRO_STACK_SIZE 4 #define TOK_HASH_SIZE 8192 /* must be a power of two */ #define TOK_ALLOC_INCR 512 /* must be a power of two */ #define TOK_MAX_SIZE 4 /* token max size in int unit when stored in string */ -typedef struct CSym { - int off; - int size;/* size in *sym */ - struct Sym **data; /* if non NULL, data has been malloced */ -} CSym; - /* token symbol management */ typedef struct TokenSym { struct TokenSym *hash_next; - struct CSym sym_define; /* direct pointer to define */ + struct Sym *sym_define; /* direct pointer to define */ struct Sym *sym_label; /* direct pointer to label */ struct Sym *sym_struct; /* direct pointer to structure */ struct Sym *sym_identifier; /* direct pointer to identifier */ @@ -366,8 +357,8 @@ typedef union CValue { /* value on stack */ typedef struct SValue { CType type; /* type */ - unsigned int r; /* register + flags */ - unsigned int r2; /* second register, used for 'long long' + unsigned short r; /* register + flags */ + unsigned short r2; /* second register, used for 'long long' type. If not used, set to VT_CONST */ CValue c; /* constant, if VT_CONST */ struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST) */ @@ -747,21 +738,19 @@ struct TCCState { #define VT_CMP 0x0033 /* the value is stored in processor flags (in vc) */ #define VT_JMP 0x0034 /* value is the consequence of jmp true (even) */ #define VT_JMPI 0x0035 /* value is the consequence of jmp false (odd) */ -#define TREG_MEM 0x0040 /* x86_64-gen.c add for tcc.h: The current value can be */ -#define VT_REF 0x0080 /* value is pointer to structure rather than address */ +#define VT_REF 0x0040 /* value is pointer to structure rather than address */ #define VT_LVAL 0x0100 /* var is an lvalue */ #define VT_SYM 0x0200 /* a symbol value is added */ #define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for char/short stored in integer registers) */ #define VT_MUSTBOUND 0x0800 /* bound checking must be done before dereferencing value */ +#define VT_BOUNDED 0x8000 /* value is bounded. The address of the + bounding function call point is in vc */ #define VT_LVAL_BYTE 0x1000 /* lvalue is a byte */ #define VT_LVAL_SHORT 0x2000 /* lvalue is a short */ #define VT_LVAL_UNSIGNED 0x4000 /* lvalue is unsigned */ #define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED) -#define VT_BOUNDED 0x8000 /* value is bounded. The address of the - bounding function call point is in vc */ -#define VT_TMP 0x10000 /* luck or tmp stack */ /* types */ #define VT_BTYPE 0x000f /* mask for basic type */ @@ -789,7 +778,6 @@ struct TCCState { #define VT_VOLATILE 0x1000 /* volatile modifier */ #define VT_DEFSIGN 0x2000 /* signed type */ #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 */ #define VT_EXTERN 0x00000080 /* extern definition */ @@ -800,14 +788,14 @@ struct TCCState { #define VT_EXPORT 0x00008000 /* win32: data exported from dll */ #define VT_WEAK 0x00010000 /* weak symbol */ #define VT_TLS 0x00040000 /* thread-local storage */ -#define VT_VIS_SHIFT 20 /* shift for symbol visibility, overlapping +#define VT_VIS_SHIFT 19 /* shift for symbol visibility, overlapping bitfield values, because bitfields never have linkage and hence never have visibility. */ #define VT_VIS_SIZE 2 /* We have four visibilities. */ #define VT_VIS_MASK (((1 << VT_VIS_SIZE)-1) << VT_VIS_SHIFT) -#define VT_STRUCT_SHIFT 20 /* shift for bitfield shift values (max: 32 - 2*6) */ +#define VT_STRUCT_SHIFT 19 /* shift for bitfield shift values (max: 32 - 2*6) */ /* type mask (except storage) */ @@ -1136,8 +1124,7 @@ ST_DATA TokenSym **table_ident; token. line feed is also returned at eof */ #define PARSE_FLAG_ASM_COMMENTS 0x0008 /* '#' can be used for line comment */ -#define PARSE_FLAG_SPACES 0x0010 /* next() returns space tokens (for -E) */ -#define PARSE_FLAG_PACK 0x0020 /* #pragma pack */ +#define PARSE_FLAG_SPACES 0x0010 /* next() returns space tokens (for -E) */ ST_FUNC TokenSym *tok_alloc(const char *str, int len); ST_FUNC char *get_tok_str(int v, CValue *cv); @@ -1195,7 +1182,7 @@ ST_DATA Sym *define_stack; 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; #define vstack (__vstack + 1) -ST_DATA int rsym, anon_sym, ind, loc, ex_rc; +ST_DATA int rsym, anon_sym, ind, loc; ST_DATA int const_wanted; /* true if constant wanted */ ST_DATA int nocode_wanted; /* true if no code generation wanted for an expression */ @@ -1205,14 +1192,12 @@ ST_DATA int func_var; /* true if current function is variadic */ ST_DATA int func_vc; ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */ ST_DATA char *funcname; -ST_DATA int pop_stack; ST_INLN int is_float(int t); ST_FUNC int ieee_finite(double d); ST_FUNC void test_lvalue(void); ST_FUNC void swap(int *p, int *q); ST_FUNC void vpushi(int v); -ST_FUNC void vpushs(addr_t v); ST_FUNC Sym *external_global_sym(int v, CType *type, int r); ST_FUNC void vset(CType *type, int r, int v); ST_FUNC void vswap(void); @@ -1246,9 +1231,6 @@ ST_FUNC void gexpr(void); ST_FUNC int expr_const(void); ST_FUNC void gen_inline_functions(void); ST_FUNC void decl(int l); -ST_FUNC void vdup(void); -ST_FUNC void gaddrof(void); -ST_FUNC int loc_stack(int size, int is_sub); #if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_C67 ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size); #endif diff --git a/tccasm.c b/tccasm.c index eec4208..38efe1c 100644 --- a/tccasm.c +++ b/tccasm.c @@ -20,6 +20,7 @@ #include "tcc.h" #ifdef CONFIG_TCC_ASM + ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n) { char buf[64]; @@ -482,7 +483,7 @@ static void asm_parse_directive(TCCState *s1) case TOK_ASM_globl: case TOK_ASM_global: case TOK_ASM_weak: - case TOK_ASM_hidden: + case TOK_ASM_hidden: tok1 = tok; do { Sym *sym; @@ -493,12 +494,12 @@ static void asm_parse_directive(TCCState *s1) sym = label_push(&s1->asm_labels, tok, 0); sym->type.t = VT_VOID; } - if (tok1 != TOK_ASM_hidden) + if (tok1 != TOK_ASM_hidden) sym->type.t &= ~VT_STATIC; if (tok1 == TOK_ASM_weak) sym->type.t |= VT_WEAK; - else if (tok1 == TOK_ASM_hidden) - sym->type.t |= STV_HIDDEN << VT_VIS_SHIFT; + else if (tok1 == TOK_ASM_hidden) + sym->type.t |= STV_HIDDEN << VT_VIS_SHIFT; next(); } while (tok == ','); break; @@ -696,15 +697,42 @@ static void asm_parse_directive(TCCState *s1) } } + /* assemble a file */ static int tcc_assemble_internal(TCCState *s1, int do_preprocess) { int opcode; -#ifdef PRINTF_ASM_CODE - ST_FUNC void printf_asm_opcode(); +#if 0 /* print stats about opcodes */ - printf_asm_opcode(); + { + const ASMInstr *pa; + int freq[4]; + int op_vals[500]; + int nb_op_vals, i, j; + + nb_op_vals = 0; + memset(freq, 0, sizeof(freq)); + for(pa = asm_instrs; pa->sym != 0; pa++) { + freq[pa->nb_ops]++; + for(i=0;inb_ops;i++) { + for(j=0;jop_type[i] == op_vals[j]) + goto found; + } + op_vals[nb_op_vals++] = pa->op_type[i]; + found: ; + } + } + for(i=0;ifilename); + put_elf_sym(symtab_section, 0, 0, + ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0, + SHN_ABS, file->filename); ret = tcc_assemble_internal(s1, do_preprocess); @@ -1090,4 +1119,4 @@ ST_FUNC void asm_global_instr(void) cstr_free(&astr); } -#endif /* CONFIG_TCC_ASM */ \ No newline at end of file +#endif /* CONFIG_TCC_ASM */ diff --git a/tccelf.c b/tccelf.c index 9faf27f..f0ed22b 100644 --- a/tccelf.c +++ b/tccelf.c @@ -1443,16 +1443,16 @@ ST_FUNC void tcc_add_runtime(TCCState *s1) #ifdef CONFIG_USE_LIBGCC if (!s1->static_link) { tcc_add_file(s1, TCC_LIBGCC); - tcc_add_support(s1, "libcrt.a"); + tcc_add_support(s1, "libtcc1.a"); } else - tcc_add_support(s1, "libcrt.a"); + tcc_add_support(s1, "libtcc1.a"); #else - tcc_add_support(s1, "libcrt.a"); + tcc_add_support(s1, "libtcc1.a"); #endif } /* tcc_add_bcheck tries to relocate a call to __bound_init in _init so - libcrt.a must be loaded before for __bound_init to be defined and + libtcc1.a must be loaded before for __bound_init to be defined and crtn.o must be loaded after to not finalize _init too early. */ tcc_add_bcheck(s1); @@ -1596,7 +1596,7 @@ ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel) put32(s1->got->data + offset, sym->st_value & 0xffffffff); } -/* Perform relocation to GOT or PLT entries */ +/* Perform relocation to GOT or PLT entries */ ST_FUNC void fill_got(TCCState *s1) { Section *s; @@ -2469,7 +2469,7 @@ static int elf_output_file(TCCState *s1, const char *filename) goto the_end; } - /* Perform relocation to GOT or PLT entries */ + /* Perform relocation to GOT or PLT entries */ if (file_type == TCC_OUTPUT_EXE && s1->static_link) fill_got(s1); diff --git a/tccgen.c b/tccgen.c index c2481b0..1a89d4a 100644 --- a/tccgen.c +++ b/tccgen.c @@ -28,7 +28,7 @@ rsym: return symbol anon_sym: anonymous symbol index */ -ST_DATA int rsym, anon_sym, ind, loc, ex_rc; +ST_DATA int rsym, anon_sym, ind, loc; ST_DATA Section *text_section, *data_section, *bss_section; /* predefined sections */ ST_DATA Section *cur_text_section; /* current section where function code is generated */ @@ -70,7 +70,6 @@ ST_DATA int func_var; /* true if current function is variadic (used by return in ST_DATA int func_vc; ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */ ST_DATA char *funcname; -ST_DATA int pop_stack; ST_DATA CType char_pointer_type, func_old_type, int_type, size_type; @@ -93,7 +92,7 @@ static int is_compatible_parameter_types(CType *type1, CType *type2); static void expr_type(CType *type); ST_FUNC void vpush64(int ty, unsigned long long v); ST_FUNC void vpush(CType *type); -ST_FUNC int gtst(int inv, int t); +ST_FUNC int gvtst(int inv, int t); ST_FUNC int is_btype_size(int bt); ST_INLN int is_float(int t) @@ -370,7 +369,7 @@ ST_FUNC void vpushi(int v) } /* push a pointer sized constant */ -ST_FUNC void vpushs(addr_t v) +static void vpushs(addr_t v) { CValue cval; cval.ptr_offset = v; @@ -520,46 +519,11 @@ ST_FUNC void vpushv(SValue *v) *vtop = *v; } -ST_FUNC void vdup(void) +static void vdup(void) { 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 */ ST_FUNC void save_reg(int r) { @@ -568,76 +532,57 @@ ST_FUNC void save_reg(int r) CType *type; /* modify all stack values */ - l = saved = 0; - for(p = vstack; p <= vtop; p++) { -#ifdef TCC_TARGET_X86_64 - if ((p->r & VT_VALMASK) == r || - ((((p->type.t & VT_BTYPE) == VT_QLONG) || ((p->type.t & VT_BTYPE) == VT_QFLOAT)) && - ((p->r2 & VT_VALMASK) == r))) -#else - if ((p->r & VT_VALMASK) == r || ((p->type.t & VT_BTYPE) == VT_LLONG && (p->r2 & VT_VALMASK) == r)) -#endif - { + saved = 0; + l = 0; + for(p=vstack;p<=vtop;p++) { + if ((p->r & VT_VALMASK) == r || + ((p->type.t & VT_BTYPE) == VT_LLONG && (p->r2 & VT_VALMASK) == r)) { /* must save value on stack if not already done */ if (!saved) { /* NOTE: must reload 'r' because r might be equal to r2 */ r = p->r & VT_VALMASK; /* store register in the stack */ type = &p->type; - if((type->t & VT_BTYPE) == VT_STRUCT){ - int ret_align; - SValue ret; - gfunc_sret(type, func_var, &ret.type, &ret_align); - type = &ret.type; - } - if ((p->r & VT_LVAL) || ((type->t & VT_BTYPE) == VT_FUNC)) + if ((p->r & VT_LVAL) || + (!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG)) #ifdef TCC_TARGET_X86_64 type = &char_pointer_type; #else type = &int_type; #endif - size = type_size(type, &align); - l = loc_stack(size, 1); + size = type_size(type, &align); + loc = (loc - size) & -align; + sv.type.t = type->t; sv.r = VT_LOCAL | VT_LVAL; - sv.c.ul = l; -#ifdef TCC_TARGET_X86_64 - if (((type->t & VT_BTYPE) == VT_QLONG) || ((type->t & VT_BTYPE) == VT_QFLOAT)) -#else - if ((type->t & VT_BTYPE) == VT_LLONG) -#endif - { -#ifdef TCC_TARGET_X86_64 - int load_size = 8, load_type = ((type->t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE; -#else - int load_size = 4, load_type = VT_INT; -#endif - sv.type.t = load_type; - store(r, &sv); - sv.c.ul += load_size; - store(p->r2, &sv); - }else{ - sv.type.t = type->t; - store(r, &sv); - } + sv.c.ul = loc; + store(r, &sv); #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) /* x86 specific: need to pop fp register ST0 if saved */ if (r == TREG_ST0) { o(0xd8dd); /* fstp %st(0) */ } #endif - saved = 1; +#ifndef TCC_TARGET_X86_64 + /* special long long case */ + if ((type->t & VT_BTYPE) == VT_LLONG) { + sv.c.ul += 4; + store(p->r2, &sv); + } +#endif + l = loc; + saved = 1; } - /* mark that stack entry as being saved on the stack */ - if (p->r & VT_LVAL) { - /* also clear the bounded flag because the - relocation address of the function was stored in - p->c.ul */ - p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL; - } else { - p->r = lvalue_type(p->type.t) | VT_LOCAL | VT_TMP; - } - p->r2 = VT_CONST; - p->c.ul = l; + /* mark that stack entry as being saved on the stack */ + if (p->r & VT_LVAL) { + /* also clear the bounded flag because the + relocation address of the function was stored in + p->c.ul */ + p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL; + } else { + p->r = lvalue_type(p->type.t) | VT_LOCAL; + } + p->r2 = VT_CONST; + p->c.ul = l; } } } @@ -667,57 +612,42 @@ ST_FUNC int get_reg_ex(int rc, int rc2) } #endif -static int for_reg(int rc) -{ - int r; - SValue *p; - if(rc){ - for(r = 0; r < NB_REGS; r++) { - if (reg_classes[r] & rc) { - for(p = vstack; p <= vtop; p++) { - if ((p->r & VT_VALMASK) == r || (p->r2 & VT_VALMASK) == r) - goto notfound; - } - goto found; - } - notfound:; - } - } - r = -1; -found: - return r; -} - /* find a free register of class 'rc'. If none, save one register */ -int get_reg(int rc) +ST_FUNC int get_reg(int rc) { - int r; + int r; SValue *p; /* find a free register */ - r = for_reg(rc); - if (r != -1) - return r; + for(r=0;rr & VT_VALMASK) == r || + (p->r2 & VT_VALMASK) == r) + goto notfound; + } + return r; + } + notfound: ; + } + /* no register left : free the first one on the stack (VERY IMPORTANT to start from the bottom to ensure that we don't spill registers used in gen_opi()) */ - for(p = vstack; p <= vtop; p++) { + for(p=vstack;p<=vtop;p++) { /* look at second register (if long long) */ - if(p->r & VT_TMP) - continue; r = p->r2 & VT_VALMASK; if (r < VT_CONST && (reg_classes[r] & rc)) goto save_found; r = p->r & VT_VALMASK; if (r < VT_CONST && (reg_classes[r] & rc)) { -save_found: - save_reg(r); + save_found: + save_reg(r); return r; } } /* Should never comes here */ - assert(0); - return -1; + return -1; } /* save registers up to (vtop - n) stack entry */ @@ -751,14 +681,16 @@ static void move_reg(int r, int s, int t) } /* get address of vtop (vtop MUST BE an lvalue) */ -ST_FUNC void gaddrof(void) +static void gaddrof(void) { if (vtop->r & VT_REF) gv(RC_INT); vtop->r &= ~VT_LVAL; /* tricky: if saved lvalue, then we can go back to lvalue */ if ((vtop->r & VT_VALMASK) == VT_LLOCAL) - vtop->r = (vtop->r & ~(VT_VALMASK | VT_LVAL_TYPE)) | VT_LOCAL | VT_LVAL| VT_TMP; + vtop->r = (vtop->r & ~(VT_VALMASK | VT_LVAL_TYPE)) | VT_LOCAL | VT_LVAL; + + } #ifdef CONFIG_TCC_BCHECK @@ -794,28 +726,25 @@ static void gbound(void) register value (such as structures). */ ST_FUNC int gv(int rc) { - int r, bit_pos, bit_size, size, align, i, ft, sbt; + int r, bit_pos, bit_size, size, align, i; int rc2; - ft = vtop->type.t; - sbt = ft & VT_BTYPE; /* NOTE: get_reg can modify vstack[] */ - if (ft & VT_BITFIELD) { + if (vtop->type.t & VT_BITFIELD) { CType type; - int bits; - bit_pos = (ft >> VT_STRUCT_SHIFT) & 0x3f; - bit_size = (ft >> (VT_STRUCT_SHIFT + 6)) & 0x3f; + int bits = 32; + bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f; + bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f; /* remove bit field info to avoid loops */ - ft = vtop->type.t &= ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); + vtop->type.t &= ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); /* cast to int to propagate signedness in following ops */ - if (sbt == VT_LLONG) { + if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { type.t = VT_LLONG; bits = 64; - } else{ + } else type.t = VT_INT; - bits = 32; - } - if((ft & VT_UNSIGNED) || sbt == VT_BOOL) + if((vtop->type.t & VT_UNSIGNED) || + (vtop->type.t & VT_BTYPE) == VT_BOOL) type.t |= VT_UNSIGNED; gen_cast(&type); /* generate shifts */ @@ -872,39 +801,41 @@ ST_FUNC int gv(int rc) gbound(); #endif - r = vtop->r & VT_VALMASK; - if(rc & ~RC_MASK) - rc2 = ex_rc; - else - rc2 = (rc & RC_FLOAT) ? RC_FLOAT : RC_INT; + r = vtop->r & VT_VALMASK; + rc2 = (rc & RC_FLOAT) ? RC_FLOAT : RC_INT; + if (rc == RC_IRET) + rc2 = RC_LRET; +#ifdef TCC_TARGET_X86_64 + else if (rc == RC_FRET) + rc2 = RC_QRET; +#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) + if (r >= VT_CONST + || (vtop->r & VT_LVAL) + || !(reg_classes[r] & rc) #ifdef TCC_TARGET_X86_64 - || (sbt == VT_QLONG && !(reg_classes[vtop->r2] & rc2)) - || (sbt == VT_QFLOAT && !(reg_classes[vtop->r2] & rc2)) + || ((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 - || (sbt == VT_LLONG && !(reg_classes[vtop->r2] & rc2)) + || ((vtop->type.t & VT_BTYPE) == VT_LLONG && !(reg_classes[vtop->r2] & rc2)) #endif - || vtop->c.i) + ) { r = get_reg(rc); #ifdef TCC_TARGET_X86_64 - if ((sbt == VT_QLONG) || (sbt == VT_QFLOAT)) + 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 (sbt == VT_LLONG) -#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; + 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; + int r2, original_type; + original_type = vtop->type.t; /* two register type load : expand to two words temporarily */ #ifndef TCC_TARGET_X86_64 @@ -917,19 +848,20 @@ ST_FUNC int gv(int rc) vpushi(ll >> 32); /* second word */ } else #endif - /* XXX: test to VT_CONST incorrect ? */ - if (r >= VT_CONST || (vtop->r & VT_LVAL)) { + if (r >= VT_CONST || /* XXX: test to VT_CONST incorrect ? */ + (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 regs. use VT_TMP XXX: totally inefficient. */ + in the stack. XXX: totally inefficient. */ + save_regs(1); /* load from memory */ vtop->type.t = load_type; load(r, vtop); vdup(); - vtop[-1].r = r | VT_TMP; /* lock register value */ + vtop[-1].r = r; /* save register value */ /* increment pointer to get second word */ - vtop->type = char_pointer_type; + vtop->type.t = addr_type; gaddrof(); vpushi(load_size); gen_op('+'); @@ -939,23 +871,23 @@ ST_FUNC int gv(int rc) /* move registers */ load(r, vtop); vdup(); - vtop[-1].r = r | VT_TMP; /* lock register value */ + vtop[-1].r = r; /* save register value */ vtop->r = vtop[-1].r2; } /* Allocate second register. Here we rely on the fact that get_reg() tries first to free r2 of an SValue. */ r2 = get_reg(rc2); load(r2, vtop); - vtop--; + vpop(); /* write second register */ vtop->r2 = r2; - vtop->r &= ~VT_TMP; - vtop->type.t = ft; - } else if ((vtop->r & VT_LVAL) && !is_float(ft)) { - int t; + vtop->type.t = original_type; + } else if ((vtop->r & VT_LVAL) && !is_float(vtop->type.t)) { + int t1, t; /* lvalue of scalar type : need to use lvalue type because of possible cast */ - t = ft; + t = vtop->type.t; + t1 = t; /* compute memory access type */ if (vtop->r & VT_REF) #ifdef TCC_TARGET_X86_64 @@ -972,14 +904,13 @@ ST_FUNC int gv(int rc) vtop->type.t = t; load(r, vtop); /* restore wanted type */ - vtop->type.t = ft; + vtop->type.t = t1; } else { /* one register type load */ load(r, vtop); } - vtop->r = r; - vtop->c.ptr_offset = 0; } + vtop->r = r; #ifdef TCC_TARGET_C67 /* uses register pairs for doubles */ if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) @@ -992,10 +923,13 @@ ST_FUNC int gv(int rc) /* generate vtop[-1] and vtop[0] in resp. classes rc1 and rc2 */ ST_FUNC void gv2(int rc1, int rc2) { + int v; + /* generate more generic register first. But VT_JMP or VT_CMP values must be generated first in all cases to avoid possible reload errors */ - if (rc1 <= rc2) { + v = vtop[0].r & VT_VALMASK; + if (v != VT_CMP && (v & ~1) != VT_JMP && rc1 <= rc2) { vswap(); gv(rc1); vswap(); @@ -1025,7 +959,6 @@ static int rc_fret(int t) if (t == VT_LDOUBLE) { return RC_ST0; } - ex_rc = RC_QRET; #endif return RC_FRET; } @@ -1084,7 +1017,6 @@ ST_FUNC void lexpand_nr(void) } #endif -#ifndef TCC_TARGET_X86_64 /* build a long long from two ints */ static void lbuild(int t) { @@ -1093,7 +1025,6 @@ static void lbuild(int t) vtop[-1].type.t = t; vpop(); } -#endif /* rotate n first stack elements to the bottom I1 ... In -> I2 ... In I1 [top is right] @@ -1134,9 +1065,8 @@ ST_FUNC void vrott(int n) /* pop stack value */ ST_FUNC void vpop(void) { - int v, fr; - fr = vtop->r; - v = fr & VT_VALMASK; + int v; + v = vtop->r & VT_VALMASK; #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) /* for x86, we need to pop the FP stack */ if (v == TREG_ST0 && !nocode_wanted) { @@ -1147,17 +1077,6 @@ ST_FUNC void vpop(void) /* need to put correct jump if && or || without test */ gsym(vtop->c.ul); } - if(fr & VT_TMP){ - int size, align; - SValue ret; - if((vtop->type.t & VT_BTYPE) == VT_FUNC) - size = 8; - else{ - gfunc_sret(&vtop->type, func_var, &ret.type, &align); - size = type_size(&ret.type, &align); - } - loc_stack(size, 0); - } vtop--; } @@ -1167,8 +1086,8 @@ static void gv_dup(void) { int rc, t, r, r1; SValue sv; + t = vtop->type.t; -#ifndef TCC_TARGET_X86_64 if ((t & VT_BTYPE) == VT_LLONG) { lexpand(); gv_dup(); @@ -1178,14 +1097,15 @@ static void gv_dup(void) vrotb(4); /* stack: H L L1 H1 */ lbuild(t); - vrott(3); + vrotb(3); + vrotb(3); vswap(); lbuild(t); vswap(); - } else -#endif - { + } else { /* duplicate value */ + rc = RC_INT; + sv.type.t = VT_INT; if (is_float(t)) { rc = RC_FLOAT; #ifdef TCC_TARGET_X86_64 @@ -1193,9 +1113,8 @@ static void gv_dup(void) rc = RC_ST0; } #endif - }else - rc = RC_INT; - sv.type.t = t; + sv.type.t = t; + } r = gv(rc); r1 = get_reg(rc); sv.r = r; @@ -1207,6 +1126,27 @@ static void gv_dup(void) vtop->r = r1; } } + +/* Generate value test + * + * Generate a test for any value (jump, comparison and integers) */ +ST_FUNC int gvtst(int inv, int t) +{ + int v = vtop->r & VT_VALMASK; + if (v != VT_CMP && v != VT_JMP && v != VT_JMPI) { + vpushi(0); + gen_op(TOK_NE); + } + if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { + /* constant jmp optimization */ + if ((vtop->c.i != 0) != inv) + t = gjmp(t); + vtop--; + return t; + } + return gtst(inv, t); +} + #ifndef TCC_TARGET_X86_64 /* generate CPU independent (unsigned) long long operations */ static void gen_opl(int op) @@ -1405,13 +1345,13 @@ static void gen_opl(int op) b = 0; gen_op(op1); if (op1 != TOK_NE) { - a = gtst(1, 0); + a = gvtst(1, 0); } if (op != TOK_EQ) { /* generate non equal test */ /* XXX: NOT PORTABLE yet */ if (a == 0) { - b = gtst(0, 0); + b = gvtst(0, 0); } else { #if defined(TCC_TARGET_I386) b = psym(0x850f, 0); @@ -1436,7 +1376,7 @@ static void gen_opl(int op) else if (op1 == TOK_GE) op1 = TOK_UGE; gen_op(op1); - a = gtst(1, a); + a = gvtst(1, a); gsym(b); vseti(VT_JMPI, a); break; @@ -2161,30 +2101,31 @@ ST_FUNC int type_size(CType *type, int *a) { Sym *s; int bt; - size_t size; bt = type->t & VT_BTYPE; if (bt == VT_STRUCT) { - assert(!(type->t & VT_VLS)); /* struct/union */ s = type->ref; *a = s->r; - size = s->c; + return s->c; } else if (bt == VT_PTR) { if (type->t & VT_ARRAY) { int ts; + s = type->ref; ts = type_size(&s->type, a); + if (ts < 0 && s->c < 0) ts = -ts; - size = (size_t)ts * s->c; + + return ts * s->c; } else { *a = PTR_SIZE; - size = PTR_SIZE; + return PTR_SIZE; } } else if (bt == VT_LDOUBLE) { *a = LDOUBLE_ALIGN; - size = LDOUBLE_SIZE; + return LDOUBLE_SIZE; } else if (bt == VT_DOUBLE || bt == VT_LLONG) { #ifdef TCC_TARGET_I386 #ifdef TCC_TARGET_PE @@ -2201,23 +2142,21 @@ ST_FUNC int type_size(CType *type, int *a) #else *a = 8; #endif - size = 8; + return 8; } else if (bt == VT_INT || bt == VT_ENUM || bt == VT_FLOAT) { *a = 4; - size = 4; + return 4; } else if (bt == VT_SHORT) { *a = 2; - size = 2; - } else if (bt == VT_QLONG || bt == VT_QFLOAT) { + return 2; + } else if (bt == VT_QLONG || bt == VT_QFLOAT) { *a = 8; - size = 16; + return 16; } else { /* char, void, function, _Bool */ *a = 1; - size = 1; + return 1; } - assert(size == (int)size); - return (int)size; } /* push type size as known at runtime time on top of value stack. Put @@ -2233,7 +2172,7 @@ ST_FUNC void vla_runtime_type_size(CType *type, int *a) static void vla_sp_save(void) { if (!(vla_flags & VLA_SP_LOC_SET)) { - *vla_sp_loc = loc_stack(PTR_SIZE, 1); + *vla_sp_loc = (loc -= PTR_SIZE); vla_flags |= VLA_SP_LOC_SET; } if (!(vla_flags & VLA_SP_SAVED)) { @@ -2502,8 +2441,6 @@ static void gen_assign_cast(CType *dt) if (sbt == VT_PTR || sbt == VT_FUNC) { tcc_warning("assignment makes integer from pointer without a cast"); } - if (sbt == VT_STRUCT) - goto error; /* XXX: more tests */ break; case VT_STRUCT: @@ -2523,78 +2460,17 @@ static void gen_assign_cast(CType *dt) gen_cast(dt); } -static void vstore_im(){ - int rc, ft, sbt, dbt, t, r; - ft = vtop[-1].type.t; - sbt = vtop->type.t & VT_BTYPE; - dbt = ft & VT_BTYPE; - if (is_float(ft)) { - rc = RC_FLOAT; -#ifdef TCC_TARGET_X86_64 - if (dbt == VT_LDOUBLE) { - rc = RC_ST0; - } -#endif - }else - rc = RC_INT; - 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); -#ifdef TCC_TARGET_X86_64 - sv.type.t = VT_PTR; -#else - sv.type.t = VT_INT; -#endif - sv.r = VT_LOCAL | VT_LVAL | VT_TMP; - sv.c.ul = vtop[-1].c.ul; - load(t, &sv); - vtop[-1].r = t | VT_LVAL; - vtop[-1].c.ul = 0; - } - /* two word case handling : store second register at word + 4 */ -#ifdef TCC_TARGET_X86_64 - if ((dbt == VT_QLONG) || (dbt == VT_QFLOAT)) -#else - if (dbt == VT_LLONG) -#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; -#endif - vtop[-1].type.t = load_type; - store(r, vtop - 1); - vswap(); - /* convert to int to increment easily */ - vtop->type = char_pointer_type; - gaddrof(); - vpushi(load_size); - gen_op('+'); - vtop->r |= VT_LVAL; - vswap(); - vtop[-1].type.t = load_type; - /* XXX: it works because r2 is spilled last ! */ - store(vtop->r2, vtop - 1); - vtop->type.t = ft; - vtop[-1].type.t = ft; - } else { - store(r, vtop - 1); - } -} - /* store vtop in lvalue pushed on stack */ ST_FUNC void vstore(void) { - int sbt, dbt, ft, size, align, bit_size, bit_pos, delayed_cast; + int sbt, dbt, ft, r, t, size, align, bit_size, bit_pos, rc, 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)) { + (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 & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT))); @@ -2612,42 +2488,31 @@ ST_FUNC void vstore(void) /* structure assignment : generate memcpy */ /* XXX: optimize if small size */ if (!nocode_wanted) { - SValue ret; - int ret_nregs, ret_align; - ret_nregs = gfunc_sret(&vtop->type, func_var, &ret.type, &ret_align); - if(ret_nregs){ - vswap(); - vpushv(vtop - 1); - vtop[0].type = ret.type; - vtop[-1].type = ret.type; - vstore_im(); - vtop -=2; - }else{ - size = type_size(&vtop->type, &align); - /* destination */ - vswap(); - vtop->type.t = VT_PTR; - gaddrof(); + size = type_size(&vtop->type, &align); - /* address of memcpy() */ + /* destination */ + vswap(); + vtop->type.t = VT_PTR; + gaddrof(); + + /* address of memcpy() */ #ifdef TCC_ARM_EABI - if(!(align & 7)) - vpush_global_sym(&func_old_type, TOK_memcpy8); - else if(!(align & 3)) - vpush_global_sym(&func_old_type, TOK_memcpy4); - else + if(!(align & 7)) + vpush_global_sym(&func_old_type, TOK_memcpy8); + else if(!(align & 3)) + vpush_global_sym(&func_old_type, TOK_memcpy4); + else #endif - vpush_global_sym(&func_old_type, TOK_memcpy); + vpush_global_sym(&func_old_type, TOK_memcpy); - vswap(); - /* source */ - vpushv(vtop - 2); - vtop->type.t = VT_PTR; - gaddrof(); - /* type size */ - vpushi(size); - gfunc_call(3); - } + vswap(); + /* source */ + vpushv(vtop - 2); + vtop->type.t = VT_PTR; + gaddrof(); + /* type size */ + vpushi(size); + gfunc_call(3); } else { vswap(); vpop(); @@ -2659,8 +2524,13 @@ ST_FUNC void vstore(void) bit_size = (ft >> (VT_STRUCT_SHIFT + 6)) & 0x3f; /* remove bit field info to avoid loops */ vtop[-1].type.t = ft & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); + /* duplicate source into other register */ - if(dbt == VT_BOOL) { + gv_dup(); + vswap(); + vrott(3); + + if((ft & VT_BTYPE) == VT_BOOL) { gen_cast(&vtop[-1].type); vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED); } @@ -2670,8 +2540,8 @@ ST_FUNC void vstore(void) vtop[-1] = vtop[-2]; /* mask and shift source */ - if(dbt != VT_BOOL) { - if(dbt == VT_LLONG) { + if((ft & VT_BTYPE) != VT_BOOL) { + if((ft & VT_BTYPE) == VT_LLONG) { vpushll((1ULL << bit_size) - 1ULL); } else { vpushi((1 << bit_size) - 1); @@ -2682,7 +2552,7 @@ ST_FUNC void vstore(void) gen_op(TOK_SHL); /* load destination, mask and or with source */ vswap(); - if(dbt == VT_LLONG) { + if((ft & VT_BTYPE) == VT_LLONG) { vpushll(~(((1ULL << bit_size) - 1ULL) << bit_pos)); } else { vpushi(~(((1 << bit_size) - 1) << bit_pos)); @@ -2691,6 +2561,10 @@ ST_FUNC void vstore(void) gen_op('|'); /* store result */ vstore(); + + /* pop off shifted source from "duplicate source..." above */ + vpop(); + } else { #ifdef CONFIG_TCC_BCHECK /* bound check case */ @@ -2701,7 +2575,56 @@ ST_FUNC void vstore(void) } #endif if (!nocode_wanted) { - vstore_im(); + 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; + } +#endif + } + 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); +#ifdef TCC_TARGET_X86_64 + sv.type.t = VT_PTR; +#else + sv.type.t = VT_INT; +#endif + sv.r = VT_LOCAL | VT_LVAL; + sv.c.ul = vtop[-1].c.ul; + load(t, &sv); + vtop[-1].r = t | VT_LVAL; + } + /* two word case handling : store second register at word + 4 (or +8 for x86-64) */ +#ifdef TCC_TARGET_X86_64 + 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 + vtop[-1].type.t = load_type; + store(r, vtop - 1); + vswap(); + /* convert to int to increment easily */ + vtop->type.t = addr_type; + gaddrof(); + vpushi(load_size); + gen_op('+'); + vtop->r |= VT_LVAL; + vswap(); + vtop[-1].type.t = load_type; + /* XXX: it works because r2 is spilled last ! */ + store(vtop->r2, vtop - 1); + } else { + store(r, vtop - 1); + } } vswap(); vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ @@ -3364,7 +3287,7 @@ static void asm_label_instr(CString *astr) static void post_type(CType *type, AttributeDef *ad) { - int n, l, t1, arg_size, size, align; + int n, l, t1, arg_size, align; Sym **plast, *s, *first; AttributeDef ad1; CType pt; @@ -3468,12 +3391,13 @@ static void post_type(CType *type, AttributeDef *ad) t1 |= type->t & VT_VLA; if (t1 & VT_VLA) { - size = type_size(&int_type, &align); - n = loc_stack(size, 1); + loc -= type_size(&int_type, &align); + loc &= -align; + n = loc; vla_runtime_type_size(type, &align); gen_op('*'); - vset(&int_type, VT_LOCAL|VT_LVAL, n); + vset(&int_type, VT_LOCAL|VT_LVAL, loc); vswap(); vstore(); } @@ -3835,7 +3759,7 @@ ST_FUNC void unary(void) vtop->c.i = vtop->c.i ^ 1; else { save_regs(1); - vseti(VT_JMP, gtst(1, 0)); + vseti(VT_JMP, gvtst(1, 0)); } break; case '~': @@ -4069,94 +3993,47 @@ ST_FUNC void unary(void) /* post operations */ while (1) { - SValue ret; - int ret_nregs, ret_align; if (tok == TOK_INC || tok == TOK_DEC) { inc(1, tok); next(); } else if (tok == '.' || tok == TOK_ARROW) { - int qualifiers, add, is_lval; + int qualifiers; /* field */ - qualifiers = vtop->type.t & (VT_CONSTANT | VT_VOLATILE); - add = 0; - if (tok == TOK_ARROW) - indir(); - - type = vtop->type; - is_lval = (vtop->r & (VT_VALMASK | VT_LVAL)) >= VT_CONST; - if(is_lval){ - test_lvalue(); - gaddrof(); - vtop->type = char_pointer_type; /* change type to 'char *' */ - }else - gfunc_sret(&vtop->type, func_var, &ret.type, &ret_align); - do{ - next(); - /* expect pointer on structure */ - if ((type.t & VT_BTYPE) != VT_STRUCT) - expect("struct or union"); - s = type.ref; - /* find field */ - tok |= SYM_FIELD; - while ((s = s->next) != NULL) { - if (s->v == tok) - break; - } - if (!s) - tcc_error("field not found: %s", get_tok_str(tok & ~SYM_FIELD, NULL)); - /* add bit */ - add += s->c; - /* change type to field type, and set to lvalue */ - type = s->type; - next(); - }while(tok == '.'); - - type.t |= qualifiers; - if (is_lval){ - p_lval: - vpushi(add); - gen_op('+'); - /* an array is never an lvalue */ - if (!(type.t & VT_ARRAY)) { - vtop->r |= lvalue_type(type.t); - #ifdef CONFIG_TCC_BCHECK - /* if bound checking, the referenced pointer must be checked */ - if (tcc_state->do_bounds_check) - vtop->r |= VT_MUSTBOUND; - #endif - } - }else{ - gfunc_sret(&vtop->type, func_var, &ret.type, &ret_align); - if(is_float(ret.type.t) || (type.t & VT_ARRAY)){ -#ifdef TCC_TARGET_X86_64 - if((ret.type.t & VT_BTYPE) != VT_LDOUBLE) + if (tok == TOK_ARROW) + indir(); + qualifiers = vtop->type.t & (VT_CONSTANT | VT_VOLATILE); + test_lvalue(); + gaddrof(); + next(); + /* expect pointer on structure */ + if ((vtop->type.t & VT_BTYPE) != VT_STRUCT) + expect("struct or union"); + s = vtop->type.ref; + /* find field */ + tok |= SYM_FIELD; + while ((s = s->next) != NULL) { + if (s->v == tok) + break; + } + if (!s) + tcc_error("field not found: %s", get_tok_str(tok & ~SYM_FIELD, NULL)); + /* add field offset to pointer */ + vtop->type = char_pointer_type; /* change type to 'char *' */ + vpushi(s->c); + gen_op('+'); + /* change type to field type, and set to lvalue */ + vtop->type = s->type; + vtop->type.t |= qualifiers; + /* an array is never an lvalue */ + if (!(vtop->type.t & VT_ARRAY)) { + vtop->r |= lvalue_type(vtop->type.t); +#ifdef CONFIG_TCC_BCHECK + /* if bound checking, the referenced pointer must be checked */ + if (tcc_state->do_bounds_check) + vtop->r |= VT_MUSTBOUND; #endif - { - save_reg(vtop->r); - vtop->r &= ~VT_TMP; - gaddrof(); - vtop->type = char_pointer_type; /* change type to 'char *' */ - goto p_lval; - } - }else{ -#ifdef TCC_TARGET_X86_64 - int load_size = 8; -#else - int load_size = 4; -#endif - if(add & load_size){ - add -= load_size; - vtop->r = vtop->r2; - vtop->r2 = VT_CONST; - } - if(add){ - vtop->type.t = VT_LLONG; - vpushi(add*8); - gen_op(TOK_SAR); - } - } - } - vtop->type = type; + } + next(); } else if (tok == '[') { next(); gexpr(); @@ -4164,8 +4041,9 @@ ST_FUNC void unary(void) indir(); skip(']'); } else if (tok == '(') { + SValue ret; Sym *sa; - int nb_args, variadic, addr; + int nb_args, ret_nregs, ret_align, variadic; /* function call */ if ((vtop->type.t & VT_BTYPE) != VT_FUNC) { @@ -4183,6 +4061,7 @@ ST_FUNC void unary(void) } /* get return type */ s = vtop->type.ref; + next(); sa = s->next; /* first parameter */ nb_args = 0; ret.r2 = VT_CONST; @@ -4194,12 +4073,12 @@ ST_FUNC void unary(void) if (!ret_nregs) { /* get some space for the returned structure */ size = type_size(&s->type, &align); - addr = loc_stack(size, 1); + loc = (loc - size) & -align; ret.type = s->type; ret.r = VT_LOCAL | VT_LVAL; /* pass it as 'int' to avoid structure arg passing problems */ - vseti(VT_LOCAL, addr); + vseti(VT_LOCAL, loc); ret.c = vtop->c; nb_args++; } @@ -4227,7 +4106,6 @@ ST_FUNC void unary(void) } ret.c.i = 0; } - next(); if (tok != ')') { for(;;) { expr_eq(); @@ -4256,8 +4134,25 @@ ST_FUNC void unary(void) } /* handle packed struct return */ - if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) - vtop->type = s->type; + if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) { + int addr, offset; + + size = type_size(&s->type, &align); + loc = (loc - size) & -align; + addr = loc; + offset = 0; + for (;;) { + vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset); + vswap(); + vstore(); + vtop--; + if (--ret_nregs == 0) + break; + /* XXX: compatible with arm only: ret_align == register_size */ + offset += ret_align; + } + vset(&s->type, VT_LOCAL | VT_LVAL, addr); + } } else { break; } @@ -4392,7 +4287,7 @@ static void expr_land(void) t = 0; save_regs(1); for(;;) { - t = gtst(1, t); + t = gvtst(1, t); if (tok != TOK_LAND) { vseti(VT_JMPI, t); break; @@ -4412,7 +4307,7 @@ static void expr_lor(void) t = 0; save_regs(1); for(;;) { - t = gtst(0, t); + t = gvtst(0, t); if (tok != TOK_LOR) { vseti(VT_JMP, t); break; @@ -4426,8 +4321,8 @@ static void expr_lor(void) /* XXX: better constant handling */ static void expr_cond(void) { - int tt, u, r, rc, t1, t2, bt1, bt2, ret_nregs, ret_align; - SValue sv, ret; + int tt, u, r1, r2, rc, t1, t2, bt1, bt2; + SValue sv; CType type, type1, type2; if (const_wanted) { @@ -4469,13 +4364,14 @@ static void expr_cond(void) } else rc = RC_INT; - save_regs(1); + gv(rc); + save_regs(1); } if (tok == ':' && gnu_ext) { gv_dup(); - tt = gtst(1, 0); + tt = gvtst(1, 0); } else { - tt = gtst(1, 0); + tt = gvtst(1, 0); gexpr(); } type1 = vtop->type; @@ -4508,14 +4404,16 @@ static void expr_cond(void) (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED)) type.t |= VT_UNSIGNED; } else if (bt1 == VT_PTR || bt2 == VT_PTR) { - /* If one is a null ptr constant the result type is the other. */ - if (is_null_pointer (vtop)) - type = type1; - else if (is_null_pointer (&sv)) - type = type2; - /* XXX: test pointer compatibility, C99 has more elaborate rules here. */ - else - type = type1; + /* If one is a null ptr constant the result type + is the other. */ + if (is_null_pointer (vtop)) + type = type1; + else if (is_null_pointer (&sv)) + type = type2; + /* XXX: test pointer compatibility, C99 has more elaborate + rules here. */ + else + type = type1; } else if (bt1 == VT_FUNC || bt2 == VT_FUNC) { /* XXX: test function pointer compatibility */ type = bt1 == VT_FUNC ? type1 : type2; @@ -4533,35 +4431,26 @@ static void expr_cond(void) (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) type.t |= VT_UNSIGNED; } - + /* now we convert second operand */ gen_cast(&type); - ret_nregs = 0; - if (VT_STRUCT == (type.t & VT_BTYPE)){ - ret_nregs = gfunc_sret(&type, func_var, &ret.type, &ret_align); - if(ret_nregs) - vtop->type = ret.type; - else - gaddrof(); - } - - if (is_float(vtop->type.t)) { + if (VT_STRUCT == (vtop->type.t & VT_BTYPE)) + 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; } #endif - } else - rc = RC_INT; - r = gv(rc); - rc = reg_classes[r] & ~RC_MASK; -#ifdef TCC_TARGET_X86_64 - if (((vtop->type.t & VT_BTYPE) == VT_QLONG) || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT)) -#else - if ((vtop->type.t & VT_BTYPE) == VT_LLONG) -#endif - ex_rc = reg_classes[vtop->r2] & ~RC_MASK; + } 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; + } + + r2 = gv(rc); /* this is horrible, but we must also convert first operand */ tt = gjmp(0); @@ -4569,21 +4458,12 @@ static void expr_cond(void) /* put again first value and cast it */ *vtop = sv; gen_cast(&type); - if (VT_STRUCT == (type.t & VT_BTYPE)){ - if(ret_nregs) - vtop->type = ret.type; - else - gaddrof(); - } - gv(rc); + if (VT_STRUCT == (vtop->type.t & VT_BTYPE)) + gaddrof(); + r1 = gv(rc); + move_reg(r2, r1, type.t); + vtop->r = r2; gsym(tt); - - if (VT_STRUCT == (type.t & VT_BTYPE)){ - if(ret_nregs) - vtop->type = type; - else - vtop->r |= VT_LVAL; - } } } } @@ -4737,7 +4617,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, skip('('); gexpr(); skip(')'); - a = gtst(1, 0); + a = gvtst(1, 0); block(bsym, csym, case_sym, def_sym, case_reg, 0); c = tok; if (c == TOK_ELSE) { @@ -4754,7 +4634,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, skip('('); gexpr(); skip(')'); - a = gtst(1, 0); + a = gvtst(1, 0); b = 0; block(&a, &b, case_sym, def_sym, case_reg, 0); gjmp_addr(d); @@ -4771,7 +4651,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, frame_bottom->next = scope_stack_bottom; scope_stack_bottom = frame_bottom; llabel = local_label_stack; - + /* save VLA state */ block_vla_sp_loc = *(saved_vla_sp_loc = vla_sp_loc); if (saved_vla_sp_loc != &vla_sp_root_loc) @@ -4823,7 +4703,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, /* pop locally defined symbols */ scope_stack_bottom = scope_stack_bottom->next; sym_pop(&local_stack, s); - + /* Pop VLA frames and restore stack pointer if required */ if (saved_vla_sp_loc != &vla_sp_root_loc) *saved_vla_sp_loc = block_vla_sp_loc; @@ -4856,23 +4736,32 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, vstore(); } else { /* returning structure packed into registers */ - int rc; + int r, size, addr, align; + size = type_size(&func_vt,&align); + if ((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & (ret_align-1))) + && (align & (ret_align-1))) { + loc = (loc - size) & -align; + addr = loc; + type = func_vt; + vset(&type, VT_LOCAL | VT_LVAL, addr); + vswap(); + vstore(); + vset(&ret_type, VT_LOCAL | VT_LVAL, addr); + } vtop->type = ret_type; if (is_float(ret_type.t)) - rc = rc_fret(ret_type.t); - else{ - rc = RC_IRET; - ex_rc = RC_LRET; - } + r = rc_fret(ret_type.t); + else + r = RC_IRET; for (;;) { - gv(rc); + gv(r); 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 */ - rc <<= 1; + r <<= 1; /* XXX: compatible with arm only: ret_align == register_size */ vtop->c.i += ret_align; vtop->r = VT_LOCAL | VT_LVAL; @@ -4924,7 +4813,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, b = 0; if (tok != ';') { gexpr(); - a = gtst(1, 0); + a = gvtst(1, 0); } skip(';'); if (tok != ')') { @@ -4953,7 +4842,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, skip('('); gsym(b); gexpr(); - c = gtst(0, 0); + c = gvtst(0, 0); gsym_addr(c, d); skip(')'); gsym(a); @@ -5698,10 +5587,11 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, sec = NULL; #ifdef CONFIG_TCC_BCHECK if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) { - loc_stack(1, 1); + loc--; } #endif - addr = loc_stack(size, 1); + loc = (loc - size) & -align; + addr = loc; #ifdef CONFIG_TCC_BCHECK /* handles bounds */ /* XXX: currently, since we do only one pass, we cannot track @@ -5709,7 +5599,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) { unsigned long *bounds_ptr; /* add padding between regions */ - loc_stack(1, 1); + loc--; /* then add local bound info */ bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(unsigned long)); bounds_ptr[0] = addr; diff --git a/tccpe.c b/tccpe.c index f7ef99e..b972d75 100644 --- a/tccpe.c +++ b/tccpe.c @@ -1773,7 +1773,7 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe) if (0 == s1->nostdlib) { static const char *libs[] = { - "libcrt.a", "msvcrt", "kernel32", "", "user32", "gdi32", NULL + "libtcc1.a", "msvcrt", "kernel32", "", "user32", "gdi32", NULL }; const char **pp, *p; for (pp = libs; 0 != (p = *pp); ++pp) { diff --git a/tccpp.c b/tccpp.c index 538f671..732c5ea 100644 --- a/tccpp.c +++ b/tccpp.c @@ -233,10 +233,7 @@ static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len) ts = tcc_malloc(sizeof(TokenSym) + len); table_ident[i] = ts; ts->tok = tok_ident++; - ts->sym_define.data = tcc_malloc(sizeof(Sym**)); - ts->sym_define.off = 0; - ts->sym_define.data[0] = NULL; - ts->sym_define.size = 1; + ts->sym_define = NULL; ts->sym_label = NULL; ts->sym_struct = NULL; ts->sym_identifier = NULL; @@ -1055,62 +1052,52 @@ static int macro_is_equal(const int *a, const int *b) ST_INLN void define_push(int v, int macro_type, int *str, Sym *first_arg) { Sym *s; - CSym *def; + s = define_find(v); if (s && !macro_is_equal(s->d, str)) tcc_warning("%s redefined", get_tok_str(v, NULL)); + s = sym_push2(&define_stack, v, macro_type, 0); s->d = str; s->next = first_arg; - def = &table_ident[v - TOK_IDENT]->sym_define; - def->data[def->off] = s; + table_ident[v - TOK_IDENT]->sym_define = s; } /* undefined a define symbol. Its name is just set to zero */ ST_FUNC void define_undef(Sym *s) { int v; - CSym *def; - v = s->v - TOK_IDENT; - if ((unsigned)v < (unsigned)(tok_ident - TOK_IDENT)){ - def = &table_ident[v]->sym_define; - def->data[def->off] = NULL; - } + v = s->v; + if (v >= TOK_IDENT && v < tok_ident) + table_ident[v - TOK_IDENT]->sym_define = NULL; + s->v = 0; } ST_INLN Sym *define_find(int v) { - CSym *def; v -= TOK_IDENT; if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) return NULL; - def = &table_ident[v]->sym_define; - return def->data[def->off]; + return table_ident[v]->sym_define; } /* free define stack until top reaches 'b' */ ST_FUNC void free_defines(Sym *b) { - Sym *top, *tmp; + Sym *top, *top1; int v; - CSym *def; top = define_stack; while (top != b) { - tmp = top->prev; + top1 = top->prev; /* do not free args or predefined defines */ if (top->d) tok_str_free(top->d); - v = top->v - TOK_IDENT; - if ((unsigned)v < (unsigned)(tok_ident - TOK_IDENT)){ - def = &table_ident[v]->sym_define; - if(def->off) - def->off = 0; - if(def->data[0]) - def->data[0] = NULL; - } + v = top->v; + if (v >= TOK_IDENT && v < tok_ident) + table_ident[v - TOK_IDENT]->sym_define = NULL; sym_free(top); - top = tmp; + top = top1; } define_stack = b; } @@ -1351,18 +1338,66 @@ static inline void add_cached_include(TCCState *s1, const char *filename, int if s1->cached_includes_hash[h] = s1->nb_cached_includes; } +static void pragma_parse(TCCState *s1) +{ + int val; + + next(); + if (tok == TOK_pack) { + /* + This may be: + #pragma pack(1) // set + #pragma pack() // reset to default + #pragma pack(push,1) // push & set + #pragma pack(pop) // restore previous + */ + next(); + skip('('); + if (tok == TOK_ASM_pop) { + next(); + if (s1->pack_stack_ptr <= s1->pack_stack) { + stk_error: + tcc_error("out of pack stack"); + } + s1->pack_stack_ptr--; + } else { + val = 0; + if (tok != ')') { + if (tok == TOK_ASM_push) { + next(); + if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE - 1) + goto stk_error; + s1->pack_stack_ptr++; + skip(','); + } + if (tok != TOK_CINT) { + pack_error: + tcc_error("invalid pack pragma"); + } + val = tokc.i; + if (val < 1 || val > 16 || (val & (val - 1)) != 0) + goto pack_error; + next(); + } + *s1->pack_stack_ptr = val; + skip(')'); + } + } +} + /* is_bof is true if first non space token at beginning of file */ ST_FUNC void preprocess(int is_bof) { TCCState *s1 = tcc_state; int i, c, n, saved_parse_flags; - uint8_t buf[1024], *p; + char buf[1024], *q; Sym *s; saved_parse_flags = parse_flags; - parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | PARSE_FLAG_LINEFEED; + parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | + PARSE_FLAG_LINEFEED; next_nomacro(); -redo: + redo: switch(tok) { case TOK_DEFINE: next_nomacro(); @@ -1385,21 +1420,19 @@ redo: goto read_name; } else if (ch == '\"') { c = ch; -read_name: + read_name: inp(); - p = buf; + q = buf; while (ch != c && ch != '\n' && ch != CH_EOF) { - if ((p - buf) < sizeof(buf) - 1) - *p++ = ch; + if ((q - buf) < sizeof(buf) - 1) + *q++ = ch; if (ch == '\\') { if (handle_stray_noerror() == 0) - --p; + --q; } else inp(); } - if (ch != c) - goto include_syntax; - *p = '\0'; + *q = '\0'; minp(); #if 0 /* eat all spaces and comments after include */ @@ -1437,8 +1470,6 @@ read_name: c = '>'; } } - if(!buf[0]) - tcc_error(" empty filename in #include"); if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE) tcc_error("#include recursion too deep"); @@ -1505,7 +1536,8 @@ include_trynext: printf("%s: including %s\n", file->prev->filename, file->filename); #endif /* update target deps */ - dynarray_add((void ***)&s1->target_deps, &s1->nb_target_deps, tcc_strdup(buf1)); + dynarray_add((void ***)&s1->target_deps, &s1->nb_target_deps, + tcc_strdup(buf1)); /* push current file in stack */ ++s1->include_stack_ptr; /* add include file debug info */ @@ -1538,7 +1570,7 @@ include_done: file->ifndef_macro = tok; } } - c = !!define_find(tok) ^ c; + c = (define_find(tok) != 0) ^ c; do_if: if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE) tcc_error("memory full (ifdef)"); @@ -1562,12 +1594,12 @@ include_done: goto skip; c = expr_preprocess(); s1->ifdef_stack_ptr[-1] = c; -test_else: + test_else: if (s1->ifdef_stack_ptr == file->ifdef_stack_ptr + 1) file->ifndef_macro = 0; -test_skip: + test_skip: if (!(c & 1)) { -skip: + skip: preprocess_skip(); is_bof = 0; goto redo; @@ -1585,11 +1617,11 @@ skip: /* need to set to zero to avoid false matches if another #ifndef at middle of file */ file->ifndef_macro = 0; + while (tok != TOK_LINEFEED) + next_nomacro(); tok_flags |= TOK_FLAG_ENDIF; + goto the_end; } - next_nomacro(); - if (tok != TOK_LINEFEED) - tcc_warning("Ignoring: %s", get_tok_str(tok, &tokc)); break; case TOK_LINE: next(); @@ -1600,7 +1632,8 @@ skip: if (tok != TOK_LINEFEED) { if (tok != TOK_STR) tcc_error("#line"); - pstrcpy(file->filename, sizeof(file->filename), (char *)tokc.cstr->data); + pstrcpy(file->filename, sizeof(file->filename), + (char *)tokc.cstr->data); } break; case TOK_ERROR: @@ -1608,161 +1641,24 @@ skip: c = tok; ch = file->buf_ptr[0]; skip_spaces(); - p = buf; + q = buf; while (ch != '\n' && ch != CH_EOF) { - if ((p - buf) < sizeof(buf) - 1) - *p++ = ch; + if ((q - buf) < sizeof(buf) - 1) + *q++ = ch; if (ch == '\\') { if (handle_stray_noerror() == 0) - --p; + --q; } else inp(); } - *p = '\0'; + *q = '\0'; if (c == TOK_ERROR) tcc_error("#error %s", buf); else tcc_warning("#warning %s", buf); break; case TOK_PRAGMA: - next(); - if (tok == TOK_pack && parse_flags & PARSE_FLAG_PACK) { - /* - This may be: - #pragma pack(1) // set - #pragma pack() // reset to default - #pragma pack(push,1) // push & set - #pragma pack(pop) // restore previous - */ - next(); - skip('('); - if (tok == TOK_ASM_pop) { - next(); - if (s1->pack_stack_ptr <= s1->pack_stack) { -stk_error: - tcc_error("out of pack stack"); - } - s1->pack_stack_ptr--; - } else { - int val = 0; - if (tok != ')') { - if (tok == TOK_ASM_push) { - next(); - s1->pack_stack_ptr++; - if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE) - goto stk_error; - skip(','); - } - if (tok != TOK_CINT) { -pack_error: - tcc_error("invalid pack pragma"); - } - val = tokc.i; - if (val < 1 || val > 16) - goto pack_error; - if (val < 1 || val > 16) - tcc_error("Value must be greater than 1 is less than or equal to 16"); - if ((val & (val - 1)) != 0) - tcc_error("Value must be a power of 2 curtain"); - next(); - } - *s1->pack_stack_ptr = val; - skip(')'); - } - }else if (tok == TOK_PUSH_MACRO || tok == TOK_POP_MACRO) { - TokenSym *ts; - CSym *def; - uint8_t *p1; - int len, t; - t = tok; - ch = file->buf_ptr[0]; - skip_spaces(); - if (ch != '(') - goto macro_xxx_syntax; - /* XXX: incorrect if comments : use next_nomacro with a special mode */ - inp(); - skip_spaces(); - if (ch == '\"'){ - inp(); - p = buf; - while (ch != '\"' && ch != '\n' && ch != CH_EOF) { - if ((p - buf) < sizeof(buf) - 1) - *p++ = ch; - if (ch == CH_EOB) { - --p; - handle_stray(); - }else - inp(); - } - if(ch != '\"') - goto macro_xxx_syntax; - *p = '\0'; - minp(); - next(); - }else{ - /* computed #pragma macro_xxx for #define xxx */ - next(); - buf[0] = '\0'; - while (tok != ')') { - if (tok != TOK_STR) { - macro_xxx_syntax: - tcc_error("'macro_xxx' expects (\"NAME\")"); - } - pstrcat(buf, sizeof(buf), (char *)tokc.cstr->data); - next(); - } - } - skip (')'); - if(!buf[0]) - tcc_error(" empty string in #pragma"); - /* find TokenSym */ - p = buf; - while (is_space(*p)) - p++; - p1 = p; - for(;;){ - if (!isidnum_table[p[0] - CH_EOF]) - break; - ++p; - } - len = p - p1; - while (is_space(*p)) - p++; - if(!p) //'\0' - tcc_error("unrecognized string: %s", buf); - ts = tok_alloc(p1, len); - if(ts){ - def = &ts->sym_define; - if(t == TOK_PUSH_MACRO){ - void *tmp = def->data[def->off]; - if(tmp){ - def->off++; - if(def->off >= def->size){ - int size = def->size; - size *= 2; - if (size >= MACRO_STACK_SIZE) - tcc_error("stack full"); - def->data = tcc_realloc(def->data, size*sizeof(Sym**)); - def->size = size; - } - def->data[def->off] = tmp; - } - }else{ - if(def->off){ - --def->off; - }else{ - tcc_warning("stack empty"); - } - } - } - }else{ - fputs("#pragma ", s1->ppfp); - while (tok != TOK_LINEFEED){ - fputs(get_tok_str(tok, &tokc), s1->ppfp); - next(); - } - goto the_end; - } + pragma_parse(s1); break; default: if (tok == TOK_LINEFEED || tok == '!' || tok == TOK_PPNUM) { @@ -1782,7 +1678,7 @@ pack_error: /* ignore other preprocess commands or #! for C scripts */ while (tok != TOK_LINEFEED) next_nomacro(); -the_end: + the_end: parse_flags = saved_parse_flags; } @@ -3134,13 +3030,12 @@ ST_FUNC int tcc_preprocess(TCCState *s1) ch = file->buf_ptr[0]; tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; parse_flags = PARSE_FLAG_ASM_COMMENTS | PARSE_FLAG_PREPROCESS | - PARSE_FLAG_LINEFEED | PARSE_FLAG_SPACES; + PARSE_FLAG_LINEFEED | PARSE_FLAG_SPACES; token_seen = 0; line_ref = 0; file_ref = NULL; iptr = s1->include_stack_ptr; - tok = TOK_LINEFEED; /* print line */ - goto print_line; + for (;;) { next(); if (tok == TOK_EOF) { @@ -3148,11 +3043,11 @@ ST_FUNC int tcc_preprocess(TCCState *s1) } else if (file != file_ref) { goto print_line; } else if (tok == TOK_LINEFEED) { - if (token_seen) + if (!token_seen) continue; ++line_ref; - token_seen = 1; - } else if (token_seen) { + token_seen = 0; + } else if (!token_seen) { d = file->line_num - line_ref; if (file != file_ref || d < 0 || d >= 8) { print_line: @@ -3160,7 +3055,8 @@ print_line: s = iptr_new > iptr ? " 1" : iptr_new < iptr ? " 2" : iptr_new > s1->include_stack ? " 3" - : ""; + : "" + ; iptr = iptr_new; fprintf(s1->ppfp, "# %d \"%s\"%s\n", file->line_num, file->filename, s); } else { @@ -3168,8 +3064,8 @@ print_line: fputs("\n", s1->ppfp), --d; } line_ref = (file_ref = file)->line_num; - token_seen = tok == TOK_LINEFEED; - if (token_seen) + token_seen = tok != TOK_LINEFEED; + if (!token_seen) continue; } fputs(get_tok_str(tok, &tokc), s1->ppfp); diff --git a/tcctok.h b/tcctok.h index c2aa040..735ccdd 100644 --- a/tcctok.h +++ b/tcctok.h @@ -138,8 +138,6 @@ /* pragma */ DEF(TOK_pack, "pack") - DEF(TOK_PUSH_MACRO, "push_macro") - DEF(TOK_POP_MACRO, "pop_macro") #if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64) /* already defined for assembler */ DEF(TOK_ASM_push, "push") @@ -287,5 +285,5 @@ #endif #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 -#include "asmx86-tok.h" +#include "i386-tok.h" #endif diff --git a/tests/Makefile b/tests/Makefile index 4c728eb..e3824ba 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -66,11 +66,11 @@ RUN_TCC = $(NATIVE_DEFINES) -DONE_SOURCE -run $(top_srcdir)/tcc.c $(TCCFLAGS) DISAS = objdump -d # libtcc test -ifdef LIBCRT - LIBCRT:=$(TOP)/$(LIBCRT) +ifdef LIBTCC1 + LIBTCC1:=$(TOP)/$(LIBTCC1) endif -all test : clean $(TESTS) +all test : $(TESTS) hello-exe: ../examples/ex1.c @echo ------------ $@ ------------ @@ -89,7 +89,7 @@ hello-run: ../examples/ex1.c @echo ------------ $@ ------------ $(TCC) -run $< -libtest: libtcc_test$(EXESUF) $(LIBCRT) +libtest: libtcc_test$(EXESUF) $(LIBTCC1) @echo ------------ $@ ------------ ./libtcc_test$(EXESUF) lib_path=.. @@ -101,7 +101,7 @@ moretests: $(MAKE) -C tests2 w32-prep: - cp ../libcrt.a ../lib + cp ../libtcc1.a ../lib # test.ref - generate using cc test.ref: tcctest.c @@ -210,14 +210,10 @@ abitest-cc$(EXESUF): abitest.c $(top_builddir)/$(LIBTCC) abitest-tcc$(EXESUF): abitest.c libtcc.c $(TCC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(NATIVE_DEFINES) -DONE_SOURCE $(LIBS) $(LDFLAGS) -I$(top_srcdir) -abitest-tcc1$(EXESUF): abitest.c $(top_builddir)/$(LIBTCC) - $(CC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(NATIVE_DEFINES) $(LIBS) $(LINK_LIBTCC) $(LDFLAGS) -I$(top_srcdir) - -abitest: abitest-cc$(EXESUF) abitest-tcc$(EXESUF) abitest-tcc1$(EXESUF) +abitest: abitest-cc$(EXESUF) abitest-tcc$(EXESUF) @echo ------------ $@ ------------ ./abitest-cc$(EXESUF) lib_path=.. include="$(top_srcdir)/include" ./abitest-tcc$(EXESUF) lib_path=.. include="$(top_srcdir)/include" - ./abitest-tcc1$(EXESUF) lib_path=.. include="$(top_srcdir)/include" vla_test$(EXESUF): vla_test.c $(TCC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) @@ -244,6 +240,6 @@ cache: tcc_g clean: $(MAKE) -C tests2 $@ rm -vf *~ *.o *.a *.bin *.i *.ref *.out *.out? *.out?b *.cc \ - *-cc *-tcc *.exe *-tcc1\ + *-cc *-tcc *.exe \ hello libtcc_test vla_test tcctest[1234] ex? tcc_g tcclib.h \ - ../lib/libcrt.a + ../lib/libtcc1.a diff --git a/tests/abitest.c b/tests/abitest.c index d840d85..3ad707a 100644 --- a/tests/abitest.c +++ b/tests/abitest.c @@ -468,7 +468,7 @@ int main(int argc, char **argv) { const char *testname = NULL; int retval = EXIT_SUCCESS; - /* if tcclib.h and libcrt.a are not installed, where can we find them */ + /* if tcclib.h and libtcc1.a are not installed, where can we find them */ for (i = 1; i < argc; ++i) { if (!memcmp(argv[i], "lib_path=",9)) tccdir = argv[i] + 9; diff --git a/tests/libtcc_test.c b/tests/libtcc_test.c index 4449afa..bead0ff 100644 --- a/tests/libtcc_test.c +++ b/tests/libtcc_test.c @@ -43,7 +43,7 @@ int main(int argc, char **argv) exit(1); } - /* if tcclib.h and libcrt.a are not installed, where can we find them */ + /* if tcclib.h and libtcc1.a are not installed, where can we find them */ if (argc == 2 && !memcmp(argv[1], "lib_path=",9)) tcc_set_lib_path(s, argv[1]+9); diff --git a/tests/tcctest.c b/tests/tcctest.c index 5fac82e..cc8ffd8 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -235,7 +235,7 @@ void intdiv_test(void) void macro_test(void) { - printf("macro:\n"); + printf("macro:\n"); pf("N=%d\n", N); printf("aaa=%d\n", AAA); @@ -379,23 +379,6 @@ comment /* And again when the name and parenthes are separated by a comment. */ TEST2 /* the comment */ (); - /* macro_push and macro_pop test */ - #define MACRO_TEST "macro_test1\n" - #pragma push_macro("MACRO_TEST") - #undef MACRO_TEST - #define MACRO_TEST "macro_test2\n" - printf(MACRO_TEST); - #pragma pop_macro("MACRO_TEST") - printf(MACRO_TEST); -/* gcc does not support - #define MACRO_TEST_MACRO "MACRO_TEST" - #pragma push_macro(MACRO_TEST_MACRO) - #undef MACRO_TEST - #define MACRO_TEST "macro_test3\n" - printf(MACRO_TEST); - #pragma pop_macro(MACRO_TEST_MACRO) - printf(MACRO_TEST); -*/ } @@ -1697,6 +1680,7 @@ void prefix ## fcast(type a)\ printf("ftof: %f %f %Lf\n", fa, da, la);\ ia = (int)a;\ llia = (long long)a;\ + a = (a >= 0) ? a : -a;\ ua = (unsigned int)a;\ llua = (unsigned long long)a;\ printf("ftoi: %d %u %lld %llu\n", ia, ua, llia, llua);\ @@ -1726,18 +1710,6 @@ void prefix ## call(void)\ printf("strto%s: %f\n", #prefix, (double)strto ## prefix("1.2", NULL));\ }\ \ -void prefix ## calc(type x, type y)\ -{\ - x=x*x;y=y*y;\ - printf("%d, %d\n", (int)x, (int)y);\ - x=x-y;y=y-x;\ - printf("%d, %d\n", (int)x, (int)y);\ - x=x/y;y=y/x;\ - printf("%d, %d\n", (int)x, (int)y);\ - x=x+x;y=y+y;\ - printf("%d, %d\n", (int)x, (int)y);\ -}\ -\ void prefix ## signed_zeros(void) \ {\ type x = 0.0, y = -0.0, n, p;\ @@ -1760,7 +1732,7 @@ void prefix ## signed_zeros(void) \ 1.0 / x != 1.0 / p);\ else\ printf ("x != +y; this is wrong!\n");\ - p = -y;\ + p = -y;\ if (x == p)\ printf ("Test 1.0 / x != 1.0 / -y returns %d (should be 0).\n",\ 1.0 / x != 1.0 / p);\ @@ -1776,8 +1748,7 @@ void prefix ## test(void)\ prefix ## fcast(234.6);\ prefix ## fcast(-2334.6);\ prefix ## call();\ - prefix ## calc(1, 1.0000000000000001);\ - prefix ## signed_zeros();\ + prefix ## signed_zeros();\ } FTEST(f, float, float, "%f") @@ -2184,15 +2155,14 @@ void whitespace_test(void) { char *str; - -#if 1 + #if 1 pri\ -ntf("whitspace:\n"); +ntf("whitspace:\n"); #endif pf("N=%d\n", 2); #ifdef CORRECT_CR_HANDLING - pri\ + pri\ ntf("aaa=%d\n", 3); #endif @@ -2204,12 +2174,11 @@ ntf("min=%d\n", 4); printf("len1=%d\n", strlen(" ")); #ifdef CORRECT_CR_HANDLING - str = " + str = " "; printf("len1=%d str[0]=%d\n", strlen(str), str[0]); #endif - printf("len1=%d\n", strlen(" -a + printf("len1=%d\n", strlen(" a ")); #endif /* ACCEPT_CR_IN_STRINGS */ } @@ -2603,6 +2572,7 @@ int constant_p_var; void builtin_test(void) { +#if GCC_MAJOR >= 3 COMPAT_TYPE(int, int); COMPAT_TYPE(int, unsigned int); COMPAT_TYPE(int, char); @@ -2612,9 +2582,9 @@ void builtin_test(void) COMPAT_TYPE(int *, void *); COMPAT_TYPE(int *, const int *); COMPAT_TYPE(char *, unsigned char *); - COMPAT_TYPE(char, unsigned char); /* space is needed because tcc preprocessor introduces a space between each token */ - COMPAT_TYPE(char **, void *); + COMPAT_TYPE(char * *, void *); +#endif printf("res = %d\n", __builtin_constant_p(1)); printf("res = %d\n", __builtin_constant_p(1 + 2)); printf("res = %d\n", __builtin_constant_p(&constant_p_var)); diff --git a/win32/tools/tiny_libmaker.c b/win32/tools/tiny_libmaker.c index 29a692a..62d2a2e 100644 --- a/win32/tools/tiny_libmaker.c +++ b/win32/tools/tiny_libmaker.c @@ -1,5 +1,5 @@ /* - * This program is for making libcrt.a without ar + * This program is for making libtcc1.a without ar * tiny_libmaker - tiny elf lib maker * usage: tiny_libmaker [lib] files... * Copyright (c) 2007 Timppa diff --git a/x86_64-gen.c b/x86_64-gen.c index 2b52bb1..ae65328 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -29,38 +29,28 @@ /* a register can belong to several classes. The classes must be sorted from more general to more precise (see gv2() code which does assumptions on it). */ -#define RC_INT 0x0001 /* generic integer register */ -#define RC_FLOAT 0x0002 /* generic float register */ -#define RC_RAX 0x0004 -#define RC_RCX 0x0008 -#define RC_RDX 0x0010 -#define RC_ST0 0x0020 /* only for long double */ -#define RC_R8 0x0040 -#define RC_R9 0x0080 -#define RC_XMM0 0x0100 -#define RC_XMM1 0x0200 -#define RC_XMM2 0x0400 -#define RC_XMM3 0x0800 -#define RC_XMM4 0x1000 -#define RC_XMM5 0x2000 -#define RC_XMM6 0x4000 -#define RC_XMM7 0x8000 -#define RC_RSI 0x10000 -#define RC_RDI 0x20000 -#define RC_INT1 0x40000 /* function_pointer */ -#define RC_INT2 0x80000 -#define RC_RBX 0x100000 -#define RC_R10 0x200000 -#define RC_R11 0x400000 -#define RC_R12 0x800000 -#define RC_R13 0x1000000 -#define RC_R14 0x2000000 -#define RC_R15 0x4000000 -#define RC_IRET RC_RAX /* function return: integer register */ -#define RC_LRET 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_MASK (RC_INT|RC_INT1|RC_INT2|RC_FLOAT) +#define RC_INT 0x0001 /* generic integer register */ +#define RC_FLOAT 0x0002 /* generic float register */ +#define RC_RAX 0x0004 +#define RC_RCX 0x0008 +#define RC_RDX 0x0010 +#define RC_ST0 0x0080 /* only for long double */ +#define RC_R8 0x0100 +#define RC_R9 0x0200 +#define RC_R10 0x0400 +#define RC_R11 0x0800 +#define RC_XMM0 0x1000 +#define RC_XMM1 0x2000 +#define RC_XMM2 0x4000 +#define RC_XMM3 0x8000 +#define RC_XMM4 0x10000 +#define RC_XMM5 0x20000 +#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_FRET RC_XMM0 /* function return: float register */ +#define RC_QRET RC_XMM1 /* function return: second float register */ /* pretty names for the registers */ enum { @@ -68,7 +58,6 @@ enum { TREG_RCX = 1, TREG_RDX = 2, TREG_RSP = 4, - TREG_ST0 = 5, TREG_RSI = 6, TREG_RDI = 7, @@ -86,11 +75,13 @@ enum { TREG_XMM6 = 22, TREG_XMM7 = 23, + TREG_ST0 = 24, + + TREG_MEM = 0x20, }; #define REX_BASE(reg) (((reg) >> 3) & 1) #define REG_VALUE(reg) ((reg) & 7) -#define FLAG_GOT 0X01 /* return registers for function */ #define REG_IRET TREG_RAX /* single word int return register */ @@ -131,30 +122,34 @@ enum { #include ST_DATA const int reg_classes[NB_REGS] = { - /* eax */ RC_INT|RC_RAX|RC_INT2, - /* ecx */ RC_INT|RC_RCX|RC_INT2, - /* edx */ RC_INT|RC_RDX, - RC_INT|RC_INT1|RC_INT2|RC_RBX, + /* eax */ RC_INT | RC_RAX, + /* ecx */ RC_INT | RC_RCX, + /* edx */ RC_INT | RC_RDX, 0, - /* st0 */ RC_ST0, - RC_RSI|RC_INT2, - RC_RDI|RC_INT2, - RC_INT|RC_R8|RC_INT2, - RC_INT|RC_R9|RC_INT2, - RC_INT|RC_INT1|RC_INT2|RC_R10, - RC_INT|RC_INT1|RC_INT2|RC_R11, - RC_INT|RC_INT1|RC_INT2|RC_R12, - RC_INT|RC_INT1|RC_INT2|RC_R13, - RC_INT|RC_INT1|RC_INT2|RC_R14, - RC_INT|RC_INT1|RC_INT2|RC_R15, - /* xmm0 */ RC_FLOAT | RC_XMM0, - RC_FLOAT|RC_XMM1, - RC_FLOAT|RC_XMM2, - RC_FLOAT|RC_XMM3, - RC_FLOAT|RC_XMM4, - RC_FLOAT|RC_XMM5, - RC_FLOAT|RC_XMM6, - RC_FLOAT|RC_XMM7, + 0, + 0, + 0, + 0, + RC_R8, + RC_R9, + RC_R10, + RC_R11, + 0, + 0, + 0, + 0, + /* xmm0 */ RC_FLOAT | RC_XMM0, + /* xmm1 */ RC_FLOAT | RC_XMM1, + /* xmm2 */ RC_FLOAT | RC_XMM2, + /* xmm3 */ RC_FLOAT | RC_XMM3, + /* xmm4 */ RC_FLOAT | RC_XMM4, + /* xmm5 */ RC_FLOAT | RC_XMM5, + /* xmm6 an xmm7 are included so gv() can be used on them, + but they are not tagged with RC_FLOAT because they are + callee saved on Windows */ + RC_XMM6, + RC_XMM7, + /* st0 */ RC_ST0 }; static unsigned long func_sub_sp_offset; @@ -309,19 +304,18 @@ static void gen_gotpcrel(int r, Sym *sym, int c) } } -static void gen_modrm_impl(int op_reg, int fr, Sym *sym, int c, int flag) +static void gen_modrm_impl(int op_reg, int r, Sym *sym, int c, int is_got) { - int r = fr & VT_VALMASK; op_reg = REG_VALUE(op_reg) << 3; - if (r == VT_CONST) { + if ((r & VT_VALMASK) == VT_CONST) { /* constant memory reference */ o(0x05 | op_reg); - if (flag & FLAG_GOT) { - gen_gotpcrel(fr, sym, c); + if (is_got) { + gen_gotpcrel(r, sym, c); } else { - gen_addrpc32(fr, sym, c); + gen_addrpc32(r, sym, c); } - } else if (r == VT_LOCAL) { + } else if ((r & VT_VALMASK) == VT_LOCAL) { /* currently, we use only ebp as base */ if (c == (char)c) { /* short reference */ @@ -330,23 +324,15 @@ static void gen_modrm_impl(int op_reg, int fr, Sym *sym, int c, int flag) } else { oad(0x85 | op_reg, c); } - } else if (c) { - if (c == (char)c) { - /* short reference */ - g(0x40 | op_reg | REG_VALUE(fr)); - if(r == TREG_RSP) - g(0x24); - g(c); + } else if ((r & VT_VALMASK) >= TREG_MEM) { + if (c) { + g(0x80 | op_reg | REG_VALUE(r)); + gen_le32(c); } else { - g(0x80 | op_reg | REG_VALUE(fr)); - if(r == TREG_RSP) - g(0x24); - gen_le32(c); + g(0x00 | op_reg | REG_VALUE(r)); } } else { - g(0x00 | op_reg | REG_VALUE(fr)); - if(r == TREG_RSP) - g(0x24); + g(0x00 | op_reg | REG_VALUE(r)); } } @@ -361,18 +347,17 @@ static void gen_modrm(int op_reg, int r, Sym *sym, int c) opcode bits */ static void gen_modrm64(int opcode, int op_reg, int r, Sym *sym, int c) { - int flag; - if((op_reg & TREG_MEM) && !(sym->type.t & VT_STATIC)) - flag = FLAG_GOT; + int is_got; + is_got = (op_reg & TREG_MEM) && !(sym->type.t & VT_STATIC); orex(1, r, op_reg, opcode); - gen_modrm_impl(op_reg, r, sym, c, flag); + gen_modrm_impl(op_reg, r, sym, c, is_got); } /* load 'r' from value 'sv' */ void load(int r, SValue *sv) { - int v, t, ft, fc, fr, ll; + int v, t, ft, fc, fr; SValue v1; #ifdef TCC_TARGET_PE @@ -383,21 +368,19 @@ void load(int r, SValue *sv) fr = sv->r; ft = sv->type.t & ~VT_DEFSIGN; fc = sv->c.ul; - ll = is64_type(ft); #ifndef TCC_TARGET_PE /* we use indirect access via got */ if ((fr & VT_VALMASK) == VT_CONST && (fr & VT_SYM) && (fr & VT_LVAL) && !(sv->sym->type.t & VT_STATIC)) { /* use the result register as a temporal register */ - int tr; + int tr = r | TREG_MEM; if (is_float(ft)) { /* we cannot use float registers as a temporal register */ tr = get_reg(RC_INT) | TREG_MEM; - }else{ - tr = r | TREG_MEM; - } + } gen_modrm64(0x8b, tr, fr, sv->sym, 0); + /* load from the temporal register */ fr = tr | VT_LVAL; } @@ -405,14 +388,7 @@ void load(int r, SValue *sv) v = fr & VT_VALMASK; if (fr & VT_LVAL) { - if(fr & VT_TMP){ - int size, align; - if((ft & VT_BTYPE) == VT_FUNC) - size = PTR_SIZE; - else - size = type_size(&sv->type, &align); - loc_stack(size, 0); - } + int b, ll; if (v == VT_LLOCAL) { v1.type.t = VT_PTR; v1.r = VT_LOCAL | VT_LVAL; @@ -421,13 +397,14 @@ void load(int r, SValue *sv) if (!(reg_classes[fr] & RC_INT)) fr = get_reg(RC_INT); load(fr, &v1); - fc = 0; } - int b; + ll = 0; if ((ft & VT_BTYPE) == VT_FLOAT) { - b = 0x100ff3; /* movss */ + b = 0x6e0f66; + r = REG_VALUE(r); /* movd */ } else if ((ft & VT_BTYPE) == VT_DOUBLE) { - b = 0x100ff2; /* movds */ + b = 0x7e0ff3; /* movq */ + r = REG_VALUE(r); } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { b = 0xdb, r = 5; /* fldt */ } else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) { @@ -439,13 +416,18 @@ void load(int r, SValue *sv) } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) { b = 0xb70f; /* movzwl */ } else { - assert(((ft & VT_BTYPE) == VT_INT) || ((ft & VT_BTYPE) == VT_LLONG) + assert(((ft & VT_BTYPE) == VT_INT) || ((ft & VT_BTYPE) == VT_LLONG) || ((ft & VT_BTYPE) == VT_PTR) || ((ft & VT_BTYPE) == VT_ENUM) || ((ft & VT_BTYPE) == VT_FUNC)); + ll = is64_type(ft); b = 0x8b; } - orex(ll, fr, r, b); - gen_modrm(r, fr, sv->sym, fc); + if (ll) { + gen_modrm64(b, r, fr, sv->sym, fc); + } else { + orex(ll, fr, r, b); + gen_modrm(r, fr, sv->sym, fc); + } } else { if (v == VT_CONST) { if (fr & VT_SYM) { @@ -464,33 +446,33 @@ void load(int r, SValue *sv) gen_gotpcrel(r, sv->sym, fc); } #endif + } else if (is64_type(ft)) { + orex(1,r,0, 0xb8 + REG_VALUE(r)); /* mov $xx, r */ + gen_le64(sv->c.ull); } else { - orex(ll,r,0, 0xb8 + REG_VALUE(r)); /* mov $xx, r */ - if (ll) - gen_le64(sv->c.ull); - else - gen_le32(fc); - } + orex(0,r,0, 0xb8 + REG_VALUE(r)); /* mov $xx, r */ + gen_le32(fc); + } } else if (v == VT_LOCAL) { orex(1,0,r,0x8d); /* lea xxx(%ebp), r */ gen_modrm(r, VT_LOCAL, sv->sym, fc); } else if (v == VT_CMP) { - orex(0, r, 0, 0xb8 + REG_VALUE(r)); - if ((fc & ~0x100) == TOK_NE){ - gen_le32(1);/* mov $0, r */ - }else{ - gen_le32(0);/* mov $1, r */ - } - if (fc & 0x100){ - fc &= ~0x100; - /* This was a float compare. If the parity bit is - set the result was unordered, meaning false for everything - except TOK_NE, and true for TOK_NE. */ - o(0x037a + (REX_BASE(r) << 8));/* jp 3*/ - } - orex(0,r,0, 0x0f); /* setxx %br */ - o(fc); - o(0xc0 + REG_VALUE(r)); + orex(0,r,0,0); + if ((fc & ~0x100) != TOK_NE) + oad(0xb8 + REG_VALUE(r), 0); /* mov $0, r */ + else + oad(0xb8 + REG_VALUE(r), 1); /* mov $1, r */ + if (fc & 0x100) + { + /* This was a float compare. If the parity bit is + set the result was unordered, meaning false for everything + except TOK_NE, and true for TOK_NE. */ + fc &= ~0x100; + o(0x037a + (REX_BASE(r) << 8)); + } + orex(0,r,0, 0x0f); /* setxx %br */ + o(fc); + o(0xc0 + REG_VALUE(r)); } else if (v == VT_JMP || v == VT_JMPI) { t = v & 1; orex(0,r,0,0); @@ -500,89 +482,117 @@ void load(int r, SValue *sv) orex(0,r,0,0); oad(0xb8 + REG_VALUE(r), t ^ 1); /* mov $0, r */ } else if (v != r) { - if (reg_classes[r] & RC_FLOAT) { - if(v == TREG_ST0){ - /* gen_cvt_ftof(VT_DOUBLE); */ - o(0xf0245cdd); /* fstpl -0x10(%rsp) */ - /* movsd -0x10(%rsp),%xmm0 */ - o(0x100ff2); - o(0xf02444 + REG_VALUE(r)*8); - }else if(reg_classes[v] & RC_FLOAT){ - o(0x7e0ff3); - o(0xc0 + REG_VALUE(v) + REG_VALUE(r)*8); - }else - assert(0); + if ((r >= TREG_XMM0) && (r <= TREG_XMM7)) { + if (v == TREG_ST0) { + /* gen_cvt_ftof(VT_DOUBLE); */ + o(0xf0245cdd); /* fstpl -0x10(%rsp) */ + /* movsd -0x10(%rsp),%xmmN */ + o(0x100ff2); + o(0x44 + REG_VALUE(r)*8); /* %xmmN */ + o(0xf024); + } else { + assert((v >= TREG_XMM0) && (v <= TREG_XMM7)); + if ((ft & VT_BTYPE) == VT_FLOAT) { + o(0x100ff3); + } else { + assert((ft & VT_BTYPE) == VT_DOUBLE); + o(0x100ff2); + } + o(0xc0 + REG_VALUE(v) + REG_VALUE(r)*8); + } } else if (r == TREG_ST0) { - assert(reg_classes[v] & RC_FLOAT); + assert((v >= TREG_XMM0) && (v <= TREG_XMM7)); /* gen_cvt_ftof(VT_LDOUBLE); */ - /* movsd %xmm0,-0x10(%rsp) */ - o(0x110ff2); - o(0xf02444 + REG_VALUE(v)*8); + /* movsd %xmmN,-0x10(%rsp) */ + o(0x110ff2); + o(0x44 + REG_VALUE(r)*8); /* %xmmN */ + o(0xf024); o(0xf02444dd); /* fldl -0x10(%rsp) */ } else { - if(fc){ - orex(1,fr,r,0x8d); /* lea xxx(%ebp), r */ - gen_modrm(r, fr, sv->sym, fc); - }else{ - orex(ll,v,r, 0x8b); - o(0xc0 + REG_VALUE(v) + REG_VALUE(r) * 8); /* mov v, r */ - } + orex(1,r,v, 0x89); + o(0xc0 + REG_VALUE(r) + REG_VALUE(v) * 8); /* mov v, r */ } } } } /* store register 'r' in lvalue 'v' */ -void store(int r, SValue *sv) +void store(int r, SValue *v) { - int fr, bt, ft, fc, ll, v; + int fr, bt, ft, fc; + int op64 = 0; + /* store the REX prefix in this variable when PIC is enabled */ + int pic = 0; #ifdef TCC_TARGET_PE SValue v2; - sv = pe_getimport(sv, &v2); + v = pe_getimport(v, &v2); #endif - ft = sv->type.t & ~VT_DEFSIGN; - fc = sv->c.ul; - fr = sv->r; - bt = ft & VT_BTYPE; - ll = is64_type(ft); - v = fr & VT_VALMASK; -//#ifndef TCC_TARGET_PE + ft = v->type.t; + fc = v->c.ul; + fr = v->r & VT_VALMASK; + bt = ft & VT_BTYPE; + +#ifndef TCC_TARGET_PE /* 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 */ - // o(0x1d8b4c); - // gen_gotpcrel(TREG_R11, v->sym, v->c.ul); - //pic = is64_type(bt) ? 0x49 : 0x41; - // } -//#endif + o(0x1d8b4c); + gen_gotpcrel(TREG_R11, v->sym, v->c.ul); + pic = is64_type(bt) ? 0x49 : 0x41; + } +#endif /* XXX: incorrect if float reg to reg */ if (bt == VT_FLOAT) { - orex(0, fr, r, 0x110ff3); /* movss */ + o(0x66); + o(pic); + o(0x7e0f); /* movd */ + r = REG_VALUE(r); } else if (bt == VT_DOUBLE) { - orex(0, fr, r, 0x110ff2);/* movds */ + o(0x66); + o(pic); + o(0xd60f); /* movq */ + r = REG_VALUE(r); } else if (bt == VT_LDOUBLE) { o(0xc0d9); /* fld %st(0) */ - orex(0, fr, r, 0xdb);/* fstpt */ + o(pic); + o(0xdb); /* fstpt */ r = 7; } else { if (bt == VT_SHORT) o(0x66); - if (bt == VT_BYTE || bt == VT_BOOL) - orex(ll, fr, r, 0x88); - else{ - orex(ll, fr, r, 0x89); - } + o(pic); + if (bt == VT_BYTE || bt == VT_BOOL) + orex(0, 0, r, 0x88); + else if (is64_type(bt)) + 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 */ @@ -603,76 +613,14 @@ static void gcall_or_jmp(int is_jmp) oad(0xe8 + is_jmp, vtop->c.ul - 4); /* call/jmp im */ } else { /* otherwise, indirect call */ - r = get_reg(RC_INT1); + r = TREG_R11; load(r, vtop); - orex(0, r, 0, 0xff); /* REX call/jmp *r */ + o(0x41); /* REX */ + o(0xff); /* call/jmp *r */ o(0xd0 + REG_VALUE(r) + (is_jmp << 4)); } } -static int func_scratch; -static int r_loc; - -int reloc_add(int inds) -{ - return psym(0, inds); -} - -void reloc_use(int t, int data) -{ - int *ptr; - while (t) { - ptr = (int *)(cur_text_section->data + t); - t = *ptr; /* next value */ - *ptr = data; - } -} - -void struct_copy(SValue *d, SValue *s, SValue *c) -{ - if(!c->c.i) - return; - save_reg(TREG_RCX); - load(TREG_RCX, c); - load(TREG_RDI, d); - load(TREG_RSI, s); - o(0xa4f3);// rep movsb -} - -void gen_putz(SValue *d, int size) -{ - if(!size) - return; - save_reg(TREG_RAX); - o(0xb0); - g(0x00); - save_reg(TREG_RCX); - o(0xb8 + REG_VALUE(TREG_RCX)); /* mov $xx, r */ - gen_le32(size); - load(TREG_RDI, d); - o(0xaaf3);//rep stos -} - -/* Generate function call. The function address is pushed first, then - all the parameters in call order. This functions pops all the - parameters and the function address. */ -void gen_offs_sp(int b, int r, int off) -{ - if(r & 0x100) - o(b); - else - orex(1, 0, r, b); - if(!off){ - o(0x2404 | (REG_VALUE(r) << 3)); - }else if (off == (char)off) { - o(0x2444 | (REG_VALUE(r) << 3)); - g(off); - } else { - o(0x2484 | (REG_VALUE(r) << 3)); - gen_le32(off); - } -} - #ifdef TCC_TARGET_PE #define REGN 4 @@ -690,6 +638,24 @@ static int arg_prepare_reg(int idx) { return arg_regs[idx]; } +static int func_scratch; + +/* Generate function call. The function address is pushed first, then + all the parameters in call order. This functions pops all the + parameters and the function address. */ + +void gen_offs_sp(int b, int r, int d) +{ + orex(1,0,r & 0x100 ? 0 : r, b); + if (d == (char)d) { + o(0x2444 | (REG_VALUE(r) << 3)); + g(d); + } else { + o(0x2484 | (REG_VALUE(r) << 3)); + gen_le32(d); + } +} + /* Return the number of registers needed to return the struct, or 0 if returning via struct pointer. */ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align) @@ -853,8 +819,9 @@ void gfunc_prolog(CType *func_type) Sym *sym; CType *type; - func_ret_sub = func_scratch = r_loc = 0; - pop_stack = loc = 0; + func_ret_sub = 0; + func_scratch = 0; + loc = 0; addr = PTR_SIZE * 2; ind += FUNC_PROLOG_SIZE; @@ -928,7 +895,7 @@ void gfunc_epilog(void) ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; /* align local size to word & save local variables */ v = (func_scratch + -loc + 15) & -16; - reloc_use(r_loc, func_scratch); + if (v >= 4096) { Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0); oad(0xb8, v); /* mov stacksize, %eax */ @@ -948,6 +915,16 @@ void gfunc_epilog(void) #else +static void gadd_sp(int val) +{ + if (val == (char)val) { + o(0xc48348); + g(val); + } else { + oad(0xc48148, val); /* add $xxx, %rsp */ + } +} + typedef enum X86_64_Mode { x86_64_mode_none, x86_64_mode_memory, @@ -986,14 +963,12 @@ static X86_64_Mode classify_x86_64_inner(CType *ty) case VT_BYTE: case VT_SHORT: case VT_LLONG: - case VT_QLONG: case VT_BOOL: case VT_PTR: case VT_FUNC: case VT_ENUM: return x86_64_mode_integer; case VT_FLOAT: - case VT_QFLOAT: case VT_DOUBLE: return x86_64_mode_sse; case VT_LDOUBLE: return x86_64_mode_x87; @@ -1004,7 +979,7 @@ static X86_64_Mode classify_x86_64_inner(CType *ty) // Detect union if (f->next && (f->c == f->next->c)) return x86_64_mode_memory; - + mode = x86_64_mode_none; for (f = f->next; f; f = f->next) mode = classify_x86_64_merge(mode, classify_x86_64_inner(&f->type)); @@ -1022,7 +997,7 @@ static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *p if (ty->t & (VT_BITFIELD|VT_ARRAY)) { *psize = 8; - *palign = 8; + *palign = 8; *reg_count = 1; ret_t = ty->t; mode = x86_64_mode_integer; @@ -1033,7 +1008,6 @@ static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *p if (size > 16) { mode = x86_64_mode_memory; - ret_t = ty->t; } else { mode = classify_x86_64_inner(ty); switch (mode) { @@ -1042,22 +1016,16 @@ static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *p *reg_count = 2; ret_t = VT_QLONG; } else { - *reg_count = 1; - if(size > 4) - ret_t = VT_LLONG; - else if(size > 2){ - ret_t = VT_INT; - }else if(size > 1) - ret_t = VT_SHORT; - else - ret_t = VT_BYTE; - } - ret_t |= (ty->t & VT_UNSIGNED); + *reg_count = 1; + ret_t = (size > 4) ? VT_LLONG : VT_INT; + } break; + case x86_64_mode_x87: *reg_count = 1; ret_t = VT_LDOUBLE; break; + case x86_64_mode_sse: if (size > 8) { *reg_count = 2; @@ -1067,15 +1035,13 @@ static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *p ret_t = (size > 4) ? VT_DOUBLE : VT_FLOAT; } break; - default: - ret_t = ty->t; - break; /* nothing to be done for x86_64_mode_memory and x86_64_mode_none*/ + default: break; /* nothing to be done for x86_64_mode_memory and x86_64_mode_none*/ } } } if (ret) { - ret->ref = ty->ref; + ret->ref = NULL; ret->t = ret_t; } @@ -1086,13 +1052,12 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty) { /* This definition must be synced with stdarg.h */ enum __va_arg_type { - __va_gen_reg, __va_float_reg, __va_ld_reg, __va_stack - }; + __va_gen_reg, __va_float_reg, __va_stack + }; int size, align, reg_count; X86_64_Mode mode = classify_x86_64_arg(ty, NULL, &size, &align, ®_count); switch (mode) { default: return __va_stack; - case x86_64_mode_x87: return __va_ld_reg; case x86_64_mode_integer: return __va_gen_reg; case x86_64_mode_sse: return __va_float_reg; } @@ -1112,21 +1077,26 @@ static const uint8_t arg_regs[REGN] = { TREG_RDI, TREG_RSI, TREG_RDX, TREG_RCX, TREG_R8, TREG_R9 }; +static int arg_prepare_reg(int idx) { + if (idx == 2 || idx == 3) + /* idx=2: r10, idx=3: r11 */ + return idx + 8; + else + return arg_regs[idx]; +} + /* Generate function call. The function address is pushed first, then all the parameters in call order. This functions pops all the parameters and the function address. */ void gfunc_call(int nb_args) { - X86_64_Mode mode; - int size, align, args_size, s, e, i, reg_count; + X86_64_Mode mode; + CType type; + int size, align, r, args_size, stack_adjust, run_start, run_end, i, reg_count; int nb_reg_args = 0; int nb_sse_args = 0; - int gen_reg, sse_reg; - CType type; + int sse_reg, gen_reg; - /* fetch cpu flag before the following sub will change the value */ - if (vtop >= vstack && (vtop->r & VT_VALMASK) == VT_CMP) - gv(RC_INT); /* calculate the number of integer/float register arguments */ for(i = 0; i < nb_args; i++) { mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); @@ -1136,197 +1106,260 @@ void gfunc_call(int nb_args) nb_reg_args += reg_count; } + /* arguments are collected in runs. Each run is a collection of 8-byte aligned arguments + and ended by a 16-byte aligned argument. This is because, from the point of view of + the callee, argument alignment is computed from the bottom up. */ + /* for struct arguments, we need to call memcpy and the function + call breaks register passing arguments we are preparing. + So, we process arguments which will be passed by stack first. */ + gen_reg = nb_reg_args; + sse_reg = nb_sse_args; + run_start = 0; args_size = 0; - gen_reg = nb_reg_args; - sse_reg = nb_sse_args; - /* for struct arguments, we need to call memcpy and the function - call breaks register passing arguments we are preparing. - So, we process arguments which will be passed by stack first. */ - for(i = 0; i < nb_args; i++) { - mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); - switch (mode) { - case x86_64_mode_x87: - if((vtop[-i].type.t & VT_BTYPE) == VT_STRUCT) - goto stack_arg1; - else - args_size = (args_size + 15) & ~15; - case x86_64_mode_memory: - stack_arg1: - args_size += size; - break; - case x86_64_mode_sse: - sse_reg -= reg_count; - if (sse_reg + reg_count > 8) - goto stack_arg1; - break; - case x86_64_mode_integer: - gen_reg -= reg_count; - if (gen_reg + reg_count > REGN) - goto stack_arg1; - break; - default: break; /* nothing to be done for x86_64_mode_none */ - } - } - - args_size = (args_size + 15) & ~15; - if (func_scratch < args_size) - func_scratch = args_size; - - gen_reg = nb_reg_args; - sse_reg = nb_sse_args; - for(s = e = 0; s < nb_args; s = e){ - int run_gen, run_sse, st_size; - run_gen = gen_reg; - run_sse = sse_reg; - st_size = 0; - for(i = s; i < nb_args; i++) { - mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); - switch (mode) { - case x86_64_mode_x87: - if((vtop[-i].type.t & VT_BTYPE) == VT_STRUCT){ - goto stack_arg2; - }else{ - ++i; - goto doing; - } - case x86_64_mode_memory: - stack_arg2: - st_size += size; - break; - case x86_64_mode_sse: - sse_reg -= reg_count; - if (sse_reg + reg_count > 8) - goto stack_arg2; - break; - case x86_64_mode_integer: - gen_reg -= reg_count; - if (gen_reg + reg_count > REGN) - goto stack_arg2; - break; - default: break; /* nothing to be done for x86_64_mode_none */ - } - } -doing: - e = i; - st_size = -st_size & 15;// 16 - (size & 15) - if(st_size) - args_size -= st_size; - - gen_reg = run_gen; - sse_reg = run_sse; - for(i = s; i < e; i++) { - SValue tmp; - /* Swap argument to top, it will possibly be changed here, - and might use more temps. All arguments must remain on the - stack, so that get_reg can correctly evict some of them onto - stack. We could use also use a vrott(nb_args) at the end - of this loop, but this seems faster. */ - if(i != 0){ - tmp = vtop[0]; - vtop[0] = vtop[-i]; - vtop[-i] = tmp; - } - - mode = classify_x86_64_arg(&vtop->type, &type, &size, &align, ®_count); - switch (mode) { - case x86_64_mode_x87: - /* Must ensure TREG_ST0 only */ - if((vtop->type.t & VT_BTYPE) == VT_STRUCT){ - vdup(); - vtop[-1].r = VT_CONST; - vtop->type = type; - gv(RC_ST0); - args_size -= size; - gen_offs_sp(0xdb, 0x107, args_size); - vtop--;//Release TREG_ST0 - }else{ - gv(RC_ST0); - args_size -= size; - gen_offs_sp(0xdb, 0x107, args_size); - vtop->r = VT_CONST;//Release TREG_ST0 - } + while (run_start != nb_args) { + int run_gen_reg = gen_reg, run_sse_reg = sse_reg; + + run_end = nb_args; + stack_adjust = 0; + for(i = run_start; (i < nb_args) && (run_end == nb_args); i++) { + mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); + switch (mode) { + case x86_64_mode_memory: + case x86_64_mode_x87: + stack_arg: + if (align == 16) + run_end = i; + else + stack_adjust += size; break; - case x86_64_mode_memory: - args_size -= size; - vset(&char_pointer_type, TREG_RSP, args_size);/* generate memcpy RSP */ - vpushv(&vtop[-1]); - vtop->type = char_pointer_type; - gaddrof(); - vpushs(size); - struct_copy(&vtop[-2], &vtop[-1], &vtop[0]); - vtop -= 3; - break; - case x86_64_mode_sse: - sse_reg -= reg_count; - if (sse_reg + reg_count > 8){ - args_size -= size; - goto gen_code; - } - break; - case x86_64_mode_integer: - gen_reg -= reg_count; - if (gen_reg + reg_count > REGN){ - args_size -= size; - gen_code: - vset(&type, TREG_RSP | VT_LVAL, args_size); - vpushv(&vtop[-1]); - vtop->type = type; - vstore(); - vtop--; - } - break; - default: break; /* nothing to be done for x86_64_mode_none */ - } - if(i != 0){ - tmp = vtop[0]; - vtop[0] = vtop[-i]; - vtop[-i] = tmp; - } - } - run_gen = gen_reg; - run_sse = sse_reg; - } + + case x86_64_mode_sse: + sse_reg -= reg_count; + if (sse_reg + reg_count > 8) goto stack_arg; + break; + + case x86_64_mode_integer: + gen_reg -= reg_count; + if (gen_reg + reg_count > REGN) goto stack_arg; + break; + default: break; /* nothing to be done for x86_64_mode_none */ + } + } + + gen_reg = run_gen_reg; + sse_reg = run_sse_reg; + + /* adjust stack to align SSE boundary */ + if (stack_adjust &= 15) { + /* fetch cpu flag before the following sub will change the value */ + if (vtop >= vstack && (vtop->r & VT_VALMASK) == VT_CMP) + gv(RC_INT); - gen_reg = nb_reg_args; - sse_reg = nb_sse_args; + stack_adjust = 16 - stack_adjust; + o(0x48); + oad(0xec81, stack_adjust); /* sub $xxx, %rsp */ + args_size += stack_adjust; + } + + for(i = run_start; i < run_end;) { + /* Swap argument to top, it will possibly be changed here, + and might use more temps. At the end of the loop we keep + in on the stack and swap it back to its original position + if it is a register. */ + SValue tmp = vtop[0]; + vtop[0] = vtop[-i]; + vtop[-i] = tmp; + + mode = classify_x86_64_arg(&vtop->type, NULL, &size, &align, ®_count); + + int arg_stored = 1; + switch (vtop->type.t & VT_BTYPE) { + case VT_STRUCT: + if (mode == x86_64_mode_sse) { + if (sse_reg > 8) + sse_reg -= reg_count; + else + arg_stored = 0; + } else if (mode == x86_64_mode_integer) { + if (gen_reg > REGN) + gen_reg -= reg_count; + else + arg_stored = 0; + } + + if (arg_stored) { + /* allocate the necessary size on stack */ + o(0x48); + oad(0xec81, size); /* sub $xxx, %rsp */ + /* generate structure store */ + r = get_reg(RC_INT); + orex(1, r, 0, 0x89); /* mov %rsp, r */ + o(0xe0 + REG_VALUE(r)); + vset(&vtop->type, r | VT_LVAL, 0); + vswap(); + vstore(); + args_size += size; + } + break; + + case VT_LDOUBLE: + assert(0); + break; + + case VT_FLOAT: + case VT_DOUBLE: + assert(mode == x86_64_mode_sse); + if (sse_reg > 8) { + --sse_reg; + r = gv(RC_FLOAT); + o(0x50); /* push $rax */ + /* movq %xmmN, (%rsp) */ + o(0xd60f66); + o(0x04 + REG_VALUE(r)*8); + o(0x24); + args_size += size; + } else { + arg_stored = 0; + } + break; + + default: + assert(mode == x86_64_mode_integer); + /* simple type */ + /* XXX: implicit cast ? */ + if (gen_reg > REGN) { + --gen_reg; + r = gv(RC_INT); + orex(0,r,0,0x50 + REG_VALUE(r)); /* push r */ + args_size += size; + } else { + arg_stored = 0; + } + break; + } + + /* And swap the argument back to it's original position. */ + tmp = vtop[0]; + vtop[0] = vtop[-i]; + vtop[-i] = tmp; + + if (arg_stored) { + vrotb(i+1); + assert((vtop->type.t == tmp.type.t) && (vtop->r == tmp.r)); + vpop(); + --nb_args; + --run_end; + } else { + ++i; + } + } + + /* handle 16 byte aligned arguments at end of run */ + run_start = i = run_end; + while (i < nb_args) { + /* Rotate argument to top since it will always be popped */ + mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); + if (align != 16) + break; + + vrotb(i+1); + + if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { + gv(RC_ST0); + oad(0xec8148, size); /* sub $xxx, %rsp */ + o(0x7cdb); /* fstpt 0(%rsp) */ + g(0x24); + g(0x00); + args_size += size; + } else { + //assert(mode == x86_64_mode_memory); + + /* allocate the necessary size on stack */ + o(0x48); + oad(0xec81, size); /* sub $xxx, %rsp */ + /* generate structure store */ + r = get_reg(RC_INT); + orex(1, r, 0, 0x89); /* mov %rsp, r */ + o(0xe0 + REG_VALUE(r)); + vset(&vtop->type, r | VT_LVAL, 0); + vswap(); + vstore(); + args_size += size; + } + + vpop(); + --nb_args; + } + } + + /* XXX This should be superfluous. */ + save_regs(0); /* save used temporary registers */ + + /* then, we prepare register passing arguments. + Note that we cannot set RDX and RCX in this loop because gv() + may break these temporary registers. Let's use R10 and R11 + instead of them */ + assert(gen_reg <= REGN); + assert(sse_reg <= 8); for(i = 0; i < nb_args; i++) { - int d; - mode = classify_x86_64_arg(&vtop->type, &type, &size, &align, ®_count); + mode = classify_x86_64_arg(&vtop->type, &type, &size, &align, ®_count); /* Alter stack entry type so that gv() knows how to treat it */ vtop->type = type; - /* Alter stack entry type so that gv() knows how to treat it */ if (mode == x86_64_mode_sse) { - sse_reg -= reg_count; - if (sse_reg + reg_count <= 8) { - if (reg_count == 2) { - ex_rc = RC_XMM0 << (sse_reg + 1); - gv(RC_XMM0 << sse_reg); - }else{ - assert(reg_count == 1); - /* Load directly to register */ - gv(RC_XMM0 << sse_reg); - } - } + if (reg_count == 2) { + sse_reg -= 2; + gv(RC_FRET); /* Use pair load into xmm0 & xmm1 */ + if (sse_reg) { /* avoid redundant movaps %xmm0, %xmm0 */ + /* movaps %xmm0, %xmmN */ + o(0x280f); + o(0xc0 + (sse_reg << 3)); + /* movaps %xmm1, %xmmN */ + o(0x280f); + o(0xc1 + ((sse_reg+1) << 3)); + } + } else { + assert(reg_count == 1); + --sse_reg; + /* Load directly to register */ + gv(RC_XMM0 << sse_reg); + } } else if (mode == x86_64_mode_integer) { - gen_reg -= reg_count; - if (gen_reg + reg_count <= REGN) { - if (reg_count == 2) { - d = arg_regs[gen_reg+1]; - ex_rc = reg_classes[d] & ~RC_MASK; - d = arg_regs[gen_reg]; - gv(reg_classes[d] & ~RC_MASK); - }else{ - assert(reg_count == 1); - d = arg_regs[gen_reg]; - gv(reg_classes[d] & ~RC_MASK); - } - } + /* simple type */ + /* XXX: implicit cast ? */ + gen_reg -= reg_count; + r = gv(RC_INT); + int d = arg_prepare_reg(gen_reg); + orex(1,d,r,0x89); /* mov */ + o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d)); + if (reg_count == 2) { + d = arg_prepare_reg(gen_reg+1); + orex(1,d,vtop->r2,0x89); /* mov */ + o(0xc0 + REG_VALUE(vtop->r2) * 8 + REG_VALUE(d)); + } } - vpop(); + vtop--; } - save_regs(0); + assert(gen_reg == 0); + assert(sse_reg == 0); + + /* We shouldn't have many operands on the stack anymore, but the + call address itself is still there, and it might be in %eax + (or edx/ecx) currently, which the below writes would clobber. + So evict all remaining operands here. */ + save_regs(0); + + /* Copy R10 and R11 into RDX and RCX, respectively */ + if (nb_reg_args > 2) { + o(0xd2894c); /* mov %r10, %rdx */ + if (nb_reg_args > 3) { + o(0xd9894c); /* mov %r11, %rcx */ + } + } + oad(0xb8, nb_sse_args < 8 ? nb_sse_args : 8); /* mov nb_sse_args, %eax */ gcall_or_jmp(0); + if (args_size) + gadd_sp(args_size); vtop--; } @@ -1349,8 +1382,7 @@ void gfunc_prolog(CType *func_type) sym = func_type->ref; addr = PTR_SIZE * 2; - pop_stack = loc = 0; - func_scratch = r_loc = 0; + loc = 0; ind += FUNC_PROLOG_SIZE; func_sub_sp_offset = ind; func_ret_sub = 0; @@ -1361,6 +1393,7 @@ void gfunc_prolog(CType *func_type) /* frame pointer and return address */ seen_stack_size = PTR_SIZE * 2; /* count the number of seen parameters */ + sym = func_type->ref; while ((sym = sym->next) != NULL) { type = &sym->type; mode = classify_x86_64_arg(type, NULL, &size, &align, ®_count); @@ -1371,7 +1404,7 @@ void gfunc_prolog(CType *func_type) break; case x86_64_mode_integer: - if (seen_reg_num + reg_count <= REGN) { + if (seen_reg_num + reg_count <= 8) { seen_reg_num += reg_count; } else { seen_reg_num = 8; @@ -1401,19 +1434,19 @@ void gfunc_prolog(CType *func_type) o(0xf845c7); gen_le32(seen_stack_size); - o(0xc084);/* test %al,%al */ - o(0x74);/* je */ - g(4*(8 - seen_sse_num) + 3); - /* save all register passing arguments */ for (i = 0; i < 8; i++) { loc -= 16; - o(0x290f);/* movaps %xmm1-7,-XXX(%rbp) */ + o(0xd60f66); /* movq */ gen_modrm(7 - i, VT_LOCAL, NULL, loc); + /* movq $0, loc+8(%rbp) */ + o(0x85c748); + gen_le32(loc + 8); + gen_le32(0); + } + for (i = 0; i < REGN; i++) { + push_arg_reg(REGN-1-i); } - for (i = 0; i < (REGN - seen_reg_num); i++) { - push_arg_reg(REGN-1 - i); - } } sym = func_type->ref; @@ -1497,8 +1530,7 @@ void gfunc_epilog(void) g(func_ret_sub >> 8); } /* align local size to word & save local variables */ - v = (func_scratch -loc + 15) & -16; - reloc_use(r_loc, func_scratch); + v = (-loc + 15) & -16; saved_ind = ind; ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; o(0xe5894855); /* push %rbp, mov %rsp, %rbp */ @@ -1556,7 +1588,7 @@ int gtst(int inv, int t) } g(0x0f); t = psym((vtop->c.i - 16) ^ inv, t); - } else if (v == VT_JMP || v == VT_JMPI) { + } else { /* VT_JMP || VT_JMPI */ /* && or || optimization */ if ((v & 1) == inv) { /* insert vtop->c jump list in t */ @@ -1569,23 +1601,6 @@ int gtst(int inv, int t) t = gjmp(t); gsym(vtop->c.i); } - } else { - if (is_float(vtop->type.t) || - (vtop->type.t & VT_BTYPE) == VT_LLONG) { - vpushi(0); - gen_op(TOK_NE); - } - if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { - /* constant jmp optimization */ - if ((vtop->c.i != 0) != inv) - t = gjmp(t); - } else { - v = gv(RC_INT); - orex(0,v,v,0x85); - o(0xc0 + REG_VALUE(v) * 9); - g(0x0f); - t = psym(0x85 ^ inv, t); - } } vtop--; return t; @@ -1594,42 +1609,39 @@ int gtst(int inv, int t) /* generate an integer binary operation */ void gen_opi(int op) { - int r, fr, opc, fc, c, ll, uu, cc, tt2; + int r, fr, opc, c; + int ll, uu, cc; - fr = vtop[0].r; - fc = vtop->c.ul; ll = is64_type(vtop[-1].type.t); - cc = (fr & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; - tt2 = (fr & (VT_LVAL | VT_LVAL_TYPE)) == VT_LVAL; + uu = (vtop[-1].type.t & VT_UNSIGNED) != 0; + cc = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; switch(op) { case '+': case TOK_ADDC1: /* add with carry generation */ opc = 0; gen_op8: - vswap(); - r = gv(RC_INT); - vswap(); if (cc && (!ll || (int)vtop->c.ll == vtop->c.ll)) { /* constant case */ + vswap(); + r = gv(RC_INT); + vswap(); c = vtop->c.i; if (c == (char)c) { /* XXX: generate inc and dec for smaller code ? */ - orex(ll, r, 0, 0x83); - o(0xc0 + REG_VALUE(r) + opc*8); - g(c); + orex(ll, r, 0, 0x83); + o(0xc0 | (opc << 3) | REG_VALUE(r)); + g(c); } else { orex(ll, r, 0, 0x81); - oad(0xc0 + REG_VALUE(r) + opc*8, c); + oad(0xc0 | (opc << 3) | REG_VALUE(r), c); } } else { - if(!tt2) - fr = gv(RC_INT); - orex(ll, fr, r, 0x03 + opc*8); - if(fr >= VT_CONST) - gen_modrm(r, fr, vtop->sym, fc); - else - o(0xc0 + REG_VALUE(fr) + REG_VALUE(r)*8); + gv2(RC_INT, RC_INT); + r = vtop[-1].r; + fr = vtop[0].r; + orex(ll, r, fr, (opc << 3) | 0x01); + o(0xc0 + REG_VALUE(r) + REG_VALUE(fr) * 8); } vtop--; if (op >= TOK_ULT && op <= TOK_GT) { @@ -1657,27 +1669,11 @@ void gen_opi(int op) opc = 1; goto gen_op8; case '*': - opc = 5; - vswap(); - r = gv(RC_INT); - vswap(); - if(!tt2) - fr = gv(RC_INT); - if(r == TREG_RAX){ - if(fr != TREG_RDX) - save_reg(TREG_RDX); - orex(ll, fr, r, 0xf7); - if(fr >= VT_CONST) - gen_modrm(opc, fr, vtop->sym, fc); - else - o(0xc0 + REG_VALUE(fr) + opc*8); - }else{ - orex(ll, fr, r, 0xaf0f); /* imul fr, r */ - if(fr >= VT_CONST) - gen_modrm(r, fr, vtop->sym, fc); - else - o(0xc0 + REG_VALUE(fr) + REG_VALUE(r)*8); - } + gv2(RC_INT, RC_INT); + r = vtop[-1].r; + fr = vtop[0].r; + orex(ll, fr, r, 0xaf0f); /* imul fr, r */ + o(0xc0 + REG_VALUE(fr) + REG_VALUE(r) * 8); vtop--; break; case TOK_SHL: @@ -1689,62 +1685,47 @@ void gen_opi(int op) case TOK_SAR: opc = 7; gen_shift: + opc = 0xc0 | (opc << 3); if (cc) { /* constant case */ vswap(); r = gv(RC_INT); vswap(); - c = vtop->c.i; - if(c == 1){ - orex(ll, r, 0, 0xd1); - o(0xc0 + REG_VALUE(r) + opc*8); - }else{ - orex(ll, r, 0, 0xc1); /* shl/shr/sar $xxx, r */ - o(0xc0 + REG_VALUE(r) + opc*8); - g(c & (ll ? 0x3f : 0x1f)); - } + orex(ll, r, 0, 0xc1); /* shl/shr/sar $xxx, r */ + o(opc | REG_VALUE(r)); + g(vtop->c.i & (ll ? 63 : 31)); } else { /* we generate the shift in ecx */ gv2(RC_INT, RC_RCX); r = vtop[-1].r; orex(ll, r, 0, 0xd3); /* shl/shr/sar %cl, r */ - o(0xc0 + REG_VALUE(r) + opc*8); + o(opc | REG_VALUE(r)); } vtop--; break; case TOK_UDIV: case TOK_UMOD: - opc = 6; uu = 1; goto divmod; case '/': case '%': case TOK_PDIV: - opc = 7; uu = 0; divmod: /* first operand must be in eax */ /* XXX: need better constraint for second operand */ - if(!tt2){ - gv2(RC_RAX, RC_INT2); - fr = vtop[0].r; - }else{ - vswap(); - gv(RC_RAX); - vswap(); - } - save_reg(TREG_RDX); - orex(ll, 0, 0, uu ? 0xd231 : 0x99); /* xor %edx,%edx : cdq RDX:RAX <- sign-extend of RAX. */ - orex(ll, fr, 0, 0xf7); /* div fr, %eax */ - if(fr >= VT_CONST) - gen_modrm(opc, fr, vtop->sym, fc); - else - o(0xc0 + REG_VALUE(fr) + opc*8); + gv2(RC_RAX, RC_RCX); + r = vtop[-1].r; + fr = vtop[0].r; + vtop--; + save_reg(TREG_RDX); + orex(ll, 0, 0, uu ? 0xd231 : 0x99); /* xor %edx,%edx : cqto */ + orex(ll, fr, 0, 0xf7); /* div fr, %eax */ + o((uu ? 0xf0 : 0xf8) + REG_VALUE(fr)); if (op == '%' || op == TOK_UMOD) r = TREG_RDX; else r = TREG_RAX; - vtop--; vtop->r = r; break; default: @@ -1763,8 +1744,9 @@ void gen_opl(int op) /* XXX: need to use ST1 too */ void gen_opf(int op) { - int a, ft, fc, swapped, fr, r; - int float_type = (vtop->type.t & VT_BTYPE) == VT_LDOUBLE ? RC_ST0 : RC_FLOAT; + int a, ft, fc, swapped, r; + int float_type = + (vtop->type.t & VT_BTYPE) == VT_LDOUBLE ? RC_ST0 : RC_FLOAT; /* convert constants to memory references */ if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { @@ -1775,23 +1757,21 @@ void gen_opf(int op) if ((vtop[0].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) gv(float_type); - swapped = 0; - fc = vtop->c.ul; - ft = vtop->type.t; - - if ((ft & VT_BTYPE) == VT_LDOUBLE) { - /* swap the stack if needed so that t1 is the register and t2 is - the memory reference */ - /* must put at least one value in the floating point register */ - if ((vtop[-1].r & VT_LVAL) && (vtop[0].r & VT_LVAL)) { - vswap(); - gv(float_type); - vswap(); - } - if (vtop[-1].r & VT_LVAL) { - vswap(); - swapped = 1; - } + /* must put at least one value in the floating point register */ + if ((vtop[-1].r & VT_LVAL) && + (vtop[0].r & VT_LVAL)) { + vswap(); + gv(float_type); + vswap(); + } + swapped = 0; + /* swap the stack if needed so that t1 is the register and t2 is + the memory reference */ + if (vtop[-1].r & VT_LVAL) { + vswap(); + swapped = 1; + } + if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { if (op >= TOK_ULT && op <= TOK_GT) { /* load on stack second operand */ load(TREG_ST0, vtop); @@ -1802,10 +1782,10 @@ void gen_opf(int op) swapped = 0; if (swapped) o(0xc9d9); /* fxch %st(1) */ - if (op == TOK_EQ || op == TOK_NE) - o(0xe9da); /* fucompp */ - else - o(0xd9de); /* fcompp */ + if (op == TOK_EQ || op == TOK_NE) + o(0xe9da); /* fucompp */ + else + o(0xd9de); /* fcompp */ o(0xe0df); /* fnstsw %ax */ if (op == TOK_EQ) { o(0x45e480); /* and $0x45, %ah */ @@ -1828,6 +1808,7 @@ void gen_opf(int op) /* no memory reference possible for long double operations */ load(TREG_ST0, vtop); swapped = !swapped; + switch(op) { default: case '+': @@ -1847,45 +1828,63 @@ void gen_opf(int op) a++; break; } + ft = vtop->type.t; + fc = vtop->c.ul; o(0xde); /* fxxxp %st, %st(1) */ o(0xc1 + (a << 3)); vtop--; } } else { - vswap(); - gv(float_type); - vswap(); - fr = vtop->r; - r = vtop[-1].r; if (op >= TOK_ULT && op <= TOK_GT) { - switch(op){ - case TOK_LE: - op = TOK_ULE; /* setae */ - break; - case TOK_LT: - op = TOK_ULT; - break; - case TOK_GE: - op = TOK_UGE; - break; - case TOK_GT: - op = TOK_UGT; /* seta */ - break; - } - assert(!(vtop[-1].r & VT_LVAL)); - if ((ft & VT_BTYPE) == VT_DOUBLE) - o(0x66); - o(0x2e0f); /* ucomisd */ - if(fr >= VT_CONST) - gen_modrm(r, fr, vtop->sym, fc); - else - o(0xc0 + REG_VALUE(fr) + REG_VALUE(r)*8); + /* if saved lvalue, then we must reload it */ + r = vtop->r; + fc = vtop->c.ul; + if ((r & VT_VALMASK) == VT_LLOCAL) { + SValue v1; + r = get_reg(RC_INT); + v1.type.t = VT_PTR; + v1.r = VT_LOCAL | VT_LVAL; + v1.c.ul = fc; + load(r, &v1); + fc = 0; + } + + if (op == TOK_EQ || op == TOK_NE) { + swapped = 0; + } else { + if (op == TOK_LE || op == TOK_LT) + swapped = !swapped; + if (op == TOK_LE || op == TOK_GE) { + op = 0x93; /* setae */ + } else { + op = 0x97; /* seta */ + } + } + + if (swapped) { + gv(RC_FLOAT); + vswap(); + } + assert(!(vtop[-1].r & VT_LVAL)); + + if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) + o(0x66); + if (op == TOK_EQ || op == TOK_NE) + o(0x2e0f); /* ucomisd */ + else + o(0x2f0f); /* comisd */ + + if (vtop->r & VT_LVAL) { + gen_modrm(vtop[-1].r, r, vtop->sym, fc); + } else { + o(0xc0 + REG_VALUE(vtop[0].r) + REG_VALUE(vtop[-1].r)*8); + } + vtop--; vtop->r = VT_CMP; vtop->c.i = op | 0x100; } else { - assert((vtop->type.t & VT_BTYPE) != VT_LDOUBLE); - /* no memory reference possible for long double operations */ + assert((vtop->type.t & VT_BTYPE) != VT_LDOUBLE); switch(op) { default: case '+': @@ -1901,20 +1900,44 @@ void gen_opf(int op) a = 6; break; } - assert((ft & VT_BTYPE) != VT_LDOUBLE); - assert(!(vtop[-1].r & VT_LVAL)); - if ((ft & VT_BTYPE) == VT_DOUBLE) { - o(0xf2); - } else { - o(0xf3); - } - o(0x0f); - o(0x58 + a); - if(fr >= VT_CONST) - gen_modrm(r, fr, vtop->sym, fc); - else - o(0xc0 + REG_VALUE(fr) + REG_VALUE(r)*8); - vtop--; + ft = vtop->type.t; + fc = vtop->c.ul; + assert((ft & VT_BTYPE) != VT_LDOUBLE); + + r = vtop->r; + /* if saved lvalue, then we must reload it */ + if ((vtop->r & VT_VALMASK) == VT_LLOCAL) { + SValue v1; + r = get_reg(RC_INT); + v1.type.t = VT_PTR; + v1.r = VT_LOCAL | VT_LVAL; + v1.c.ul = fc; + load(r, &v1); + fc = 0; + } + + assert(!(vtop[-1].r & VT_LVAL)); + if (swapped) { + assert(vtop->r & VT_LVAL); + gv(RC_FLOAT); + vswap(); + } + + if ((ft & VT_BTYPE) == VT_DOUBLE) { + o(0xf2); + } else { + o(0xf3); + } + o(0x0f); + o(0x58 + a); + + if (vtop->r & VT_LVAL) { + gen_modrm(vtop[-1].r, r, vtop->sym, fc); + } else { + o(0xc0 + REG_VALUE(vtop[0].r) + REG_VALUE(vtop[-1].r)*8); + } + + vtop--; } } } @@ -1923,96 +1946,103 @@ void gen_opf(int op) and 'long long' cases. */ void gen_cvt_itof(int t) { - int ft, bt, tbt, r; - - ft = vtop->type.t; - bt = ft & VT_BTYPE; - tbt = t & VT_BTYPE; - r = gv(RC_INT); - - if (tbt == VT_LDOUBLE) { + if ((t & VT_BTYPE) == VT_LDOUBLE) { save_reg(TREG_ST0); - if ((ft & VT_BTYPE) == VT_LLONG) { + gv(RC_INT); + if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { /* signed long long to float/double/long double (unsigned case is handled generically) */ - o(0x50 + REG_VALUE(r)); /* push r */ + o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ o(0x242cdf); /* fildll (%rsp) */ o(0x08c48348); /* add $8, %rsp */ - } else if ((ft & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) { + } else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == + (VT_INT | VT_UNSIGNED)) { /* unsigned int to float/double/long double */ o(0x6a); /* push $0 */ g(0x00); - o(0x50 + REG_VALUE(r)); /* push r */ + o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ o(0x242cdf); /* fildll (%rsp) */ o(0x10c48348); /* add $16, %rsp */ } else { /* int to float/double/long double */ - o(0x50 + REG_VALUE(r)); /* push r */ + o(0x50 + (vtop->r & VT_VALMASK)); /* push r */ o(0x2404db); /* fildl (%rsp) */ o(0x08c48348); /* add $8, %rsp */ } vtop->r = TREG_ST0; } else { - int r_xmm; - r_xmm = get_reg(RC_FLOAT); - o(0xf2 + (tbt == VT_FLOAT)); - if ((ft & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED) || bt == VT_LLONG) { + int r = get_reg(RC_FLOAT); + gv(RC_INT); + o(0xf2 + ((t & VT_BTYPE) == VT_FLOAT?1:0)); + if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == + (VT_INT | VT_UNSIGNED) || + (vtop->type.t & VT_BTYPE) == VT_LLONG) { o(0x48); /* REX */ } o(0x2a0f); - o(0xc0 + REG_VALUE(r) + REG_VALUE(r_xmm)*8); /* cvtsi2sd or cvtsi2ss */ - vtop->r = r_xmm; + o(0xc0 + (vtop->r & VT_VALMASK) + REG_VALUE(r)*8); /* cvtsi2sd */ + vtop->r = r; } } /* convert from one floating point type to another */ void gen_cvt_ftof(int t) { - int ft, bt, tbt, r; + int ft, bt, tbt; ft = vtop->type.t; bt = ft & VT_BTYPE; tbt = t & VT_BTYPE; - - if(bt == VT_LDOUBLE) - r = get_reg(RC_FLOAT); - else - r = gv(RC_FLOAT); - if (bt == VT_FLOAT) { + + if (bt == VT_FLOAT) { + gv(RC_FLOAT); if (tbt == VT_DOUBLE) { + o(0x140f); /* unpcklps */ + o(0xc0 + REG_VALUE(vtop->r)*9); o(0x5a0f); /* cvtps2pd */ - o(0xc0 + REG_VALUE(r) + REG_VALUE(r) * 8); + o(0xc0 + REG_VALUE(vtop->r)*9); } else if (tbt == VT_LDOUBLE) { - /* movss %xmm0-7,-0x10(%rsp) */ + save_reg(RC_ST0); + /* movss %xmm0,-0x10(%rsp) */ o(0x110ff3); - o(0xf02444 + REG_VALUE(r)*8); + o(0x44 + REG_VALUE(vtop->r)*8); + o(0xf024); o(0xf02444d9); /* flds -0x10(%rsp) */ vtop->r = TREG_ST0; } } else if (bt == VT_DOUBLE) { + gv(RC_FLOAT); if (tbt == VT_FLOAT) { + o(0x140f66); /* unpcklpd */ + o(0xc0 + REG_VALUE(vtop->r)*9); o(0x5a0f66); /* cvtpd2ps */ - o(0xc0 + REG_VALUE(r) + REG_VALUE(r) * 8); + o(0xc0 + REG_VALUE(vtop->r)*9); } else if (tbt == VT_LDOUBLE) { - /* movsd %xmm0-7,-0x10(%rsp) */ + save_reg(RC_ST0); + /* movsd %xmm0,-0x10(%rsp) */ o(0x110ff2); - o(0xf02444 + REG_VALUE(r)*8); + o(0x44 + REG_VALUE(vtop->r)*8); + o(0xf024); o(0xf02444dd); /* fldl -0x10(%rsp) */ vtop->r = TREG_ST0; } } else { + int r; gv(RC_ST0); + r = get_reg(RC_FLOAT); if (tbt == VT_DOUBLE) { o(0xf0245cdd); /* fstpl -0x10(%rsp) */ - /* movsd -0x10(%rsp),%xmm0-7 */ + /* movsd -0x10(%rsp),%xmm0 */ o(0x100ff2); - o(0xf02444 + REG_VALUE(r)*8); + o(0x44 + REG_VALUE(r)*8); + o(0xf024); vtop->r = r; } else if (tbt == VT_FLOAT) { o(0xf0245cd9); /* fstps -0x10(%rsp) */ - /* movss -0x10(%rsp),%xmm0-7 */ + /* movss -0x10(%rsp),%xmm0 */ o(0x100ff3); - o(0xf02444 + REG_VALUE(r)*8); + o(0x44 + REG_VALUE(r)*8); + o(0xf024); vtop->r = r; } } @@ -2021,20 +2051,20 @@ void gen_cvt_ftof(int t) /* convert fp to int 't' type */ void gen_cvt_ftoi(int t) { - int ft, bt, ll, r, r_xmm; - + int ft, bt, size, r; ft = vtop->type.t; bt = ft & VT_BTYPE; - if (bt == VT_LDOUBLE) { gen_cvt_ftof(VT_DOUBLE); bt = VT_DOUBLE; } - r_xmm = gv(RC_FLOAT); - if ((t & VT_BTYPE) == VT_INT) - ll = 0; + + gv(RC_FLOAT); + if (t != VT_INT) + size = 8; else - ll = 1; + size = 4; + r = get_reg(RC_INT); if (bt == VT_FLOAT) { o(0xf3); @@ -2043,8 +2073,8 @@ void gen_cvt_ftoi(int t) } else { assert(0); } - orex(ll, r, r_xmm, 0x2c0f); /* cvttss2si or cvttsd2si */ - o(0xc0 + REG_VALUE(r_xmm) + (REG_VALUE(r) << 3)); + orex(size == 8, r, 0, 0x2c0f); /* cvttss2si or cvttsd2si */ + o(0xc0 + REG_VALUE(vtop->r) + REG_VALUE(r)*8); vtop->r = r; } @@ -2068,19 +2098,27 @@ ST_FUNC void gen_vla_sp_restore(int addr) { /* Subtract from the stack pointer, and push the resulting value onto the stack */ ST_FUNC void gen_vla_alloc(CType *type, int align) { +#ifdef TCC_TARGET_PE + /* alloca does more than just adjust %rsp on Windows */ + vpush_global_sym(&func_old_type, TOK_alloca); + vswap(); /* Move alloca ref past allocation size */ + gfunc_call(1); + vset(type, REG_IRET, 0); +#else int r; r = gv(RC_INT); /* allocation size */ /* sub r,%rsp */ o(0x2b48); o(0xe0 | REG_VALUE(r)); - /* and ~15, %rsp */ + /* We align to 16 bytes rather than align */ + /* and ~15, %rsp */ o(0xf0e48348); /* mov %rsp, r */ - orex(1, 0, r, 0x8d); - o(0x2484 | (REG_VALUE(r)*8)); - r_loc = reloc_add(r_loc); + o(0x8948); + o(0xe0 | REG_VALUE(r)); vpop(); vset(type, r, 0); +#endif } From 899d26605c5276964ac2ae1f8238a75a5afeb480 Mon Sep 17 00:00:00 2001 From: grischka Date: Tue, 6 May 2014 18:24:41 +0200 Subject: [PATCH 25/52] Revert "update static void parse_number()" because: - Constructing fp numbers isn't quite trivial - 3 additional calls to strchr per number is noticeable slow Also: exclude abitest.c:ret_longdouble_test2 on _WIN32 for mixed gcc/tcc scenario test case: - make -k test (on win32): -2.120000 0.500000 23000000000.000000 +2.120000 0.500000 22999999999.999996 ... ret_longdouble_test2... failure This reverts 857f7dbfa65179e6690dbee7ab915fb4458cee11 and deaee6c2496ecb25858290405fef8ef79aece979 --- tccpp.c | 396 ++++++++++++++++++++++++++++++------------------ tests/abitest.c | 3 + 2 files changed, 254 insertions(+), 145 deletions(-) diff --git a/tccpp.c b/tccpp.c index 732c5ea..2da65cd 100644 --- a/tccpp.c +++ b/tccpp.c @@ -58,6 +58,7 @@ static const int *unget_saved_macro_ptr; static int unget_saved_buffer[TOK_MAX_SIZE + 1]; static int unget_buffer_enabled; static TokenSym *hash_ident[TOK_HASH_SIZE]; +static char token_buf[STRING_MAX_SIZE + 1]; /* true if isid(c) || isnum(c) */ static unsigned char isidnum_table[256-CH_EOF]; @@ -1789,156 +1790,261 @@ static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long cstr_wccat(outstr, '\0'); } +/* we use 64 bit numbers */ +#define BN_SIZE 2 + +/* bn = (bn << shift) | or_val */ +static void bn_lshift(unsigned int *bn, int shift, int or_val) +{ + int i; + unsigned int v; + for(i=0;i> (32 - shift); + } +} + +static void bn_zero(unsigned int *bn) +{ + int i; + for(i=0;i= 'a' && c <= 'f') - t = c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - t = c - 'A' + 10; - else if(isnum(c)) - t = c - '0'; - else - break; - if (t >= b) - tcc_error("invalid digit"); - ld = ld * b + t; - c = *p++; - } - if (c == '.'){ - c = *p++; - sh = fb; - while (1){ - if (c == '\0') - break; - if (c >= 'a' && c <= 'f') - t = c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - t = c - 'A' + 10; - else if (isnum(c)) - t =c - '0'; - else - break; - if (t >= b){ - if(b == 10 && (c == 'e' || c == 'E' || c == 'f' || c == 'F')) - break; - tcc_error("invalid digit"); - } - ld += sh*t; - sh*=fb; - c = *p++; - } - } - if ((b == 16 || b == 2) && c != 'p' && c != 'P') - expect("exponent"); - if(((c == 'e' || c == 'E') && b == 10) || - ((c == 'p' || c == 'P') && (b == 16 || b == 2))){ - c = *p++; - if(c == '+' || c == '-'){ - if (c == '-') - sh = fb; - c = *p++; - }else - sh = b; - if (!isnum(c)) - expect("exponent digits"); - exp = 0; - do{ - exp = exp * 10 + c - '0'; - c = *p++; - }while(isnum(c)); - while (exp != 0){ - if (exp & 1) - ld *= sh; - exp >>= 1; - sh *= sh; - } - } - t = toup(c); - if (t == 'F') { - c = *p++; - tok = TOK_CFLOAT; - tokc.f = (float)ld; - } else if (t == 'L') { - c = *p++; -#ifdef TCC_TARGET_PE - tok = TOK_CDOUBLE; - tokc.d = (double)ld; -#else - tok = TOK_CLDOUBLE; - tokc.ld = ld; -#endif - } else { - tok = TOK_CDOUBLE; - tokc.d = (double)ld; - } - } else { - uint64_t n = 0, n1; - int warn = 1; - int lcount, ucount; - if (b == 10 && c == '0') { - b = 8; } - while(1){ - if (c == '\0') - break; - if (c >= 'a' && c <= 'f') - t = c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - t = c - 'A' + 10; - else if(isnum(c)) - t = c - '0'; - else - break; - if (t >= b) - tcc_error("invalid digit"); - n1 = n; - n = n * b + t; - if (n < n1 && warn){ - tcc_warning("integer constant overflow"); - warn = 0; - } - c = *p++; - } + } + /* parse all digits. cannot check octal numbers at this stage + because of floating point constants */ + while (1) { + if (ch >= 'a' && ch <= 'f') + t = ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') + t = ch - 'A' + 10; + else if (isnum(ch)) + t = ch - '0'; + else + break; + if (t >= b) + break; + if (q >= token_buf + STRING_MAX_SIZE) { + num_too_long: + tcc_error("number too long"); + } + *q++ = ch; + ch = *p++; + } + if (ch == '.' || + ((ch == 'e' || ch == 'E') && b == 10) || + ((ch == 'p' || ch == 'P') && (b == 16 || b == 2))) { + if (b != 10) { + /* NOTE: strtox should support that for hexa numbers, but + non ISOC99 libcs do not support it, so we prefer to do + it by hand */ + /* hexadecimal or binary floats */ + /* XXX: handle overflows */ + *q = '\0'; + if (b == 16) + shift = 4; + else + shift = 2; + bn_zero(bn); + q = token_buf; + while (1) { + t = *q++; + if (t == '\0') { + break; + } else if (t >= 'a') { + t = t - 'a' + 10; + } else if (t >= 'A') { + t = t - 'A' + 10; + } else { + t = t - '0'; + } + bn_lshift(bn, shift, t); + } + frac_bits = 0; + if (ch == '.') { + ch = *p++; + while (1) { + t = ch; + if (t >= 'a' && t <= 'f') { + t = t - 'a' + 10; + } else if (t >= 'A' && t <= 'F') { + t = t - 'A' + 10; + } else if (t >= '0' && t <= '9') { + t = t - '0'; + } else { + break; + } + if (t >= b) + tcc_error("invalid digit"); + bn_lshift(bn, shift, t); + frac_bits += shift; + ch = *p++; + } + } + if (ch != 'p' && ch != 'P') + expect("exponent"); + ch = *p++; + s = 1; + exp_val = 0; + if (ch == '+') { + ch = *p++; + } else if (ch == '-') { + s = -1; + ch = *p++; + } + if (ch < '0' || ch > '9') + expect("exponent digits"); + while (ch >= '0' && ch <= '9') { + exp_val = exp_val * 10 + ch - '0'; + ch = *p++; + } + exp_val = exp_val * s; + + /* now we can generate the number */ + /* XXX: should patch directly float number */ + d = (double)bn[1] * 4294967296.0 + (double)bn[0]; + d = ldexp(d, exp_val - frac_bits); + t = toup(ch); + if (t == 'F') { + ch = *p++; + tok = TOK_CFLOAT; + /* float : should handle overflow */ + tokc.f = (float)d; + } else if (t == 'L') { + ch = *p++; +#ifdef TCC_TARGET_PE + tok = TOK_CDOUBLE; + tokc.d = d; +#else + tok = TOK_CLDOUBLE; + /* XXX: not large enough */ + tokc.ld = (long double)d; +#endif + } else { + tok = TOK_CDOUBLE; + tokc.d = d; + } + } else { + /* decimal floats */ + if (ch == '.') { + if (q >= token_buf + STRING_MAX_SIZE) + goto num_too_long; + *q++ = ch; + ch = *p++; + float_frac_parse: + while (ch >= '0' && ch <= '9') { + if (q >= token_buf + STRING_MAX_SIZE) + goto num_too_long; + *q++ = ch; + ch = *p++; + } + } + if (ch == 'e' || ch == 'E') { + if (q >= token_buf + STRING_MAX_SIZE) + goto num_too_long; + *q++ = ch; + ch = *p++; + if (ch == '-' || ch == '+') { + if (q >= token_buf + STRING_MAX_SIZE) + goto num_too_long; + *q++ = ch; + ch = *p++; + } + if (ch < '0' || ch > '9') + expect("exponent digits"); + while (ch >= '0' && ch <= '9') { + if (q >= token_buf + STRING_MAX_SIZE) + goto num_too_long; + *q++ = ch; + ch = *p++; + } + } + *q = '\0'; + t = toup(ch); + errno = 0; + if (t == 'F') { + ch = *p++; + tok = TOK_CFLOAT; + tokc.f = strtof(token_buf, NULL); + } else if (t == 'L') { + ch = *p++; +#ifdef TCC_TARGET_PE + tok = TOK_CDOUBLE; + tokc.d = strtod(token_buf, NULL); +#else + tok = TOK_CLDOUBLE; + tokc.ld = strtold(token_buf, NULL); +#endif + } else { + tok = TOK_CDOUBLE; + tokc.d = strtod(token_buf, NULL); + } + } + } else { + unsigned long long n, n1; + int lcount, ucount; + + /* integer number */ + *q = '\0'; + q = token_buf; + if (b == 10 && *q == '0') { + b = 8; + q++; + } + n = 0; + while(1) { + t = *q++; + /* no need for checks except for base 10 / 8 errors */ + if (t == '\0') { + break; + } else if (t >= 'a') { + t = t - 'a' + 10; + } else if (t >= 'A') { + t = t - 'A' + 10; + } else { + t = t - '0'; + if (t >= b) + tcc_error("invalid digit"); + } + n1 = n; + n = n * b + t; + /* detect overflow */ + /* XXX: this test is not reliable */ + if (n < n1) + tcc_error("integer constant overflow"); + } + /* XXX: not exactly ANSI compliant */ if ((n & 0xffffffff00000000LL) != 0) { if ((n >> 63) != 0) @@ -1953,7 +2059,7 @@ float_frac_parse: lcount = 0; ucount = 0; for(;;) { - t = toup(c); + t = toup(ch); if (t == 'L') { if (lcount >= 2) tcc_error("three 'l's in integer constant"); @@ -1968,7 +2074,7 @@ float_frac_parse: #if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE } #endif - c = *p++; + ch = *p++; } else if (t == 'U') { if (ucount >= 1) tcc_error("two 'u's in integer constant"); @@ -1977,7 +2083,7 @@ float_frac_parse: tok = TOK_CUINT; else if (tok == TOK_CLLONG) tok = TOK_CULLONG; - c = *p++; + ch = *p++; } else { break; } @@ -1987,7 +2093,7 @@ float_frac_parse: else tokc.ull = n; } - if (c) + if (ch) tcc_error("invalid number\n"); } diff --git a/tests/abitest.c b/tests/abitest.c index 3ad707a..e2978b0 100644 --- a/tests/abitest.c +++ b/tests/abitest.c @@ -486,7 +486,10 @@ int main(int argc, char **argv) { RUN_TEST(ret_2float_test); RUN_TEST(ret_2double_test); RUN_TEST(ret_longlong_test2); +#if !defined _WIN32 || !defined __GNUC__ + /* on win32, 'long double' is 10-byte with gcc, but is 'double' with tcc/msvc */ RUN_TEST(ret_longdouble_test2); +#endif RUN_TEST(reg_pack_test); RUN_TEST(reg_pack_longlong_test); RUN_TEST(sret_test); From ad787abea6d4e6ee0717c4e791d10b1f6281e91d Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Thu, 8 May 2014 15:39:50 +0800 Subject: [PATCH 26/52] fix bug if (seen_reg_num + reg_count <= 8) --- x86_64-gen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x86_64-gen.c b/x86_64-gen.c index ae65328..625bb4f 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -1404,7 +1404,7 @@ void gfunc_prolog(CType *func_type) break; case x86_64_mode_integer: - if (seen_reg_num + reg_count <= 8) { + if (seen_reg_num + reg_count <= REGN) { seen_reg_num += reg_count; } else { seen_reg_num = 8; From 0f51ccd4e4152e920f01d1dcbdecfd8fb62cb57c Mon Sep 17 00:00:00 2001 From: grischka Date: Thu, 8 May 2014 17:32:29 +0200 Subject: [PATCH 27/52] win64: try to fix linkage - revert to R_X86_64_PC32 for near calls on PE - revert to s1->section_align set to zero by default Untested. Compared to release_0_9_26 the pe-image looks back to normal. There are some differences in dissassembly (r10/r11 usage) but maybe that's ok. --- libtcc.c | 1 - tccelf.c | 30 ++++++++++++++++-------------- x86_64-gen.c | 10 +++++++--- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/libtcc.c b/libtcc.c index deda7e6..7caa7c1 100644 --- a/libtcc.c +++ b/libtcc.c @@ -1033,7 +1033,6 @@ LIBTCCAPI TCCState *tcc_new(void) ".dynhashtab", SHF_PRIVATE); s->alacarte_link = 1; s->nocommon = 1; - s->section_align = ELF_PAGE_SIZE; #ifdef CHAR_IS_UNSIGNED s->char_is_unsigned = 1; diff --git a/tccelf.c b/tccelf.c index f0ed22b..2fbe692 100644 --- a/tccelf.c +++ b/tccelf.c @@ -1596,7 +1596,7 @@ ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel) put32(s1->got->data + offset, sym->st_value & 0xffffffff); } -/* Perform relocation to GOT or PLT entries */ +/* Perform relocation to GOT or PLT entries */ ST_FUNC void fill_got(TCCState *s1) { Section *s; @@ -1848,6 +1848,7 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, int *sec_order) { int i, j, k, file_type, sh_order_index, file_offset; + unsigned long s_align; long long tmp; addr_t addr; ElfW(Phdr) *ph; @@ -1855,10 +1856,12 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, file_type = s1->output_type; sh_order_index = 1; + file_offset = 0; if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) file_offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); - else - file_offset = 0; + s_align = ELF_PAGE_SIZE; + if (s1->section_align) + s_align = s1->section_align; if (phnum > 0) { if (s1->has_text_addr) { @@ -1866,10 +1869,10 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, addr = s1->text_addr; /* we ensure that (addr % ELF_PAGE_SIZE) == file_offset % ELF_PAGE_SIZE */ - a_offset = (int) (addr & (s1->section_align - 1)); - p_offset = file_offset & (s1->section_align - 1); + a_offset = (int) (addr & (s_align - 1)); + p_offset = file_offset & (s_align - 1); if (a_offset < p_offset) - a_offset += s1->section_align; + a_offset += s_align; file_offset += (a_offset - p_offset); } else { if (file_type == TCC_OUTPUT_DLL) @@ -1877,7 +1880,7 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, else addr = ELF_START_ADDR; /* compute address after headers */ - addr += (file_offset & (s1->section_align - 1)); + addr += (file_offset & (s_align - 1)); } ph = &phdr[0]; @@ -1899,7 +1902,7 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, ph->p_flags = PF_R | PF_X; else ph->p_flags = PF_R | PF_W; - ph->p_align = s1->section_align; + ph->p_align = s_align; /* Decide the layout of sections loaded in memory. This must be done before program headers are filled since they contain @@ -1991,12 +1994,11 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { /* if in the middle of a page, we duplicate the page in memory so that one copy is RX and the other is RW */ - if ((addr & (s1->section_align - 1)) != 0) - addr += s1->section_align; + if ((addr & (s_align - 1)) != 0) + addr += s_align; } else { - addr = (addr + s1->section_align - 1) & ~(s1->section_align - 1); - file_offset = (file_offset + s1->section_align - 1) & - ~(s1->section_align - 1); + addr = (addr + s_align - 1) & ~(s_align - 1); + file_offset = (file_offset + s_align - 1) & ~(s_align - 1); } } } @@ -2469,7 +2471,7 @@ static int elf_output_file(TCCState *s1, const char *filename) goto the_end; } - /* Perform relocation to GOT or PLT entries */ + /* Perform relocation to GOT or PLT entries */ if (file_type == TCC_OUTPUT_EXE && s1->static_link) fill_got(s1); diff --git a/x86_64-gen.c b/x86_64-gen.c index 625bb4f..c9829f0 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -288,7 +288,8 @@ static void gen_gotpcrel(int r, Sym *sym, int c) rel = (ElfW(Rela) *)(sr->data + sr->data_offset - sizeof(ElfW(Rela))); rel->r_addend = -4; #else - printf("picpic: %s %x %x | %02x %02x %02x\n", get_tok_str(sym->v, NULL), c, r, + tcc_error("internal error: no GOT on PE: %s %x %x | %02x %02x %02x\n", + get_tok_str(sym->v, NULL), c, r, cur_text_section->data[ind-3], cur_text_section->data[ind-2], cur_text_section->data[ind-1] @@ -603,8 +604,11 @@ static void gcall_or_jmp(int is_jmp) /* constant case */ if (vtop->r & VT_SYM) { /* relocation case */ - greloc(cur_text_section, vtop->sym, - ind + 1, R_X86_64_PLT32); +#ifdef TCC_TARGET_PE + greloc(cur_text_section, vtop->sym, ind + 1, R_X86_64_PC32); +#else + greloc(cur_text_section, vtop->sym, ind + 1, R_X86_64_PLT32); +#endif } else { /* put an empty PC32 relocation */ put_elf_reloc(symtab_section, cur_text_section, From 14d0aa450f9a926a852ea01fbdecf27425264d14 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Fri, 9 May 2014 22:35:19 +0800 Subject: [PATCH 28/52] Add warning For example: struct A { int b []; }; --- tccgen.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tccgen.c b/tccgen.c index 1a89d4a..c37e27b 100644 --- a/tccgen.c +++ b/tccgen.c @@ -3030,6 +3030,8 @@ static void struct_decl(CType *type, int u, int tdef) skip(';'); } skip('}'); + if (!c && flexible) + tcc_error("flexible array member '%s' in otherwise empty struct", get_tok_str(v, NULL)); /* store size and alignment */ s->c = (c + maxalign - 1) & -maxalign; s->r = maxalign; From 03687729ecd22de41575f9f6404f107fbfe54b66 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Fri, 9 May 2014 22:41:45 +0800 Subject: [PATCH 29/52] Add warning 2 For example: struct A { int b: 16; int c: 16 }; sizeof (struct A); --- tccgen.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tccgen.c b/tccgen.c index c37e27b..c823d42 100644 --- a/tccgen.c +++ b/tccgen.c @@ -3795,6 +3795,8 @@ ST_FUNC void unary(void) if (!(type.t & VT_VLA)) { if (size < 0) tcc_error("sizeof applied to an incomplete type"); + if(type.t & VT_BITFIELD) + tcc_error("'%s' applied to a bit-field", get_tok_str(t, NULL)); vpushs(size); } else { vla_runtime_type_size(&type, &align); From 8d5e0cf083f2cf931b8ab616ec67c9003ae65d11 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Tue, 13 May 2014 21:57:35 +0800 Subject: [PATCH 30/52] fix 14d0aa450f9a926a852ea01fbdecf27425264d14 --- tccgen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tccgen.c b/tccgen.c index c823d42..4cc9543 100644 --- a/tccgen.c +++ b/tccgen.c @@ -2911,7 +2911,7 @@ static void struct_decl(CType *type, int u, int tdef) if (v == 0 && (type1.t & VT_BTYPE) != VT_STRUCT) expect("identifier"); if (type_size(&type1, &align) < 0) { - if ((a == TOK_STRUCT) && (type1.t & VT_ARRAY) && c) + if ((a == TOK_STRUCT) && (type1.t & VT_ARRAY)) flexible = 1; else tcc_error("field '%s' has incomplete type", From 72f466c24c5347516ca5a81221e29129dafe1c63 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Tue, 13 May 2014 22:00:42 +0800 Subject: [PATCH 31/52] Modify tcc_error ("invalid type",); --- tccgen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tccgen.c b/tccgen.c index 4cc9543..0937883 100644 --- a/tccgen.c +++ b/tccgen.c @@ -2839,7 +2839,7 @@ static void struct_decl(CType *type, int u, int tdef) s = struct_find(v); if (s) { if (s->type.t != a) - tcc_error("invalid type"); + tcc_error("invalid type: '%s'", get_tok_str(v, NULL)); goto do_decl; } else if (tok >= TOK_IDENT && !tdef) tcc_error("unknown struct/union/enum"); From c6345b5a8af36d5577307860644010b1528257d3 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Tue, 13 May 2014 22:05:38 +0800 Subject: [PATCH 32/52] restore 2dd8587c2f32d17a2cd0443a60a614a3fa9bbe29 --- libtcc.c | 6 +- tcc.h | 12 +- tccgen.c | 6 +- tccpp.c | 302 ++++++++++++++++++++++++++++++++---------------- tcctok.h | 2 + tests/tcctest.c | 31 ++++- 6 files changed, 248 insertions(+), 111 deletions(-) diff --git a/libtcc.c b/libtcc.c index 7caa7c1..4bb7f1b 100644 --- a/libtcc.c +++ b/libtcc.c @@ -868,6 +868,7 @@ LIBTCCAPI void tcc_undefine_symbol(TCCState *s1, const char *sym) static void tcc_cleanup(void) { int i, n; + CSym *def; if (NULL == tcc_state) return; tcc_state = NULL; @@ -877,8 +878,11 @@ static void tcc_cleanup(void) /* free tokens */ n = tok_ident - TOK_IDENT; - for(i = 0; i < n; i++) + for(i = 0; i < n; i++){ + def = &table_ident[i]->sym_define; + tcc_free(def->data); tcc_free(table_ident[i]); + } tcc_free(table_ident); /* free sym_pools */ diff --git a/tcc.h b/tcc.h index c93cedf..c49eac4 100644 --- a/tcc.h +++ b/tcc.h @@ -303,15 +303,22 @@ #define VSTACK_SIZE 256 #define STRING_MAX_SIZE 1024 #define PACK_STACK_SIZE 8 +#define MACRO_STACK_SIZE 4 #define TOK_HASH_SIZE 8192 /* must be a power of two */ #define TOK_ALLOC_INCR 512 /* must be a power of two */ #define TOK_MAX_SIZE 4 /* token max size in int unit when stored in string */ +typedef struct CSym { + int off; + int size;/* size in *sym */ + struct Sym **data; /* if non NULL, data has been malloced */ +} CSym; + /* token symbol management */ typedef struct TokenSym { struct TokenSym *hash_next; - struct Sym *sym_define; /* direct pointer to define */ + struct CSym sym_define; /* direct pointer to define */ struct Sym *sym_label; /* direct pointer to label */ struct Sym *sym_struct; /* direct pointer to structure */ struct Sym *sym_identifier; /* direct pointer to identifier */ @@ -1124,7 +1131,8 @@ ST_DATA TokenSym **table_ident; token. line feed is also returned at eof */ #define PARSE_FLAG_ASM_COMMENTS 0x0008 /* '#' can be used for line comment */ -#define PARSE_FLAG_SPACES 0x0010 /* next() returns space tokens (for -E) */ +#define PARSE_FLAG_SPACES 0x0010 /* next() returns space tokens (for -E) */ +#define PARSE_FLAG_PACK 0x0020 /* #pragma pack */ ST_FUNC TokenSym *tok_alloc(const char *str, int len); ST_FUNC char *get_tok_str(int v, CValue *cv); diff --git a/tccgen.c b/tccgen.c index 0937883..db821e1 100644 --- a/tccgen.c +++ b/tccgen.c @@ -5234,13 +5234,13 @@ static void init_putz(CType *t, Section *sec, unsigned long c, int size) } else { vpush_global_sym(&func_old_type, TOK_memset); vseti(VT_LOCAL, c); -#ifdef TCC_TARGET_ARM +# ifdef TCC_TARGET_ARM vpushs(size); vpushi(0); -#else +# else vpushi(0); vpushs(size); -#endif +# endif gfunc_call(3); } } diff --git a/tccpp.c b/tccpp.c index 2da65cd..9947171 100644 --- a/tccpp.c +++ b/tccpp.c @@ -234,7 +234,10 @@ static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len) ts = tcc_malloc(sizeof(TokenSym) + len); table_ident[i] = ts; ts->tok = tok_ident++; - ts->sym_define = NULL; + ts->sym_define.data = tcc_malloc(sizeof(Sym**)); + ts->sym_define.off = 0; + ts->sym_define.data[0] = NULL; + ts->sym_define.size = 1; ts->sym_label = NULL; ts->sym_struct = NULL; ts->sym_identifier = NULL; @@ -1053,52 +1056,62 @@ static int macro_is_equal(const int *a, const int *b) ST_INLN void define_push(int v, int macro_type, int *str, Sym *first_arg) { Sym *s; - + CSym *def; s = define_find(v); if (s && !macro_is_equal(s->d, str)) tcc_warning("%s redefined", get_tok_str(v, NULL)); - s = sym_push2(&define_stack, v, macro_type, 0); s->d = str; s->next = first_arg; - table_ident[v - TOK_IDENT]->sym_define = s; + def = &table_ident[v - TOK_IDENT]->sym_define; + def->data[def->off] = s; } /* undefined a define symbol. Its name is just set to zero */ ST_FUNC void define_undef(Sym *s) { int v; - v = s->v; - if (v >= TOK_IDENT && v < tok_ident) - table_ident[v - TOK_IDENT]->sym_define = NULL; - s->v = 0; + CSym *def; + v = s->v - TOK_IDENT; + if ((unsigned)v < (unsigned)(tok_ident - TOK_IDENT)){ + def = &table_ident[v]->sym_define; + def->data[def->off] = NULL; + } } ST_INLN Sym *define_find(int v) { + CSym *def; v -= TOK_IDENT; if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) return NULL; - return table_ident[v]->sym_define; + def = &table_ident[v]->sym_define; + return def->data[def->off]; } /* free define stack until top reaches 'b' */ ST_FUNC void free_defines(Sym *b) { - Sym *top, *top1; + Sym *top, *tmp; int v; + CSym *def; top = define_stack; while (top != b) { - top1 = top->prev; + tmp = top->prev; /* do not free args or predefined defines */ if (top->d) tok_str_free(top->d); - v = top->v; - if (v >= TOK_IDENT && v < tok_ident) - table_ident[v - TOK_IDENT]->sym_define = NULL; + v = top->v - TOK_IDENT; + if ((unsigned)v < (unsigned)(tok_ident - TOK_IDENT)){ + def = &table_ident[v]->sym_define; + if(def->off) + def->off = 0; + if(def->data[0]) + def->data[0] = NULL; + } sym_free(top); - top = top1; + top = tmp; } define_stack = b; } @@ -1339,66 +1352,18 @@ static inline void add_cached_include(TCCState *s1, const char *filename, int if s1->cached_includes_hash[h] = s1->nb_cached_includes; } -static void pragma_parse(TCCState *s1) -{ - int val; - - next(); - if (tok == TOK_pack) { - /* - This may be: - #pragma pack(1) // set - #pragma pack() // reset to default - #pragma pack(push,1) // push & set - #pragma pack(pop) // restore previous - */ - next(); - skip('('); - if (tok == TOK_ASM_pop) { - next(); - if (s1->pack_stack_ptr <= s1->pack_stack) { - stk_error: - tcc_error("out of pack stack"); - } - s1->pack_stack_ptr--; - } else { - val = 0; - if (tok != ')') { - if (tok == TOK_ASM_push) { - next(); - if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE - 1) - goto stk_error; - s1->pack_stack_ptr++; - skip(','); - } - if (tok != TOK_CINT) { - pack_error: - tcc_error("invalid pack pragma"); - } - val = tokc.i; - if (val < 1 || val > 16 || (val & (val - 1)) != 0) - goto pack_error; - next(); - } - *s1->pack_stack_ptr = val; - skip(')'); - } - } -} - /* is_bof is true if first non space token at beginning of file */ ST_FUNC void preprocess(int is_bof) { TCCState *s1 = tcc_state; int i, c, n, saved_parse_flags; - char buf[1024], *q; + uint8_t buf[1024], *p; Sym *s; saved_parse_flags = parse_flags; - parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | - PARSE_FLAG_LINEFEED; + parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | PARSE_FLAG_LINEFEED; next_nomacro(); - redo: +redo: switch(tok) { case TOK_DEFINE: next_nomacro(); @@ -1421,19 +1386,21 @@ ST_FUNC void preprocess(int is_bof) goto read_name; } else if (ch == '\"') { c = ch; - read_name: +read_name: inp(); - q = buf; + p = buf; while (ch != c && ch != '\n' && ch != CH_EOF) { - if ((q - buf) < sizeof(buf) - 1) - *q++ = ch; + if ((p - buf) < sizeof(buf) - 1) + *p++ = ch; if (ch == '\\') { if (handle_stray_noerror() == 0) - --q; + --p; } else inp(); } - *q = '\0'; + if (ch != c) + goto include_syntax; + *p = '\0'; minp(); #if 0 /* eat all spaces and comments after include */ @@ -1471,6 +1438,8 @@ ST_FUNC void preprocess(int is_bof) c = '>'; } } + if(!buf[0]) + tcc_error(" empty filename in #include"); if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE) tcc_error("#include recursion too deep"); @@ -1537,8 +1506,7 @@ include_trynext: printf("%s: including %s\n", file->prev->filename, file->filename); #endif /* update target deps */ - dynarray_add((void ***)&s1->target_deps, &s1->nb_target_deps, - tcc_strdup(buf1)); + dynarray_add((void ***)&s1->target_deps, &s1->nb_target_deps, tcc_strdup(buf1)); /* push current file in stack */ ++s1->include_stack_ptr; /* add include file debug info */ @@ -1571,7 +1539,7 @@ include_done: file->ifndef_macro = tok; } } - c = (define_find(tok) != 0) ^ c; + c = !!define_find(tok) ^ c; do_if: if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE) tcc_error("memory full (ifdef)"); @@ -1595,12 +1563,12 @@ include_done: goto skip; c = expr_preprocess(); s1->ifdef_stack_ptr[-1] = c; - test_else: +test_else: if (s1->ifdef_stack_ptr == file->ifdef_stack_ptr + 1) file->ifndef_macro = 0; - test_skip: +test_skip: if (!(c & 1)) { - skip: +skip: preprocess_skip(); is_bof = 0; goto redo; @@ -1618,11 +1586,11 @@ include_done: /* need to set to zero to avoid false matches if another #ifndef at middle of file */ file->ifndef_macro = 0; - while (tok != TOK_LINEFEED) - next_nomacro(); tok_flags |= TOK_FLAG_ENDIF; - goto the_end; } + next_nomacro(); + if (tok != TOK_LINEFEED) + tcc_warning("Ignoring: %s", get_tok_str(tok, &tokc)); break; case TOK_LINE: next(); @@ -1633,8 +1601,7 @@ include_done: if (tok != TOK_LINEFEED) { if (tok != TOK_STR) tcc_error("#line"); - pstrcpy(file->filename, sizeof(file->filename), - (char *)tokc.cstr->data); + pstrcpy(file->filename, sizeof(file->filename), (char *)tokc.cstr->data); } break; case TOK_ERROR: @@ -1642,24 +1609,161 @@ include_done: c = tok; ch = file->buf_ptr[0]; skip_spaces(); - q = buf; + p = buf; while (ch != '\n' && ch != CH_EOF) { - if ((q - buf) < sizeof(buf) - 1) - *q++ = ch; + if ((p - buf) < sizeof(buf) - 1) + *p++ = ch; if (ch == '\\') { if (handle_stray_noerror() == 0) - --q; + --p; } else inp(); } - *q = '\0'; + *p = '\0'; if (c == TOK_ERROR) tcc_error("#error %s", buf); else tcc_warning("#warning %s", buf); break; case TOK_PRAGMA: - pragma_parse(s1); + next(); + if (tok == TOK_pack && parse_flags & PARSE_FLAG_PACK) { + /* + This may be: + #pragma pack(1) // set + #pragma pack() // reset to default + #pragma pack(push,1) // push & set + #pragma pack(pop) // restore previous + */ + next(); + skip('('); + if (tok == TOK_ASM_pop) { + next(); + if (s1->pack_stack_ptr <= s1->pack_stack) { +stk_error: + tcc_error("out of pack stack"); + } + s1->pack_stack_ptr--; + } else { + int val = 0; + if (tok != ')') { + if (tok == TOK_ASM_push) { + next(); + s1->pack_stack_ptr++; + if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE) + goto stk_error; + skip(','); + } + if (tok != TOK_CINT) { +pack_error: + tcc_error("invalid pack pragma"); + } + val = tokc.i; + if (val < 1 || val > 16) + goto pack_error; + if (val < 1 || val > 16) + tcc_error("Value must be greater than 1 is less than or equal to 16"); + if ((val & (val - 1)) != 0) + tcc_error("Value must be a power of 2 curtain"); + next(); + } + *s1->pack_stack_ptr = val; + skip(')'); + } + }else if (tok == TOK_PUSH_MACRO || tok == TOK_POP_MACRO) { + TokenSym *ts; + CSym *def; + uint8_t *p1; + int len, t; + t = tok; + ch = file->buf_ptr[0]; + skip_spaces(); + if (ch != '(') + goto macro_xxx_syntax; + /* XXX: incorrect if comments : use next_nomacro with a special mode */ + inp(); + skip_spaces(); + if (ch == '\"'){ + inp(); + p = buf; + while (ch != '\"' && ch != '\n' && ch != CH_EOF) { + if ((p - buf) < sizeof(buf) - 1) + *p++ = ch; + if (ch == CH_EOB) { + --p; + handle_stray(); + }else + inp(); + } + if(ch != '\"') + goto macro_xxx_syntax; + *p = '\0'; + minp(); + next(); + }else{ + /* computed #pragma macro_xxx for #define xxx */ + next(); + buf[0] = '\0'; + while (tok != ')') { + if (tok != TOK_STR) { + macro_xxx_syntax: + tcc_error("'macro_xxx' expects (\"NAME\")"); + } + pstrcat(buf, sizeof(buf), (char *)tokc.cstr->data); + next(); + } + } + skip (')'); + if(!buf[0]) + tcc_error(" empty string in #pragma"); + /* find TokenSym */ + p = buf; + while (is_space(*p)) + p++; + p1 = p; + for(;;){ + if (!isidnum_table[p[0] - CH_EOF]) + break; + ++p; + } + len = p - p1; + while (is_space(*p)) + p++; + if(!p) //'\0' + tcc_error("unrecognized string: %s", buf); + ts = tok_alloc(p1, len); + if(ts){ + def = &ts->sym_define; + if(t == TOK_PUSH_MACRO){ + void *tmp = def->data[def->off]; + if(tmp){ + def->off++; + if(def->off >= def->size){ + int size = def->size; + size *= 2; + if (size >= MACRO_STACK_SIZE) + tcc_error("stack full"); + def->data = tcc_realloc(def->data, size*sizeof(Sym**)); + def->size = size; + } + def->data[def->off] = tmp; + } + }else{ + if(def->off){ + --def->off; + }else{ + tcc_warning("stack empty"); + } + } + } + }else{ + fputs("#pragma ", s1->ppfp); + while (tok != TOK_LINEFEED){ + fputs(get_tok_str(tok, &tokc), s1->ppfp); + next(); + } + goto the_end; + } break; default: if (tok == TOK_LINEFEED || tok == '!' || tok == TOK_PPNUM) { @@ -1679,7 +1783,7 @@ include_done: /* ignore other preprocess commands or #! for C scripts */ while (tok != TOK_LINEFEED) next_nomacro(); - the_end: +the_end: parse_flags = saved_parse_flags; } @@ -3136,12 +3240,13 @@ ST_FUNC int tcc_preprocess(TCCState *s1) ch = file->buf_ptr[0]; tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; parse_flags = PARSE_FLAG_ASM_COMMENTS | PARSE_FLAG_PREPROCESS | - PARSE_FLAG_LINEFEED | PARSE_FLAG_SPACES; + PARSE_FLAG_LINEFEED | PARSE_FLAG_SPACES; token_seen = 0; line_ref = 0; file_ref = NULL; iptr = s1->include_stack_ptr; - + tok = TOK_LINEFEED; /* print line */ + goto print_line; for (;;) { next(); if (tok == TOK_EOF) { @@ -3149,11 +3254,11 @@ ST_FUNC int tcc_preprocess(TCCState *s1) } else if (file != file_ref) { goto print_line; } else if (tok == TOK_LINEFEED) { - if (!token_seen) + if (token_seen) continue; ++line_ref; - token_seen = 0; - } else if (!token_seen) { + token_seen = 1; + } else if (token_seen) { d = file->line_num - line_ref; if (file != file_ref || d < 0 || d >= 8) { print_line: @@ -3161,8 +3266,7 @@ print_line: s = iptr_new > iptr ? " 1" : iptr_new < iptr ? " 2" : iptr_new > s1->include_stack ? " 3" - : "" - ; + : ""; iptr = iptr_new; fprintf(s1->ppfp, "# %d \"%s\"%s\n", file->line_num, file->filename, s); } else { @@ -3170,8 +3274,8 @@ print_line: fputs("\n", s1->ppfp), --d; } line_ref = (file_ref = file)->line_num; - token_seen = tok != TOK_LINEFEED; - if (!token_seen) + token_seen = tok == TOK_LINEFEED; + if (token_seen) continue; } fputs(get_tok_str(tok, &tokc), s1->ppfp); diff --git a/tcctok.h b/tcctok.h index 735ccdd..41a8840 100644 --- a/tcctok.h +++ b/tcctok.h @@ -138,6 +138,8 @@ /* pragma */ DEF(TOK_pack, "pack") + DEF(TOK_PUSH_MACRO, "push_macro") + DEF(TOK_POP_MACRO, "pop_macro") #if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64) /* already defined for assembler */ DEF(TOK_ASM_push, "push") diff --git a/tests/tcctest.c b/tests/tcctest.c index cc8ffd8..ee4a0e6 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -235,7 +235,7 @@ void intdiv_test(void) void macro_test(void) { - printf("macro:\n"); + printf("macro:\n"); pf("N=%d\n", N); printf("aaa=%d\n", AAA); @@ -379,6 +379,23 @@ comment /* And again when the name and parenthes are separated by a comment. */ TEST2 /* the comment */ (); + /* macro_push and macro_pop test */ + #define MACRO_TEST "macro_test1\n" + #pragma push_macro("MACRO_TEST") + #undef MACRO_TEST + #define MACRO_TEST "macro_test2\n" + printf(MACRO_TEST); + #pragma pop_macro("MACRO_TEST") + printf(MACRO_TEST); +/* gcc does not support + #define MACRO_TEST_MACRO "MACRO_TEST" + #pragma push_macro(MACRO_TEST_MACRO) + #undef MACRO_TEST + #define MACRO_TEST "macro_test3\n" + printf(MACRO_TEST); + #pragma pop_macro(MACRO_TEST_MACRO) + printf(MACRO_TEST); +*/ } @@ -2155,14 +2172,15 @@ void whitespace_test(void) { char *str; - #if 1 + +#if 1 pri\ -ntf("whitspace:\n"); +ntf("whitspace:\n"); #endif pf("N=%d\n", 2); #ifdef CORRECT_CR_HANDLING - pri\ + pri\ ntf("aaa=%d\n", 3); #endif @@ -2174,11 +2192,12 @@ ntf("min=%d\n", 4); printf("len1=%d\n", strlen(" ")); #ifdef CORRECT_CR_HANDLING - str = " + str = " "; printf("len1=%d str[0]=%d\n", strlen(str), str[0]); #endif - printf("len1=%d\n", strlen(" a + printf("len1=%d\n", strlen(" +a ")); #endif /* ACCEPT_CR_IN_STRINGS */ } From 07614b5e22073cbb2c1b298ab906d57372619604 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Wed, 14 May 2014 12:45:58 +0800 Subject: [PATCH 33/52] clean '\t' --- libtcc.c | 6 +- tccgen.c | 6 +- tccpp.c | 312 ++++++++++++++++++++++++------------------------ tcctok.h | 2 +- tests/tcctest.c | 28 ++--- 5 files changed, 177 insertions(+), 177 deletions(-) diff --git a/libtcc.c b/libtcc.c index 4bb7f1b..dc01831 100644 --- a/libtcc.c +++ b/libtcc.c @@ -879,10 +879,10 @@ static void tcc_cleanup(void) /* free tokens */ n = tok_ident - TOK_IDENT; for(i = 0; i < n; i++){ - def = &table_ident[i]->sym_define; - tcc_free(def->data); + def = &table_ident[i]->sym_define; + tcc_free(def->data); tcc_free(table_ident[i]); - } + } tcc_free(table_ident); /* free sym_pools */ diff --git a/tccgen.c b/tccgen.c index db821e1..0937883 100644 --- a/tccgen.c +++ b/tccgen.c @@ -5234,13 +5234,13 @@ static void init_putz(CType *t, Section *sec, unsigned long c, int size) } else { vpush_global_sym(&func_old_type, TOK_memset); vseti(VT_LOCAL, c); -# ifdef TCC_TARGET_ARM +#ifdef TCC_TARGET_ARM vpushs(size); vpushi(0); -# else +#else vpushi(0); vpushs(size); -# endif +#endif gfunc_call(3); } } diff --git a/tccpp.c b/tccpp.c index 9947171..a384548 100644 --- a/tccpp.c +++ b/tccpp.c @@ -1056,7 +1056,7 @@ static int macro_is_equal(const int *a, const int *b) ST_INLN void define_push(int v, int macro_type, int *str, Sym *first_arg) { Sym *s; - CSym *def; + CSym *def; s = define_find(v); if (s && !macro_is_equal(s->d, str)) tcc_warning("%s redefined", get_tok_str(v, NULL)); @@ -1064,19 +1064,19 @@ ST_INLN void define_push(int v, int macro_type, int *str, Sym *first_arg) s->d = str; s->next = first_arg; def = &table_ident[v - TOK_IDENT]->sym_define; - def->data[def->off] = s; + def->data[def->off] = s; } /* undefined a define symbol. Its name is just set to zero */ ST_FUNC void define_undef(Sym *s) { int v; - CSym *def; + CSym *def; v = s->v - TOK_IDENT; if ((unsigned)v < (unsigned)(tok_ident - TOK_IDENT)){ - def = &table_ident[v]->sym_define; - def->data[def->off] = NULL; - } + def = &table_ident[v]->sym_define; + def->data[def->off] = NULL; + } } ST_INLN Sym *define_find(int v) @@ -1085,7 +1085,7 @@ ST_INLN Sym *define_find(int v) v -= TOK_IDENT; if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) return NULL; - def = &table_ident[v]->sym_define; + def = &table_ident[v]->sym_define; return def->data[def->off]; } @@ -1094,7 +1094,7 @@ ST_FUNC void free_defines(Sym *b) { Sym *top, *tmp; int v; - CSym *def; + CSym *def; top = define_stack; while (top != b) { @@ -1104,12 +1104,12 @@ ST_FUNC void free_defines(Sym *b) tok_str_free(top->d); v = top->v - TOK_IDENT; if ((unsigned)v < (unsigned)(tok_ident - TOK_IDENT)){ - def = &table_ident[v]->sym_define; - if(def->off) - def->off = 0; + def = &table_ident[v]->sym_define; + if(def->off) + def->off = 0; if(def->data[0]) - def->data[0] = NULL; - } + def->data[0] = NULL; + } sym_free(top); top = tmp; } @@ -1398,8 +1398,8 @@ read_name: } else inp(); } - if (ch != c) - goto include_syntax; + if (ch != c) + goto include_syntax; *p = '\0'; minp(); #if 0 @@ -1438,8 +1438,8 @@ read_name: c = '>'; } } - if(!buf[0]) - tcc_error(" empty filename in #include"); + if(!buf[0]) + tcc_error(" empty filename in #include"); if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE) tcc_error("#include recursion too deep"); @@ -1588,9 +1588,9 @@ skip: file->ifndef_macro = 0; tok_flags |= TOK_FLAG_ENDIF; } - next_nomacro(); - if (tok != TOK_LINEFEED) - tcc_warning("Ignoring: %s", get_tok_str(tok, &tokc)); + next_nomacro(); + if (tok != TOK_LINEFEED) + tcc_warning("Ignoring: %s", get_tok_str(tok, &tokc)); break; case TOK_LINE: next(); @@ -1626,144 +1626,144 @@ skip: tcc_warning("#warning %s", buf); break; case TOK_PRAGMA: - next(); - if (tok == TOK_pack && parse_flags & PARSE_FLAG_PACK) { - /* - This may be: - #pragma pack(1) // set - #pragma pack() // reset to default - #pragma pack(push,1) // push & set - #pragma pack(pop) // restore previous - */ - next(); - skip('('); - if (tok == TOK_ASM_pop) { - next(); - if (s1->pack_stack_ptr <= s1->pack_stack) { + next(); + if (tok == TOK_pack && parse_flags & PARSE_FLAG_PACK) { + /* + This may be: + #pragma pack(1) // set + #pragma pack() // reset to default + #pragma pack(push,1) // push & set + #pragma pack(pop) // restore previous + */ + next(); + skip('('); + if (tok == TOK_ASM_pop) { + next(); + if (s1->pack_stack_ptr <= s1->pack_stack) { stk_error: - tcc_error("out of pack stack"); - } - s1->pack_stack_ptr--; - } else { - int val = 0; - if (tok != ')') { - if (tok == TOK_ASM_push) { - next(); - s1->pack_stack_ptr++; - if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE) - goto stk_error; - skip(','); - } - if (tok != TOK_CINT) { + tcc_error("out of pack stack"); + } + s1->pack_stack_ptr--; + } else { + int val = 0; + if (tok != ')') { + if (tok == TOK_ASM_push) { + next(); + s1->pack_stack_ptr++; + if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE) + goto stk_error; + skip(','); + } + if (tok != TOK_CINT) { pack_error: - tcc_error("invalid pack pragma"); - } - val = tokc.i; - if (val < 1 || val > 16) - goto pack_error; - if (val < 1 || val > 16) - tcc_error("Value must be greater than 1 is less than or equal to 16"); - if ((val & (val - 1)) != 0) - tcc_error("Value must be a power of 2 curtain"); - next(); - } - *s1->pack_stack_ptr = val; - skip(')'); - } - }else if (tok == TOK_PUSH_MACRO || tok == TOK_POP_MACRO) { - TokenSym *ts; - CSym *def; - uint8_t *p1; - int len, t; - t = tok; - ch = file->buf_ptr[0]; - skip_spaces(); - if (ch != '(') - goto macro_xxx_syntax; - /* XXX: incorrect if comments : use next_nomacro with a special mode */ - inp(); - skip_spaces(); - if (ch == '\"'){ - inp(); - p = buf; - while (ch != '\"' && ch != '\n' && ch != CH_EOF) { - if ((p - buf) < sizeof(buf) - 1) - *p++ = ch; - if (ch == CH_EOB) { - --p; - handle_stray(); - }else - inp(); - } - if(ch != '\"') - goto macro_xxx_syntax; - *p = '\0'; - minp(); - next(); - }else{ - /* computed #pragma macro_xxx for #define xxx */ - next(); - buf[0] = '\0'; - while (tok != ')') { - if (tok != TOK_STR) { - macro_xxx_syntax: - tcc_error("'macro_xxx' expects (\"NAME\")"); - } - pstrcat(buf, sizeof(buf), (char *)tokc.cstr->data); - next(); - } - } - skip (')'); - if(!buf[0]) - tcc_error(" empty string in #pragma"); - /* find TokenSym */ - p = buf; - while (is_space(*p)) - p++; - p1 = p; - for(;;){ + tcc_error("invalid pack pragma"); + } + val = tokc.i; + if (val < 1 || val > 16) + goto pack_error; + if (val < 1 || val > 16) + tcc_error("Value must be greater than 1 is less than or equal to 16"); + if ((val & (val - 1)) != 0) + tcc_error("Value must be a power of 2 curtain"); + next(); + } + *s1->pack_stack_ptr = val; + skip(')'); + } + }else if (tok == TOK_PUSH_MACRO || tok == TOK_POP_MACRO) { + TokenSym *ts; + CSym *def; + uint8_t *p1; + int len, t; + t = tok; + ch = file->buf_ptr[0]; + skip_spaces(); + if (ch != '(') + goto macro_xxx_syntax; + /* XXX: incorrect if comments : use next_nomacro with a special mode */ + inp(); + skip_spaces(); + if (ch == '\"'){ + inp(); + p = buf; + while (ch != '\"' && ch != '\n' && ch != CH_EOF) { + if ((p - buf) < sizeof(buf) - 1) + *p++ = ch; + if (ch == CH_EOB) { + --p; + handle_stray(); + }else + inp(); + } + if(ch != '\"') + goto macro_xxx_syntax; + *p = '\0'; + minp(); + next(); + }else{ + /* computed #pragma macro_xxx for #define xxx */ + next(); + buf[0] = '\0'; + while (tok != ')') { + if (tok != TOK_STR) { + macro_xxx_syntax: + tcc_error("'macro_xxx' expects (\"NAME\")"); + } + pstrcat(buf, sizeof(buf), (char *)tokc.cstr->data); + next(); + } + } + skip (')'); + if(!buf[0]) + tcc_error(" empty string in #pragma"); + /* find TokenSym */ + p = buf; + while (is_space(*p)) + p++; + p1 = p; + for(;;){ if (!isidnum_table[p[0] - CH_EOF]) break; - ++p; - } - len = p - p1; - while (is_space(*p)) - p++; - if(!p) //'\0' - tcc_error("unrecognized string: %s", buf); - ts = tok_alloc(p1, len); - if(ts){ - def = &ts->sym_define; - if(t == TOK_PUSH_MACRO){ - void *tmp = def->data[def->off]; - if(tmp){ - def->off++; - if(def->off >= def->size){ - int size = def->size; - size *= 2; - if (size >= MACRO_STACK_SIZE) - tcc_error("stack full"); - def->data = tcc_realloc(def->data, size*sizeof(Sym**)); - def->size = size; - } - def->data[def->off] = tmp; - } - }else{ - if(def->off){ - --def->off; - }else{ - tcc_warning("stack empty"); - } - } - } - }else{ - fputs("#pragma ", s1->ppfp); - while (tok != TOK_LINEFEED){ - fputs(get_tok_str(tok, &tokc), s1->ppfp); - next(); - } - goto the_end; - } + ++p; + } + len = p - p1; + while (is_space(*p)) + p++; + if(!p) //'\0' + tcc_error("unrecognized string: %s", buf); + ts = tok_alloc(p1, len); + if(ts){ + def = &ts->sym_define; + if(t == TOK_PUSH_MACRO){ + void *tmp = def->data[def->off]; + if(tmp){ + def->off++; + if(def->off >= def->size){ + int size = def->size; + size *= 2; + if (size >= MACRO_STACK_SIZE) + tcc_error("stack full"); + def->data = tcc_realloc(def->data, size*sizeof(Sym**)); + def->size = size; + } + def->data[def->off] = tmp; + } + }else{ + if(def->off){ + --def->off; + }else{ + tcc_warning("stack empty"); + } + } + } + }else{ + fputs("#pragma ", s1->ppfp); + while (tok != TOK_LINEFEED){ + fputs(get_tok_str(tok, &tokc), s1->ppfp); + next(); + } + goto the_end; + } break; default: if (tok == TOK_LINEFEED || tok == '!' || tok == TOK_PPNUM) { @@ -3245,8 +3245,8 @@ ST_FUNC int tcc_preprocess(TCCState *s1) line_ref = 0; file_ref = NULL; iptr = s1->include_stack_ptr; - tok = TOK_LINEFEED; /* print line */ - goto print_line; + tok = TOK_LINEFEED; /* print line */ + goto print_line; for (;;) { next(); if (tok == TOK_EOF) { diff --git a/tcctok.h b/tcctok.h index 41a8840..ffb5c0a 100644 --- a/tcctok.h +++ b/tcctok.h @@ -139,7 +139,7 @@ /* pragma */ DEF(TOK_pack, "pack") DEF(TOK_PUSH_MACRO, "push_macro") - DEF(TOK_POP_MACRO, "pop_macro") + DEF(TOK_POP_MACRO, "pop_macro") #if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64) /* already defined for assembler */ DEF(TOK_ASM_push, "push") diff --git a/tests/tcctest.c b/tests/tcctest.c index ee4a0e6..3a62354 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -380,21 +380,21 @@ comment comment. */ TEST2 /* the comment */ (); /* macro_push and macro_pop test */ - #define MACRO_TEST "macro_test1\n" - #pragma push_macro("MACRO_TEST") - #undef MACRO_TEST - #define MACRO_TEST "macro_test2\n" - printf(MACRO_TEST); - #pragma pop_macro("MACRO_TEST") - printf(MACRO_TEST); + #define MACRO_TEST "macro_test1\n" + #pragma push_macro("MACRO_TEST") + #undef MACRO_TEST + #define MACRO_TEST "macro_test2\n" + printf(MACRO_TEST); + #pragma pop_macro("MACRO_TEST") + printf(MACRO_TEST); /* gcc does not support - #define MACRO_TEST_MACRO "MACRO_TEST" - #pragma push_macro(MACRO_TEST_MACRO) - #undef MACRO_TEST - #define MACRO_TEST "macro_test3\n" - printf(MACRO_TEST); - #pragma pop_macro(MACRO_TEST_MACRO) - printf(MACRO_TEST); + #define MACRO_TEST_MACRO "MACRO_TEST" + #pragma push_macro(MACRO_TEST_MACRO) + #undef MACRO_TEST + #define MACRO_TEST "macro_test3\n" + printf(MACRO_TEST); + #pragma pop_macro(MACRO_TEST_MACRO) + printf(MACRO_TEST); */ } From fcb3772a3424ff64b43516bde98f113e454c7a6f Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Wed, 14 May 2014 20:44:53 +0800 Subject: [PATCH 34/52] Add warning 3 struct st {int a;} ss; int b; b = ss; --- tccgen.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tccgen.c b/tccgen.c index 0937883..9076da5 100644 --- a/tccgen.c +++ b/tccgen.c @@ -2441,6 +2441,8 @@ static void gen_assign_cast(CType *dt) if (sbt == VT_PTR || sbt == VT_FUNC) { tcc_warning("assignment makes integer from pointer without a cast"); } + if (sbt == VT_STRUCT) + goto error; /* XXX: more tests */ break; case VT_STRUCT: From 5d0785d0e1d71860b61b1c365ff46c8e399ad0e6 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Wed, 14 May 2014 21:01:00 +0800 Subject: [PATCH 35/52] Add warning 4 num en{a1,a2,a3}; enum en ee; ee = 0xffffffffff; char a; a = 0xffff; --- tccgen.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/tccgen.c b/tccgen.c index 9076da5..1f87141 100644 --- a/tccgen.c +++ b/tccgen.c @@ -90,6 +90,8 @@ static void vla_runtime_type_size(CType *type, int *a); static void vla_sp_save(void); static int is_compatible_parameter_types(CType *type1, CType *type2); static void expr_type(CType *type); +static int is_force; + ST_FUNC void vpush64(int ty, unsigned long long v); ST_FUNC void vpush(CType *type); ST_FUNC int gvtst(int inv, int t); @@ -1984,11 +1986,30 @@ static void gen_cast(CType *type) ; #endif else if (dbt != VT_LLONG) { - int s = 0; - if ((dbt & VT_BTYPE) == VT_BYTE) + int s, dt, warr = 0; + long long ll; + dt = dbt & VT_BTYPE; + ll = vtop->c.ll; + if (dt == VT_BYTE){ + if((ll != (unsigned char)ll) && (ll != (char)ll)) + warr = 1; s = 24; - else if ((dbt & VT_BTYPE) == VT_SHORT) + }else if (dt == VT_SHORT){ + if((ll != (unsigned short)ll) && (ll != (short)ll)) + warr = 1; s = 16; + }else{ + if((ll != (unsigned int)ll) && (ll != (int)ll)) + warr = 1; + s = 0; + } + if(warr && !is_force){ + if(dt == VT_ENUM){ + tcc_warning("large integer implicitly truncated to unsigned type"); + dbt = VT_UNSIGNED; + }else + tcc_warning("overflow in implicit constant conversion"); + } if(dbt & VT_UNSIGNED) vtop->c.ui = ((unsigned int)vtop->c.ll << s) >> s; else @@ -2465,14 +2486,15 @@ static void gen_assign_cast(CType *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, cc, r, t, size, align, bit_size, bit_pos, rc, delayed_cast; ft = vtop[-1].type.t; sbt = vtop->type.t & VT_BTYPE; dbt = ft & VT_BTYPE; + cc = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; if ((((sbt == VT_INT || sbt == VT_SHORT) && dbt == VT_BYTE) || (sbt == VT_INT && dbt == VT_SHORT)) - && !(vtop->type.t & VT_BITFIELD)) { + && !(vtop->type.t & VT_BITFIELD) && !cc) { /* optimize char/short casts */ delayed_cast = VT_MUSTCAST; vtop->type.t = ft & (VT_TYPE & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT))); @@ -3718,7 +3740,9 @@ ST_FUNC void unary(void) return; } unary(); + is_force = 1; gen_cast(&type); + is_force = 0; } } else if (tok == '{') { /* save all registers */ From 5a514107c420bd8dd724c27d1e7e905571a6aba5 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Thu, 15 May 2014 12:09:43 +0800 Subject: [PATCH 36/52] When tcc.exe update, abitest-tcc.exe not updated. For security, you must first clean up --- tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index e3824ba..9ace5b0 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -70,7 +70,7 @@ ifdef LIBTCC1 LIBTCC1:=$(TOP)/$(LIBTCC1) endif -all test : $(TESTS) +all test : clean $(TESTS) hello-exe: ../examples/ex1.c @echo ------------ $@ ------------ From 52891b6ff680a03c966776b530cf94de9f831b07 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Fri, 16 May 2014 12:15:00 +0800 Subject: [PATCH 37/52] fix push_macro, asked Tom to help me testfix push_macro --- tcc.h | 2 +- tccpp.c | 4 ++-- tests/tcctest.c | 7 +++++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/tcc.h b/tcc.h index c49eac4..24cb599 100644 --- a/tcc.h +++ b/tcc.h @@ -303,7 +303,7 @@ #define VSTACK_SIZE 256 #define STRING_MAX_SIZE 1024 #define PACK_STACK_SIZE 8 -#define MACRO_STACK_SIZE 4 +#define MACRO_STACK_SIZE 8 #define TOK_HASH_SIZE 8192 /* must be a power of two */ #define TOK_ALLOC_INCR 512 /* must be a power of two */ diff --git a/tccpp.c b/tccpp.c index a384548..91c2aee 100644 --- a/tccpp.c +++ b/tccpp.c @@ -234,7 +234,7 @@ static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len) ts = tcc_malloc(sizeof(TokenSym) + len); table_ident[i] = ts; ts->tok = tok_ident++; - ts->sym_define.data = tcc_malloc(sizeof(Sym**)); + ts->sym_define.data = tcc_malloc(sizeof(Sym*)); ts->sym_define.off = 0; ts->sym_define.data[0] = NULL; ts->sym_define.size = 1; @@ -1743,7 +1743,7 @@ pack_error: size *= 2; if (size >= MACRO_STACK_SIZE) tcc_error("stack full"); - def->data = tcc_realloc(def->data, size*sizeof(Sym**)); + def->data = tcc_realloc(def->data, size*sizeof(Sym*)); def->size = size; } def->data[def->off] = tmp; diff --git a/tests/tcctest.c b/tests/tcctest.c index 3a62354..3fc7b82 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -383,7 +383,14 @@ comment #define MACRO_TEST "macro_test1\n" #pragma push_macro("MACRO_TEST") #undef MACRO_TEST + #define MACRO_TEST "macro_test2\n" + #pragma push_macro("MACRO_TEST") + #undef MACRO_TEST + + #define MACRO_TEST "macro_test3\n" + printf(MACRO_TEST); + #pragma pop_macro("MACRO_TEST") printf(MACRO_TEST); #pragma pop_macro("MACRO_TEST") printf(MACRO_TEST); From 276553c6b2b4df0ac9593d15b8889d470edb27de Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Fri, 16 May 2014 15:44:51 +0800 Subject: [PATCH 38/52] add push_macro test again --- tccpp.c | 2 +- tests/tcctest.c | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/tccpp.c b/tccpp.c index 91c2aee..4aa8b95 100644 --- a/tccpp.c +++ b/tccpp.c @@ -1741,7 +1741,7 @@ pack_error: if(def->off >= def->size){ int size = def->size; size *= 2; - if (size >= MACRO_STACK_SIZE) + if (size > MACRO_STACK_SIZE) tcc_error("stack full"); def->data = tcc_realloc(def->data, size*sizeof(Sym*)); def->size = size; diff --git a/tests/tcctest.c b/tests/tcctest.c index 3fc7b82..e0b307b 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -382,16 +382,29 @@ comment /* macro_push and macro_pop test */ #define MACRO_TEST "macro_test1\n" #pragma push_macro("MACRO_TEST") + printf(MACRO_TEST); #undef MACRO_TEST #define MACRO_TEST "macro_test2\n" #pragma push_macro("MACRO_TEST") + printf(MACRO_TEST); #undef MACRO_TEST #define MACRO_TEST "macro_test3\n" + #pragma push_macro("MACRO_TEST") printf(MACRO_TEST); + #undef MACRO_TEST + + #define MACRO_TEST "macro_test4\n" + printf(MACRO_TEST); + #undef MACRO_TEST + #pragma pop_macro("MACRO_TEST") printf(MACRO_TEST); + + #pragma pop_macro("MACRO_TEST") + printf(MACRO_TEST); + #pragma pop_macro("MACRO_TEST") printf(MACRO_TEST); /* gcc does not support From 196c9995151e046fcbc78d8a72f66a7176fd1456 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Sat, 17 May 2014 00:55:02 +0800 Subject: [PATCH 39/52] 1 macro_push and macro_pop work I made a mistake, no matter the definition does not define can be macro_push. And the modified tcctest.c test 2, pack: in the compiler under the mode of s1->ppfp, I have no clear ideas1->ppfp Some advice thank you Roy to me.This patch, I hope I can pass the Roy test --- tcc.h | 1 - tccpp.c | 27 ++++++++++++--------------- tests/tcctest.c | 44 ++++++++++++++++++++++++++++---------------- 3 files changed, 40 insertions(+), 32 deletions(-) diff --git a/tcc.h b/tcc.h index 24cb599..d0859d3 100644 --- a/tcc.h +++ b/tcc.h @@ -1132,7 +1132,6 @@ ST_DATA TokenSym **table_ident; returned at eof */ #define PARSE_FLAG_ASM_COMMENTS 0x0008 /* '#' can be used for line comment */ #define PARSE_FLAG_SPACES 0x0010 /* next() returns space tokens (for -E) */ -#define PARSE_FLAG_PACK 0x0020 /* #pragma pack */ ST_FUNC TokenSym *tok_alloc(const char *str, int len); ST_FUNC char *get_tok_str(int v, CValue *cv); diff --git a/tccpp.c b/tccpp.c index 4aa8b95..ac1717b 100644 --- a/tccpp.c +++ b/tccpp.c @@ -1627,7 +1627,7 @@ skip: break; case TOK_PRAGMA: next(); - if (tok == TOK_pack && parse_flags & PARSE_FLAG_PACK) { + if (tok == TOK_pack && s1->output_type != TCC_OUTPUT_PREPROCESS) { /* This may be: #pragma pack(1) // set @@ -1736,32 +1736,29 @@ pack_error: def = &ts->sym_define; if(t == TOK_PUSH_MACRO){ void *tmp = def->data[def->off]; - if(tmp){ - def->off++; - if(def->off >= def->size){ - int size = def->size; - size *= 2; - if (size > MACRO_STACK_SIZE) - tcc_error("stack full"); - def->data = tcc_realloc(def->data, size*sizeof(Sym*)); - def->size = size; - } - def->data[def->off] = tmp; + def->off++; + if(def->off >= def->size){ + int size = def->size; + size *= 2; + if (size > MACRO_STACK_SIZE) + tcc_error("stack full"); + def->data = tcc_realloc(def->data, size*sizeof(Sym*)); + def->size = size; } + def->data[def->off] = tmp; }else{ if(def->off){ --def->off; - }else{ - tcc_warning("stack empty"); } } } - }else{ + }else if(s1->output_type == TCC_OUTPUT_PREPROCESS){ fputs("#pragma ", s1->ppfp); while (tok != TOK_LINEFEED){ fputs(get_tok_str(tok, &tokc), s1->ppfp); next(); } + fputs("\n", s1->ppfp); goto the_end; } break; diff --git a/tests/tcctest.c b/tests/tcctest.c index e0b307b..54465a6 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -379,34 +379,46 @@ comment /* And again when the name and parenthes are separated by a comment. */ TEST2 /* the comment */ (); + /* macro_push and macro_pop test */ - #define MACRO_TEST "macro_test1\n" - #pragma push_macro("MACRO_TEST") - printf(MACRO_TEST); #undef MACRO_TEST + #ifdef MACRO_TEST + printf("define MACRO_TEST\n"); + #else + printf("undef MACRO_TEST\n"); + #endif - #define MACRO_TEST "macro_test2\n" #pragma push_macro("MACRO_TEST") - printf(MACRO_TEST); - #undef MACRO_TEST - - #define MACRO_TEST "macro_test3\n" + #define MACRO_TEST #pragma push_macro("MACRO_TEST") - printf(MACRO_TEST); - #undef MACRO_TEST - - #define MACRO_TEST "macro_test4\n" - printf(MACRO_TEST); #undef MACRO_TEST + #pragma push_macro("MACRO_TEST") #pragma pop_macro("MACRO_TEST") - printf(MACRO_TEST); + #ifdef MACRO_TEST + printf("define MACRO_TEST\n"); + #else + printf("undef MACRO_TEST\n"); + #endif #pragma pop_macro("MACRO_TEST") - printf(MACRO_TEST); + #ifdef MACRO_TEST + printf("define MACRO_TEST\n"); + #else + printf("undef MACRO_TEST\n"); + #endif #pragma pop_macro("MACRO_TEST") - printf(MACRO_TEST); + #ifdef MACRO_TEST + printf("define MACRO_TEST\n"); + #else + printf("undef MACRO_TEST\n"); + #endif + + /* pack test */ + #pragma pack(push,8) + #pragma pack(pop) + /* gcc does not support #define MACRO_TEST_MACRO "MACRO_TEST" #pragma push_macro(MACRO_TEST_MACRO) From a94ed430945d5012bd5d3abee24ed75ecb73d07c Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Sat, 17 May 2014 12:06:18 +0800 Subject: [PATCH 40/52] Improved '\ n' output effect (# pragma pack (push, 8), # pragma pack (pop)) --- tccpp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tccpp.c b/tccpp.c index ac1717b..053fd57 100644 --- a/tccpp.c +++ b/tccpp.c @@ -61,6 +61,7 @@ static TokenSym *hash_ident[TOK_HASH_SIZE]; static char token_buf[STRING_MAX_SIZE + 1]; /* true if isid(c) || isnum(c) */ static unsigned char isidnum_table[256-CH_EOF]; +static int token_seen; static const char tcc_keywords[] = #define DEF(id, str) str "\0" @@ -1758,7 +1759,7 @@ pack_error: fputs(get_tok_str(tok, &tokc), s1->ppfp); next(); } - fputs("\n", s1->ppfp); + token_seen = 0;//printf '\n' goto the_end; } break; @@ -3229,7 +3230,7 @@ ST_FUNC int tcc_preprocess(TCCState *s1) Sym *define_start; BufferedFile *file_ref, **iptr, **iptr_new; - int token_seen, line_ref, d; + int line_ref, d; const char *s; preprocess_init(s1); @@ -3238,7 +3239,6 @@ ST_FUNC int tcc_preprocess(TCCState *s1) tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; parse_flags = PARSE_FLAG_ASM_COMMENTS | PARSE_FLAG_PREPROCESS | PARSE_FLAG_LINEFEED | PARSE_FLAG_SPACES; - token_seen = 0; line_ref = 0; file_ref = NULL; iptr = s1->include_stack_ptr; From e5e7f488e22190f893152c0b2f73e9ba499c4169 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Sat, 17 May 2014 12:32:00 +0800 Subject: [PATCH 41/52] int main() { struct st { int aa:16; int bb:16; } s; s.aa = 1; s.bb = 2; return 0; } objdump -d: elf64-x86-64 Disassembly of section .text: 0000000000000000
: 0: 55 push %rbp 1: 48 89 e5 mov %rsp,%rbp 4: 48 81 ec 10 00 00 00 sub $0x10,%rsp b: b8 01 00 00 00 mov $0x1,%eax 10: 48 89 c1 mov %rax,%rcx 13: 81 e1 ff ff 00 00 and $0xffff,%ecx 19: 8b 55 fc mov -0x4(%rbp),%edx 1c: 81 e2 00 00 ff ff and $0xffff0000,%edx 22: 09 d1 or %edx,%ecx 24: 89 4d fc mov %ecx,-0x4(%rbp) 27: b8 02 00 00 00 mov $0x2,%eax 2c: 48 89 c1 mov %rax,%rcx 2f: 81 e1 ff ff 00 00 and $0xffff,%ecx 35: c1 e1 10 shl $0x10,%ecx 38: 8b 55 fc mov -0x4(%rbp),%edx 3b: 81 e2 ff ff 00 00 and $0xffff,%edx 41: 09 d1 or %edx,%ecx 43: 89 4d fc mov %ecx,-0x4(%rbp) 46: b8 00 00 00 00 mov $0x0,%eax 4b: e9 00 00 00 00 jmpq 50 50: c9 leaveq 51: c3 retq After the patch Disassembly of section .text: 0000000000000000
: 0: 55 push %rbp 1: 48 89 e5 mov %rsp,%rbp 4: 48 81 ec 10 00 00 00 sub $0x10,%rsp b: 8b 45 fc mov -0x4(%rbp),%eax e: 81 e0 00 00 ff ff and $0xffff0000,%eax 14: 83 c8 01 or $0x1,%eax 17: 89 45 fc mov %eax,-0x4(%rbp) 1a: 8b 45 fc mov -0x4(%rbp),%eax 1d: 81 e0 ff ff 00 00 and $0xffff,%eax 23: 81 c8 00 00 02 00 or $0x20000,%eax 29: 89 45 fc mov %eax,-0x4(%rbp) 2c: b8 00 00 00 00 mov $0x0,%eax 31: e9 00 00 00 00 jmpq 36 36: c9 leaveq 37: c3 retq --- tccgen.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/tccgen.c b/tccgen.c index 1f87141..c0674d6 100644 --- a/tccgen.c +++ b/tccgen.c @@ -1019,6 +1019,7 @@ ST_FUNC void lexpand_nr(void) } #endif +#ifndef TCC_TARGET_X86_64 /* build a long long from two ints */ static void lbuild(int t) { @@ -1027,6 +1028,7 @@ static void lbuild(int t) vtop[-1].type.t = t; vpop(); } +#endif /* rotate n first stack elements to the bottom I1 ... In -> I2 ... In I1 [top is right] @@ -1088,8 +1090,8 @@ static void gv_dup(void) { int rc, t, r, r1; SValue sv; - t = vtop->type.t; +#ifndef TCC_TARGET_X86_64 if ((t & VT_BTYPE) == VT_LLONG) { lexpand(); gv_dup(); @@ -1099,15 +1101,14 @@ static void gv_dup(void) vrotb(4); /* stack: H L L1 H1 */ lbuild(t); - vrotb(3); - vrotb(3); + vrott(3); vswap(); lbuild(t); vswap(); - } else { + } else +#endif + { /* duplicate value */ - rc = RC_INT; - sv.type.t = VT_INT; if (is_float(t)) { rc = RC_FLOAT; #ifdef TCC_TARGET_X86_64 @@ -1115,8 +1116,9 @@ static void gv_dup(void) rc = RC_ST0; } #endif - sv.type.t = t; - } + }else + rc = RC_INT; + sv.type.t = t; r = gv(rc); r1 = get_reg(rc); sv.r = r; @@ -2549,11 +2551,6 @@ ST_FUNC void vstore(void) /* remove bit field info to avoid loops */ vtop[-1].type.t = ft & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); - /* duplicate source into other register */ - gv_dup(); - vswap(); - vrott(3); - if((ft & VT_BTYPE) == VT_BOOL) { gen_cast(&vtop[-1].type); vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED); @@ -2585,10 +2582,6 @@ ST_FUNC void vstore(void) gen_op('|'); /* store result */ vstore(); - - /* pop off shifted source from "duplicate source..." above */ - vpop(); - } else { #ifdef CONFIG_TCC_BCHECK /* bound check case */ From f8b4f59f8bef4520fcf85d45f2a87b79e9b1b506 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Tue, 20 May 2014 14:59:37 +0800 Subject: [PATCH 42/52] In the local use of local stack, use a global stack in the global time --- tccgen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tccgen.c b/tccgen.c index c0674d6..d286dd4 100644 --- a/tccgen.c +++ b/tccgen.c @@ -3990,7 +3990,7 @@ ST_FUNC void unary(void) #endif ) tcc_warning("implicit declaration of function '%s'", name); - s = external_global_sym(t, &func_old_type, 0); + s = external_sym(t, &func_old_type, 0, NULL); } if ((s->type.t & (VT_STATIC | VT_INLINE | VT_BTYPE)) == (VT_STATIC | VT_INLINE | VT_FUNC)) { From 0199123dd7c06a7b10d4200d93221bd3e6f36c49 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Tue, 20 May 2014 15:18:59 +0800 Subject: [PATCH 43/52] clean '\t' --- lib/libtcc1.c | 364 ++++++++++++++++++++++++------------------------ tests/tcctest.c | 186 ++++++++++++------------- 2 files changed, 275 insertions(+), 275 deletions(-) diff --git a/lib/libtcc1.c b/lib/libtcc1.c index 284965e..87f4e84 100644 --- a/lib/libtcc1.c +++ b/lib/libtcc1.c @@ -54,29 +54,29 @@ typedef long double XFtype; #define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE) /* the following deal with IEEE single-precision numbers */ -#define EXCESS 126 -#define SIGNBIT 0x80000000 -#define HIDDEN (1 << 23) -#define SIGN(fp) ((fp) & SIGNBIT) -#define EXP(fp) (((fp) >> 23) & 0xFF) -#define MANT(fp) (((fp) & 0x7FFFFF) | HIDDEN) -#define PACK(s,e,m) ((s) | ((e) << 23) | (m)) +#define EXCESS 126 +#define SIGNBIT 0x80000000 +#define HIDDEN (1 << 23) +#define SIGN(fp) ((fp) & SIGNBIT) +#define EXP(fp) (((fp) >> 23) & 0xFF) +#define MANT(fp) (((fp) & 0x7FFFFF) | HIDDEN) +#define PACK(s,e,m) ((s) | ((e) << 23) | (m)) /* the following deal with IEEE double-precision numbers */ -#define EXCESSD 1022 -#define HIDDEND (1 << 20) -#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) -#define SIGND(fp) ((fp.l.upper) & SIGNBIT) -#define MANTD(fp) (((((fp.l.upper) & 0xFFFFF) | HIDDEND) << 10) | \ - (fp.l.lower >> 22)) -#define HIDDEND_LL ((long long)1 << 52) -#define MANTD_LL(fp) ((fp.ll & (HIDDEND_LL-1)) | HIDDEND_LL) -#define PACKD_LL(s,e,m) (((long long)((s)+((e)<<20))<<32)|(m)) +#define EXCESSD 1022 +#define HIDDEND (1 << 20) +#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) +#define SIGND(fp) ((fp.l.upper) & SIGNBIT) +#define MANTD(fp) (((((fp.l.upper) & 0xFFFFF) | HIDDEND) << 10) | \ + (fp.l.lower >> 22)) +#define HIDDEND_LL ((long long)1 << 52) +#define MANTD_LL(fp) ((fp.ll & (HIDDEND_LL-1)) | HIDDEND_LL) +#define PACKD_LL(s,e,m) (((long long)((s)+((e)<<20))<<32)|(m)) /* the following deal with x86 long double-precision numbers */ -#define EXCESSLD 16382 -#define EXPLD(fp) (fp.l.upper & 0x7fff) -#define SIGNLD(fp) ((fp.l.upper) & 0x8000) +#define EXCESSLD 16382 +#define EXPLD(fp) (fp.l.upper & 0x7fff) +#define SIGNLD(fp) ((fp.l.upper) & 0x8000) /* only for x86 */ union ldouble_long { @@ -114,32 +114,32 @@ union float_long { /* XXX: use gcc/tcc intrinsic ? */ #if defined(TCC_TARGET_I386) #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ - __asm__ ("subl %5,%1\n\tsbbl %3,%0" \ - : "=r" ((USItype) (sh)), \ - "=&r" ((USItype) (sl)) \ - : "0" ((USItype) (ah)), \ - "g" ((USItype) (bh)), \ - "1" ((USItype) (al)), \ - "g" ((USItype) (bl))) + __asm__ ("subl %5,%1\n\tsbbl %3,%0" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "0" ((USItype) (ah)), \ + "g" ((USItype) (bh)), \ + "1" ((USItype) (al)), \ + "g" ((USItype) (bl))) #define umul_ppmm(w1, w0, u, v) \ - __asm__ ("mull %3" \ - : "=a" ((USItype) (w0)), \ - "=d" ((USItype) (w1)) \ - : "%0" ((USItype) (u)), \ - "rm" ((USItype) (v))) + __asm__ ("mull %3" \ + : "=a" ((USItype) (w0)), \ + "=d" ((USItype) (w1)) \ + : "%0" ((USItype) (u)), \ + "rm" ((USItype) (v))) #define udiv_qrnnd(q, r, n1, n0, dv) \ - __asm__ ("divl %4" \ - : "=a" ((USItype) (q)), \ - "=d" ((USItype) (r)) \ - : "0" ((USItype) (n0)), \ - "1" ((USItype) (n1)), \ - "rm" ((USItype) (dv))) + __asm__ ("divl %4" \ + : "=a" ((USItype) (q)), \ + "=d" ((USItype) (r)) \ + : "0" ((USItype) (n0)), \ + "1" ((USItype) (n1)), \ + "rm" ((USItype) (dv))) #define count_leading_zeros(count, x) \ - do { \ - USItype __cbtmp; \ - __asm__ ("bsrl %1,%0" \ - : "=r" (__cbtmp) : "rm" ((USItype) (x))); \ - (count) = __cbtmp ^ 31; \ + do { \ + USItype __cbtmp; \ + __asm__ ("bsrl %1,%0" \ + : "=r" (__cbtmp) : "rm" ((USItype) (x))); \ + (count) = __cbtmp ^ 31; \ } while (0) #else #error unsupported CPU type @@ -168,33 +168,33 @@ static UDWtype __udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp) if (d1 == 0) { if (d0 > n1) - { - /* 0q = nn / 0D */ + { + /* 0q = nn / 0D */ - udiv_qrnnd (q0, n0, n1, n0, d0); - q1 = 0; + udiv_qrnnd (q0, n0, n1, n0, d0); + q1 = 0; - /* Remainder in n0. */ - } + /* Remainder in n0. */ + } else - { - /* qq = NN / 0d */ + { + /* qq = NN / 0d */ - if (d0 == 0) - d0 = 1 / d0; /* Divide intentionally by zero. */ + if (d0 == 0) + d0 = 1 / d0; /* Divide intentionally by zero. */ - udiv_qrnnd (q1, n1, 0, n1, d0); - udiv_qrnnd (q0, n0, n1, n0, d0); + udiv_qrnnd (q1, n1, 0, n1, d0); + udiv_qrnnd (q0, n0, n1, n0, d0); - /* Remainder in n0. */ - } + /* Remainder in n0. */ + } if (rp != 0) - { - rr.s.low = n0; - rr.s.high = 0; - *rp = rr.ll; - } + { + rr.s.low = n0; + rr.s.high = 0; + *rp = rr.ll; + } } #else /* UDIV_NEEDS_NORMALIZATION */ @@ -202,160 +202,160 @@ static UDWtype __udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp) if (d1 == 0) { if (d0 > n1) - { - /* 0q = nn / 0D */ + { + /* 0q = nn / 0D */ - count_leading_zeros (bm, d0); + count_leading_zeros (bm, d0); - if (bm != 0) - { - /* Normalize, i.e. make the most significant bit of the - denominator set. */ + if (bm != 0) + { + /* Normalize, i.e. make the most significant bit of the + denominator set. */ - d0 = d0 << bm; - n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm)); - n0 = n0 << bm; - } + d0 = d0 << bm; + n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm)); + n0 = n0 << bm; + } - udiv_qrnnd (q0, n0, n1, n0, d0); - q1 = 0; + udiv_qrnnd (q0, n0, n1, n0, d0); + q1 = 0; - /* Remainder in n0 >> bm. */ - } + /* Remainder in n0 >> bm. */ + } else - { - /* qq = NN / 0d */ + { + /* qq = NN / 0d */ - if (d0 == 0) - d0 = 1 / d0; /* Divide intentionally by zero. */ + if (d0 == 0) + d0 = 1 / d0; /* Divide intentionally by zero. */ - count_leading_zeros (bm, d0); + count_leading_zeros (bm, d0); - if (bm == 0) - { - /* From (n1 >= d0) /\ (the most significant bit of d0 is set), - conclude (the most significant bit of n1 is set) /\ (the - leading quotient digit q1 = 1). + if (bm == 0) + { + /* From (n1 >= d0) /\ (the most significant bit of d0 is set), + conclude (the most significant bit of n1 is set) /\ (the + leading quotient digit q1 = 1). - This special case is necessary, not an optimization. - (Shifts counts of W_TYPE_SIZE are undefined.) */ + This special case is necessary, not an optimization. + (Shifts counts of W_TYPE_SIZE are undefined.) */ - n1 -= d0; - q1 = 1; - } - else - { - /* Normalize. */ + n1 -= d0; + q1 = 1; + } + else + { + /* Normalize. */ - b = W_TYPE_SIZE - bm; + b = W_TYPE_SIZE - bm; - d0 = d0 << bm; - n2 = n1 >> b; - n1 = (n1 << bm) | (n0 >> b); - n0 = n0 << bm; + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; - udiv_qrnnd (q1, n1, n2, n1, d0); - } + udiv_qrnnd (q1, n1, n2, n1, d0); + } - /* n1 != d0... */ + /* n1 != d0... */ - udiv_qrnnd (q0, n0, n1, n0, d0); + udiv_qrnnd (q0, n0, n1, n0, d0); - /* Remainder in n0 >> bm. */ - } + /* Remainder in n0 >> bm. */ + } if (rp != 0) - { - rr.s.low = n0 >> bm; - rr.s.high = 0; - *rp = rr.ll; - } + { + rr.s.low = n0 >> bm; + rr.s.high = 0; + *rp = rr.ll; + } } #endif /* UDIV_NEEDS_NORMALIZATION */ else { if (d1 > n1) - { - /* 00 = nn / DD */ + { + /* 00 = nn / DD */ - q0 = 0; - q1 = 0; + q0 = 0; + q1 = 0; - /* Remainder in n1n0. */ - if (rp != 0) - { - rr.s.low = n0; - rr.s.high = n1; - *rp = rr.ll; - } - } + /* Remainder in n1n0. */ + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } else - { - /* 0q = NN / dd */ + { + /* 0q = NN / dd */ - count_leading_zeros (bm, d1); - if (bm == 0) - { - /* From (n1 >= d1) /\ (the most significant bit of d1 is set), - conclude (the most significant bit of n1 is set) /\ (the - quotient digit q0 = 0 or 1). + count_leading_zeros (bm, d1); + if (bm == 0) + { + /* From (n1 >= d1) /\ (the most significant bit of d1 is set), + conclude (the most significant bit of n1 is set) /\ (the + quotient digit q0 = 0 or 1). - This special case is necessary, not an optimization. */ + This special case is necessary, not an optimization. */ - /* The condition on the next line takes advantage of that - n1 >= d1 (true due to program flow). */ - if (n1 > d1 || n0 >= d0) - { - q0 = 1; - sub_ddmmss (n1, n0, n1, n0, d1, d0); - } - else - q0 = 0; + /* The condition on the next line takes advantage of that + n1 >= d1 (true due to program flow). */ + if (n1 > d1 || n0 >= d0) + { + q0 = 1; + sub_ddmmss (n1, n0, n1, n0, d1, d0); + } + else + q0 = 0; - q1 = 0; + q1 = 0; - if (rp != 0) - { - rr.s.low = n0; - rr.s.high = n1; - *rp = rr.ll; - } - } - else - { - UWtype m1, m0; - /* Normalize. */ + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } + else + { + UWtype m1, m0; + /* Normalize. */ - b = W_TYPE_SIZE - bm; + b = W_TYPE_SIZE - bm; - d1 = (d1 << bm) | (d0 >> b); - d0 = d0 << bm; - n2 = n1 >> b; - n1 = (n1 << bm) | (n0 >> b); - n0 = n0 << bm; + d1 = (d1 << bm) | (d0 >> b); + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; - udiv_qrnnd (q0, n1, n2, n1, d1); - umul_ppmm (m1, m0, q0, d0); + udiv_qrnnd (q0, n1, n2, n1, d1); + umul_ppmm (m1, m0, q0, d0); - if (m1 > n1 || (m1 == n1 && m0 > n0)) - { - q0--; - sub_ddmmss (m1, m0, m1, m0, d1, d0); - } + if (m1 > n1 || (m1 == n1 && m0 > n0)) + { + q0--; + sub_ddmmss (m1, m0, m1, m0, d1, d0); + } - q1 = 0; + q1 = 0; - /* Remainder in (n1n0 - m1m0) >> bm. */ - if (rp != 0) - { - sub_ddmmss (n1, n0, n1, n0, m1, m0); - rr.s.low = (n1 << b) | (n0 >> bm); - rr.s.high = n1 >> bm; - *rp = rr.ll; - } - } - } + /* Remainder in (n1n0 - m1m0) >> bm. */ + if (rp != 0) + { + sub_ddmmss (n1, n0, n1, n0, m1, m0); + rr.s.low = (n1 << b) | (n0 >> bm); + rr.s.high = n1 >> bm; + *rp = rr.ll; + } + } + } } ww.s.low = q0; @@ -537,13 +537,13 @@ unsigned long long __fixunssfdi (float a1) fl1.f = a1; if (fl1.l == 0) - return (0); + return (0); exp = EXP (fl1.l) - EXCESS - 24; l = MANT(fl1.l); if (exp >= 41) - return (unsigned long long)-1; + return (unsigned long long)-1; else if (exp >= 0) return (unsigned long long)l << exp; else if (exp >= -23) @@ -561,14 +561,14 @@ unsigned long long __fixunsdfdi (double a1) dl1.d = a1; if (dl1.ll == 0) - return (0); + return (0); exp = EXPD (dl1) - EXCESSD - 53; l = MANTD_LL(dl1); if (exp >= 12) - return (unsigned long long)-1; + return (unsigned long long)-1; else if (exp >= 0) return l << exp; else if (exp >= -52) @@ -586,14 +586,14 @@ unsigned long long __fixunsxfdi (long double a1) dl1.ld = a1; if (dl1.l.lower == 0 && dl1.l.upper == 0) - return (0); + return (0); exp = EXPLD (dl1) - EXCESSLD - 64; l = dl1.l.lower; if (exp > 0) - return (unsigned long long)-1; + return (unsigned long long)-1; else if (exp >= -63) return l >> -exp; else diff --git a/tests/tcctest.c b/tests/tcctest.c index 54465a6..66a1cac 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -155,8 +155,8 @@ static int onetwothree = 123; #define B3 4 #endif -#define __INT64_C(c) c ## LL -#define INT64_MIN (-__INT64_C(9223372036854775807)-1) +#define __INT64_C(c) c ## LL +#define INT64_MIN (-__INT64_C(9223372036854775807)-1) int qq(int x) { @@ -1444,30 +1444,30 @@ struct complexinit { const static struct complexinit cix[] = { [0] = { - .a = 2000, - .b = (const struct complexinit0[]) { - { 2001, 2002 }, - { 2003, 2003 }, - {} - } + .a = 2000, + .b = (const struct complexinit0[]) { + { 2001, 2002 }, + { 2003, 2003 }, + {} + } } }; struct complexinit2 { - int a; - int b[]; + int a; + int b[]; }; struct complexinit2 cix20; struct complexinit2 cix21 = { - .a = 3000, - .b = { 3001, 3002, 3003 } + .a = 3000, + .b = { 3001, 3002, 3003 } }; struct complexinit2 cix22 = { - .a = 4000, - .b = { 4001, 4002, 4003, 4004, 4005, 4006 } + .a = 4000, + .b = { 4001, 4002, 4003, 4004, 4005, 4006 } }; void init_test(void) @@ -1564,10 +1564,10 @@ void init_test(void) printf("\n"); /* complex init check */ printf("cix: %d %d %d %d %d %d %d\n", - cix[0].a, - cix[0].b[0].a, cix[0].b[0].b, - cix[0].b[1].a, cix[0].b[1].b, - cix[0].b[2].a, cix[0].b[2].b); + cix[0].a, + cix[0].b[0].a, cix[0].b[0].b, + cix[0].b[1].a, cix[0].b[1].b, + cix[0].b[2].a, cix[0].b[2].b); printf("cix2: %d %d\n", cix21.b[2], cix22.b[5]); printf("sizeof cix20 %d, cix21 %d, sizeof cix22 %d\n", sizeof cix20, sizeof cix21, sizeof cix22); } @@ -2454,21 +2454,21 @@ static char * strncat1(char * dest,const char * src,size_t count) { int d0, d1, d2, d3; __asm__ __volatile__( - "repne\n\t" - "scasb\n\t" - "decl %1\n\t" - "movl %8,%3\n" - "1:\tdecl %3\n\t" - "js 2f\n\t" - "lodsb\n\t" - "stosb\n\t" - "testb %%al,%%al\n\t" - "jne 1b\n" - "2:\txorl %2,%2\n\t" - "stosb" - : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3) - : "0" (src),"1" (dest),"2" (0),"3" (0xffffffff), "g" (count) - : "memory"); + "repne\n\t" + "scasb\n\t" + "decl %1\n\t" + "movl %8,%3\n" + "1:\tdecl %3\n\t" + "js 2f\n\t" + "lodsb\n\t" + "stosb\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n" + "2:\txorl %2,%2\n\t" + "stosb" + : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3) + : "0" (src),"1" (dest),"2" (0),"3" (0xffffffff), "g" (count) + : "memory"); return dest; } @@ -2476,20 +2476,20 @@ static char * strncat2(char * dest,const char * src,size_t count) { int d0, d1, d2, d3; __asm__ __volatile__( - "repne scasb\n\t" /* one-line repne prefix + string op */ - "decl %1\n\t" - "movl %8,%3\n" - "1:\tdecl %3\n\t" - "js 2f\n\t" - "lodsb\n\t" - "stosb\n\t" - "testb %%al,%%al\n\t" - "jne 1b\n" - "2:\txorl %2,%2\n\t" - "stosb" - : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3) - : "0" (src),"1" (dest),"2" (0),"3" (0xffffffff), "g" (count) - : "memory"); + "repne scasb\n\t" /* one-line repne prefix + string op */ + "decl %1\n\t" + "movl %8,%3\n" + "1:\tdecl %3\n\t" + "js 2f\n\t" + "lodsb\n\t" + "stosb\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n" + "2:\txorl %2,%2\n\t" + "stosb" + : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3) + : "0" (src),"1" (dest),"2" (0),"3" (0xffffffff), "g" (count) + : "memory"); return dest; } @@ -2497,17 +2497,17 @@ static inline void * memcpy1(void * to, const void * from, size_t n) { int d0, d1, d2; __asm__ __volatile__( - "rep ; movsl\n\t" - "testb $2,%b4\n\t" - "je 1f\n\t" - "movsw\n" - "1:\ttestb $1,%b4\n\t" - "je 2f\n\t" - "movsb\n" - "2:" - : "=&c" (d0), "=&D" (d1), "=&S" (d2) - :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from) - : "memory"); + "rep ; movsl\n\t" + "testb $2,%b4\n\t" + "je 1f\n\t" + "movsw\n" + "1:\ttestb $1,%b4\n\t" + "je 2f\n\t" + "movsb\n" + "2:" + : "=&c" (d0), "=&D" (d1), "=&S" (d2) + :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from) + : "memory"); return (to); } @@ -2515,38 +2515,38 @@ static inline void * memcpy2(void * to, const void * from, size_t n) { int d0, d1, d2; __asm__ __volatile__( - "rep movsl\n\t" /* one-line rep prefix + string op */ - "testb $2,%b4\n\t" - "je 1f\n\t" - "movsw\n" - "1:\ttestb $1,%b4\n\t" - "je 2f\n\t" - "movsb\n" - "2:" - : "=&c" (d0), "=&D" (d1), "=&S" (d2) - :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from) - : "memory"); + "rep movsl\n\t" /* one-line rep prefix + string op */ + "testb $2,%b4\n\t" + "je 1f\n\t" + "movsw\n" + "1:\ttestb $1,%b4\n\t" + "je 2f\n\t" + "movsb\n" + "2:" + : "=&c" (d0), "=&D" (d1), "=&S" (d2) + :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from) + : "memory"); return (to); } static __inline__ void sigaddset1(unsigned int *set, int _sig) { - __asm__("btsl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc"); + __asm__("btsl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc"); } static __inline__ void sigdelset1(unsigned int *set, int _sig) { - asm("btrl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc"); + asm("btrl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc"); } static __inline__ __const__ unsigned int swab32(unsigned int x) { - __asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */ - "rorl $16,%0\n\t" /* swap words */ - "xchgb %b0,%h0" /* swap higher bytes */ - :"=q" (x) - : "0" (x)); - return x; + __asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */ + "rorl $16,%0\n\t" /* swap words */ + "xchgb %b0,%h0" /* swap higher bytes */ + :"=q" (x) + : "0" (x)); + return x; } static __inline__ unsigned long long mul64(unsigned int a, unsigned int b) @@ -2675,23 +2675,23 @@ int weak_toolate() { return 0; } void __attribute__((weak)) weak_test(void) { - printf("weak_f1=%d\n", weak_f1 ? weak_f1() : 123); - printf("weak_f2=%d\n", weak_f2 ? weak_f2() : 123); - printf("weak_f3=%d\n", weak_f3 ? weak_f3() : 123); - printf("weak_v1=%d\n",&weak_v1 ? weak_v1 : 123); - printf("weak_v2=%d\n",&weak_v2 ? weak_v2 : 123); - printf("weak_v3=%d\n",&weak_v3 ? weak_v3 : 123); + printf("weak_f1=%d\n", weak_f1 ? weak_f1() : 123); + printf("weak_f2=%d\n", weak_f2 ? weak_f2() : 123); + printf("weak_f3=%d\n", weak_f3 ? weak_f3() : 123); + printf("weak_v1=%d\n",&weak_v1 ? weak_v1 : 123); + printf("weak_v2=%d\n",&weak_v2 ? weak_v2 : 123); + printf("weak_v3=%d\n",&weak_v3 ? weak_v3 : 123); - printf("weak_fpa=%d\n",&weak_fpa ? weak_fpa() : 123); - printf("weak_fpb=%d\n",&weak_fpb ? weak_fpb() : 123); - printf("weak_fpc=%d\n",&weak_fpc ? weak_fpc() : 123); - - printf("weak_asm_f1=%d\n", weak_asm_f1 != NULL); - printf("weak_asm_f2=%d\n", weak_asm_f2 != NULL); - printf("weak_asm_f3=%d\n", weak_asm_f3 != NULL); - printf("weak_asm_v1=%d\n",&weak_asm_v1 != NULL); - printf("weak_asm_v2=%d\n",&weak_asm_v2 != NULL); - printf("weak_asm_v3=%d\n",&weak_asm_v3 != NULL); + printf("weak_fpa=%d\n",&weak_fpa ? weak_fpa() : 123); + printf("weak_fpb=%d\n",&weak_fpb ? weak_fpb() : 123); + printf("weak_fpc=%d\n",&weak_fpc ? weak_fpc() : 123); + + printf("weak_asm_f1=%d\n", weak_asm_f1 != NULL); + printf("weak_asm_f2=%d\n", weak_asm_f2 != NULL); + printf("weak_asm_f3=%d\n", weak_asm_f3 != NULL); + printf("weak_asm_v1=%d\n",&weak_asm_v1 != NULL); + printf("weak_asm_v2=%d\n",&weak_asm_v2 != NULL); + printf("weak_asm_v3=%d\n",&weak_asm_v3 != NULL); } int __attribute__((weak)) weak_f2() { return 222; } From 3d608d4b54edfdd9f394f06d2be0741387ac733a Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Tue, 20 May 2014 15:23:55 +0800 Subject: [PATCH 44/52] Delete a = (a > = 0)? A: -a; \ --- lib/libtcc1.c | 45 ++++++++++++++++++++++++--------------------- tests/tcctest.c | 21 ++++++++++++++++----- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/lib/libtcc1.c b/lib/libtcc1.c index 87f4e84..58324a9 100644 --- a/lib/libtcc1.c +++ b/lib/libtcc1.c @@ -533,21 +533,22 @@ unsigned long long __fixunssfdi (float a1) register union float_long fl1; register int exp; register unsigned long l; - + int s; fl1.f = a1; if (fl1.l == 0) - return (0); + return 0; exp = EXP (fl1.l) - EXCESS - 24; l = MANT(fl1.l); - if (exp >= 41) - return (unsigned long long)-1; + s = SIGN(fl1.l)? -1: 1; + if (exp >= 64) + return (unsigned long long)-1; else if (exp >= 0) - return (unsigned long long)l << exp; + return ((unsigned long long)l << exp)*s; else if (exp >= -23) - return l >> -exp; + return (l >> -exp)*s; else return 0; } @@ -557,22 +558,22 @@ unsigned long long __fixunsdfdi (double a1) register union double_long dl1; register int exp; register unsigned long long l; - + int s; dl1.d = a1; if (dl1.ll == 0) - return (0); + return (0); exp = EXPD (dl1) - EXCESSD - 53; l = MANTD_LL(dl1); - - if (exp >= 12) - return (unsigned long long)-1; + s = SIGND(dl1)? -1: 1; + if (exp >= 64) + return (unsigned long long)-1; else if (exp >= 0) - return l << exp; + return (l << exp)*s; else if (exp >= -52) - return l >> -exp; + return (l >> -exp)*s; else return 0; } @@ -582,20 +583,22 @@ unsigned long long __fixunsxfdi (long double a1) register union ldouble_long dl1; register int exp; register unsigned long long l; - + int s; dl1.ld = a1; if (dl1.l.lower == 0 && dl1.l.upper == 0) - return (0); + return (0); exp = EXPLD (dl1) - EXCESSLD - 64; - + s = SIGNLD(dl1)? -1: 1; l = dl1.l.lower; - if (exp > 0) - return (unsigned long long)-1; - else if (exp >= -63) - return l >> -exp; + if (exp >= 64) + return (unsigned long long)-1; + else if (exp >= 0) + return ((unsigned long long)l << exp)*s; + else if (exp >= -64) + return (l >> -exp)*s; else return 0; } @@ -637,7 +640,7 @@ extern void abort(void); #endif enum __va_arg_type { - __va_gen_reg, __va_float_reg, __va_stack + __va_gen_reg, __va_float_reg, __va_ld_reg, __va_stack }; //This should be in sync with the declaration on our include/stdarg.h diff --git a/tests/tcctest.c b/tests/tcctest.c index 66a1cac..22a8278 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -1729,7 +1729,6 @@ void prefix ## fcast(type a)\ printf("ftof: %f %f %Lf\n", fa, da, la);\ ia = (int)a;\ llia = (long long)a;\ - a = (a >= 0) ? a : -a;\ ua = (unsigned int)a;\ llua = (unsigned long long)a;\ printf("ftoi: %d %u %lld %llu\n", ia, ua, llia, llua);\ @@ -1759,6 +1758,18 @@ void prefix ## call(void)\ printf("strto%s: %f\n", #prefix, (double)strto ## prefix("1.2", NULL));\ }\ \ +void prefix ## calc(type x, type y)\ +{\ + x=x*x;y=y*y;\ + printf("%d, %d\n", (int)x, (int)y);\ + x=x-y;y=y-x;\ + printf("%d, %d\n", (int)x, (int)y);\ + x=x/y;y=y/x;\ + printf("%d, %d\n", (int)x, (int)y);\ + x=x+x;y=y+y;\ + printf("%d, %d\n", (int)x, (int)y);\ +}\ +\ void prefix ## signed_zeros(void) \ {\ type x = 0.0, y = -0.0, n, p;\ @@ -1781,7 +1792,7 @@ void prefix ## signed_zeros(void) \ 1.0 / x != 1.0 / p);\ else\ printf ("x != +y; this is wrong!\n");\ - p = -y;\ + p = -y;\ if (x == p)\ printf ("Test 1.0 / x != 1.0 / -y returns %d (should be 0).\n",\ 1.0 / x != 1.0 / p);\ @@ -1797,6 +1808,7 @@ void prefix ## test(void)\ prefix ## fcast(234.6);\ prefix ## fcast(-2334.6);\ prefix ## call();\ + prefix ## calc(1, 1.0000000000000001);\ prefix ## signed_zeros();\ } @@ -2623,7 +2635,6 @@ int constant_p_var; void builtin_test(void) { -#if GCC_MAJOR >= 3 COMPAT_TYPE(int, int); COMPAT_TYPE(int, unsigned int); COMPAT_TYPE(int, char); @@ -2633,9 +2644,9 @@ void builtin_test(void) COMPAT_TYPE(int *, void *); COMPAT_TYPE(int *, const int *); COMPAT_TYPE(char *, unsigned char *); + COMPAT_TYPE(char, unsigned char); /* space is needed because tcc preprocessor introduces a space between each token */ - COMPAT_TYPE(char * *, void *); -#endif + COMPAT_TYPE(char **, void *); printf("res = %d\n", __builtin_constant_p(1)); printf("res = %d\n", __builtin_constant_p(1 + 2)); printf("res = %d\n", __builtin_constant_p(&constant_p_var)); From 9c78da8a32f679e3662d80d361a5eec31740cf95 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Wed, 21 May 2014 12:50:12 +0800 Subject: [PATCH 45/52] forget Delete __va_ld_reg --- lib/libtcc1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/libtcc1.c b/lib/libtcc1.c index 58324a9..b944f4f 100644 --- a/lib/libtcc1.c +++ b/lib/libtcc1.c @@ -640,7 +640,7 @@ extern void abort(void); #endif enum __va_arg_type { - __va_gen_reg, __va_float_reg, __va_ld_reg, __va_stack + __va_gen_reg, __va_float_reg, __va_stack }; //This should be in sync with the declaration on our include/stdarg.h From bcf60562e056265d0197bd3765a4d5256e2ca7ec Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Fri, 23 May 2014 15:46:08 +0800 Subject: [PATCH 46/52] The number of rows to display warning is wrong For example: #define TOK_ASM_weak TOK_WEAK1 #define TOK_ASM_weak TOK_WEAK Output: C8.c:3: warning: TOK_ASM_weak redefined --- libtcc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libtcc.c b/libtcc.c index dc01831..721eaed 100644 --- a/libtcc.c +++ b/libtcc.c @@ -576,12 +576,15 @@ static void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap) for (f = file; f && f->filename[0] == ':'; f = f->prev) ; if (f) { + int line_num = f->line_num; for(pf = s1->include_stack; pf < s1->include_stack_ptr; pf++) strcat_printf(buf, sizeof(buf), "In file included from %s:%d:\n", (*pf)->filename, (*pf)->line_num); - if (f->line_num > 0) { + if (line_num > 0) { + if(tok == TOK_LINEFEED) + line_num--; strcat_printf(buf, sizeof(buf), "%s:%d: ", - f->filename, f->line_num); + f->filename, line_num); } else { strcat_printf(buf, sizeof(buf), "%s: ", f->filename); From 698b16960a9978fd830a14983605ad8b6bc8945d Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Wed, 28 May 2014 10:38:26 +0800 Subject: [PATCH 47/52] Modify the 66_macro_concat_end.expect I was busy recently, forget test. Thank Austin --- tests/tests2/66_macro_concat_end.expect | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tests2/66_macro_concat_end.expect b/tests/tests2/66_macro_concat_end.expect index 224e5c9..8dbf5bb 100644 --- a/tests/tests2/66_macro_concat_end.expect +++ b/tests/tests2/66_macro_concat_end.expect @@ -1 +1 @@ -66_macro_concat_end.c:2: error: '##' invalid at end of macro +66_macro_concat_end.c:1: error: '##' invalid at end of macro From 89134dd7b021389331d91e0552babf6de5108588 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Wed, 28 May 2014 21:51:50 +0800 Subject: [PATCH 48/52] Considering the effect of CH_EOF on line_num --- libtcc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libtcc.c b/libtcc.c index 721eaed..d761582 100644 --- a/libtcc.c +++ b/libtcc.c @@ -581,7 +581,7 @@ static void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap) strcat_printf(buf, sizeof(buf), "In file included from %s:%d:\n", (*pf)->filename, (*pf)->line_num); if (line_num > 0) { - if(tok == TOK_LINEFEED) + if(tok == TOK_LINEFEED || (tok == CH_EOF && line_num > 1)) line_num--; strcat_printf(buf, sizeof(buf), "%s:%d: ", f->filename, line_num); From d316836008f4738d5a020b28aa33e96a82a81aca Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Wed, 28 May 2014 22:09:49 +0800 Subject: [PATCH 49/52] Let init_putz one-time generation. At the same time, increase the GCC style warning --------------------------------------------------------------------------- int main() { int a[10] = {[5]=5}; return 0; } Disassembly of section .text: 0000000000000000
: 0: 55 push %rbp 1: 48 89 e5 mov %rsp,%rbp 4: 48 81 ec 30 00 00 00 sub $0x30,%rsp b: b8 05 00 00 00 mov $0x5,%eax 10: 89 45 ec mov %eax,-0x14(%rbp) 13: 48 b8 14 00 00 00 00 movabs $0x14,%rax 1a: 00 00 00 1d: 49 89 c2 mov %rax,%r10 20: b8 00 00 00 00 mov $0x0,%eax 25: 48 89 c6 mov %rax,%rsi 28: 48 8d 45 d8 lea -0x28(%rbp),%rax 2c: 48 89 c7 mov %rax,%rdi 2f: 4c 89 d2 mov %r10,%rdx 32: b8 00 00 00 00 mov $0x0,%eax 37: e8 fc ff ff ff callq 38 3c: 48 b8 10 00 00 00 00 movabs $0x10,%rax 43: 00 00 00 46: 49 89 c2 mov %rax,%r10 49: b8 00 00 00 00 mov $0x0,%eax 4e: 48 89 c6 mov %rax,%rsi 51: 48 8d 45 f0 lea -0x10(%rbp),%rax 55: 48 89 c7 mov %rax,%rdi 58: 4c 89 d2 mov %r10,%rdx 5b: b8 00 00 00 00 mov $0x0,%eax 60: e8 fc ff ff ff callq 61 65: b8 00 00 00 00 mov $0x0,%eax 6a: e9 00 00 00 00 jmpq 6f 6f: c9 leaveq 70: c3 retq After the patch 0000000000000000
: 0: 55 push %rbp 1: 48 89 e5 mov %rsp,%rbp 4: 48 81 ec 30 00 00 00 sub $0x30,%rsp b: 48 b8 28 00 00 00 00 movabs $0x28,%rax 12: 00 00 00 15: 49 89 c2 mov %rax,%r10 18: b8 00 00 00 00 mov $0x0,%eax 1d: 48 89 c6 mov %rax,%rsi 20: 48 8d 45 d8 lea -0x28(%rbp),%rax 24: 48 89 c7 mov %rax,%rdi 27: 4c 89 d2 mov %r10,%rdx 2a: b8 00 00 00 00 mov $0x0,%eax 2f: e8 fc ff ff ff callq 30 34: b8 05 00 00 00 mov $0x5,%eax 39: 89 45 ec mov %eax,-0x14(%rbp) 3c: b8 00 00 00 00 mov $0x0,%eax 41: e9 00 00 00 00 jmpq 46 46: c9 leaveq 47: c3 retq ----------------------------------------------------------------------------------- "c5.c" int main() { // union st struct st { char c; short s; // char cc[]; }; // union st struct st ss = { 1, 2, 3}; // int a = ss; char cb[1] = {1,2,3}; return 0; } c5.c:12: warning: excess elements in struct initializer c5.c:14: warning: excess elements in array initializer c5.c:14: warning: excess elements in array initializer --- tccgen.c | 116 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 64 insertions(+), 52 deletions(-) diff --git a/tccgen.c b/tccgen.c index d286dd4..b2a7717 100644 --- a/tccgen.c +++ b/tccgen.c @@ -90,6 +90,7 @@ static void vla_runtime_type_size(CType *type, int *a); static void vla_sp_save(void); static int is_compatible_parameter_types(CType *type1, CType *type2); static void expr_type(CType *type); +static int is_putz; static int is_force; ST_FUNC void vpush64(int ty, unsigned long long v); @@ -5039,11 +5040,11 @@ static void decl_designator(CType *type, Section *sec, unsigned long c, nb_elems = 1; if (gnu_ext && (l = is_label()) != 0) goto struct_field; + s = type->ref; while (tok == '[' || tok == '.') { if (tok == '[') { if (!(type->t & VT_ARRAY)) expect("array type"); - s = type->ref; next(); index = expr_const(); if (index < 0 || (s->c >= 0 && index >= s->c)) @@ -5077,7 +5078,6 @@ static void decl_designator(CType *type, Section *sec, unsigned long c, struct_field: if ((type->t & VT_BTYPE) != VT_STRUCT) expect("struct/union type"); - s = type->ref; l |= SYM_FIELD; f = s->next; while (f) { @@ -5107,17 +5107,30 @@ static void decl_designator(CType *type, Section *sec, unsigned long c, } else { if (type->t & VT_ARRAY) { index = *cur_index; - type = pointed_type(type); - c += index * type_size(type, &align); + if (s->c >= 0 && index >= s->c){ + if(!size_only) + tcc_warning("excess elements in array initializer"); + type = NULL; + size_only = 1; + }else{ + type = pointed_type(type); + c += index * type_size(type, &align); + } } else { f = *cur_field; - if (!f) - tcc_error("too many field init"); - /* XXX: fix this mess by using explicit storage field */ - type1 = f->type; - type1.t |= (type->t & ~VT_TYPE); - type = &type1; - c += f->c; + if (f){ + /* XXX: fix this mess by using explicit storage field */ + type1 = f->type; + type1.t |= (type->t & ~VT_TYPE); + type = &type1; + c += f->c; + }else{ + if(!size_only) + tcc_warning("excess elements in %s initializer", + get_tok_str(s->type.t, NULL)); + type = NULL; + size_only = 1; + } } } decl_initializer(type, sec, c, 0, size_only); @@ -5277,6 +5290,8 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, Sym *s, *f; CType *t1; + if(!type) + goto Ignore; if (type->t & VT_VLA) { int a; @@ -5367,14 +5382,10 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, index = 0; while (tok != '}') { decl_designator(type, sec, c, &index, NULL, size_only); - if (n >= 0 && index >= n) - tcc_error("index too large"); /* must put zero in holes (note that doing it that way ensures that it even works with designators) */ - if (!size_only && array_length < index) { - init_putz(t1, sec, c + array_length * size1, - (index - array_length) * size1); - } + if (!is_putz && array_length < index) + is_putz = 1; index++; if (index > array_length) array_length = index; @@ -5391,10 +5402,8 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, if (!no_oblock) skip('}'); /* put zeros at the end */ - if (!size_only && n >= 0 && array_length < n) { - init_putz(t1, sec, c + array_length * size1, - (n - array_length) * size1); - } + if (!is_putz && n >= 0 && array_length < n) + is_putz = 1; /* patch type size if needed */ if (n < 0) s->c = array_length; @@ -5440,46 +5449,44 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, n = s->c; while (tok != '}') { decl_designator(type, sec, c, NULL, &f, size_only); - index = f->c; - if (!size_only && array_length < index) { - init_putz(type, sec, c + array_length, - index - array_length); - } - index = index + type_size(&f->type, &align1); - if (index > array_length) - array_length = index; + if(f){ + index = f->c; + if (!is_putz && array_length < index) + is_putz = 1; + index = index + type_size(&f->type, &align1); + if (index > array_length) + array_length = index; - /* gr: skip fields from same union - ugly. */ - while (f->next) { - ///printf("index: %2d %08x -- %2d %08x\n", f->c, f->type.t, f->next->c, f->next->type.t); - /* test for same offset */ - if (f->next->c != f->c) - break; - /* if yes, test for bitfield shift */ - if ((f->type.t & VT_BITFIELD) && (f->next->type.t & VT_BITFIELD)) { - int bit_pos_1 = (f->type.t >> VT_STRUCT_SHIFT) & 0x3f; - int bit_pos_2 = (f->next->type.t >> VT_STRUCT_SHIFT) & 0x3f; - //printf("bitfield %d %d\n", bit_pos_1, bit_pos_2); - if (bit_pos_1 != bit_pos_2) + /* gr: skip fields from same union - ugly. */ + while (f->next) { + ///printf("index: %2d %08x -- %2d %08x\n", f->c, f->type.t, f->next->c, f->next->type.t); + /* test for same offset */ + if (f->next->c != f->c) break; + /* if yes, test for bitfield shift */ + if ((f->type.t & VT_BITFIELD) && (f->next->type.t & VT_BITFIELD)) { + int bit_pos_1 = (f->type.t >> VT_STRUCT_SHIFT) & 0x3f; + int bit_pos_2 = (f->next->type.t >> VT_STRUCT_SHIFT) & 0x3f; + //printf("bitfield %d %d\n", bit_pos_1, bit_pos_2); + if (bit_pos_1 != bit_pos_2) + break; + } + f = f->next; } - f = f->next; - } - f = f->next; - if (no_oblock && f == NULL) - break; + f = f->next; + if (no_oblock && f == NULL) + break; + } if (tok == '}') break; skip(','); } - /* put zeros at the end */ - if (!size_only && array_length < n) { - init_putz(type, sec, c + array_length, - n - array_length); - } if (!no_oblock) skip('}'); + /* put zeros at the end */ + if (!is_putz && array_length < n) + is_putz = 1; while (par_count) { skip(')'); par_count--; @@ -5489,6 +5496,7 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, decl_initializer(type, sec, c, first, size_only); skip('}'); } else if (size_only) { +Ignore: /* just skip expression */ parlevel = parlevel1 = 0; while ((parlevel > 0 || parlevel1 > 0 || @@ -5533,6 +5541,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, Sym *flexible_array; flexible_array = NULL; + is_putz = 0; if ((type->t & VT_BTYPE) == VT_STRUCT) { Sym *field = type->ref->next; if (field) { @@ -5551,7 +5560,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, literals). It also simplifies local initializers handling */ tok_str_new(&init_str); - if (size < 0 || (flexible_array && has_init)) { + if (size < 0 || ((((type->t & VT_BTYPE) == VT_STRUCT) || (type->t & VT_ARRAY)) && + has_init && (tok < TOK_IDENT))){ if (!has_init) tcc_error("unknown type size"); /* get all init string */ @@ -5742,6 +5752,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, #endif } if (has_init || (type->t & VT_VLA)) { + if(is_putz) + init_putz(type, sec, addr, size); decl_initializer(type, sec, addr, 1, 0); /* restore parse state if needed */ if (init_str.str) { From 7a3f6d49415fd5f1fa99d25aba40c7884d5774a4 Mon Sep 17 00:00:00 2001 From: YX Hao Date: Mon, 16 Jun 2014 16:00:46 +0800 Subject: [PATCH 50/52] Win: Enable use "*.def + *.c" files as library instead of *.a by "-l" option example: "-lshell32" will try "shell32.def + shell32.c" Add lib type "%s/%s.c" for tcc_add_library() ('-l' option parse) So tcc can use all files as scripts. --- libtcc.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/libtcc.c b/libtcc.c index d761582..070c6f3 100644 --- a/libtcc.c +++ b/libtcc.c @@ -1300,7 +1300,7 @@ ST_FUNC int tcc_add_crt(TCCState *s, const char *filename) LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname) { #ifdef TCC_TARGET_PE - const char *libs[] = { "%s/%s.def", "%s/lib%s.def", "%s/%s.dll", "%s/lib%s.dll", "%s/lib%s.a", NULL }; + const char *libs[] = { "%s/%s.def", "%s/lib%s.def", "%s/%s.dll", "%s/lib%s.dll", "%s/lib%s.a", "%s/%s.c", NULL }; const char **pp = s->static_link ? libs + 4 : libs; #else const char *libs[] = { "%s/lib%s.so", "%s/lib%s.a", NULL }; @@ -1308,8 +1308,15 @@ LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname) #endif while (*pp) { if (0 == tcc_add_library_internal(s, *pp, - libraryname, 0, s->library_paths, s->nb_library_paths)) + libraryname, 0, s->library_paths, s->nb_library_paths)) { +#ifdef TCC_TARGET_PE + /* extra search for *.c file together with *.def file */ + if (pp < libs + 2) + tcc_add_library_internal(s, *(libs + 5), libraryname, 0, + s->library_paths, s->nb_library_paths); +#endif return 0; + } ++pp; } return -1; From 1fa0fe2786c851fc06766e8a77a882298d2cc64b Mon Sep 17 00:00:00 2001 From: Thomas Coudray Date: Fri, 20 Jun 2014 13:26:29 +0100 Subject: [PATCH 51/52] Revert "Win: Enable use "*.def + *.c" files as library instead of *.a by "-l" option" This reverts commit 7a3f6d49415fd5f1fa99d25aba40c7884d5774a4. --- libtcc.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/libtcc.c b/libtcc.c index 070c6f3..d761582 100644 --- a/libtcc.c +++ b/libtcc.c @@ -1300,7 +1300,7 @@ ST_FUNC int tcc_add_crt(TCCState *s, const char *filename) LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname) { #ifdef TCC_TARGET_PE - const char *libs[] = { "%s/%s.def", "%s/lib%s.def", "%s/%s.dll", "%s/lib%s.dll", "%s/lib%s.a", "%s/%s.c", NULL }; + const char *libs[] = { "%s/%s.def", "%s/lib%s.def", "%s/%s.dll", "%s/lib%s.dll", "%s/lib%s.a", NULL }; const char **pp = s->static_link ? libs + 4 : libs; #else const char *libs[] = { "%s/lib%s.so", "%s/lib%s.a", NULL }; @@ -1308,15 +1308,8 @@ LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname) #endif while (*pp) { if (0 == tcc_add_library_internal(s, *pp, - libraryname, 0, s->library_paths, s->nb_library_paths)) { -#ifdef TCC_TARGET_PE - /* extra search for *.c file together with *.def file */ - if (pp < libs + 2) - tcc_add_library_internal(s, *(libs + 5), libraryname, 0, - s->library_paths, s->nb_library_paths); -#endif + libraryname, 0, s->library_paths, s->nb_library_paths)) return 0; - } ++pp; } return -1; From f26fdaefd8b35489f26462992010b9ecd76d8fe3 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Mon, 23 Jun 2014 01:08:54 +0800 Subject: [PATCH 52/52] revert vstore() --- tccgen.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tccgen.c b/tccgen.c index b2a7717..387b986 100644 --- a/tccgen.c +++ b/tccgen.c @@ -2552,6 +2552,11 @@ ST_FUNC void vstore(void) /* remove bit field info to avoid loops */ vtop[-1].type.t = ft & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); + /* duplicate source into other register */ + gv_dup(); + vswap(); + vrott(3); + if((ft & VT_BTYPE) == VT_BOOL) { gen_cast(&vtop[-1].type); vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED); @@ -2583,6 +2588,9 @@ ST_FUNC void vstore(void) gen_op('|'); /* store result */ vstore(); + + /* pop off shifted source from "duplicate source..." above */ + vpop(); } else { #ifdef CONFIG_TCC_BCHECK /* bound check case */