Continuing d6072d37 (Add __builtin_frame_address(0)) implement __builtin_frame_address for levels greater than zero, in order for tinycc to be able to compile its own lib/bcheck.c after cffb7af9 (lib/bcheck: Prevent __bound_local_new / __bound_local_delete from being miscompiled). I'm new to the internals, and used the most simple way to do it. Generated code is not very good for levels >= 2, compare gcc tcc level=0 mov %ebp,%eax lea 0x0(%ebp),%eax level=1 mov 0x0(%ebp),%eax mov 0x0(%ebp),%eax level=2 mov 0x0(%ebp),%eax mov 0x0(%ebp),%eax mov (%eax),%eax mov %eax,-0x10(%ebp) mov -0x10(%ebp),%eax mov (%eax),%eax level=3 mov 0x0(%ebp),%eax mov 0x0(%ebp),%eax mov (%eax),%eax mov (%eax),%ecx mov (%eax),%eax mov (%ecx),%eax But this is still an improvement and for bcheck we need level=1 for which the code is good. For the tests I had to force gcc use -O0 to not inline the functions. And -fno-omit-frame-pointer just in case. If someone knows how to improve the generated code - help is appreciated. Thanks, Kirill
Unified · Split
| @@ -3665,20 +3665,23 @@ ST_FUNC void unary(void) · 3664 unmodified lines | |||
| 3665 | break; | 3665 | break; |
| 3666 | case TOK_builtin_frame_address: | 3666 | case TOK_builtin_frame_address: |
| 3667 | { | 3667 | { |
| 3668 | int level; | ||
| 3668 | CType type; | 3669 | CType type; |
| 3669 | next(); | 3670 | next(); |
| 3670 | skip('('); | 3671 | skip('('); |
| 3671 | if (tok != TOK_CINT) { | 3672 | if (tok != TOK_CINT || tokc.i < 0) { |
| 3672 | tcc_error("__builtin_frame_address only takes integers"); | 3673 | tcc_error("__builtin_frame_address only takes positive integers"); |
| 3673 | } | ||
| 3674 | if (tokc.i != 0) { | ||
| 3675 | tcc_error("TCC only supports __builtin_frame_address(0)"); | ||
| 3676 | } | 3674 | } |
| 3675 | level = tokc.i; | ||
| 3677 | next(); | 3676 | next(); |
| 3678 | skip(')'); | 3677 | skip(')'); |
| 3679 | type.t = VT_VOID; | 3678 | type.t = VT_VOID; |
| 3680 | mk_pointer(&type); | 3679 | mk_pointer(&type); |
| 3681 | vset(&type, VT_LOCAL, 0); | 3680 | vset(&type, VT_LOCAL, 0); /* local frame */ |
| 3681 | while (level--) { | ||
| 3682 | mk_pointer(&vtop->type); | ||
| 3683 | indir(); /* -> parent frame */ | ||
| 3684 | } | ||
| 3682 | } | 3685 | } |
| 3683 | break; | 3686 | break; |
| 3684 | #ifdef TCC_TARGET_X86_64 | 3687 | #ifdef TCC_TARGET_X86_64 |
| @@ -73,7 +73,7 @@ libtcc_test$(EXESUF): libtcc_test.c ../$(LIBTCC) · 72 unmodified lines | |||
| 73 | # copy only tcclib.h so GCC's stddef and stdarg will be used | 73 | # copy only tcclib.h so GCC's stddef and stdarg will be used |
| 74 | test.ref: tcctest.c | 74 | test.ref: tcctest.c |
| 75 | cp ../include/tcclib.h . | 75 | cp ../include/tcclib.h . |
| 76 | $(CC) -o tcctest.gcc $< -I. $(CPPFLAGS) -w $(CFLAGS) $(NATIVE_DEFINES) -std=gnu99 $(LDFLAGS) | 76 | $(CC) -o tcctest.gcc $< -I. $(CPPFLAGS) -w $(CFLAGS) $(NATIVE_DEFINES) -std=gnu99 -O0 -fno-omit-frame-pointer $(LDFLAGS) |
| 77 | ./tcctest.gcc > $@ | 77 | ./tcctest.gcc > $@ |
| 78 | 78 | ||
| 79 | # auto test | 79 | # auto test |
| @@ -89,6 +89,7 @@ void global_data_test(void); · 88 unmodified lines | |||
| 89 | void cmp_comparison_test(void); | 89 | void cmp_comparison_test(void); |
| 90 | void math_cmp_test(void); | 90 | void math_cmp_test(void); |
| 91 | void callsave_test(void); | 91 | void callsave_test(void); |
| 92 | void builtin_frame_address_test(void); | ||
| 92 | 93 | ||
| 93 | int fib(int n); | 94 | int fib(int n); |
| 94 | void num(int n); | 95 | void num(int n); |
| @@ -598,6 +599,7 @@ int main(int argc, char **argv) · 503 unmodified lines | |||
| 598 | cmp_comparison_test(); | 599 | cmp_comparison_test(); |
| 599 | math_cmp_test(); | 600 | math_cmp_test(); |
| 600 | callsave_test(); | 601 | callsave_test(); |
| 602 | builtin_frame_address_test(); | ||
| 601 | return 0; | 603 | return 0; |
| 602 | } | 604 | } |
| 603 | 605 | ||
| @@ -2680,3 +2682,28 @@ void callsave_test(void) · 2076 unmodified lines | |||
| 2680 | printf ("%d\n", i); | 2682 | printf ("%d\n", i); |
| 2681 | #endif | 2683 | #endif |
| 2682 | } | 2684 | } |
| 2685 | |||
| 2686 | |||
| 2687 | void bfa3(ptrdiff_t str_offset) | ||
| 2688 | { | ||
| 2689 | printf("bfa3: %s\n", (char *)__builtin_frame_address(3) + str_offset); | ||
| 2690 | } | ||
| 2691 | void bfa2(ptrdiff_t str_offset) | ||
| 2692 | { | ||
| 2693 | printf("bfa2: %s\n", (char *)__builtin_frame_address(2) + str_offset); | ||
| 2694 | bfa3(str_offset); | ||
| 2695 | } | ||
| 2696 | void bfa1(ptrdiff_t str_offset) | ||
| 2697 | { | ||
| 2698 | printf("bfa1: %s\n", (char *)__builtin_frame_address(1) + str_offset); | ||
| 2699 | bfa2(str_offset); | ||
| 2700 | } | ||
| 2701 | |||
| 2702 | void builtin_frame_address_test(void) | ||
| 2703 | { | ||
| 2704 | char str[] = "__builtin_frame_address"; | ||
| 2705 | char *fp0 = __builtin_frame_address(0); | ||
| 2706 | |||
| 2707 | printf("str: %s\n", str); | ||
| 2708 | bfa1(str-fp0); | ||
| 2709 | } | ||