diff options
Diffstat (limited to 'gcc-4.9/libgcc')
-rw-r--r-- | gcc-4.9/libgcc/ChangeLog | 79 | ||||
-rw-r--r-- | gcc-4.9/libgcc/Makefile.in | 12 | ||||
-rw-r--r-- | gcc-4.9/libgcc/config/avr/lib1funcs.S | 229 | ||||
-rw-r--r-- | gcc-4.9/libgcc/config/avr/t-avr | 3 | ||||
-rw-r--r-- | gcc-4.9/libgcc/config/i386/sfp-machine.h | 2 | ||||
-rw-r--r-- | gcc-4.9/libgcc/config/libbid/ChangeLog | 4 | ||||
-rw-r--r-- | gcc-4.9/libgcc/config/nios2/linux-unwind.h | 3 | ||||
-rw-r--r-- | gcc-4.9/libgcc/config/pa/linux-atomic.c | 304 | ||||
-rw-r--r-- | gcc-4.9/libgcc/config/pa/linux-unwind.h | 34 | ||||
-rw-r--r-- | gcc-4.9/libgcc/config/sh/lib1funcs.S | 18 | ||||
-rw-r--r-- | gcc-4.9/libgcc/dyn-ipa.c | 111 | ||||
-rw-r--r-- | gcc-4.9/libgcc/libgcov-driver-kernel.c | 203 | ||||
-rw-r--r-- | gcc-4.9/libgcc/libgcov-driver-system.c | 23 | ||||
-rw-r--r-- | gcc-4.9/libgcc/libgcov-driver.c | 469 | ||||
-rw-r--r-- | gcc-4.9/libgcc/libgcov-kernel.h | 121 | ||||
-rw-r--r-- | gcc-4.9/libgcc/libgcov-merge.c | 2 | ||||
-rw-r--r-- | gcc-4.9/libgcc/libgcov-profiler.c | 136 | ||||
-rw-r--r-- | gcc-4.9/libgcc/libgcov-util.c | 684 | ||||
-rw-r--r-- | gcc-4.9/libgcc/libgcov.h | 40 |
19 files changed, 1950 insertions, 527 deletions
diff --git a/gcc-4.9/libgcc/ChangeLog b/gcc-4.9/libgcc/ChangeLog index d17c8c8..44b3f37 100644 --- a/gcc-4.9/libgcc/ChangeLog +++ b/gcc-4.9/libgcc/ChangeLog @@ -1,3 +1,76 @@ +2015-01-20 Chung-Lin Tang <cltang@codesourcery.com> + + Backport from mainline + * config/nios2/linux-unwind.h (nios2_fallback_frame_state): + Update rt_sigframe format and address for current Nios II + Linux conventions. + +2014-12-09 John David Anglin <danglin@gcc.gnu.org> + + Backport from mainline + 2014-11-24 John David Anglin <danglin@gcc.gnu.org> + + * config/pa/linux-atomic.c (ABORT_INSTRUCTION): Use __builtin_trap() + instead. + + 2014-11-21 Guy Martin <gmsoft@tuxicoman.be> + John David Anglin <danglin@gcc.gnu.org> + + * config/pa/linux-atomic.c (__kernel_cmpxchg2): New. + (FETCH_AND_OP_2): New. Use for subword and double word operations. + (OP_AND_FETCH_2): Likewise. + (COMPARE_AND_SWAP_2): Likewise. + (SYNC_LOCK_TEST_AND_SET_2): Likewise. + (SYNC_LOCK_RELEASE_2): Likewise. + (SUBWORD_SYNC_OP): Remove. + (SUBWORD_VAL_CAS): Likewise. + (SUBWORD_BOOL_CAS): Likewise. + (FETCH_AND_OP_WORD): Update. + Consistently use signed types. + +2014-12-09 Oleg Endo <olegendo@gcc.gnu.org> + + Backport from mainline + 2014-11-30 Oleg Endo <olegendo@gcc.gnu.org> + + PR target/55351 + * config/sh/lib1funcs.S: Check value of __SHMEDIA__ instead of checking + whether it's defined. + +2014-10-30 Release Manager + + * GCC 4.9.2 released. + +2014-10-26 John David Anglin <danglin@gcc.gnu.org> + + * config/pa/linux-unwind.h (pa32_read_access_ok): New function. + (pa32_fallback_frame_state): Use pa32_read_access_ok to check if + memory read accesses are ok. + +2014-10-22 Georg-Johann Lay <avr@gjlay.de> + + PR target/63223 + * config/avr/lib1funcs.S (__do_global_dtors): Reverse execution + order to first...last. + +2014-09-18 Joseph Myers <joseph@codesourcery.com> + + * config/i386/sfp-machine.h (FP_TRAPPING_EXCEPTIONS): Treat clear + bits not set bits as indicating trapping exceptions. + +2014-09-11 Georg-Johann Lay <avr@gjlay.de> + + Backport from 2014-09-11 trunk r215152. + + PR target/63223 + * config/avr/libgcc.S (__tablejump2__): Rewrite to use RAMPZ, ELPM + and R24 as needed. Make work for all devices and .text locations. + (__do_global_ctors, __do_global_dtors): Use word addresses. + (__tablejump__, __tablejump_elpm__): Remove functions. + * t-avr (LIB1ASMFUNCS): Remove _tablejump, _tablejump_elpm. + Add _tablejump2. + (XICALL, XIJMP): New macros. + 2014-08-04 Rohit <rohitarulraj@freescale.com> PR target/60102 @@ -57,7 +130,7 @@ (__gcov_delta_counter_op): Process delta profile counter values. (__gcov_single_counter_op): Process single profile counter values. (fp_scale): Callback function for float-point scaling. - (int_scale): Callback function for integer fraction scaling. + (int_scale): Callback function for integer fraction scaling. (gcov_profile_scale): Scaling profile counters. (gcov_profile_normalize): Normalize profile counters. * libgcov.h: Add headers and functions for gcov-tool use. @@ -458,7 +531,7 @@ (gcov_exit_merge_summary): Ditto. (gcov_exit_dump_gcov): Ditto. -2014-01-08 Rong Xu <xur@google.com> +2014-01-08 Rong Xu <xur@google.com> * libgcov-driver.c: Use libgcov.h. (buffer_fn_data): Use xmalloc instead of malloc. @@ -1348,7 +1421,7 @@ * config/mips/crtn.S (fini, init): New labels. 2012-02-19 Edgar E. Iglesias <edgar.iglesias@gmail.com> - * config/microblaze/modsi3.S (modsi3): Fix case with 0x80000000 + * config/microblaze/modsi3.S (modsi3): Fix case with 0x80000000 as dividend. 2013-02-16 Alan Modra <amodra@gmail.com> diff --git a/gcc-4.9/libgcc/Makefile.in b/gcc-4.9/libgcc/Makefile.in index 1e941f2..a8122c1 100644 --- a/gcc-4.9/libgcc/Makefile.in +++ b/gcc-4.9/libgcc/Makefile.in @@ -1147,10 +1147,14 @@ install-leaf: $(install-shared) $(install-libunwind) cp ../../gcc/gcov-iov.h $$gcov_src_dest; \ cp $(srcdir)/../gcc/gcov-io.h $$gcov_src_dest; \ cp $(srcdir)/../gcc/gcov-io.c $$gcov_src_dest; \ - cp $(srcdir)/libgcov-driver.c $$gcov_src_dest; \ - chmod 644 $$gcov_src_dest/gcov-iov.h \ - $$gcov_src_dest/gcov-io.h $$gcov_src_dest/gcov-io.c \ - $$gcov_src_dest/libgcov-driver.c; \ + cp $(srcdir)/../gcc/gcov-counter.def $$gcov_src_dest; \ + cp $(srcdir)/libgcov-driver.c $$gcov_src_dest; \ + cp $(srcdir)/libgcov-driver-kernel.c $$gcov_src_dest; \ + cp $(srcdir)/libgcov.h $$gcov_src_dest; \ + cp $(srcdir)/libgcov-kernel.h $$gcov_src_dest; \ + cp $(srcdir)/libgcov-profiler.c $$gcov_src_dest; \ + cp $(srcdir)/libgcov-merge.c $$gcov_src_dest; \ + chmod 644 $$gcov_src_dest/*.[ch]; \ fi install: install-leaf install-unwind_h diff --git a/gcc-4.9/libgcc/config/avr/lib1funcs.S b/gcc-4.9/libgcc/config/avr/lib1funcs.S index 6f1c77e..5ad1e93 100644 --- a/gcc-4.9/libgcc/config/avr/lib1funcs.S +++ b/gcc-4.9/libgcc/config/avr/lib1funcs.S @@ -46,6 +46,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see input sections together are small enough to reach every location with a RCALL/RJMP instruction. */ +#if defined (__AVR_HAVE_EIJMP_EICALL__) && !defined (__AVR_HAVE_ELPMX__) +#error device not supported +#endif + .macro mov_l r_dest, r_src #if defined (__AVR_HAVE_MOVW__) movw \r_dest, \r_src @@ -79,6 +83,14 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define XJMP rjmp #endif +#if defined (__AVR_HAVE_EIJMP_EICALL__) +#define XICALL eicall +#define XIJMP eijmp +#else +#define XICALL icall +#define XIJMP ijmp +#endif + ;; Prologue stuff .macro do_prologue_saves n_pushed n_frame=0 @@ -2127,11 +2139,7 @@ DEFUN __prologue_saves__ out __SP_L__,r28 #endif /* #SP = 8/16 */ -#if defined (__AVR_HAVE_EIJMP_EICALL__) - eijmp -#else - ijmp -#endif + XIJMP ENDF __prologue_saves__ #endif /* defined (L_prologue) */ @@ -2213,38 +2221,54 @@ _cleanup: .section .text.libgcc, "ax", @progbits -#ifdef L_tablejump +#ifdef L_tablejump2 DEFUN __tablejump2__ - lsl r30 - rol r31 - ;; FALLTHRU -ENDF __tablejump2__ - -DEFUN __tablejump__ -#if defined (__AVR_HAVE_LPMX__) - lpm __tmp_reg__, Z+ - lpm r31, Z - mov r30, __tmp_reg__ + lsl r30 + rol r31 #if defined (__AVR_HAVE_EIJMP_EICALL__) - eijmp -#else - ijmp + ;; Word address of gs() jumptable entry in R24:Z + rol r24 + out __RAMPZ__, r24 +#elif defined (__AVR_HAVE_ELPM__) + ;; Word address of jumptable entry in Z + clr __tmp_reg__ + rol __tmp_reg__ + out __RAMPZ__, __tmp_reg__ #endif -#else /* !HAVE_LPMX */ - lpm - adiw r30, 1 - push r0 - lpm - push r0 -#if defined (__AVR_HAVE_EIJMP_EICALL__) - in __tmp_reg__, __EIND__ - push __tmp_reg__ + ;; Read word address from jumptable and jump + +#if defined (__AVR_HAVE_ELPMX__) + elpm __tmp_reg__, Z+ + elpm r31, Z + mov r30, __tmp_reg__ +#ifdef __AVR_HAVE_RAMPD__ + ;; Reset RAMPZ to 0 so that EBI devices don't read garbage from RAM + out __RAMPZ__, __zero_reg__ +#endif /* RAMPD */ + XIJMP +#elif defined (__AVR_HAVE_ELPM__) + elpm + push r0 + adiw r30, 1 + elpm + push r0 + ret +#elif defined (__AVR_HAVE_LPMX__) + lpm __tmp_reg__, Z+ + lpm r31, Z + mov r30, __tmp_reg__ + ijmp +#else + lpm + push r0 + adiw r30, 1 + lpm + push r0 + ret #endif - ret -#endif /* !HAVE_LPMX */ -ENDF __tablejump__ -#endif /* defined (L_tablejump) */ +ENDF __tablejump2__ +#endif /* L_tablejump2 */ #ifdef L_copy_data .section .init4,"ax",@progbits @@ -2336,116 +2360,67 @@ ENDF __do_clear_bss #ifdef L_ctors .section .init6,"ax",@progbits DEFUN __do_global_ctors -#if defined(__AVR_HAVE_ELPM__) - ldi r17, hi8(__ctors_start) - ldi r28, lo8(__ctors_end) - ldi r29, hi8(__ctors_end) - ldi r16, hh8(__ctors_end) - rjmp .L__do_global_ctors_start + ldi r17, pm_hi8(__ctors_start) + ldi r28, pm_lo8(__ctors_end) + ldi r29, pm_hi8(__ctors_end) +#ifdef __AVR_HAVE_EIJMP_EICALL__ + ldi r16, pm_hh8(__ctors_end) +#endif /* HAVE_EIJMP */ + rjmp .L__do_global_ctors_start .L__do_global_ctors_loop: - sbiw r28, 2 - sbc r16, __zero_reg__ - mov_h r31, r29 - mov_l r30, r28 - out __RAMPZ__, r16 - XCALL __tablejump_elpm__ + sbiw r28, 1 +#ifdef __AVR_HAVE_EIJMP_EICALL__ + sbc r16, __zero_reg__ + mov r24, r16 +#endif /* HAVE_EIJMP */ + mov_h r31, r29 + mov_l r30, r28 + XCALL __tablejump2__ .L__do_global_ctors_start: - cpi r28, lo8(__ctors_start) - cpc r29, r17 - ldi r24, hh8(__ctors_start) - cpc r16, r24 - brne .L__do_global_ctors_loop -#else - ldi r17, hi8(__ctors_start) - ldi r28, lo8(__ctors_end) - ldi r29, hi8(__ctors_end) - rjmp .L__do_global_ctors_start -.L__do_global_ctors_loop: - sbiw r28, 2 - mov_h r31, r29 - mov_l r30, r28 - XCALL __tablejump__ -.L__do_global_ctors_start: - cpi r28, lo8(__ctors_start) - cpc r29, r17 - brne .L__do_global_ctors_loop -#endif /* defined(__AVR_HAVE_ELPM__) */ + cpi r28, pm_lo8(__ctors_start) + cpc r29, r17 +#ifdef __AVR_HAVE_EIJMP_EICALL__ + ldi r24, pm_hh8(__ctors_start) + cpc r16, r24 +#endif /* HAVE_EIJMP */ + brne .L__do_global_ctors_loop ENDF __do_global_ctors #endif /* L_ctors */ #ifdef L_dtors .section .fini6,"ax",@progbits DEFUN __do_global_dtors -#if defined(__AVR_HAVE_ELPM__) - ldi r17, hi8(__dtors_end) - ldi r28, lo8(__dtors_start) - ldi r29, hi8(__dtors_start) - ldi r16, hh8(__dtors_start) - rjmp .L__do_global_dtors_start + ldi r17, pm_hi8(__dtors_end) + ldi r28, pm_lo8(__dtors_start) + ldi r29, pm_hi8(__dtors_start) +#ifdef __AVR_HAVE_EIJMP_EICALL__ + ldi r16, pm_hh8(__dtors_start) +#endif /* HAVE_EIJMP */ + rjmp .L__do_global_dtors_start .L__do_global_dtors_loop: - sbiw r28, 2 - sbc r16, __zero_reg__ - mov_h r31, r29 - mov_l r30, r28 - out __RAMPZ__, r16 - XCALL __tablejump_elpm__ +#ifdef __AVR_HAVE_EIJMP_EICALL__ + mov r24, r16 +#endif /* HAVE_EIJMP */ + mov_h r31, r29 + mov_l r30, r28 + XCALL __tablejump2__ + adiw r28, 1 +#ifdef __AVR_HAVE_EIJMP_EICALL__ + adc r16, __zero_reg__ +#endif /* HAVE_EIJMP */ .L__do_global_dtors_start: - cpi r28, lo8(__dtors_end) - cpc r29, r17 - ldi r24, hh8(__dtors_end) - cpc r16, r24 - brne .L__do_global_dtors_loop -#else - ldi r17, hi8(__dtors_end) - ldi r28, lo8(__dtors_start) - ldi r29, hi8(__dtors_start) - rjmp .L__do_global_dtors_start -.L__do_global_dtors_loop: - mov_h r31, r29 - mov_l r30, r28 - XCALL __tablejump__ - adiw r28, 2 -.L__do_global_dtors_start: - cpi r28, lo8(__dtors_end) - cpc r29, r17 - brne .L__do_global_dtors_loop -#endif /* defined(__AVR_HAVE_ELPM__) */ + cpi r28, pm_lo8(__dtors_end) + cpc r29, r17 +#ifdef __AVR_HAVE_EIJMP_EICALL__ + ldi r24, pm_hh8(__dtors_end) + cpc r16, r24 +#endif /* HAVE_EIJMP */ + brne .L__do_global_dtors_loop ENDF __do_global_dtors #endif /* L_dtors */ .section .text.libgcc, "ax", @progbits -#ifdef L_tablejump_elpm -DEFUN __tablejump_elpm__ -#if defined (__AVR_HAVE_ELPMX__) - elpm __tmp_reg__, Z+ - elpm r31, Z - mov r30, __tmp_reg__ -#if defined (__AVR_HAVE_RAMPD__) - ;; Reset RAMPZ to 0 so that EBI devices don't read garbage from RAM - out __RAMPZ__, __zero_reg__ -#endif /* RAMPD */ -#if defined (__AVR_HAVE_EIJMP_EICALL__) - eijmp -#else - ijmp -#endif - -#elif defined (__AVR_HAVE_ELPM__) - elpm - adiw r30, 1 - push r0 - elpm - push r0 -#if defined (__AVR_HAVE_EIJMP_EICALL__) - in __tmp_reg__, __EIND__ - push __tmp_reg__ -#endif - ret -#endif -ENDF __tablejump_elpm__ -#endif /* defined (L_tablejump_elpm) */ - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Loading n bytes from Flash; n = 3,4 ;; R22... = Flash[Z] diff --git a/gcc-4.9/libgcc/config/avr/t-avr b/gcc-4.9/libgcc/config/avr/t-avr index 4613047..1f73569 100644 --- a/gcc-4.9/libgcc/config/avr/t-avr +++ b/gcc-4.9/libgcc/config/avr/t-avr @@ -26,8 +26,7 @@ LIB1ASMFUNCS = \ _epilogue \ _exit \ _cleanup \ - _tablejump \ - _tablejump_elpm \ + _tablejump2 \ _load_3 _load_4 \ _xload_1 _xload_2 _xload_3 _xload_4 \ _movmemx \ diff --git a/gcc-4.9/libgcc/config/i386/sfp-machine.h b/gcc-4.9/libgcc/config/i386/sfp-machine.h index 148044a..8a1923b 100644 --- a/gcc-4.9/libgcc/config/i386/sfp-machine.h +++ b/gcc-4.9/libgcc/config/i386/sfp-machine.h @@ -60,7 +60,7 @@ void __sfp_handle_exceptions (int); __sfp_handle_exceptions (_fex); \ } while (0); -#define FP_TRAPPING_EXCEPTIONS ((_fcw >> FP_EX_SHIFT) & FP_EX_ALL) +#define FP_TRAPPING_EXCEPTIONS ((~_fcw >> FP_EX_SHIFT) & FP_EX_ALL) #define FP_ROUNDMODE (_fcw & FP_RND_MASK) #endif diff --git a/gcc-4.9/libgcc/config/libbid/ChangeLog b/gcc-4.9/libgcc/config/libbid/ChangeLog index c3f8386..68d46d2 100644 --- a/gcc-4.9/libgcc/config/libbid/ChangeLog +++ b/gcc-4.9/libgcc/config/libbid/ChangeLog @@ -1,3 +1,7 @@ +2014-10-30 Release Manager + + * GCC 4.9.2 released. + 2014-07-16 Release Manager * GCC 4.9.1 released. diff --git a/gcc-4.9/libgcc/config/nios2/linux-unwind.h b/gcc-4.9/libgcc/config/nios2/linux-unwind.h index 92ff1f6..ba4bd80 100644 --- a/gcc-4.9/libgcc/config/nios2/linux-unwind.h +++ b/gcc-4.9/libgcc/config/nios2/linux-unwind.h @@ -67,10 +67,9 @@ nios2_fallback_frame_state (struct _Unwind_Context *context, if (pc[0] == (0x00800004 | (__NR_rt_sigreturn << 6))) { struct rt_sigframe { - char retcode[12]; siginfo_t info; struct nios2_ucontext uc; - } *rt_ = context->ra; + } *rt_ = context->cfa; struct nios2_mcontext *regs = &rt_->uc.uc_mcontext; int i; diff --git a/gcc-4.9/libgcc/config/pa/linux-atomic.c b/gcc-4.9/libgcc/config/pa/linux-atomic.c index d92d6ef..19e37b6 100644 --- a/gcc-4.9/libgcc/config/pa/linux-atomic.c +++ b/gcc-4.9/libgcc/config/pa/linux-atomic.c @@ -41,11 +41,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see using the kernel helper defined below. There is no support for 64-bit operations yet. */ -/* A privileged instruction to crash a userspace program with SIGILL. */ -#define ABORT_INSTRUCTION asm ("iitlbp %r0,(%sr0, %r0)") - /* Determine kernel LWS function call (0=32-bit, 1=64-bit userspace). */ -#define LWS_CAS (sizeof(unsigned long) == 4 ? 0 : 1) +#define LWS_CAS (sizeof(long) == 4 ? 0 : 1) /* Kernel helper for compare-and-exchange a 32-bit value. */ static inline long @@ -64,7 +61,7 @@ __kernel_cmpxchg (int oldval, int newval, int *mem) : "r1", "r20", "r22", "r23", "r29", "r31", "memory" ); if (__builtin_expect (lws_errno == -EFAULT || lws_errno == -ENOSYS, 0)) - ABORT_INSTRUCTION; + __builtin_trap (); /* If the kernel LWS call succeeded (lws_errno == 0), lws_ret contains the old value from memory. If this value is equal to OLDVAL, the @@ -75,6 +72,30 @@ __kernel_cmpxchg (int oldval, int newval, int *mem) return lws_errno; } +static inline long +__kernel_cmpxchg2 (void * oldval, void * newval, void *mem, int val_size) +{ + register unsigned long lws_mem asm("r26") = (unsigned long) (mem); + register long lws_ret asm("r28"); + register long lws_errno asm("r21"); + register unsigned long lws_old asm("r25") = (unsigned long) oldval; + register unsigned long lws_new asm("r24") = (unsigned long) newval; + register int lws_size asm("r23") = val_size; + asm volatile ( "ble 0xb0(%%sr2, %%r0) \n\t" + "ldi %2, %%r20 \n\t" + : "=r" (lws_ret), "=r" (lws_errno) + : "i" (2), "r" (lws_mem), "r" (lws_old), "r" (lws_new), "r" (lws_size) + : "r1", "r20", "r22", "r29", "r31", "fr4", "memory" + ); + if (__builtin_expect (lws_errno == -EFAULT || lws_errno == -ENOSYS, 0)) + __builtin_trap (); + + /* If the kernel LWS call fails, retrun EBUSY */ + if (!lws_errno && lws_ret) + lws_errno = -EBUSY; + + return lws_errno; +} #define HIDDEN __attribute__ ((visibility ("hidden"))) /* Big endian masks */ @@ -84,6 +105,80 @@ __kernel_cmpxchg (int oldval, int newval, int *mem) #define MASK_1 0xffu #define MASK_2 0xffffu +#define FETCH_AND_OP_2(OP, PFX_OP, INF_OP, TYPE, WIDTH, INDEX) \ + TYPE HIDDEN \ + __sync_fetch_and_##OP##_##WIDTH (TYPE *ptr, TYPE val) \ + { \ + TYPE tmp, newval; \ + int failure; \ + \ + do { \ + tmp = *ptr; \ + newval = PFX_OP (tmp INF_OP val); \ + failure = __kernel_cmpxchg2 (&tmp, &newval, ptr, INDEX); \ + } while (failure != 0); \ + \ + return tmp; \ + } + +FETCH_AND_OP_2 (add, , +, long long, 8, 3) +FETCH_AND_OP_2 (sub, , -, long long, 8, 3) +FETCH_AND_OP_2 (or, , |, long long, 8, 3) +FETCH_AND_OP_2 (and, , &, long long, 8, 3) +FETCH_AND_OP_2 (xor, , ^, long long, 8, 3) +FETCH_AND_OP_2 (nand, ~, &, long long, 8, 3) + +FETCH_AND_OP_2 (add, , +, short, 2, 1) +FETCH_AND_OP_2 (sub, , -, short, 2, 1) +FETCH_AND_OP_2 (or, , |, short, 2, 1) +FETCH_AND_OP_2 (and, , &, short, 2, 1) +FETCH_AND_OP_2 (xor, , ^, short, 2, 1) +FETCH_AND_OP_2 (nand, ~, &, short, 2, 1) + +FETCH_AND_OP_2 (add, , +, signed char, 1, 0) +FETCH_AND_OP_2 (sub, , -, signed char, 1, 0) +FETCH_AND_OP_2 (or, , |, signed char, 1, 0) +FETCH_AND_OP_2 (and, , &, signed char, 1, 0) +FETCH_AND_OP_2 (xor, , ^, signed char, 1, 0) +FETCH_AND_OP_2 (nand, ~, &, signed char, 1, 0) + +#define OP_AND_FETCH_2(OP, PFX_OP, INF_OP, TYPE, WIDTH, INDEX) \ + TYPE HIDDEN \ + __sync_##OP##_and_fetch_##WIDTH (TYPE *ptr, TYPE val) \ + { \ + TYPE tmp, newval; \ + int failure; \ + \ + do { \ + tmp = *ptr; \ + newval = PFX_OP (tmp INF_OP val); \ + failure = __kernel_cmpxchg2 (&tmp, &newval, ptr, INDEX); \ + } while (failure != 0); \ + \ + return PFX_OP (tmp INF_OP val); \ + } + +OP_AND_FETCH_2 (add, , +, long long, 8, 3) +OP_AND_FETCH_2 (sub, , -, long long, 8, 3) +OP_AND_FETCH_2 (or, , |, long long, 8, 3) +OP_AND_FETCH_2 (and, , &, long long, 8, 3) +OP_AND_FETCH_2 (xor, , ^, long long, 8, 3) +OP_AND_FETCH_2 (nand, ~, &, long long, 8, 3) + +OP_AND_FETCH_2 (add, , +, short, 2, 1) +OP_AND_FETCH_2 (sub, , -, short, 2, 1) +OP_AND_FETCH_2 (or, , |, short, 2, 1) +OP_AND_FETCH_2 (and, , &, short, 2, 1) +OP_AND_FETCH_2 (xor, , ^, short, 2, 1) +OP_AND_FETCH_2 (nand, ~, &, short, 2, 1) + +OP_AND_FETCH_2 (add, , +, signed char, 1, 0) +OP_AND_FETCH_2 (sub, , -, signed char, 1, 0) +OP_AND_FETCH_2 (or, , |, signed char, 1, 0) +OP_AND_FETCH_2 (and, , &, signed char, 1, 0) +OP_AND_FETCH_2 (xor, , ^, signed char, 1, 0) +OP_AND_FETCH_2 (nand, ~, &, signed char, 1, 0) + #define FETCH_AND_OP_WORD(OP, PFX_OP, INF_OP) \ int HIDDEN \ __sync_fetch_and_##OP##_4 (int *ptr, int val) \ @@ -105,48 +200,6 @@ FETCH_AND_OP_WORD (and, , &) FETCH_AND_OP_WORD (xor, , ^) FETCH_AND_OP_WORD (nand, ~, &) -#define NAME_oldval(OP, WIDTH) __sync_fetch_and_##OP##_##WIDTH -#define NAME_newval(OP, WIDTH) __sync_##OP##_and_fetch_##WIDTH - -/* Implement both __sync_<op>_and_fetch and __sync_fetch_and_<op> for - subword-sized quantities. */ - -#define SUBWORD_SYNC_OP(OP, PFX_OP, INF_OP, TYPE, WIDTH, RETURN) \ - TYPE HIDDEN \ - NAME##_##RETURN (OP, WIDTH) (TYPE *ptr, TYPE val) \ - { \ - int *wordptr = (int *) ((unsigned long) ptr & ~3); \ - unsigned int mask, shift, oldval, newval; \ - int failure; \ - \ - shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \ - mask = MASK_##WIDTH << shift; \ - \ - do { \ - oldval = *wordptr; \ - newval = ((PFX_OP (((oldval & mask) >> shift) \ - INF_OP (unsigned int) val)) << shift) & mask; \ - newval |= oldval & ~mask; \ - failure = __kernel_cmpxchg (oldval, newval, wordptr); \ - } while (failure != 0); \ - \ - return (RETURN & mask) >> shift; \ - } - -SUBWORD_SYNC_OP (add, , +, unsigned short, 2, oldval) -SUBWORD_SYNC_OP (sub, , -, unsigned short, 2, oldval) -SUBWORD_SYNC_OP (or, , |, unsigned short, 2, oldval) -SUBWORD_SYNC_OP (and, , &, unsigned short, 2, oldval) -SUBWORD_SYNC_OP (xor, , ^, unsigned short, 2, oldval) -SUBWORD_SYNC_OP (nand, ~, &, unsigned short, 2, oldval) - -SUBWORD_SYNC_OP (add, , +, unsigned char, 1, oldval) -SUBWORD_SYNC_OP (sub, , -, unsigned char, 1, oldval) -SUBWORD_SYNC_OP (or, , |, unsigned char, 1, oldval) -SUBWORD_SYNC_OP (and, , &, unsigned char, 1, oldval) -SUBWORD_SYNC_OP (xor, , ^, unsigned char, 1, oldval) -SUBWORD_SYNC_OP (nand, ~, &, unsigned char, 1, oldval) - #define OP_AND_FETCH_WORD(OP, PFX_OP, INF_OP) \ int HIDDEN \ __sync_##OP##_and_fetch_4 (int *ptr, int val) \ @@ -168,19 +221,41 @@ OP_AND_FETCH_WORD (and, , &) OP_AND_FETCH_WORD (xor, , ^) OP_AND_FETCH_WORD (nand, ~, &) -SUBWORD_SYNC_OP (add, , +, unsigned short, 2, newval) -SUBWORD_SYNC_OP (sub, , -, unsigned short, 2, newval) -SUBWORD_SYNC_OP (or, , |, unsigned short, 2, newval) -SUBWORD_SYNC_OP (and, , &, unsigned short, 2, newval) -SUBWORD_SYNC_OP (xor, , ^, unsigned short, 2, newval) -SUBWORD_SYNC_OP (nand, ~, &, unsigned short, 2, newval) +typedef unsigned char bool; + +#define COMPARE_AND_SWAP_2(TYPE, WIDTH, INDEX) \ + TYPE HIDDEN \ + __sync_val_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \ + TYPE newval) \ + { \ + TYPE actual_oldval; \ + int fail; \ + \ + while (1) \ + { \ + actual_oldval = *ptr; \ + \ + if (__builtin_expect (oldval != actual_oldval, 0)) \ + return actual_oldval; \ + \ + fail = __kernel_cmpxchg2 (&actual_oldval, &newval, ptr, INDEX); \ + \ + if (__builtin_expect (!fail, 1)) \ + return actual_oldval; \ + } \ + } \ + \ + bool HIDDEN \ + __sync_bool_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \ + TYPE newval) \ + { \ + int failure = __kernel_cmpxchg2 (&oldval, &newval, ptr, INDEX); \ + return (failure != 0); \ + } -SUBWORD_SYNC_OP (add, , +, unsigned char, 1, newval) -SUBWORD_SYNC_OP (sub, , -, unsigned char, 1, newval) -SUBWORD_SYNC_OP (or, , |, unsigned char, 1, newval) -SUBWORD_SYNC_OP (and, , &, unsigned char, 1, newval) -SUBWORD_SYNC_OP (xor, , ^, unsigned char, 1, newval) -SUBWORD_SYNC_OP (nand, ~, &, unsigned char, 1, newval) +COMPARE_AND_SWAP_2 (long long, 8, 3) +COMPARE_AND_SWAP_2 (short, 2, 1) +COMPARE_AND_SWAP_2 (char, 1, 0) int HIDDEN __sync_val_compare_and_swap_4 (int *ptr, int oldval, int newval) @@ -201,41 +276,6 @@ __sync_val_compare_and_swap_4 (int *ptr, int oldval, int newval) } } -#define SUBWORD_VAL_CAS(TYPE, WIDTH) \ - TYPE HIDDEN \ - __sync_val_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \ - TYPE newval) \ - { \ - int *wordptr = (int *)((unsigned long) ptr & ~3), fail; \ - unsigned int mask, shift, actual_oldval, actual_newval; \ - \ - shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \ - mask = MASK_##WIDTH << shift; \ - \ - while (1) \ - { \ - actual_oldval = *wordptr; \ - \ - if (__builtin_expect (((actual_oldval & mask) >> shift) \ - != (unsigned int) oldval, 0)) \ - return (actual_oldval & mask) >> shift; \ - \ - actual_newval = (actual_oldval & ~mask) \ - | (((unsigned int) newval << shift) & mask); \ - \ - fail = __kernel_cmpxchg (actual_oldval, actual_newval, \ - wordptr); \ - \ - if (__builtin_expect (!fail, 1)) \ - return (actual_oldval & mask) >> shift; \ - } \ - } - -SUBWORD_VAL_CAS (unsigned short, 2) -SUBWORD_VAL_CAS (unsigned char, 1) - -typedef unsigned char bool; - bool HIDDEN __sync_bool_compare_and_swap_4 (int *ptr, int oldval, int newval) { @@ -243,18 +283,24 @@ __sync_bool_compare_and_swap_4 (int *ptr, int oldval, int newval) return (failure == 0); } -#define SUBWORD_BOOL_CAS(TYPE, WIDTH) \ - bool HIDDEN \ - __sync_bool_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \ - TYPE newval) \ +#define SYNC_LOCK_TEST_AND_SET_2(TYPE, WIDTH, INDEX) \ +TYPE HIDDEN \ + __sync_lock_test_and_set_##WIDTH (TYPE *ptr, TYPE val) \ { \ - TYPE actual_oldval \ - = __sync_val_compare_and_swap_##WIDTH (ptr, oldval, newval); \ - return (oldval == actual_oldval); \ + TYPE oldval; \ + int failure; \ + \ + do { \ + oldval = *ptr; \ + failure = __kernel_cmpxchg2 (&oldval, &val, ptr, INDEX); \ + } while (failure != 0); \ + \ + return oldval; \ } -SUBWORD_BOOL_CAS (unsigned short, 2) -SUBWORD_BOOL_CAS (unsigned char, 1) +SYNC_LOCK_TEST_AND_SET_2 (long long, 8, 3) +SYNC_LOCK_TEST_AND_SET_2 (short, 2, 1) +SYNC_LOCK_TEST_AND_SET_2 (signed char, 1, 0) int HIDDEN __sync_lock_test_and_set_4 (int *ptr, int val) @@ -269,37 +315,29 @@ __sync_lock_test_and_set_4 (int *ptr, int val) return oldval; } -#define SUBWORD_TEST_AND_SET(TYPE, WIDTH) \ - TYPE HIDDEN \ - __sync_lock_test_and_set_##WIDTH (TYPE *ptr, TYPE val) \ - { \ - int failure; \ - unsigned int oldval, newval, shift, mask; \ - int *wordptr = (int *) ((unsigned long) ptr & ~3); \ - \ - shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \ - mask = MASK_##WIDTH << shift; \ - \ - do { \ - oldval = *wordptr; \ - newval = (oldval & ~mask) \ - | (((unsigned int) val << shift) & mask); \ - failure = __kernel_cmpxchg (oldval, newval, wordptr); \ - } while (failure != 0); \ - \ - return (oldval & mask) >> shift; \ +#define SYNC_LOCK_RELEASE_2(TYPE, WIDTH, INDEX) \ + void HIDDEN \ + __sync_lock_release_##WIDTH (TYPE *ptr) \ + { \ + TYPE failure, oldval, zero = 0; \ + \ + do { \ + oldval = *ptr; \ + failure = __kernel_cmpxchg2 (&oldval, &zero, ptr, INDEX); \ + } while (failure != 0); \ } -SUBWORD_TEST_AND_SET (unsigned short, 2) -SUBWORD_TEST_AND_SET (unsigned char, 1) +SYNC_LOCK_RELEASE_2 (long long, 8, 3) +SYNC_LOCK_RELEASE_2 (short, 2, 1) +SYNC_LOCK_RELEASE_2 (signed char, 1, 0) -#define SYNC_LOCK_RELEASE(TYPE, WIDTH) \ - void HIDDEN \ - __sync_lock_release_##WIDTH (TYPE *ptr) \ - { \ - *ptr = 0; \ - } +void HIDDEN +__sync_lock_release_4 (int *ptr) +{ + int failure, oldval; -SYNC_LOCK_RELEASE (int, 4) -SYNC_LOCK_RELEASE (short, 2) -SYNC_LOCK_RELEASE (char, 1) + do { + oldval = *ptr; + failure = __kernel_cmpxchg (oldval, 0, ptr); + } while (failure != 0); +} diff --git a/gcc-4.9/libgcc/config/pa/linux-unwind.h b/gcc-4.9/libgcc/config/pa/linux-unwind.h index 485f2d9..4a3cfff 100644 --- a/gcc-4.9/libgcc/config/pa/linux-unwind.h +++ b/gcc-4.9/libgcc/config/pa/linux-unwind.h @@ -32,6 +32,17 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include <signal.h> #include <sys/ucontext.h> +/* Return TRUE if read access to *P is allowed. */ + +static inline long +pa32_read_access_ok (void *p) +{ + long ret; + + __asm__ ("proberi (%1),3,%0" : "=r" (ret) : "r" (p) :); + return ret; +} + /* Unfortunately, because of various bugs and changes to the kernel, we have several cases to deal with. @@ -48,7 +59,12 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see tell us how to locate the sigcontext structure. Note that with a 2.4 64-bit kernel, the signal context is not properly - passed back to userspace so the unwind will not work correctly. */ + passed back to userspace so the unwind will not work correctly. + + There is also a bug in various glibc versions. The (CONTEXT)->ra + for the outermost frame is not marked as undefined, so we need to + check whether read access is allowed for all the accesses used in + searching for the signal trampoline. */ #define MD_FALLBACK_FRAME_STATE_FOR pa32_fallback_frame_state @@ -73,14 +89,17 @@ pa32_fallback_frame_state (struct _Unwind_Context *context, e4008200 be,l 0x100(%sr2, %r0), %sr0, %r31 08000240 nop */ - if (pc[0] == 0x34190000 || pc[0] == 0x34190002) + if (pa32_read_access_ok (pc) + && (pc[0] == 0x34190000 || pc[0] == 0x34190002)) off = 4*4; - else if (pc[4] == 0x34190000 || pc[4] == 0x34190002) + else if (pa32_read_access_ok (&pc[4]) + && (pc[4] == 0x34190000 || pc[4] == 0x34190002)) { pc += 4; off = 10 * 4; } - else if (pc[5] == 0x34190000 || pc[5] == 0x34190002) + else if (pa32_read_access_ok (&pc[5]) + && (pc[5] == 0x34190000 || pc[5] == 0x34190002)) { pc += 5; off = 10 * 4; @@ -96,13 +115,16 @@ pa32_fallback_frame_state (struct _Unwind_Context *context, word boundary and we can then determine the frame offset. */ sp = (unsigned long)context->ra; pc = (unsigned int *)sp; - if ((pc[0] == 0x34190000 || pc[0] == 0x34190002) && (sp & 4)) + if ((sp & 4) + && pa32_read_access_ok (pc) + && (pc[0] == 0x34190000 || pc[0] == 0x34190002)) off = 5 * 4; else return _URC_END_OF_STACK; } - if (pc[1] != 0x3414015a + if (!pa32_read_access_ok (&pc[3]) + || pc[1] != 0x3414015a || pc[2] != 0xe4008200 || pc[3] != 0x08000240) return _URC_END_OF_STACK; diff --git a/gcc-4.9/libgcc/config/sh/lib1funcs.S b/gcc-4.9/libgcc/config/sh/lib1funcs.S index 3410cf7..cfd6dc2 100644 --- a/gcc-4.9/libgcc/config/sh/lib1funcs.S +++ b/gcc-4.9/libgcc/config/sh/lib1funcs.S @@ -1278,7 +1278,7 @@ GLOBAL(sdivsi3_2): #endif ENDFUNC(GLOBAL(sdivsi3_2)) #endif -#elif defined __SHMEDIA__ +#elif __SHMEDIA__ /* m5compact-nofpu */ // clobbered: r18,r19,r20,r21,r25,tr0,tr1,tr2 .mode SHmedia @@ -1683,7 +1683,7 @@ GLOBAL(udivsi3): add.l r18,r25,r0 blink tr0,r63 #endif -#elif defined (__SHMEDIA__) +#elif __SHMEDIA__ /* m5compact-nofpu - more emphasis on code size than on speed, but don't ignore speed altogether - div1 needs 9 cycles, subc 7 and rotcl 4. So use a short shmedia loop. */ @@ -1707,7 +1707,7 @@ LOCAL(udivsi3_dontsub): bnei r25,-32,tr1 add.l r20,r63,r0 blink tr2,r63 -#else /* ! defined (__SHMEDIA__) */ +#else /* ! __SHMEDIA__ */ LOCAL(div8): div1 r5,r4 LOCAL(div7): @@ -1773,7 +1773,7 @@ LOCAL(large_divisor): #endif /* L_udivsi3 */ #ifdef L_udivdi3 -#ifdef __SHMEDIA__ +#if __SHMEDIA__ .mode SHmedia .section .text..SHmedia32,"ax" .align 2 @@ -1901,7 +1901,7 @@ LOCAL(no_lo_adj): #endif /* L_udivdi3 */ #ifdef L_divdi3 -#ifdef __SHMEDIA__ +#if __SHMEDIA__ .mode SHmedia .section .text..SHmedia32,"ax" .align 2 @@ -1925,7 +1925,7 @@ GLOBAL(divdi3): #endif /* L_divdi3 */ #ifdef L_umoddi3 -#ifdef __SHMEDIA__ +#if __SHMEDIA__ .mode SHmedia .section .text..SHmedia32,"ax" .align 2 @@ -2054,7 +2054,7 @@ LOCAL(no_lo_adj): #endif /* L_umoddi3 */ #ifdef L_moddi3 -#ifdef __SHMEDIA__ +#if __SHMEDIA__ .mode SHmedia .section .text..SHmedia32,"ax" .align 2 @@ -3142,7 +3142,7 @@ GLOBAL(GCC_pop_shmedia_regs_nofpu): #ifdef L_div_table #if __SH5__ -#if defined(__pic__) && defined(__SHMEDIA__) +#if defined(__pic__) && __SHMEDIA__ .global GLOBAL(sdivsi3) FUNC(GLOBAL(sdivsi3)) #if __SH5__ == 32 @@ -3215,7 +3215,7 @@ Defects for bias -330: #else /* ! __pic__ || ! __SHMEDIA__ */ .section .rodata #endif /* __pic__ */ -#if defined(TEXT_DATA_BUG) && defined(__pic__) && defined(__SHMEDIA__) +#if defined(TEXT_DATA_BUG) && defined(__pic__) && __SHMEDIA__ .balign 2 .type Local_div_table,@object .size Local_div_table,128 diff --git a/gcc-4.9/libgcc/dyn-ipa.c b/gcc-4.9/libgcc/dyn-ipa.c index e66b02b..ef6da8d 100644 --- a/gcc-4.9/libgcc/dyn-ipa.c +++ b/gcc-4.9/libgcc/dyn-ipa.c @@ -107,8 +107,9 @@ struct checksum_alias struct checksum_alias *next_alias; gcov_type guid; const struct gcov_fn_info *fi_ptr; - /* Does this function have all-zero arc counts? */ - int zero_counts; + /* Non-NULL pointer to flag if this function has all-zero arc counts, to be + set if we perform fixup. */ + char *zero_count_fixup; }; /* Module info is stored in dyn_caph->sup_modules @@ -178,10 +179,10 @@ extern gcov_unsigned_t __gcov_lipo_merge_modu_edges; extern gcov_unsigned_t __gcov_lipo_weak_inclusion; #if defined(inhibit_libc) -void __gcov_build_callgraph (void) {} +void __gcov_build_callgraph (char **zero_counts) {} #else -int __gcov_compute_module_groups (void) ATTRIBUTE_HIDDEN; +int __gcov_compute_module_groups (char **zero_counts) ATTRIBUTE_HIDDEN; void __gcov_finalize_dyn_callgraph (void) ATTRIBUTE_HIDDEN; static void gcov_dump_callgraph (gcov_type); static void gcov_dump_cgraph_node_short (struct dyn_cgraph_node *node); @@ -378,18 +379,19 @@ lineno_checksum_get_key (const void *p) } /* Create a new checksum_alias struct for function with GUID, FI_PTR, - and ZERO_COUNTS flag. Prepends to list NEXT and returns new struct. */ + and ZERO_COUNT_FIXUP flag pointer. Prepends to list NEXT and returns + new struct. */ static struct checksum_alias * new_checksum_alias (gcov_type guid, const struct gcov_fn_info *fi_ptr, - int zero_counts, + char *zero_count_fixup, struct checksum_alias *next) { struct checksum_alias *alias = XNEW (struct checksum_alias); alias->next_alias = next; alias->fi_ptr = fi_ptr; alias->guid = guid; - alias->zero_counts = zero_counts; + alias->zero_count_fixup = zero_count_fixup; return alias; } @@ -407,11 +409,12 @@ find_cfg_checksum (struct checksum_alias_info *list, unsigned cfg_checksum) } /* Insert a new checksum_alias struct into LIST for function with - CFG_CHECKSUM and associated GUID, FI_PTR, and ZERO_COUNTS flag. */ + CFG_CHECKSUM and associated GUID, FI_PTR, and ZERO_COUNT_FIXUP + flag pointer. */ static struct checksum_alias_info * cfg_checksum_insert (unsigned cfg_checksum, gcov_type guid, - const struct gcov_fn_info *fi_ptr, int zero_counts, + const struct gcov_fn_info *fi_ptr, char *zero_count_fixup, struct checksum_alias_info *list) { struct checksum_alias_info *alias_info; @@ -419,7 +422,8 @@ cfg_checksum_insert (unsigned cfg_checksum, gcov_type guid, if (alias_info) { gcc_assert (alias_info->alias_list); - alias_info->alias_list = new_checksum_alias (guid, fi_ptr, zero_counts, + alias_info->alias_list = new_checksum_alias (guid, fi_ptr, + zero_count_fixup, alias_info->alias_list); return list; } @@ -428,7 +432,8 @@ cfg_checksum_insert (unsigned cfg_checksum, gcov_type guid, alias_info = XNEW (struct checksum_alias_info); alias_info->next_cfg_checksum = list; alias_info->cfg_checksum = cfg_checksum; - alias_info->alias_list = new_checksum_alias (guid, fi_ptr, zero_counts, + alias_info->alias_list = new_checksum_alias (guid, fi_ptr, + zero_count_fixup, NULL); return alias_info; } @@ -436,12 +441,12 @@ cfg_checksum_insert (unsigned cfg_checksum, gcov_type guid, /* Insert a new checksum_alias struct into lineno_pointer_sets for function with LINENO_CHECKSUM and CFG_CHECKSUM with associated GUID, FI_PTR, and - ZERO_COUNTS flag. */ + ZERO_COUNT_FIXUP flag pointer. */ static void checksum_set_insert (unsigned lineno_checksum, unsigned cfg_checksum, gcov_type guid, const struct gcov_fn_info *fi_ptr, - int zero_counts) + char *zero_count_fixup) { struct dyn_pointer_set *p = the_dyn_call_graph.lineno_pointer_sets; if (!p) @@ -452,7 +457,7 @@ checksum_set_insert (unsigned lineno_checksum, unsigned cfg_checksum, if (*m) { (*m)->cfg_checksum_list = cfg_checksum_insert (cfg_checksum, guid, - fi_ptr, zero_counts, + fi_ptr, zero_count_fixup, (*m)->cfg_checksum_list); } else @@ -460,7 +465,8 @@ checksum_set_insert (unsigned lineno_checksum, unsigned cfg_checksum, *m = XNEW (struct lineno_checksum_alias); (*m)->lineno_checksum = lineno_checksum; (*m)->cfg_checksum_list = cfg_checksum_insert (cfg_checksum, guid, - fi_ptr, zero_counts, NULL); + fi_ptr, zero_count_fixup, + NULL); p->n_elements++; } } @@ -801,10 +807,10 @@ gcov_build_callgraph_ic_fn (struct dyn_cgraph_node *caller, } } -/* Build the dynamic call graph. */ +/* Build the dynamic call graph and update ZERO_COUNTS flags. */ static void -gcov_build_callgraph (void) +gcov_build_callgraph (char **zero_counts) { struct gcov_info *gi_ptr; unsigned m_ix; @@ -852,9 +858,19 @@ gcov_build_callgraph (void) if (total_arc_count != 0) the_dyn_call_graph.num_nodes_executed++; if (fixup_type) - checksum_set_insert (fi_ptr->lineno_checksum, - fi_ptr->cfg_checksum, caller->guid, - fi_ptr, total_arc_count == 0); + { + char *zero_count_fixup = NULL; + /* Passing in a non-NULL zero_count_fixup pointer + indicates that the counts were all zero for this + function, and the fixup routine will set the flag + if the function's counters are updated to non-zero + values. */ + if (total_arc_count == 0) + zero_count_fixup = &zero_counts[m_ix][f_ix]; + checksum_set_insert (fi_ptr->lineno_checksum, + fi_ptr->cfg_checksum, caller->guid, + fi_ptr, zero_count_fixup); + } } ci_ptr++; } @@ -1251,7 +1267,14 @@ gcov_collect_imported_modules (const void *value, out_array = (struct gcov_import_mod_array *) data1; if (m->imp_mod != out_array->importing_module) + { out_array->imported_modules[out_array->len++] = m; + /* Sanity check that the importing (primary) module is not + actually the same as the new aux module. This could happen if + we accidentally read in the same gcda file twice. */ + gcc_assert (m->imp_mod->mod_info->ident != + out_array->importing_module->mod_info->ident); + } return 1; } @@ -2234,6 +2257,7 @@ gcov_compute_random_module_groups (unsigned max_group_size) } } +#if 0 /* Write out MOD_INFO into the gcda file. IS_PRIMARY is a flag indicating if the module is the primary module in the group. */ @@ -2241,7 +2265,7 @@ static void gcov_write_module_info (const struct gcov_info *mod_info, unsigned is_primary) { - gcov_unsigned_t len = 0, filename_len = 0, src_filename_len = 0, i, j; + gcov_unsigned_t len = 0, filename_len = 0, src_filename_len = 0, i; gcov_unsigned_t num_strings; gcov_unsigned_t *aligned_fname; struct gcov_module_info *module_info = mod_info->mod_info; @@ -2256,14 +2280,8 @@ gcov_write_module_info (const struct gcov_info *mod_info, + module_info->num_system_paths + module_info->num_cpp_defines + module_info->num_cpp_includes + module_info->num_cl_args; - for (i = 0; i < num_strings; i++) - { - gcov_unsigned_t string_len - = (strlen (module_info->string_array[i]) + sizeof (gcov_unsigned_t)) - / sizeof (gcov_unsigned_t); - len += string_len; - len += 1; /* Each string is lead by a length. */ - } + len += gcov_compute_string_array_len (module_info->string_array, + num_strings); len += 11; /* 11 more fields */ @@ -2296,21 +2314,9 @@ gcov_write_module_info (const struct gcov_info *mod_info, gcov_write_unsigned (aligned_fname[i]); /* Now write the string array. */ - for (j = 0; j < num_strings; j++) - { - gcov_unsigned_t *aligned_string; - gcov_unsigned_t string_len = - (strlen (module_info->string_array[j]) + sizeof (gcov_unsigned_t)) / - sizeof (gcov_unsigned_t); - aligned_string = (gcov_unsigned_t *) - alloca ((string_len + 1) * sizeof (gcov_unsigned_t)); - memset (aligned_string, 0, (string_len + 1) * sizeof (gcov_unsigned_t)); - aligned_string[0] = string_len; - strcpy ((char*) (aligned_string + 1), module_info->string_array[j]); - for (i = 0; i < (string_len + 1); i++) - gcov_write_unsigned (aligned_string[i]); - } + gcov_write_string_array (module_info->string_array, num_strings); } +#endif /* Write out MOD_INFO and its imported modules into gcda file. */ @@ -2320,6 +2326,8 @@ gcov_write_module_infos (struct gcov_info *mod_info) unsigned imp_len = 0; const struct dyn_imp_mod **imp_mods; + if (flag_alg_mode == INCLUSION_BASED_PRIORITY_ALGORITHM) + SET_MODULE_INCLUDE_ALL_AUX (mod_info->mod_info); gcov_write_module_info (mod_info, 1); imp_mods = gcov_get_sorted_import_module_array (mod_info, &imp_len); @@ -2976,7 +2984,7 @@ gcov_fixup_counters_checksum (const struct checksum_alias_info *info, for (alias = info->alias_list; alias; alias = alias->next_alias) { - if (alias->zero_counts) + if (alias->zero_count_fixup) { found = 1; break; @@ -2991,7 +2999,7 @@ gcov_fixup_counters_checksum (const struct checksum_alias_info *info, for (alias = info->alias_list; alias; alias = alias->next_alias) { - if (alias->zero_counts) + if (alias->zero_count_fixup) continue; merge_ctrs (merged_ctrs, alias->fi_ptr->ctrs, alias->guid); found = 1; @@ -3009,9 +3017,10 @@ gcov_fixup_counters_checksum (const struct checksum_alias_info *info, for (alias = info->alias_list; alias; alias = alias->next_alias) { - if (!alias->zero_counts) + if (!alias->zero_count_fixup) continue; copy_ctrs (alias->fi_ptr->ctrs, alias->guid, merged_ctrs); + *alias->zero_count_fixup = 1; } return 1; @@ -3059,11 +3068,13 @@ gcov_fixup_zero_counters (void) return changed; } -/* Compute module groups needed for L-IPO compilation. Returns 1 if any - counter fixups were applied, requiring a profile rewrite, 0 otherwise. */ +/* Compute module groups needed for L-IPO compilation. The ZERO_COUNTS + flags are set for functions with zero count fixups applied. Returns 1 + if any counter fixups were applied, requiring a profile rewrite, + 0 otherwise. */ int -__gcov_compute_module_groups (void) +__gcov_compute_module_groups (char **zero_counts) { gcov_type cut_off_count; char *seed = getenv ("LIPO_RANDOM_GROUPING"); @@ -3110,7 +3121,7 @@ __gcov_compute_module_groups (void) fixup_type = atoi (do_fixup); /* First compute dynamic call graph. */ - gcov_build_callgraph (); + gcov_build_callgraph (zero_counts); cut_off_count = gcov_compute_cutoff_count (); diff --git a/gcc-4.9/libgcc/libgcov-driver-kernel.c b/gcc-4.9/libgcc/libgcov-driver-kernel.c new file mode 100644 index 0000000..34298ed --- /dev/null +++ b/gcc-4.9/libgcc/libgcov-driver-kernel.c @@ -0,0 +1,203 @@ +/* Routines required for instrumenting a program. */ +/* Compile this one with gcc. */ +/* Copyright (C) 1989-2014 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + + +/* A utility function for outputing errors. */ + +static int __attribute__((format(printf, 1, 2))) +gcov_error (const char *fmt, ...) +{ + int ret; + va_list argp; + va_start (argp, fmt); + ret = vprintk (fmt, argp); + va_end (argp); + return ret; +} + +static void +allocate_filename_struct (struct gcov_filename_aux *gf) +{ + const char *gcov_prefix; + int gcov_prefix_strip = 0; + size_t prefix_length = 0; + char *gi_filename_up; + + /* Allocate and initialize the filename scratch space plus one. */ + gi_filename = (char *) xmalloc (prefix_length + gcov_max_filename + 2); + if (prefix_length) + memcpy (gi_filename, gcov_prefix, prefix_length); + gi_filename_up = gi_filename + prefix_length; + + gf->gi_filename_up = gi_filename_up; + gf->prefix_length = prefix_length; + gf->gcov_prefix_strip = gcov_prefix_strip; +} + +static int +gcov_open_by_filename (char *gi_filename) +{ + gcov_open (gi_filename); + return 0; +} + + +/* Strip GCOV_PREFIX_STRIP levels of leading '/' from FILENAME and + put the result into GI_FILENAME_UP. */ + +static void +gcov_strip_leading_dirs (int prefix_length, int gcov_prefix_strip, + const char *filename, char *gi_filename_up) +{ + strcpy (gi_filename_up, filename); +} + +/* Current virual gcda file. This is for kernel use only. */ +gcov_kernel_vfile *gcov_current_file; + +/* Set current virutal gcda file. It needs to be set before dumping + profile data. */ + +void +gcov_set_vfile (gcov_kernel_vfile *file) +{ + gcov_current_file = file; +} + +/* File fclose operation in kernel mode. */ + +int +kernel_file_fclose (gcov_kernel_vfile *fp) +{ + return 0; +} + +/* File ftell operation in kernel mode. It currently should not + be called. */ + +long +kernel_file_ftell (gcov_kernel_vfile *fp) +{ + return 0; +} + +/* File fseek operation in kernel mode. It should only be called + with OFFSET==0 and WHENCE==0 to a freshly opened file. */ + +int +kernel_file_fseek (gcov_kernel_vfile *fp, long offset, int whence) +{ + gcc_assert (offset == 0 && whence == 0 && fp->count == 0); + return 0; +} + +/* File ftruncate operation in kernel mode. It currently should not + be called. */ + +int +kernel_file_ftruncate (gcov_kernel_vfile *fp, off_t value) +{ + gcc_assert (0); /* should not reach here */ + return 0; +} + +/* File fread operation in kernel mode. It currently should not + be called. */ + +int +kernel_file_fread (void *ptr, size_t size, size_t nitems, + gcov_kernel_vfile *fp) +{ + gcc_assert (0); /* should not reach here */ + return 0; +} + +/* File fwrite operation in kernel mode. It outputs the data + to a buffer in the virual file. */ + +int +kernel_file_fwrite (const void *ptr, size_t size, + size_t nitems, gcov_kernel_vfile *fp) +{ + char *vbuf; + unsigned vsize, vpos; + unsigned len; + + if (!fp) return 0; + + vbuf = fp->buf; + vsize = fp->size; + vpos = fp->count; + + + if (vsize < vpos) + { + printk (KERN_ERR + "GCOV_KERNEL: something wrong in file %s: vbuf=%p vsize=%u" + " vpos=%u\n", + fp->info->filename, vbuf, vsize, vpos); + return 0; + } + + len = vsize - vpos; + len /= size; + + /* Increase the virtual file size if it is not suffcient. */ + while (len < nitems) + { + vsize *= 2; + len = vsize - vpos; + len /= size; + } + + if (vsize != fp->size) + { + vbuf = fp->buf = (char *) gcov_realloc_file_buf(vsize, vpos); + fp->size = vsize; + } + + if (len > nitems) + len = nitems; + + memcpy (vbuf+vpos, ptr, size*len); + fp->count += len*size; + + if (len != nitems) + printk (KERN_ERR + "GCOV_KERNEL: something wrong in file %s: size=%lu nitems=%lu" + " len=%d vsize=%u vpos=%u \n", + fp->info->filename, size, nitems, len, vsize, vpos); + return len; +} + +/* File fileno operation in kernel mode. It currently should not + be called. */ + +int +kernel_file_fileno (gcov_kernel_vfile *fp) +{ + gcc_assert (0); /* should not reach here */ + return 0; +} diff --git a/gcc-4.9/libgcc/libgcov-driver-system.c b/gcc-4.9/libgcc/libgcov-driver-system.c index d0bed49..1095474 100644 --- a/gcc-4.9/libgcc/libgcov-driver-system.c +++ b/gcc-4.9/libgcc/libgcov-driver-system.c @@ -156,8 +156,6 @@ gcov_open_by_filename (char *gi_filename) } -#define GCOV_GET_FILENAME gcov_strip_leading_dirs - /* Strip GCOV_PREFIX_STRIP levels of leading '/' from FILENAME and put the result into GI_FILENAME_UP. */ @@ -197,24 +195,3 @@ gcov_strip_leading_dirs (int prefix_length, int gcov_prefix_strip, else strcpy (gi_filename_up, filename); } - - -/* Open a gcda file specified by GI_FILENAME. - Return -1 on error. Return 0 on success. */ - -static int -gcov_exit_open_gcda_file (struct gcov_info *gi_ptr, struct gcov_filename_aux *gf) -{ - int gcov_prefix_strip; - size_t prefix_length; - char *gi_filename_up; - - gcov_prefix_strip = gf->gcov_prefix_strip; - gi_filename_up = gf->gi_filename_up; - prefix_length = gf->prefix_length; - - GCOV_GET_FILENAME (prefix_length, gcov_prefix_strip, gi_ptr->filename, - gi_filename_up); - - return gcov_open_by_filename (gi_filename); -} diff --git a/gcc-4.9/libgcc/libgcov-driver.c b/gcc-4.9/libgcc/libgcov-driver.c index dc8cf36..3c569f1 100644 --- a/gcc-4.9/libgcc/libgcov-driver.c +++ b/gcc-4.9/libgcc/libgcov-driver.c @@ -34,28 +34,24 @@ void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {} #else /* inhibit_libc */ +#if !defined(__KERNEL__) #include <string.h> #if GCOV_LOCKED #include <fcntl.h> #include <errno.h> #include <sys/stat.h> #endif +#endif /* __KERNEL__ */ #ifdef L_gcov #include "gcov-io.c" -#ifndef IN_GCOV_TOOL -extern gcov_unsigned_t __gcov_sampling_period; -extern gcov_unsigned_t __gcov_has_sampling; -static int gcov_sampling_period_initialized = 0; -#endif - /* Unique identifier assigned to each module (object file). */ static gcov_unsigned_t gcov_cur_module_id = 0; /* Dynamic call graph build and form module groups. */ -int __gcov_compute_module_groups (void) ATTRIBUTE_HIDDEN; +int __gcov_compute_module_groups (char **zero_counts) ATTRIBUTE_HIDDEN; void __gcov_finalize_dyn_callgraph (void) ATTRIBUTE_HIDDEN; /* The following functions can be called from outside of this file. */ @@ -67,7 +63,11 @@ extern int get_gcov_dump_complete (void) ATTRIBUTE_HIDDEN; extern void set_gcov_list (struct gcov_info *) ATTRIBUTE_HIDDEN; __attribute__((weak)) void __coverage_callback (gcov_type, int); -#ifndef IN_GCOV_TOOL +#if !defined(IN_GCOV_TOOL) && !defined(__KERNEL__) +extern gcov_unsigned_t __gcov_sampling_period; +extern gcov_unsigned_t __gcov_has_sampling; +static int gcov_sampling_period_initialized = 0; + /* Create a strong reference to these symbols so that they are unconditionally pulled into the instrumented binary, even when the only reference is a weak reference. This is necessary because @@ -129,6 +129,24 @@ set_gcov_list (struct gcov_info *head) __gcov_list = head; } +/* Flag if the current function being read was marked as having fixed-up + zero counters. */ +static int __gcov_curr_fn_fixed_up; + +/* Set function fixed up flag. */ +void +set_gcov_fn_fixed_up (int fixed_up) +{ + __gcov_curr_fn_fixed_up = fixed_up; +} + +/* Return function fixed up flag. */ +int +get_gcov_fn_fixed_up (void) +{ + return __gcov_curr_fn_fixed_up; +} + /* Size of the longest file name. */ /* We need to expose this static variable when compiling for gcov-tool. */ #ifndef IN_GCOV_TOOL @@ -181,8 +199,8 @@ free_fn_data (const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer, for (ix = 0; ix != limit; ix++) if (gi_ptr->merge[ix]) - free (buffer->info.ctrs[n_ctr++].values); - free (buffer); + xfree (buffer->info.ctrs[n_ctr++].values); + xfree (buffer); return next; } @@ -386,7 +404,10 @@ static int run_accounted = 0; /* This funtions computes the program level summary and the histo-gram. It computes and returns CRC32 and stored summary in THIS_PRG. */ -static gcov_unsigned_t +#if !IN_GCOV_TOOL +static +#endif +gcov_unsigned_t gcov_exit_compute_summary (struct gcov_summary *this_prg) { struct gcov_info *gi_ptr; @@ -451,14 +472,58 @@ struct gcov_filename_aux{ }; /* Including system dependent components. */ +#if !defined (__KERNEL__) #include "libgcov-driver-system.c" +#else +#include "libgcov-driver-kernel.c" +#endif + +static int +scan_build_info (struct gcov_info *gi_ptr) +{ + gcov_unsigned_t i, length; + gcov_unsigned_t num_strings = 0; + char **build_info_strings; + length = gcov_read_unsigned (); + build_info_strings = gcov_read_build_info (length, &num_strings); + if (!build_info_strings) + { + gcov_error ("profiling:%s:Error reading build info\n", gi_filename); + return -1; + } + if (!gi_ptr->build_info) + { + gcov_error ("profiling:%s:Mismatched build info sections, expected " + "none, found %u strings)\n", gi_filename, num_strings); + return -1; + } + + for (i = 0; i < num_strings; i++) + { + if (strcmp (build_info_strings[i], gi_ptr->build_info[i])) + { + gcov_error ("profiling:%s:Mismatched build info string " + "(expected %s, read %s)\n", + gi_filename, gi_ptr->build_info[i], + build_info_strings[i]); + return -1; + } + xfree (build_info_strings[i]); + } + xfree (build_info_strings); + return 0; +} + +#if !defined(__KERNEL__) /* Scan through the current open gcda file corresponding to GI_PTR - to locate the end position of the last summary, returned in - SUMMARY_END_POS_P. Return 0 on success, -1 on error. */ + to locate the end position just before function data should be rewritten, + returned in SUMMARY_END_POS_P. E.g. scan past the last summary and other + sections that won't be rewritten, like the build info. Return 0 on success, + -1 on error. */ static int -gcov_scan_summary_end (struct gcov_info *gi_ptr, - gcov_position_t *summary_end_pos_p) +gcov_scan_to_function_data (struct gcov_info *gi_ptr, + gcov_position_t *summary_end_pos_p) { gcov_unsigned_t tag, version, stamp; tag = gcov_read_unsigned (); @@ -493,8 +558,21 @@ gcov_scan_summary_end (struct gcov_info *gi_ptr, return -1; } + /* If there is a build info section, scan past it as well. */ + if (tag == GCOV_TAG_BUILD_INFO) + { + if (scan_build_info (gi_ptr) < 0) + return -1; + + *summary_end_pos_p = gcov_position (); + tag = gcov_read_unsigned (); + } + /* The next section should be the function counters. */ + gcc_assert (tag == GCOV_TAG_FUNCTION); + return 0; } +#endif /* __KERNEL__ */ /* This function merges counters in GI_PTR to an existing gcda file. Return 0 on success. @@ -514,6 +592,7 @@ gcov_exit_merge_gcda (struct gcov_info *gi_ptr, int error = 0; struct gcov_fn_buffer **fn_tail = &fn_buffer; struct gcov_summary_buffer **sum_tail = &sum_buffer; + int *zero_fixup_flags = NULL; length = gcov_read_unsigned (); if (!gcov_version (gi_ptr, length, gi_filename)) @@ -565,6 +644,31 @@ gcov_exit_merge_gcda (struct gcov_info *gi_ptr, next_summary:; } + if (tag == GCOV_TAG_BUILD_INFO) + { + if (scan_build_info (gi_ptr) < 0) + return -1; + + /* Since the stamps matched if we got here, this should be from + the same compilation and the build info strings should match. */ + tag = gcov_read_unsigned (); + } + + if (tag == GCOV_TAG_COMDAT_ZERO_FIXUP) + { + gcov_unsigned_t num_fns = 0; + length = gcov_read_unsigned (); + zero_fixup_flags = gcov_read_comdat_zero_fixup (length, &num_fns); + if (!zero_fixup_flags) + { + gcov_error ("profiling:%s:Error reading zero fixup flags\n", + gi_filename); + return -1; + } + + tag = gcov_read_unsigned (); + } + /* Merge execution counts for each function. */ for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++, tag = gcov_read_unsigned ()) @@ -598,6 +702,9 @@ gcov_exit_merge_gcda (struct gcov_info *gi_ptr, continue; } + if (zero_fixup_flags) + set_gcov_fn_fixed_up (zero_fixup_flags[f_ix]); + length = gcov_read_unsigned (); if (length != gfi_ptr->ident) goto read_mismatch; @@ -629,6 +736,7 @@ gcov_exit_merge_gcda (struct gcov_info *gi_ptr, if ((error = gcov_is_error ())) goto read_error; } + xfree (zero_fixup_flags); if (tag && tag != GCOV_TAG_MODULE_INFO) { @@ -646,6 +754,57 @@ read_error: return -1; } +#if !defined(__KERNEL__) +/* Write NUM_FNS ZERO_COUNTS fixup flags to a gcda file starting from its + current location. */ + +static void +gcov_write_comdat_zero_fixup (char *zero_counts, unsigned num_fns) +{ + unsigned f_ix; + gcov_unsigned_t len = GCOV_TAG_COMDAT_ZERO_FIXUP_LENGTH (num_fns); + gcov_unsigned_t bitvector = 0, b_ix = 0; + gcov_write_tag_length (GCOV_TAG_COMDAT_ZERO_FIXUP, len); + + gcov_write_unsigned (num_fns); + for (f_ix = 0; f_ix != num_fns; f_ix++) + { + if (zero_counts[f_ix]) + bitvector |= 1 << b_ix; + if (++b_ix == 32) + { + gcov_write_unsigned (bitvector); + b_ix = 0; + bitvector = 0; + } + } + if (b_ix > 0) + gcov_write_unsigned (bitvector); +} +#endif /* __KERNEL__ */ + +/* Write build_info strings from GI_PTR to a gcda file starting from its current + location. */ + +static void +gcov_write_build_info (struct gcov_info *gi_ptr) +{ + gcov_unsigned_t num = 0; + gcov_unsigned_t len = 1; + + if (!gi_ptr->build_info) + return; + + /* Count the number of strings, which is terminated with an empty string. */ + while (gi_ptr->build_info[num][0]) + num++; + + len += gcov_compute_string_array_len (gi_ptr->build_info, num); + gcov_write_tag_length (GCOV_TAG_BUILD_INFO, len); + gcov_write_unsigned (num); + gcov_write_string_array (gi_ptr->build_info, num); +} + /* Write counters in GI_PTR to a gcda file starting from its current location. */ @@ -676,7 +835,7 @@ gcov_write_func_counters (struct gcov_info *gi_ptr) if (gfi_ptr && gfi_ptr->key == gi_ptr) length = GCOV_TAG_FUNCTION_LENGTH; else - length = 0; + length = 0; } gcov_write_tag_length (GCOV_TAG_FUNCTION, length); @@ -704,8 +863,10 @@ gcov_write_func_counters (struct gcov_info *gi_ptr) gcov_write_counter (*c_ptr++); ci_ptr++; } +#if !defined(__KERNEL__) if (buffered) fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS); +#endif /* __KERNEL__ */ } gi_ptr->eof_pos = gcov_position (); @@ -748,10 +909,12 @@ gcov_exit_write_gcda (struct gcov_info *gi_ptr, { gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &sum_buffer->summary); next_sum_buffer = sum_buffer->next; - free (sum_buffer); + xfree (sum_buffer); sum_buffer = next_sum_buffer; } + gcov_write_build_info (gi_ptr); + /* Write the counters. */ gcov_write_func_counters (gi_ptr); } @@ -835,6 +998,8 @@ gcov_exit_merge_summary (const struct gcov_info *gi_ptr, struct gcov_summary *pr return 0; } +__attribute__((weak)) gcov_unsigned_t __gcov_lipo_sampling_period; + /* Sort N entries in VALUE_ARRAY in descending order. Each entry in VALUE_ARRAY has two values. The sorting is based on the second value. */ @@ -906,6 +1071,62 @@ gcov_sort_topn_counter_arrays (const struct gcov_info *gi_ptr) } } +/* Scaling LIPO sampled profile counters. */ +static void +gcov_scaling_lipo_counters (const struct gcov_info *gi_ptr) +{ + unsigned int i,j,k; + int f_ix; + const struct gcov_fn_info *gfi_ptr; + const struct gcov_ctr_info *ci_ptr; + + if (__gcov_lipo_sampling_period <= 1) + return; + + for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++) + { + gfi_ptr = gi_ptr->functions[f_ix]; + ci_ptr = gfi_ptr->ctrs; + for (i = 0; i < GCOV_COUNTERS; i++) + { + if (!gcov_counter_active (gi_ptr, i)) + continue; + if (i == GCOV_COUNTER_ICALL_TOPNV) + { + for (j = 0; j < ci_ptr->num; j += GCOV_ICALL_TOPN_NCOUNTS) + for (k = 2; k < GCOV_ICALL_TOPN_NCOUNTS; k += 2) + ci_ptr->values[j+k] *= __gcov_lipo_sampling_period; + } + if (i == GCOV_COUNTER_DIRECT_CALL) + { + for (j = 0; j < ci_ptr->num; j += 2) + ci_ptr->values[j+1] *= __gcov_lipo_sampling_period; + } + ci_ptr++; + } + } +} + +/* Open a gcda file specified by GI_FILENAME. + Return -1 on error. Return 0 on success. */ + +static int +gcov_exit_open_gcda_file (struct gcov_info *gi_ptr, struct gcov_filename_aux *gf) +{ + int gcov_prefix_strip; + size_t prefix_length; + char *gi_filename_up; + + gcov_prefix_strip = gf->gcov_prefix_strip; + gi_filename_up = gf->gi_filename_up; + prefix_length = gf->prefix_length; + + gcov_strip_leading_dirs (prefix_length, gcov_prefix_strip, gi_ptr->filename, + gi_filename_up); + + return gcov_open_by_filename (gi_filename); +} + /* Dump the coverage counts for one gcov_info object. We merge with existing counts when possible, to avoid growing the .da files ad infinitum. We use this program's checksum to make sure we only accumulate whole program @@ -918,9 +1139,14 @@ gcov_exit_dump_gcov (struct gcov_info *gi_ptr, struct gcov_filename_aux *gf, gcov_unsigned_t crc32, struct gcov_summary *all_prg, struct gcov_summary *this_prg) { +/* We have to make the decl static as kernel has limited stack size. + If we put prg to stack, we will running into nasty stack overflow. */ +#if defined(__KERNEL__) + static +#endif struct gcov_summary prg; /* summary for this object over all program. */ int error; - gcov_unsigned_t tag; + gcov_unsigned_t tag = 0; gcov_position_t summary_pos = 0; gcov_position_t eof_pos = 0; @@ -928,12 +1154,15 @@ gcov_exit_dump_gcov (struct gcov_info *gi_ptr, struct gcov_filename_aux *gf, sum_buffer = 0; gcov_sort_topn_counter_arrays (gi_ptr); + gcov_scaling_lipo_counters (gi_ptr); error = gcov_exit_open_gcda_file (gi_ptr, gf); if (error == -1) return; +#if !defined(__KERNEL__) tag = gcov_read_unsigned (); +#endif if (tag) { /* Merge data from file. */ @@ -964,8 +1193,21 @@ gcov_exit_dump_gcov (struct gcov_info *gi_ptr, struct gcov_filename_aux *gf, /* fall through */ read_fatal:; +#if !defined(__KERNEL__) while (fn_buffer) fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS); +#else + + /* In LIPO mode, dump the primary module info. */ + if (gi_ptr->mod_info && gi_ptr->mod_info->is_primary) + { + /* Overwrite the zero word at the of the file. */ + gcov_seek (gi_ptr->eof_pos); + gcov_write_module_info (gi_ptr, 1); + /* Write the end marker */ + gcov_write_unsigned (0); + } +#endif if ((error = gcov_close ())) gcov_error (error < 0 ? @@ -974,6 +1216,7 @@ read_fatal:; gi_filename); } +#if !defined (__KERNEL__) /* Write imported files (auxiliary modules) for primary module GI_PTR into file GI_FILENAME. */ @@ -1009,7 +1252,7 @@ gcov_write_import_file (char *gi_filename, struct gcov_info *gi_ptr) fprintf (imports_file, "%s%s\n", imp_mods[i]->imp_mod->mod_info->da_filename, GCOV_DATA_SUFFIX); } - free (imp_mods); + xfree (imp_mods); } fclose (imports_file); } @@ -1020,9 +1263,24 @@ gcov_dump_module_info (struct gcov_filename_aux *gf) { struct gcov_info *gi_ptr; + unsigned max_module_id = 0; + for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next) + { + unsigned mod_id = gi_ptr->mod_info->ident; + if (max_module_id < mod_id) + max_module_id = mod_id; + } + char **zero_counts = (char **) xcalloc (max_module_id, sizeof (char *)); + for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next) + { + unsigned mod_id = gi_ptr->mod_info->ident; + zero_counts[mod_id-1] = (char *) xcalloc (gi_ptr->n_functions, + sizeof (char)); + } + /* Compute the module groups and record whether there were any counter fixups applied that require rewriting the counters. */ - int changed = __gcov_compute_module_groups (); + int changed = __gcov_compute_module_groups (zero_counts); /* Now write out module group info. */ for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next) @@ -1034,10 +1292,10 @@ gcov_dump_module_info (struct gcov_filename_aux *gf) if (changed) { - /* Scan file to find the end of the summary section, which is + /* Scan file to find the start of the function section, which is where we will start re-writing the counters. */ gcov_position_t summary_end_pos; - if (gcov_scan_summary_end (gi_ptr, &summary_end_pos) == -1) + if (gcov_scan_to_function_data (gi_ptr, &summary_end_pos) == -1) gcov_error ("profiling:%s:Error scanning summaries\n", gi_filename); else @@ -1045,8 +1303,15 @@ gcov_dump_module_info (struct gcov_filename_aux *gf) gcov_position_t eof_pos = gi_ptr->eof_pos; gcov_rewrite (); gcov_seek (summary_end_pos); + + unsigned mod_id = gi_ptr->mod_info->ident; + gcov_write_comdat_zero_fixup (zero_counts[mod_id-1], + gi_ptr->n_functions); + gcov_position_t zero_fixup_eof_pos = gcov_position (); + gcov_write_func_counters (gi_ptr); - gcc_assert (eof_pos == gi_ptr->eof_pos); + gcc_assert (eof_pos + (zero_fixup_eof_pos - summary_end_pos) + == gi_ptr->eof_pos); } } else @@ -1065,7 +1330,11 @@ gcov_dump_module_info (struct gcov_filename_aux *gf) "profiling:%s:Error writing\n", gi_filename); gcov_write_import_file (gi_filename, gi_ptr); + free (zero_counts[gi_ptr->mod_info->ident-1]); } + + free (zero_counts); + __gcov_finalize_dyn_callgraph (); } @@ -1102,7 +1371,8 @@ gcov_exit (void) /* The IS_PRIMARY field is overloaded to indicate if this module is FDO/LIPO. */ - dump_module_info |= gi_ptr->mod_info->is_primary; + if (gi_ptr->mod_info) + dump_module_info |= gi_ptr->mod_info->is_primary; } run_accounted = 1; @@ -1110,38 +1380,7 @@ gcov_exit (void) gcov_dump_module_info (&gf); if (gi_filename) - free (gi_filename); -} - -/* Reset all counters to zero. */ - -void -gcov_clear (void) -{ - const struct gcov_info *gi_ptr; - - for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next) - { - unsigned f_ix; - - for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) - { - unsigned t_ix; - const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix]; - - if (!gfi_ptr || gfi_ptr->key != gi_ptr) - continue; - const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs; - for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++) - { - if (!gi_ptr->merge[t_ix]) - continue; - - memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num); - ci_ptr++; - } - } - } + xfree (gi_filename); } /* Add a new object file onto the bb chain. Invoked automatically @@ -1160,6 +1399,13 @@ __gcov_init (struct gcov_info *info) if (env_value_int >= 1) __gcov_sampling_period = env_value_int; } + env_value_str = getenv ("GCOV_LIPO_SAMPLING_PERIOD"); + if (env_value_str) + { + int env_value_int = atoi(env_value_str); + if (env_value_int >= 0) + __gcov_lipo_sampling_period = env_value_int; + } gcov_sampling_period_initialized = 1; } #endif @@ -1189,5 +1435,116 @@ __gcov_init (struct gcov_info *info) info->version = 0; } +#else /* __KERNEL__ */ + +static struct gcov_filename_aux gf; +static gcov_unsigned_t crc32; +static struct gcov_summary all_prg; +static struct gcov_summary this_prg; +void +gcov_kernel_dump_gcov_init (void) +{ + crc32 = gcov_exit_compute_summary (&this_prg); + allocate_filename_struct (&gf); + memset (&all_prg, 0, sizeof (all_prg)); +} + +void +gcov_kernel_dump_one_gcov(struct gcov_info *info) +{ + gcov_exit_dump_gcov (info, &gf, crc32, &all_prg, &this_prg); +} + +#endif /* __KERNEL__ */ + +/* Reset all counters to zero. */ + +void +gcov_clear (void) +{ + const struct gcov_info *gi_ptr; + + for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next) + { + unsigned f_ix; + + for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) + { + unsigned t_ix; + const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix]; + const struct gcov_ctr_info *ci_ptr; + + if (!gfi_ptr || gfi_ptr->key != gi_ptr) + continue; + ci_ptr = gfi_ptr->ctrs; + for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++) + { + if (!gi_ptr->merge[t_ix]) + continue; + + memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num); + ci_ptr++; + } + } + } +} + +/* Write out MOD_INFO into the gcda file. IS_PRIMARY is a flag + indicating if the module is the primary module in the group. */ + +void +gcov_write_module_info (const struct gcov_info *mod_info, + unsigned is_primary) +{ + gcov_unsigned_t len = 0, filename_len = 0, src_filename_len = 0, i; + gcov_unsigned_t num_strings; + gcov_unsigned_t *aligned_fname; + struct gcov_module_info *module_info = mod_info->mod_info; + filename_len = (strlen (module_info->da_filename) + + sizeof (gcov_unsigned_t)) / sizeof (gcov_unsigned_t); + src_filename_len = (strlen (module_info->source_filename) + + sizeof (gcov_unsigned_t)) / sizeof (gcov_unsigned_t); + len = filename_len + src_filename_len; + len += 2; /* each name string is led by a length. */ + + num_strings = module_info->num_quote_paths + module_info->num_bracket_paths + + module_info->num_system_paths + + module_info->num_cpp_defines + module_info->num_cpp_includes + + module_info->num_cl_args; + len += gcov_compute_string_array_len (module_info->string_array, + num_strings); + + len += 11; /* 11 more fields */ + + gcov_write_tag_length (GCOV_TAG_MODULE_INFO, len); + gcov_write_unsigned (module_info->ident); + gcov_write_unsigned (is_primary); + gcov_write_unsigned (module_info->flags); + gcov_write_unsigned (module_info->lang); + gcov_write_unsigned (module_info->ggc_memory); + gcov_write_unsigned (module_info->num_quote_paths); + gcov_write_unsigned (module_info->num_bracket_paths); + gcov_write_unsigned (module_info->num_system_paths); + gcov_write_unsigned (module_info->num_cpp_defines); + gcov_write_unsigned (module_info->num_cpp_includes); + gcov_write_unsigned (module_info->num_cl_args); + + /* Now write the filenames */ + aligned_fname = (gcov_unsigned_t *) alloca ((filename_len + src_filename_len + 2) * + sizeof (gcov_unsigned_t)); + memset (aligned_fname, 0, + (filename_len + src_filename_len + 2) * sizeof (gcov_unsigned_t)); + aligned_fname[0] = filename_len; + strcpy ((char*) (aligned_fname + 1), module_info->da_filename); + aligned_fname[filename_len + 1] = src_filename_len; + strcpy ((char*) (aligned_fname + filename_len + 2), module_info->source_filename); + + for (i = 0; i < (filename_len + src_filename_len + 2); i++) + gcov_write_unsigned (aligned_fname[i]); + + /* Now write the string array. */ + gcov_write_string_array (module_info->string_array, num_strings); +} + #endif /* L_gcov */ #endif /* inhibit_libc */ diff --git a/gcc-4.9/libgcc/libgcov-kernel.h b/gcc-4.9/libgcc/libgcov-kernel.h new file mode 100644 index 0000000..b44af53 --- /dev/null +++ b/gcc-4.9/libgcc/libgcov-kernel.h @@ -0,0 +1,121 @@ +/* Header file for libgcov-*.c. + Copyright (C) 1996-2014 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 3, or (at your option) any later + version. + + GCC is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef GCC_LIBGCOV_KERNEL_H +#define GCC_LIBGCOV_KERNEL_H + +/* work around the poisoned malloc/calloc in system.h. */ +#ifndef xmalloc +#define xmalloc vmalloc +#endif +#ifndef xcalloc +#define xcalloc vcalloc +#endif +#ifndef xrealloc +#define xrealloc vrealloc +#endif +#ifndef xfree +#define xfree vfree +#endif +#ifndef alloca +#define alloca __builtin_alloca +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + + /* Define MACROs to be used by kernel compilation. */ +# define L_gcov +# define L_gcov_interval_profiler +# define L_gcov_pow2_profiler +# define L_gcov_one_value_profiler +# define L_gcov_indirect_call_profiler_v2 +# define L_gcov_direct_call_profiler +# define L_gcov_indirect_call_profiler +# define L_gcov_indirect_call_topn_profiler +# define L_gcov_time_profiler +# define L_gcov_average_profiler +# define L_gcov_ior_profiler +# define L_gcov_merge_add +# define L_gcov_merge_single +# define L_gcov_merge_delta +# define L_gcov_merge_ior +# define L_gcov_merge_time_profile +# define L_gcov_merge_icall_topn +# define L_gcov_merge_dc + +# define IN_LIBGCOV 1 +# define IN_GCOV 0 +#define THREAD_PREFIX +#define GCOV_LINKAGE /* nothing */ +#define BITS_PER_UNIT 8 +#define LONG_LONG_TYPE_SIZE 64 +#define MEMMODEL_RELAXED 0 + +#define ENABLE_ASSERT_CHECKING 1 + +/* gcc_assert() prints out a warning if the check fails. It + will not abort. */ +#if ENABLE_ASSERT_CHECKING +# define gcc_assert(EXPR) \ + ((void)(!(EXPR) ? printk (KERN_WARNING \ + "GCOV assertion fails: func=%s line=%d\n", \ + __FUNCTION__, __LINE__), 0 : 0)) +#else +# define gcc_assert(EXPR) ((void)(0 && (EXPR))) +#endif + +/* In Linux kernel mode, a virtual file is used for file operations. */ +struct gcov_info; +typedef struct { + long size; /* size of buf */ + long count; /* element written into buf */ + struct gcov_info *info; + char *buf; +} gcov_kernel_vfile; + +#define _GCOV_FILE gcov_kernel_vfile + +/* Wrappers to the file operations. */ +#define _GCOV_fclose kernel_file_fclose +#define _GCOV_ftell kernel_file_ftell +#define _GCOV_fseek kernel_file_fseek +#define _GCOV_ftruncate kernel_file_ftruncate +#define _GCOV_fread kernel_file_fread +#define _GCOV_fwrite kernel_file_fwrite +#define _GCOV_fileno kernel_file_fileno + +/* Declarations for virtual files operations. */ +extern int kernel_file_fclose (gcov_kernel_vfile *); +extern long kernel_file_ftell (gcov_kernel_vfile *); +extern int kernel_file_fseek (gcov_kernel_vfile *, long, int); +extern int kernel_file_ftruncate (gcov_kernel_vfile *, off_t); +extern int kernel_file_fread (void *, size_t, size_t, + gcov_kernel_vfile *); +extern int kernel_file_fwrite (const void *, size_t, size_t, + gcov_kernel_vfile *); +extern int kernel_file_fileno (gcov_kernel_vfile *); + +#endif /* GCC_LIBGCOV_KERNEL_H */ diff --git a/gcc-4.9/libgcc/libgcov-merge.c b/gcc-4.9/libgcc/libgcov-merge.c index ddbf06a..997dab3 100644 --- a/gcc-4.9/libgcc/libgcov-merge.c +++ b/gcc-4.9/libgcc/libgcov-merge.c @@ -108,10 +108,12 @@ __gcov_merge_dc (gcov_type *counters, unsigned n_counters) else if (__gcov_is_gid_insane (global_id)) global_id = counters[i]; +#if !defined(__KERNEL__) /* In the case of inconsistency, use the src's target. */ if (counters[i] != global_id) fprintf (stderr, "Warning: Inconsistent call targets in" " direct-call profile.\n"); +#endif } else if (global_id) counters[i] = global_id; diff --git a/gcc-4.9/libgcc/libgcov-profiler.c b/gcc-4.9/libgcc/libgcov-profiler.c index 3057b61..7552ada 100644 --- a/gcc-4.9/libgcc/libgcov-profiler.c +++ b/gcc-4.9/libgcc/libgcov-profiler.c @@ -221,13 +221,29 @@ __gcov_indirect_call_profiler_atomic_v2 (gcov_type value, void* cur_func) the descriptors to see if they point to the same function. */ if (cur_func == __gcov_indirect_call_callee || (VTABLE_USES_DESCRIPTORS && __gcov_indirect_call_callee - && *(void **) cur_func == *(void **) __gcov_indirect_call_callee)) + && *(void **) cur_func == *(void **) __gcov_indirect_call_callee)) __gcov_one_value_profiler_body_atomic (__gcov_indirect_call_counters, value); } #endif +/* +#if defined(L_gcov_direct_call_profiler) || defined(L_gcov_indirect_call_topn_profiler) +__attribute__ ((weak)) gcov_unsigned_t __gcov_lipo_sampling_period; +#endif +*/ + +extern gcov_unsigned_t __gcov_lipo_sampling_period; + #ifdef L_gcov_indirect_call_topn_profiler + +#include "gthr.h" + +#ifdef __GTHREAD_MUTEX_INIT +__thread int in_profiler; +ATTRIBUTE_HIDDEN __gthread_mutex_t __indir_topn_val_mx = __GTHREAD_MUTEX_INIT; +#endif + /* Tries to keep track the most frequent N values in the counters where N is specified by parameter TOPN_VAL. To track top N values, 2*N counter entries are used. @@ -252,10 +268,18 @@ __gcov_topn_value_profiler_body (gcov_type *counters, gcov_type value, /* There are 2*topn_val values tracked, each value takes two slots in the counter array */ - for ( i = 0; i < (topn_val << 2); i += 2) +#ifdef __GTHREAD_MUTEX_INIT + /* If this is reentry, return. */ + if (in_profiler == 1) + return; + + in_profiler = 1; + __gthread_mutex_lock (&__indir_topn_val_mx); +#endif + for (i = 0; i < topn_val << 2; i += 2) { entry = &value_array[i]; - if ( entry[0] == value) + if (entry[0] == value) { entry[1]++ ; found = 1; @@ -271,7 +295,13 @@ __gcov_topn_value_profiler_body (gcov_type *counters, gcov_type value, } if (found) - return; + { + in_profiler = 0; +#ifdef __GTHREAD_MUTEX_INIT + __gthread_mutex_unlock (&__indir_topn_val_mx); +#endif + return; + } /* lfu_entry is either an empty entry or an entry with lowest count, which will be evicted. */ @@ -280,56 +310,49 @@ __gcov_topn_value_profiler_body (gcov_type *counters, gcov_type value, #define GCOV_ICALL_COUNTER_CLEAR_THRESHOLD 3000 - /* Too many evictions -- time to clear bottom entries to + /* Too many evictions -- time to clear bottom entries to avoid hot values bumping each other out. */ - if ( !have_zero_count - && ++*num_eviction >= GCOV_ICALL_COUNTER_CLEAR_THRESHOLD) + if (!have_zero_count + && ++*num_eviction >= GCOV_ICALL_COUNTER_CLEAR_THRESHOLD) { unsigned i, j; - gcov_type *p, minv; - gcov_type* tmp_cnts - = (gcov_type *)alloca (topn_val * sizeof(gcov_type)); + gcov_type **p; + gcov_type **tmp_cnts + = (gcov_type **)alloca (topn_val * sizeof(gcov_type *)); *num_eviction = 0; - for ( i = 0; i < topn_val; i++ ) - tmp_cnts[i] = 0; - /* Find the largest topn_val values from the group of - 2*topn_val values and put them into tmp_cnts. */ + 2*topn_val values and put the addresses into tmp_cnts. */ + for (i = 0; i < topn_val; i++) + tmp_cnts[i] = &value_array[i * 2 + 1]; - for ( i = 0; i < 2 * topn_val; i += 2 ) + for (i = topn_val * 2; i < topn_val << 2; i += 2) { - p = 0; - for ( j = 0; j < topn_val; j++ ) - { - if ( !p || tmp_cnts[j] < *p ) - p = &tmp_cnts[j]; - } - if ( value_array[i + 1] > *p ) - *p = value_array[i + 1]; + p = &tmp_cnts[0]; + for (j = 1; j < topn_val; j++) + if (*tmp_cnts[j] > **p) + p = &tmp_cnts[j]; + if (value_array[i + 1] < **p) + *p = &value_array[i + 1]; } - minv = tmp_cnts[0]; - for ( j = 1; j < topn_val; j++ ) - { - if (tmp_cnts[j] < minv) - minv = tmp_cnts[j]; - } - /* Zero out low value entries */ - for ( i = 0; i < 2 * topn_val; i += 2 ) + /* Zero out low value entries. */ + for (i = 0; i < topn_val; i++) { - if (value_array[i + 1] < minv) - { - value_array[i] = 0; - value_array[i + 1] = 0; - } + *tmp_cnts[i] = 0; + *(tmp_cnts[i] - 1) = 0; } } + +#ifdef __GTHREAD_MUTEX_INIT + in_profiler = 0; + __gthread_mutex_unlock (&__indir_topn_val_mx); +#endif } #if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS) -__thread +__thread #endif gcov_type *__gcov_indirect_call_topn_counters ATTRIBUTE_HIDDEN; @@ -338,6 +361,11 @@ __thread #endif void *__gcov_indirect_call_topn_callee ATTRIBUTE_HIDDEN; +#if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS) +__thread +#endif +gcov_unsigned_t __gcov_indirect_call_sampling_counter ATTRIBUTE_HIDDEN; + #ifdef TARGET_VTABLE_USES_DESCRIPTORS #define VTABLE_USES_DESCRIPTORS 1 #else @@ -355,12 +383,16 @@ __gcov_indirect_call_topn_profiler (void *cur_func, the descriptors to see if they point to the same function. */ if (cur_func == callee_func || (VTABLE_USES_DESCRIPTORS && callee_func - && *(void **) cur_func == *(void **) callee_func)) + && *(void **) cur_func == *(void **) callee_func)) { - gcov_type global_id - = ((struct gcov_info *) cur_module_gcov_info)->mod_info->ident; - global_id = GEN_FUNC_GLOBAL_ID (global_id, cur_func_id); - __gcov_topn_value_profiler_body (counter, global_id, GCOV_ICALL_TOPN_VAL); + if (++__gcov_indirect_call_sampling_counter >= __gcov_lipo_sampling_period) + { + __gcov_indirect_call_sampling_counter = 0; + gcov_type global_id + = ((struct gcov_info *) cur_module_gcov_info)->mod_info->ident; + global_id = GEN_FUNC_GLOBAL_ID (global_id, cur_func_id); + __gcov_topn_value_profiler_body (counter, global_id, GCOV_ICALL_TOPN_VAL); + } __gcov_indirect_call_topn_callee = 0; } } @@ -376,7 +408,13 @@ gcov_type *__gcov_direct_call_counters ATTRIBUTE_HIDDEN; __thread #endif void *__gcov_direct_call_callee ATTRIBUTE_HIDDEN; +#if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS) +__thread +#endif +gcov_unsigned_t __gcov_direct_call_sampling_counter ATTRIBUTE_HIDDEN; + /* Direct call profiler. */ + void __gcov_direct_call_profiler (void *cur_func, void *cur_module_gcov_info, @@ -384,11 +422,15 @@ __gcov_direct_call_profiler (void *cur_func, { if (cur_func == __gcov_direct_call_callee) { - gcov_type global_id - = ((struct gcov_info *) cur_module_gcov_info)->mod_info->ident; - global_id = GEN_FUNC_GLOBAL_ID (global_id, cur_func_id); - __gcov_direct_call_counters[0] = global_id; - __gcov_direct_call_counters[1]++; + if (++__gcov_direct_call_sampling_counter >= __gcov_lipo_sampling_period) + { + __gcov_direct_call_sampling_counter = 0; + gcov_type global_id + = ((struct gcov_info *) cur_module_gcov_info)->mod_info->ident; + global_id = GEN_FUNC_GLOBAL_ID (global_id, cur_func_id); + __gcov_direct_call_counters[0] = global_id; + __gcov_direct_call_counters[1]++; + } __gcov_direct_call_callee = 0; } } diff --git a/gcc-4.9/libgcc/libgcov-util.c b/gcc-4.9/libgcc/libgcov-util.c index 09d5886..4435cff 100644 --- a/gcc-4.9/libgcc/libgcov-util.c +++ b/gcc-4.9/libgcc/libgcov-util.c @@ -66,6 +66,7 @@ static void tag_lines (unsigned, unsigned); static void tag_counters (unsigned, unsigned); static void tag_summary (unsigned, unsigned); static void tag_module_info (unsigned, unsigned); +static void tag_zero_fixup (unsigned, unsigned); /* The gcov_info for the first module. */ static struct gcov_info *curr_gcov_info; @@ -88,6 +89,8 @@ static int k_ctrs_types; /* The longest length of all the filenames. */ static int max_filename_len; +static int *zero_fixup_flags = NULL; + /* Merge functions for counters. Similar to __gcov_dyn_ipa_merge_* functions in dyn-ipa.c, which were derived from these, except the versions in dyn-ipa are used when merging from another array. */ @@ -143,6 +146,7 @@ static const tag_format_t tag_table[] = {GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary}, {GCOV_TAG_PROGRAM_SUMMARY, "PROGRAM_SUMMARY", tag_summary}, {GCOV_TAG_MODULE_INFO, "MODULE INFO", tag_module_info}, + {GCOV_TAG_COMDAT_ZERO_FIXUP, "ZERO FIXUP", tag_zero_fixup}, {0, NULL, NULL} }; @@ -169,14 +173,18 @@ tag_function (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED) k_ctrs[i].num = 0; k_ctrs_types = 0; + if (zero_fixup_flags) + { + set_gcov_fn_fixed_up (zero_fixup_flags[num_fn_info]); + if (get_gcov_fn_fixed_up () && verbose) + fprintf (stderr, "Function id=%d fixed up\n", curr_fn_info->ident); + } + curr_fn_info->key = curr_gcov_info; curr_fn_info->ident = gcov_read_unsigned (); curr_fn_info->lineno_checksum = gcov_read_unsigned (); curr_fn_info->cfg_checksum = gcov_read_unsigned (); num_fn_info++; - - if (verbose) - fnotice (stdout, "tag one function id=%d\n", curr_fn_info->ident); } /* Handler for reading block tag. */ @@ -226,7 +234,13 @@ tag_counters (unsigned tag, unsigned length) gcc_assert (values); for (ix = 0; ix != n_counts; ix++) - values[ix] = gcov_read_counter (); + { + gcov_type val = gcov_read_counter (); + if (!get_gcov_fn_fixed_up ()) + values[ix] = val; + else + values[ix] = 0; + } } /* Handler for reading summary tag. */ @@ -323,7 +337,7 @@ lipo_process_substitute_string_1 (char *input_str, char *t; if (verbose) - printf ("Substitute: %s \n", input_str); + fprintf (stderr, "Substitute: %s \n", input_str); t = (char*) xmalloc (strlen (input_str) + 1 + strlen (new_str) - strlen (cur_str)); *p = 0; @@ -332,7 +346,7 @@ lipo_process_substitute_string_1 (char *input_str, strcat (t, new_str); strcat (t, p + strlen (cur_str)); if (verbose) - printf (" --> %s\n", t); + fprintf (stderr, " --> %s\n", t); return t; } @@ -397,6 +411,16 @@ tag_module_info (unsigned tag ATTRIBUTE_UNUSED, unsigned length) free (mod_info); } +/* Handler for reading the COMDAT zero-profile fixup section. */ + +static void +tag_zero_fixup (unsigned tag ATTRIBUTE_UNUSED, unsigned length) +{ + gcov_unsigned_t num_fns = 0; + zero_fixup_flags = gcov_read_comdat_zero_fixup (length, &num_fns); + gcc_assert (zero_fixup_flags); +} + /* Read the content of a gcda file FILENAME, and return a gcov_info data structure. Program level summary CURRENT_SUMMARY will also be updated. */ @@ -464,62 +488,63 @@ read_gcda_file (const char *filename) tag = gcov_read_unsigned (); if (!tag) - break; + break; length = gcov_read_unsigned (); base = gcov_position (); mask = GCOV_TAG_MASK (tag) >> 1; for (tag_depth = 4; mask; mask >>= 8) - { - if (((mask & 0xff) != 0xff)) - { - warning (0, "%s:tag `%x' is invalid\n", filename, tag); - break; - } - tag_depth--; - } + { + if (((mask & 0xff) != 0xff)) + { + warning (0, "%s:tag `%x' is invalid\n", filename, tag); + break; + } + tag_depth--; + } for (format = tag_table; format->name; format++) - if (format->tag == tag) - goto found; + if (format->tag == tag) + goto found; format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1]; found:; if (tag) - { - if (depth && depth < tag_depth) - { - if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag)) - warning (0, "%s:tag `%x' is incorrectly nested\n", - filename, tag); - } - depth = tag_depth; - tags[depth - 1] = tag; - } + { + if (depth && depth < tag_depth) + { + if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag)) + warning (0, "%s:tag `%x' is incorrectly nested\n", + filename, tag); + } + depth = tag_depth; + tags[depth - 1] = tag; + } if (format->proc) { - unsigned long actual_length; + unsigned long actual_length; - (*format->proc) (tag, length); + (*format->proc) (tag, length); - actual_length = gcov_position () - base; - if (actual_length > length) - warning (0, "%s:record size mismatch %lu bytes overread\n", - filename, actual_length - length); - else if (length > actual_length) - warning (0, "%s:record size mismatch %lu bytes unread\n", - filename, length - actual_length); - } + actual_length = gcov_position () - base; + if (actual_length > length) + warning (0, "%s:record size mismatch %lu bytes overread\n", + filename, actual_length - length); + else if (length > actual_length) + warning (0, "%s:record size mismatch %lu bytes unread\n", + filename, length - actual_length); + } gcov_sync (base, length); if ((error = gcov_is_error ())) - { - warning (0, error < 0 ? "%s:counter overflow at %lu\n" : - "%s:read error at %lu\n", filename, - (long unsigned) gcov_position ()); - break; - } + { + warning (0, error < 0 ? "%s:counter overflow at %lu\n" : + "%s:read error at %lu\n", filename, + (long unsigned) gcov_position ()); + break; + } } read_gcda_finalize (obj_info); + free (zero_fixup_flags); gcov_close (); return obj_info; @@ -539,6 +564,18 @@ set_use_modu_list (void) flag_use_modu_list = 1; } +/* Source profile directory name. */ + +static const char *source_profile_dir; + +/* Return Source profile directory name. */ + +const char * +get_source_profile_dir (void) +{ + return source_profile_dir; +} + /* Handler to open and read a gcda file FILENAME. */ static int @@ -569,6 +606,20 @@ read_file_handler (const char *filename) unsigned mod_id = obj_info->mod_info->ident; int create = (flag_use_modu_list ? 0 : 1); + if (!source_profile_dir) + { + static char resolved_path[PATH_MAX + 1]; + char *abs_path = realpath (filename, resolved_path); + + if (abs_path) + { + char *p = strstr (abs_path, obj_info->mod_info->da_filename); + gcc_assert (p); + *p = 0; + source_profile_dir = abs_path; + } + } + if (!is_module_available (obj_info->mod_info->source_filename, &mod_id, create)) { @@ -605,6 +656,7 @@ ftw_read_file (const char *filename, #else /* _WIN32 */ /* Funtion to find all the gcda files recursively in DIR. */ + static void myftw (char *dir, char* pattern, int (*handler)(const char *)) { @@ -648,18 +700,6 @@ myftw (char *dir, char* pattern, int (*handler)(const char *)) } #endif -/* Source profile directory name. */ - -static const char *source_profile_dir; - -/* Return Source profile directory name. */ - -const char * -get_source_profile_dir (void) -{ - return source_profile_dir; -} - /* Initializer for reading a profile dir. */ static inline void @@ -694,7 +734,6 @@ gcov_read_profile_dir (const char* dir_name, int recompute_summary ATTRIBUTE_UNU fnotice (stderr, "%s is not a directory\n", dir_name); return NULL; } - source_profile_dir = getcwd (NULL, 0); #if !defined(_WIN32) ftw (".", ftw_read_file, 50); @@ -831,7 +870,8 @@ gcov_merge (struct gcov_info *info1, struct gcov_info *info2, int w) Return NULL if there is no match. */ static struct gcov_info * -find_match_gcov_info (struct gcov_info **array, int size, struct gcov_info *info) +find_match_gcov_info (struct gcov_info **array, int size, + struct gcov_info *info) { struct gcov_info *gi_ptr; struct gcov_info *ret = NULL; @@ -935,6 +975,7 @@ gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile tgt_tail->next = gi_ptr; tgt_tail = gi_ptr; } + tgt_tail->next = 0; return 0; } @@ -1085,7 +1126,7 @@ gcov_profile_scale (struct gcov_info *profile, float scale_factor, int n, int d) unsigned f_ix; if (verbose) - fnotice (stdout, "scale_factor is %f or %d/%d\n", scale_factor, n, d); + fnotice (stderr, "scale_factor is %f or %d/%d\n", scale_factor, n, d); /* Scaling the counters. */ for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next) @@ -1153,8 +1194,533 @@ gcov_profile_normalize (struct gcov_info *profile, gcov_type max_val) scale_factor = (float)max_val / curr_max_val; #if !defined (_WIN32) if (verbose) - fnotice (stdout, "max_val is %lld\n", (long long) curr_max_val); + fnotice (stdout, "max_val is %lld\n", curr_max_val); #endif return gcov_profile_scale (profile, scale_factor, 0, 0); } + +/* The following variables are defined in gcc/gcov-tool.c. */ +extern int overlap_func_level; +extern int overlap_obj_level; +extern int overlap_hot_only; +extern int overlap_use_fullname; +extern double overlap_hot_threshold; + +/* Compute the overlap score of two values. The score is defined as: + min (V1/SUM_1, V2/SUM_2) */ + +static double +calculate_2_entries (const unsigned long v1, const unsigned long v2, + const double sum_1, const double sum_2) +{ + double val1 = (sum_1 == 0.0 ? 0.0 : v1/sum_1); + double val2 = (sum_2 == 0.0 ? 0.0 : v2/sum_2); + + if (val2 < val1) + val1 = val2; + + return val1; +} + +/* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2. + SUM_1 is the sum_all for profile1 where GCOV_INFO1 belongs. + SUM_2 is the sum_all for profile2 where GCOV_INFO2 belongs. + This function also updates cumulative score CUM_1_RESULT and + CUM_2_RESULT. */ + +static double +compute_one_gcov (const struct gcov_info *gcov_info1, + const struct gcov_info *gcov_info2, + const double sum_1, const double sum_2, + double *cum_1_result, double *cum_2_result) +{ + unsigned f_ix; + double ret = 0; + double cum_1 = 0, cum_2 = 0; + const struct gcov_info *gcov_info = 0; + double *cum_p; + double sum; + + gcc_assert (gcov_info1 || gcov_info2); + if (!gcov_info1) + { + gcov_info = gcov_info2; + cum_p = cum_2_result; + sum = sum_2; + *cum_1_result = 0; + } else + if (!gcov_info2) + { + gcov_info = gcov_info1; + cum_p = cum_1_result; + sum = sum_1; + *cum_2_result = 0; + } + + if (gcov_info) + { + for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++) + { + unsigned t_ix; + const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix]; + if (!gfi_ptr || gfi_ptr->key != gcov_info) + continue; + const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs; + for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) + { + unsigned c_num; + + if (!gcov_info->merge[t_ix]) + continue; + + for (c_num = 0; c_num < ci_ptr->num; c_num++) + { + cum_1 += ci_ptr->values[c_num] / sum; + } + ci_ptr++; + } + } + *cum_p = cum_1; + return 0.0; + } + + for (f_ix = 0; f_ix < gcov_info1->n_functions; f_ix++) + { + unsigned t_ix; + double func_cum_1 = 0.0; + double func_cum_2 = 0.0; + double func_val = 0.0; + int nonzero = 0; + int hot = 0; + const struct gcov_fn_info *gfi_ptr1 = gcov_info1->functions[f_ix]; + const struct gcov_fn_info *gfi_ptr2 = gcov_info2->functions[f_ix]; + + if (!gfi_ptr1 || gfi_ptr1->key != gcov_info1) + continue; + if (!gfi_ptr2 || gfi_ptr2->key != gcov_info2) + continue; + + const struct gcov_ctr_info *ci_ptr1 = gfi_ptr1->ctrs; + const struct gcov_ctr_info *ci_ptr2 = gfi_ptr2->ctrs; + for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) + { + unsigned c_num; + + if (!gcov_info1->merge[t_ix]) + continue; + + for (c_num = 0; c_num < ci_ptr1->num; c_num++) + { + if (ci_ptr1->values[c_num] | ci_ptr2->values[c_num]) + { + func_val += calculate_2_entries (ci_ptr1->values[c_num], + ci_ptr2->values[c_num], + sum_1, sum_2); + + func_cum_1 += ci_ptr1->values[c_num] / sum_1; + func_cum_2 += ci_ptr2->values[c_num] / sum_2; + nonzero = 1; + if (ci_ptr1->values[c_num] / sum_1 >= overlap_hot_threshold || + ci_ptr2->values[c_num] / sum_2 >= overlap_hot_threshold) + hot = 1; + } + } + ci_ptr1++; + ci_ptr2++; + } + ret += func_val; + cum_1 += func_cum_1; + cum_2 += func_cum_2; + if (overlap_func_level && nonzero && (!overlap_hot_only || hot)) + { + printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n", + gfi_ptr1->ident, func_val*100, func_cum_1*100, func_cum_2*100); + } + } + *cum_1_result = cum_1; + *cum_2_result = cum_2; + return ret; +} + +/* Test if all counter values in this GCOV_INFO are cold. + "Cold" is defined as the counter value being less than + or equal to THRESHOLD. */ + +static bool +gcov_info_count_all_cold (const struct gcov_info *gcov_info, + gcov_type threshold) +{ + unsigned f_ix; + + for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++) + { + unsigned t_ix; + const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix]; + + if (!gfi_ptr || gfi_ptr->key != gcov_info) + continue; + const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs; + for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) + { + unsigned c_num; + + if (!gcov_info->merge[t_ix]) + continue; + + for (c_num = 0; c_num < ci_ptr->num; c_num++) + { + if (ci_ptr->values[c_num] > threshold) + return false; + } + ci_ptr++; + } + } + + return true; +} + +/* Test if all counter values in this GCOV_INFO are 0. */ + +static bool +gcov_info_count_all_zero (const struct gcov_info *gcov_info) +{ + return gcov_info_count_all_cold (gcov_info, 0); +} + +/* A pair of matched GCOV_INFO. + The flag is a bitvector: + b0: obj1's all counts are 0; + b1: obj1's all counts are cold (but no 0); + b2: obj1 is hot; + b3: no obj1 to match obj2; + b4: obj2's all counts are 0; + b5: obj2's all counts are cold (but no 0); + b6: obj2 is hot; + b7: no obj2 to match obj1; + */ +struct overlap_t { + const struct gcov_info *obj1; + const struct gcov_info *obj2; + char flag; +}; + +#define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10)) +#define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20)) +#define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40)) + +/* Cumlative overlap dscore for profile1 and profile2. */ +static double overlap_sum_1, overlap_sum_2; + +/* sum_all for profile1 and profile2. */ +static gcov_type p1_sum_all, p2_sum_all; + +/* run_max for profile1 and profile2. */ +static gcov_type p1_run_max, p2_run_max; + +/* The number of gcda files in the profiles. */ +static unsigned gcda_files[2]; + +/* The number of unique gcda files in the profiles + (not existing in the other profile). */ +static unsigned unique_gcda_files[2]; + +/* The number of gcda files that all counter values are 0. */ +static unsigned zero_gcda_files[2]; + +/* The number of gcda files that all counter values are cold (but not 0). */ +static unsigned cold_gcda_files[2]; + +/* The number of gcda files that includes hot counter values. */ +static unsigned hot_gcda_files[2]; + +/* The number of gcda files with hot count value in either profiles. */ +static unsigned both_hot_cnt; + +/* The number of gcda files with all counts cold (but not 0) in + both profiles. */ +static unsigned both_cold_cnt; + +/* The number of gcda files with all counts 0 in both profiles. */ +static unsigned both_zero_cnt; + +/* Extract the basename of the filename NAME. */ + +static char * +extract_file_basename (const char *name) +{ + char *str; + int len = 0; + char *path = xstrdup (name); + char sep_str[2]; + + sep_str[0] = DIR_SEPARATOR; + sep_str[1] = 0; + str = strstr(path, sep_str); + do{ + len = strlen(str) + 1; + path = &path[strlen(path) - len + 2]; + str = strstr(path, sep_str); + } while(str); + + return path; +} + +/* Utility function to get the filename. */ + +static const char * +get_file_basename (const char *name) +{ + if (overlap_use_fullname) + return name; + return extract_file_basename (name); +} + +/* A utility function to set the flag for the gcda files. */ + +static void +set_flag (struct overlap_t *e) +{ + char flag = 0; + + if (!e->obj1) + { + unique_gcda_files[1]++; + flag = 0x8; + } + else + { + gcda_files[0]++; + if (gcov_info_count_all_zero (e->obj1)) + { + zero_gcda_files[0]++; + flag = 0x1; + } + else + if (gcov_info_count_all_cold (e->obj1, overlap_sum_1 + * overlap_hot_threshold)) + { + cold_gcda_files[0]++; + flag = 0x2; + } + else + { + hot_gcda_files[0]++; + flag = 0x4; + } + } + + if (!e->obj2) + { + unique_gcda_files[0]++; + flag |= (0x8 << 4); + } + else + { + gcda_files[1]++; + if (gcov_info_count_all_zero (e->obj2)) + { + zero_gcda_files[1]++; + flag |= (0x1 << 4); + } + else + if (gcov_info_count_all_cold (e->obj2, overlap_sum_2 + * overlap_hot_threshold)) + { + cold_gcda_files[1]++; + flag |= (0x2 << 4); + } + else + { + hot_gcda_files[1]++; + flag |= (0x4 << 4); + } + } + + gcc_assert (flag); + e->flag = flag; +} + +/* Test if INFO1 and INFO2 are from the matched source file. + Return 1 if they match; return 0 otherwise. */ + +static int +matched_gcov_info (const struct gcov_info *info1, const struct gcov_info *info2) +{ + /* For FDO, we have to match the name. This can be expensive. + Maybe we should use hash here. */ + if (strcmp (info1->filename, info2->filename)) + return 0; + + if (info1->n_functions != info2->n_functions) + { + fnotice (stderr, "mismatched profiles in %s (%d functions" + " vs %d functions)\n", + info1->filename, + info1->n_functions, + info2->n_functions); + return 0; + } + return 1; +} + +/* Defined in libgcov-driver.c. */ +extern gcov_unsigned_t gcov_exit_compute_summary (struct gcov_summary *); +extern void set_gcov_list (struct gcov_info*); + +/* Compute the overlap score of two profiles with the head of GCOV_LIST1 and + GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no + match and 1.0 meaning a perfect match. */ + +static double +calculate_overlap (struct gcov_info *gcov_list1, + struct gcov_info *gcov_list2) +{ + struct gcov_summary this_prg; + unsigned list1_cnt = 0, list2_cnt= 0, all_cnt; + unsigned int i, j; + size_t max_length; + const struct gcov_info *gi_ptr; + struct overlap_t *all_infos; + + set_gcov_list (gcov_list1); + gcov_exit_compute_summary (&this_prg); + overlap_sum_1 = (double) (this_prg.ctrs[0].sum_all); + p1_sum_all = this_prg.ctrs[0].sum_all; + p1_run_max = this_prg.ctrs[0].run_max; + set_gcov_list (gcov_list2); + gcov_exit_compute_summary (&this_prg); + overlap_sum_2 = (double) (this_prg.ctrs[0].sum_all); + p2_sum_all = this_prg.ctrs[0].sum_all; + p2_run_max = this_prg.ctrs[0].run_max; + + for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next) + list1_cnt++; + for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next) + list2_cnt++; + all_cnt = list1_cnt + list2_cnt; + all_infos = (struct overlap_t *) xmalloc (sizeof (struct overlap_t) + * all_cnt * 2); + gcc_assert (all_infos); + + i = 0; + for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next, i++) + { + all_infos[i].obj1 = gi_ptr; + all_infos[i].obj2 = 0; + } + + for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next, i++) + { + all_infos[i].obj1 = 0; + all_infos[i].obj2 = gi_ptr; + } + + for (i = list1_cnt; i < all_cnt; i++) + { + if (all_infos[i].obj2 == 0) + continue; + for (j = 0; j < list1_cnt; j++) + { + if (all_infos[j].obj2 != 0) + continue; + if (matched_gcov_info (all_infos[i].obj2, all_infos[j].obj1)) + { + all_infos[j].obj2 = all_infos[i].obj2; + all_infos[i].obj2 = 0; + break; + } + } + } + + for (i = 0; i < all_cnt; i++) + if (all_infos[i].obj1 || all_infos[i].obj2) + { + set_flag (all_infos + i); + if (FLAG_ONE_HOT (all_infos[i].flag)) + both_hot_cnt++; + if (FLAG_BOTH_COLD(all_infos[i].flag)) + both_cold_cnt++; + if (FLAG_BOTH_ZERO(all_infos[i].flag)) + both_zero_cnt++; + } + + double prg_val = 0; + double sum_val = 0; + double sum_cum_1 = 0; + double sum_cum_2 = 0; + + for (i = 0; i < all_cnt; i++) + { + double val; + double cum_1, cum_2; + const char *filename; + + if (all_infos[i].obj1 == 0 && all_infos[i].obj2 == 0) + continue; + if (FLAG_BOTH_ZERO (all_infos[i].flag)) + continue; + + if (all_infos[i].obj1) + filename = get_file_basename (all_infos[i].obj1->filename); + else + filename = get_file_basename (all_infos[i].obj2->filename); + + if (overlap_func_level) + printf("\n processing %36s:\n", filename); + + val = compute_one_gcov (all_infos[i].obj1, all_infos[i].obj2, + overlap_sum_1, overlap_sum_2, &cum_1, &cum_2); + + if (overlap_obj_level && (!overlap_hot_only || FLAG_ONE_HOT (all_infos[i].flag))) + { + printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n", + filename, val*100, cum_1*100, cum_2*100); + sum_val += val; + sum_cum_1 += cum_1; + sum_cum_2 += cum_2; + } + + prg_val += val; + + } + + if (overlap_obj_level) + printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n", + "", sum_val*100, sum_cum_1*100, sum_cum_2*100); + + printf (" Statistics:\n" + " profile1_# profile2_# overlap_#\n"); + printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files[0], gcda_files[1], + gcda_files[0]-unique_gcda_files[0]); + printf (" unique files: %12u\t%12u\n", unique_gcda_files[0], + unique_gcda_files[1]); + printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files[0], + hot_gcda_files[1], both_hot_cnt); + printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files[0], + cold_gcda_files[1], both_cold_cnt); + printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files[0], + zero_gcda_files[1], both_zero_cnt); + printf (" sum_all: %12lld \t%12lld\n", p1_sum_all, p2_sum_all); + printf (" run_max: %12lld \t%12lld\n", p1_run_max, p2_run_max); + + return prg_val; +} + +/* Computer the overlap score of two lists of gcov_info objects PROFILE1 and PROFILE2. + Return 0 on success: without mismatch. Reutrn 1 on error. */ + +int +gcov_profile_overlap (struct gcov_info *profile1, struct gcov_info *profile2) +{ + double result; + + result = calculate_overlap (profile1, profile2); + + if (result > 0) + { + printf("\nProgram level overlap result is %3.2f%%\n\n", result*100); + return 0; + } + return 1; +} diff --git a/gcc-4.9/libgcc/libgcov.h b/gcc-4.9/libgcc/libgcov.h index fdfb650..c1ebe6e 100644 --- a/gcc-4.9/libgcc/libgcov.h +++ b/gcc-4.9/libgcc/libgcov.h @@ -25,6 +25,7 @@ #ifndef GCC_LIBGCOV_H #define GCC_LIBGCOV_H +#ifndef __KERNEL__ /* work around the poisoned malloc/calloc in system.h. */ #ifndef xmalloc #define xmalloc malloc @@ -35,16 +36,24 @@ #ifndef xrealloc #define xrealloc realloc #endif +#ifndef xfree +#define xfree free +#endif +#else /* __KERNEL__ */ +#include "libgcov-kernel.h" +#endif /* __KERNEL__ */ #ifndef IN_GCOV_TOOL /* About the target. */ /* This path will be used by libgcov runtime. */ +#ifndef __KERNEL__ #include "tconfig.h" #include "tsystem.h" #include "coretypes.h" #include "tm.h" #include "libgcc_tm.h" +#endif /* __KERNEL__ */ #undef FUNC_ID_WIDTH #undef FUNC_ID_MASK @@ -128,7 +137,6 @@ typedef unsigned gcov_position_t; #define GCOV_LOCKED 0 #endif -/* xur??? */ #define FUNC_ID_WIDTH 32 #define FUNC_ID_MASK ((1ll << FUNC_ID_WIDTH) - 1) @@ -189,6 +197,7 @@ extern unsigned gcov_get_merge_weight (); #define gcov_read_unsigned __gcov_read_unsigned #define gcov_read_counter __gcov_read_counter #define gcov_read_summary __gcov_read_summary +#define gcov_read_buildinfo __gcov_read_buildinfo #define gcov_read_module_info __gcov_read_module_info #define gcov_sort_n_vals __gcov_sort_n_vals @@ -246,12 +255,16 @@ struct gcov_info unsigned n_functions; /* number of functions */ -#ifndef IN_GCOV_TOOL +#if !defined (IN_GCOV_TOOL) && !defined (__KERNEL__) const struct gcov_fn_info *const *functions; /* pointer to pointers to function information */ -#else +#elif defined (IN_GCOV_TOOL) const struct gcov_fn_info **functions; +#else + struct gcov_fn_info **functions; #endif /* !IN_GCOV_TOOL */ + char **build_info; /* strings to include in BUILD_INFO + section of gcda file. */ }; /* Information about a single imported module. */ @@ -339,6 +352,8 @@ GCOV_LINKAGE void gcov_write_summary (gcov_unsigned_t /*tag*/, ATTRIBUTE_HIDDEN; GCOV_LINKAGE void gcov_seek (gcov_position_t /*position*/) ATTRIBUTE_HIDDEN; GCOV_LINKAGE void gcov_truncate (void) ATTRIBUTE_HIDDEN; +void gcov_write_module_info (const struct gcov_info *, unsigned) + ATTRIBUTE_HIDDEN; GCOV_LINKAGE void gcov_write_module_infos (struct gcov_info *mod_info) ATTRIBUTE_HIDDEN; GCOV_LINKAGE const struct dyn_imp_mod ** @@ -346,6 +361,9 @@ gcov_get_sorted_import_module_array (struct gcov_info *mod_info, unsigned *len) ATTRIBUTE_HIDDEN; GCOV_LINKAGE inline void gcov_rewrite (void); +extern void set_gcov_fn_fixed_up (int fixed_up); +extern int get_gcov_fn_fixed_up (void); + /* "Counts" stored in gcda files can be a real counter value, or an target address. When differentiate these two types because when manipulating counts, we should only change real counter values, @@ -358,7 +376,13 @@ gcov_get_counter (void) /* This version is for reading count values in libgcov runtime: we read from gcda files. */ - return gcov_read_counter (); + if (get_gcov_fn_fixed_up ()) + { + gcov_read_counter (); + return 0; + } + else + return gcov_read_counter (); #else /* This version is for gcov-tool. We read the value from memory and multiply it by the merge weight. */ @@ -377,7 +401,13 @@ gcov_get_counter_target (void) /* This version is for reading count target values in libgcov runtime: we read from gcda files. */ - return gcov_read_counter (); + if (get_gcov_fn_fixed_up ()) + { + gcov_read_counter (); + return 0; + } + else + return gcov_read_counter (); #else /* This version is for gcov-tool. We read the value from memory and we do NOT multiply it by the merge weight. */ |