diff --git a/gcc/ChangeLog b/gcc/ChangeLog index fd386b92050..e620e306403 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2016-01-21 Bernd Enlinger + Nick Clifton + + PR target/69129 + PR target/69012 + * config/mips/mips.c (mips_compute_frame_info): Initialise + args_size and hard_frame_pointer_offset fields of the frame + structure before calling mips_global_pointer. + 2016-01-21 David Edelsohn * configure.ac (gcc_cv_as_dwloc): Test support for debug frame section diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index ea18ad643e4..dd54d6ab37a 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -10347,8 +10347,6 @@ mips_compute_frame_info (void) memset (frame, 0, sizeof (*frame)); size = get_frame_size (); - cfun->machine->global_pointer = mips_global_pointer (); - /* The first two blocks contain the outgoing argument area and the $gp save slot. This area isn't needed in leaf functions. We can also skip it if we know that none of the called functions will use this space. @@ -10375,6 +10373,26 @@ mips_compute_frame_info (void) frame->args_size = crtl->outgoing_args_size; frame->cprestore_size = MIPS_GP_SAVE_AREA_SIZE; } + + /* MIPS16 code offsets the frame pointer by the size of the outgoing + arguments. This tends to increase the chances of using unextended + instructions for local variables and incoming arguments. */ + if (TARGET_MIPS16) + frame->hard_frame_pointer_offset = frame->args_size; + + /* PR 69129 / 69012: Beware of a possible race condition. mips_global_pointer + might call mips_cfun_has_inflexible_gp_ref_p which in turn can call + mips_find_gp_ref which will iterate over the current insn sequence. + If any of these insns use the cprestore_save_slot_operand or + cprestore_load_slot_operand predicates in order to be recognised then + they will call mips_cprestore_address_p which calls + mips_get_cprestore_base_and_offset which expects the frame information + to be filled in... In fact mips_get_cprestore_base_and_offset only + needs the args_size and hard_frame_pointer_offset fields to be filled + in, which is why the global_pointer field is initialised here and not + earlier. */ + cfun->machine->global_pointer = mips_global_pointer (); + offset = frame->args_size + frame->cprestore_size; /* Move above the local variables. */ @@ -10520,12 +10538,6 @@ mips_compute_frame_info (void) frame->acc_save_offset = frame->acc_sp_offset - offset; if (frame->num_cop0_regs > 0) frame->cop0_save_offset = frame->cop0_sp_offset - offset; - - /* MIPS16 code offsets the frame pointer by the size of the outgoing - arguments. This tends to increase the chances of using unextended - instructions for local variables and incoming arguments. */ - if (TARGET_MIPS16) - frame->hard_frame_pointer_offset = frame->args_size; } /* Return the style of GP load sequence that is being used for the diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 25b72d7e0e6..08aafd10722 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2016-01-21 Nick Clifton + + PR target/69129 + * gcc.target/mips/pr69129.c: New. + 2016-01-21 Paolo Carlini PR c++/58046 diff --git a/gcc/testsuite/gcc.target/mips/pr69129.c b/gcc/testsuite/gcc.target/mips/pr69129.c new file mode 100644 index 00000000000..186582f50d8 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/pr69129.c @@ -0,0 +1,29 @@ +_Noreturn void fn1 (int) __attribute__((__visibility__("hidden"))); + +void +fn2 (void *p1) +{ + int a[7]; + float *b; + int c, n; + + if (c != p1) /* { dg-warning "comparison between pointer and integer" } */ + fn1 (1); + + n = 0; + for (; c; n++) + { + int d; + if (a[n] != d) + fn1(n); + } + + b = p1; + + while (1) + { + *b = 3.40282347e38f; + if (a[0]) + return; + } +}