fixes 5c35ba66c5
Implementation was consistent within tcc but incompatible
with the ABI (for example library functions vprintf etc)
Also:
- tccpp.c/get_tok_str() : avoid "unknown format "%llu" warning
- x86_64_gen.c/gen_vla_alloc() : fix vstack leak
The case below previously was causing an assertion failure
in the target specific generator.
It probably is not incorrect not to allow this even if
gcc does.
struct S { long b; };
void f(struct S *x)
{
struct S y[1] = { *x };
}
The check for structs was too late and on amd64 and aarch64 could
lead to accepting and then asserting with code like:
struct S {...} s;
char *c = (char*)0x10 - s;
... for fast redeclaration checks
Also, check function parameters too:
void foo(int a) { int a; ... }
Also, try to fix struct/union/enum's on different scopes:
{ struct xxx { int x; };
{ struct xxx { int y; }; ... }}
and some (probably not all) combination with incomplete
declarations "struct xxx;"
Replaces 2bfedb1867
and 07d896c8e5
Fixes cf95ac399c
A constant expression removed from the loop.
If subroutine have 50000+ local variables, then currently
compilation of such code takes obly 15 sec. Was 2 min.
gcc-4.1.2 compiles such code in 7 sec. pcc -- 3.44 min.
A test generator:
#include <stdio.h>
int main() {
puts("#include <stdio.h>"); puts("int main()"); puts("{");
for (int i = 0; i < 50000; ++i) printf("int X%d = 1;\n", i);
for (int i = 0; i < 50000; ++i) puts("scanf(\"%d\", &X0);");
puts("}");
return 0;
}
don't catch redefinition for local vars. With this option on
tcc accepts the following code:
int main()
{
int a = 0;
long a = 0;
}
But if you shure there is no problem with your local variables,
then a compilation speed can be improved if you have a lots of
the local variables (50000+)
From gcc docs: "You may also specify attributes between the enum, struct or union tag and the name of the type rather than after the closing brace."
Adds `82_attribs_position.c` in `tests/tests2`
the check on incomplete struct/union/enum types was too early,
disallowing mixed specifiers and qualifiers. Simply rely on
the size (->c) field for that. See testcases.
A CString used to be copied into a token string, which is an int array.
On a 64-bit architecture the pointers were misaligned, so ASan gave
lots of warnings. On a 64-bit architecture that required memory
accesses to be correctly aligned it would not work at all.
The CString is now included in CValue instead.
Some test cases:
#define SE ({ switch (0) { } 0; })
// Should give error:
int x = SE;
void f(void) { static int x = SE; }
void f(void) { enum e { a = SE }; }
void f(void) { switch (0) { case SE: break; } }
// Correct:
int f(void) { return SE; }
int f(void) { return sizeof(SE); }
- avoid memory allocation by using its (int) token number
- avoid additional function parameter by using Attribute
Also: fix some strange looking error messages
In a case like
typedef int T[1];
const T x;
we must make a copy of the typedef type so that we can add the type
qualifiers to it.
The following code used to give
error: incompatible types for redefinition of 'f'
typedef int T[1];
void f(const int [1]);
void f(const T);
don't crash
a test program:
================
typedef struct X { int len; } X;
#define init(s,len) s.len = len;
int main(void) {
X myX;
init(myX,10);
return 0;
}
================
After a patch:
error: field name expected
a test program:
========
typedef struct X { int len; } X;
int main(void) {
X myX;
myX.10 = 10;
return 0;
}
========
Error message before a patch:
error: ';' expected (got "(null)")
After a patch:
error: field name expected
* Documentation is now in "docs".
* Source code is now in "src".
* Misc. fixes here and there so that everything still works.
I think I got everything in this commit, but I only tested this
on Linux (Make) and Windows (CMake), so I might've messed
something up on other platforms...
Jsut for testing. It works for me (don't break anything)
Small fixes for x86_64-gen.c in "tccpp: fix issues, add tests"
are dropped in flavor of this patch.
Pip Cet:
Okay, here's a first patch that fixes the problem (but I've found
another bug, yet unfixed, in the process), though it's not
particularly pretty code (I tried hard to keep the changes to the
minimum necessary). If we decide to actually get rid of VT_QLONG and
VT_QFLOAT (please, can we?), there are some further simplifications in
tccgen.c that might offset some of the cost of this patch.
The idea is that an integer is no longer enough to describe how an
argument is stored in registers. There are a number of possibilities
(none, integer register, two integer registers, float register, two
float registers, integer register plus float register, float register
plus integer register), and instead of enumerating them I've
introduced a RegArgs type that stores the offsets for each of our
registers (for the other architectures, it's simply an int specifying
the number of registers). If someone strongly prefers an enum, we
could do that instead, but I believe this is a place where keeping
things general is worth it, because this way it should be doable to
add SSE or AVX support.
There is one line in the patch that looks suspicious:
} else {
addr = (addr + align - 1) & -align;
param_addr = addr;
addr += size;
- sse_param_index += reg_count;
}
break;
However, this actually fixes one half of a bug we have when calling a
function with eight double arguments "interrupted" by a two-double
structure after the seventh double argument:
f(double,double,double,double,double,double,double,struct { double
x,y; },double);
In this case, the last argument should be passed in %xmm7. This patch
fixes the problem in gfunc_prolog, but not the corresponding problem
in gfunc_call, which I'll try tackling next.
* fix some macro expansion issues
* add some pp tests in tests/pp
* improved tcc -E output for better diff'ability
* remove -dD feature (quirky code, exotic feature,
didn't work well)
Based partially on ideas / researches from PipCet
Some issues remain with VA_ARGS macros (if used in a
rather tricky way).
Also, to keep it simple, the pp doesn't automtically
add any extra spaces to separate tokens which otherwise
would form wrong tokens if re-read from tcc -E output
(such as '+' '=') GCC does that, other compilers don't.
* cleanups
- #line 01 "file" / # 01 "file" processing
- #pragma comment(lib,"foo")
- tcc -E: forward some pragmas to output (pack, comment(lib))
- fix macro parameter list parsing mess from
a3fc543459a715d7143d
(some coffee might help, next time ;)
- introduce TOK_PPSTR - to have character constants as
written in the file (similar to TOK_PPNUM)
- allow '\' appear in macros
- new functions begin/end_macro to:
- fix switching macro levels during expansion
- allow unget_tok to unget more than one tok
- slight speedup by using bitflags in isidnum_table
Also:
- x86_64.c : fix decl after statements
- i386-gen,c : fix a vstack leak with VLA on windows
- configure/Makefile : build on windows (MSYS) was broken
- tcc_warning: fflush stderr to keep output order (win32)
Author: Philip <pipcet@gmail.com>
Our VLA code can be made a lot simpler (simple enough for
even me to understand it) by giving up on the optimization idea, which
is very tempting. There's a patch to do that attached, feel free to
test and commit it if you like. (It passes all the tests, at least
I think this code only affects the ARM EABI target, and only when
returning small structures that might be unaligned. However, it was both
leaking vstack entries and failing to achieve what I think is its
purpose, to ensure the sret argument would be aligned properly. Both
issues fixed.
This patch disables the optimization of saving stack pointers lazily,
which didn't fully take into account that control flow might not reach
the stack-saving instructions. I've decided to leave in the extra calls
to vla_sp_save() in case anyone wants to restore this optimization.
Tests added and enabled.
There are two remaining bugs: VLA variables can be modified, and jumping
into the scope of a declared VLA will cause a segfault rather than a
compiler error. Both of these do not affect correct C code, but should
be fixed at some point. Once VLA variables have been made properly
immutable, we can share them with the saved stack pointer and save stack
and instructions.
- pop_macro incorrect with initially undefined macro
- horrible implementation (tcc_open_bf)
- crashes eventually (abuse of Sym->prev_tok)
- the (unrelated) asm_label part is the opposite of a fix
(Despite of its name this variable has nothing to do with
the built-in assembler)
This reverts commit 0c8447db79.
* give warning if pragma is unknown for tcc
* don't free asm_label in sym_free(),
it's a job of the asm_free_labels().
The above pragmas are used in the mingw headers.
Thise pragmas are implemented in gcc-4.5+ and current
clang.
This is for a case when no '{' is used in the initialization code.
An option name is -fold-struct-init-code. A linux 2.4.26 can't
find initrd when compiled with a new algorithm.
- a warning: unnamed struct/union that defines no instances
- allow a nested named struct declaration w/o identifier
only when option -fms-extensions is used
On Linux 32: sizeof(long)=32 == sizeof(void *)=32
on Linux 64: sizeof(long)=64 == sizeof(void *)=64
on Windows 64: sizeof(long)=32 != sizeof(void *)=64
The following check in tccgen.c is removed
if (nocode_wanted)
tcc_error("statement expression in global scope");
This check is introduced in commit 5bcc3eed7b and breaks compilation
of the linux 2.4.26 kernel.
int i = i++ causes a segfault because of missing guard. Looking
recursively at all backend functions called from middle end several more
guard appeared to be missing.
The common code to move a returned structure packed into
registers into memory on the caller side didn't take the
register size into account when allocating local storage,
so sometimes that lead to stack overwrites (e.g. in 73_arm64.c),
on x86_64. This fixes it by generally making gfunc_sret also return
the register size.
__clear_cache is defined in lib-arm64.c with a single call to
__arm64_clear_cache, which is the real built-in function and is
turned into inline assembler by gen_clear_cache in arm64-gen.c
More precisely, treat (0 << x) and so on as constant expressions, but
not if const_wanted as we do not want to allow "case (x*0):", ...
Do not optimise (0 / x) and (0 % x) here as x might be zero, though
for an architecture that does not generate an exception for division
by zero the back end might choose to optimise those.
a test program:
struct {
int a[2], b[2];
} cases[] = {
{ ((int)0), (((int)0)) },
((int)0), (((int)0)) /* error: ',' expected (got ")") */
};
int main() { return 0; }
This commit allow to skip ')' in the decl_initializer() and to see ','
A test program:
//////////////
int main()
{
void *p = ({ 0 ; ((void *)1); });
}
/////////////
Porblem is introduced in a commit a80acab: Display error on statement expressions with complex return type
This error is exposed when compiling a linux 2.4.26. tcc 0.9.23 can sucessfully compile
this version of the linux.
Current tcc don't understand an initialization of the empty struct
This problem was found trying to compile a linux kernel 2.4.26
which can be compiled by tcc 0.9.23
A test program:
////////////////////
// ./tcc -c test_3.c
// test_3.c:31: error: too many field init
#undef __GNUC__
#undef __GNUC_MINOR__
#define __GNUC__ 2
#define __GNUC_MINOR__ 95
typedef struct { } rwlock_t;
struct fs_struct {
int count;
rwlock_t lock;
int umask;
};
#define INIT_FS { \
1, \
RW_LOCK_UNLOCKED, \
0022, \
}
#if (__GNUC__ > 2 || __GNUC_MINOR__ > 91)
typedef struct { } rwlock_t;
#define RW_LOCK_UNLOCKED (rwlock_t) { }
#else
typedef struct { int gcc_is_buggy; } rwlock_t;
#define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
#endif
static struct fs_struct init_fs = INIT_FS;
// static struct fs_struct init_fs = { { (1) }, (rwlock_t) { 0 }, 0022, };
// ^ with this all Ok
// static struct fs_struct init_fs = { { (1) }, (rwlock_t) { }, 0022, };
// ^ current tcc don't understand, but tcc 0.9.23 can
int main()
{
return 0;
}
////////////////////
A regression is detected after a patch 69fdb57edd
////////////////////
// A test for patch 69fdb57edd
// Author: grischka <grischka>
// Date: Wed Jun 17 02:09:07 2009 +0200
// unions: initzialize only one field
// struct {
// union {
// int a,b;
// };
// int c;
// } sss = { 1,2 };
// This had previously assigned 1,2 to a,b and 0 to c which is wrong.
//
// Expected: sss.a=1 sss.b=1 sss.c=2
int main()
{
struct {
union {
int a,b;
};
int c;
} sss = { 1, 2 };
printf ("sss.a=%d sss.b=%d sss.c=%d\n", sss.a, sss.b, sss.c);
return 0;
}
////////////////////
A regression was found trying to compile a linux kernel 2.4.26
which can be compiled by tcc 0.9.23
///////////////////
#include <stdio.h>
// test for a bug:
// compiler don't understand am extern array of structs
// $ tcc test_1.c
// test_1.c:8: error: unknown struct/union/enum
extern struct FILE std_files[4];
int main()
{
return 0;
}
//////////////////
tcc-current
/* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */
static void struct_decl(CType *type, int u, int tdef)
...
if (tok != '{') {
v = tok;
next();
/* struct already defined ? return it */
if (v < TOK_IDENT)
expect("struct/union/enum name");
s = struct_find(v);
if (s) {
if (s->type.t != a)
tcc_error("invalid type");
goto do_decl;
} else if (tok >= TOK_IDENT && !tdef)
tcc_error("unknown struct/union/enum");
} else {
v = anon_sym++;
}
tcc-0.9.23 which don't have such error
/* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */
static void struct_decl(CType *type, int u)
....
if (tok != '{') {
v = tok;
next();
/* struct already defined ? return it */
if (v < TOK_IDENT)
expect("struct/union/enum name");
s = struct_find(v);
if (s) {
if (s->type.t != a)
error("invalid type");
goto do_decl;
}
} else {
v = anon_sym++;
}
libtcc.c: Add greloca, a generalisation of greloc that takes an addend.
tcc.h: Add greloca and put_elf_reloca.
tccelf.c: Add put_elf_reloca, a generalisation of put_elf_reloc.
tccgen.c: On x86_64, use greloca instead of greloc in init_putv.
The back end functions gen_op(comparison) and gtst() might allocate
registers so case_reg should be left on the value stack while they
are called and set again afterwards.
This for example suppresses string constants such as with
int main()
{
return sizeof "foo";
}
Actually, setting
nocode_wanted = 1;
in libtcc.c for the initial global level seemed wrong, since
obviously "nocode_wanted" means code as any side effects, also
such as string constants.
This reverts a part of 2de1b2d14c
(documented as "Some in-between fixes" in Changelog)
This adds parsing of (GCC compatible) visibility attribute
in order to mark selected global symbols as hidden. The generated
.o files contain hidden symbols already, the TCC linker doesn't
yet do the right thing.
*** UNCONDITIONALLY ***
Esp. sihce tinycc winapi headers are not as complete as people might
expect this can otherwise lead to obscure problems that are difficult
to debug.
(Originally 'warn_implicit_function_declaration' was set to 1
always for windows but someone must have deleted that line)
This was going wrong (case TOK_LAND in unary: computed labels)
- vset(&s->type, VT_CONST | VT_SYM, 0);
- vtop->sym = s;
This does the right thing and is shorter:
+ vpushsym(&s->type, s);
Test case was:
int main(int argc, char **argv)
{
int x;
static void *label_return = &&lbl_return;
printf("label_return = %p\n", label_return);
goto *label_return; //<<<<< here segfault on linux X86_64 without the memset on vset
printf("unreachable\n");
lbl_return:
return 0;
}
Also::
- Rename "void* CValue.ptr" to more usable "addr_t ptr_offset"
and start to use it in obvious cases.
- use __attribute__ ((noreturn)) only with gnu compiler
- Revert CValue memsets ("After several days searching ...")
commit 4bc83ac393
Doesn't mean that the vsetX/vpush thingy isn't brittle and
there still might be bugs as to differences in how the CValue
union was set and is then interpreted later on.
However the big memset hammer was just too slow (-3% overall).
For program manipulating argv or arge as pointer with construct such as:
(while *argv++) {
do_something_with_argv;
}
it is necessary to have argv and arge inside a region. This patch create
regions argv and arge) if main is declared with those parameters.
I found the problem it was because CValue stack variables have rubish as it inital values
and assigning to a member that is smaller than the big union item and trying to
recover it later as a different member gives bak garbage.
ST_FUNC void vset(TCCState* tcc_state, CType *type, int r, int v)
{
CValue cval;
memset(&cval, 0, sizeof(CValue));
cval.i = v; //,<<<<<<<<<<< here is the main bug that mix with garbage
vsetc(tcc_state, type, r, &cval);
}
/* store a value or an expression directly in global data or in local array */
static void init_putv(TCCState* tcc_state, CType *type, Section *sec, unsigned long c,
int v, int expr_type)
{
...
case VT_PTR:
if (tcc_state->tccgen_vtop->r & VT_SYM) {
greloc(tcc_state, sec, tcc_state->tccgen_vtop->sym, c, R_DATA_PTR);
}
//<<< on the next line is where we try to get the assigned value to cvalue.i as cvalue.ull
*(addr_t *)ptr |= (tcc_state->tccgen_vtop->c.ull & bit_mask) << bit_pos;
break;
Also this patch makes vla tests pass on linux 32 bits
When checking for exact compatibility between types (such as in
__builtin_types_compatible_p) consider the case of default signedness to
be incompatible with both of the explicit signedness for char. That is,
char is incompatible with signed char *and* unsigned char, no matter
what the default signedness for char is.
negate(x) is subtract(-0,x), not subtract(+0,x), which makes
a difference with signed zeros. Also +x was expressed as x+0,
in order for the integer promotions to happen, but also mangles signed
zeros, so just don't do that with floating types.
Applying 64bit relocs assumes that the CVal is initialized to zero
for the whole 64bit. Consolidate this a bit, at the same time
zeroing the .ull member more consistently when needed. Fixes segfault
on x86_64-linux using global vars in tcctest.c.
Refactoring (no logical changes):
- use memcpy in tccgen.c:ieee_finite(double d)
- use union to store attribute flags in Sym
Makefile: "CFLAGS+=-fno-strict-aliasing" basically not necessary
anymore but I left it for now because gcc sometimes behaves
unexpectedly without.
Also:
- configure: back to mode 100755
- tcc.h: remove unused variables tdata/tbss_section
- x86_64-gen.c: adjust gfunc_sret for prototype
- tccgen: error out for cast to void, as in
void foo(void) { return 1; }
This avoids an assertion failure in x86_64-gen.c, also.
also fix tests2/03_struct.c accordingly
- Error: "memory full" - be more specific
- Makefiles: remove circular dependencies, lookup tcctest.c from VPATH
- tcc.h: cleanup lib, include, crt and libgcc search paths"
avoid duplication or trailing slashes with no CONFIG_MULTIARCHDIR
(as from 9382d6f1a0)
- tcc.h: remove ";{B}" from PE search path
in ce5e12c2f9 James Lyon wrote:
"... I'm not sure this is the right way to fix this problem."
And the answer is: No, please. (copying libtcc1.a for tests instead)
- win32/build_tcc.bat: do not move away a versioned file
The procedure calling standard for ARM architecture mandate the use of
the base standard for variadic function. Therefore, hgen float aggregate
must be returned via stack when greater than 4 bytes and via core
registers else in case of variadic function.
This patch improve gfunc_sret() to take into account whether the
function is variadic or not and make use of gfunc_sret() return value to
determine whether to pass a structure via stack in gfunc_prolog(). It
also take advantage of knowing if a function is variadic or not move
float result value from VFP register to core register in gfunc_epilog().
Move the logic to do a test of an integer value (ex if (0)) out of
arch-specific code to tccgen.c to avoid code duplication. This also
fixes test of long long value which was only testing the bottom half of
such values on 32 bits architectures.
- avoid assumption "ret_align == register_size" which is
false for non-arm targets
- rename symbol "sret" to more descriptive "ret_nregs"
This fixes commit dcec8673f2
Also:
- remove multiple definitions in win32/include/math.h