This patch allows a function to request clearing of all instruction and execution hazards upon normal return via __attribute__ ((use_hazard_barrier_return)).
2017-04-25 Prachi Godbole <prachi.godb...@imgtec.com> gcc/ * config/mips/mips.h (machine_function): New variable use_hazard_barrier_return_p. * config/mips/mips.md (UNSPEC_JRHB): New unspec. (mips_hb_return_internal): New insn pattern. * config/mips/mips.c (mips_attribute_table): Add attribute use_hazard_barrier_return. (mips_use_hazard_barrier_return_p): New static function. (mips_function_attr_inlinable_p): Likewise. (mips_compute_frame_info): Set use_hazard_barrier_return_p. Emit error for unsupported architecture choice. (mips_function_ok_for_sibcall, mips_can_use_return_insn): Return false for use_hazard_barrier_return. (mips_expand_epilogue): Emit hazard barrier return. * doc/extend.texi: Document use_hazard_barrier_return. gcc/testsuite/ * gcc.target/mips/hazard-barrier-return-attribute.c: New test. --- Rehash of original patch posted by Prachi with minimal changes. Tested against mips-mti-elf with mips32r2/-EB and mips32r2/-EB/-micromips. gcc/config/mips/mips.c | 58 +++++++++++++++++-- gcc/config/mips/mips.h | 3 + gcc/config/mips/mips.md | 15 +++++ gcc/doc/extend.texi | 6 ++ .../mips/hazard-barrier-return-attribute.c | 20 +++++++ 5 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.target/mips/hazard-barrier-return-attribute.c diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 89d1be6cea6..6ce12fce52e 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -630,6 +630,7 @@ static const struct attribute_spec mips_attribute_table[] = { mips_handle_use_shadow_register_set_attr, NULL }, { "keep_interrupts_masked", 0, 0, false, true, true, false, NULL, NULL }, { "use_debug_exception_return", 0, 0, false, true, true, false, NULL, NULL }, + { "use_hazard_barrier_return", 0, 0, true, false, false, false, NULL, NULL }, { NULL, 0, 0, false, false, false, false, NULL, NULL } }; @@ -1309,6 +1310,16 @@ mips_use_debug_exception_return_p (tree type) TYPE_ATTRIBUTES (type)) != NULL; } +/* Check if the attribute to use hazard barrier return is set for + the function declaration DECL. */ + +static bool +mips_use_hazard_barrier_return_p (const_tree decl) +{ + return lookup_attribute ("use_hazard_barrier_return", + DECL_ATTRIBUTES (decl)) != NULL; +} + /* Return the set of compression modes that are explicitly required by the attributes in ATTRIBUTES. */ @@ -1494,6 +1505,19 @@ mips_can_inline_p (tree caller, tree callee) return default_target_can_inline_p (caller, callee); } +/* Implement TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P. + + A function requesting clearing of all instruction and execution hazards + before returning cannot be inlined - thereby not clearing any hazards. + All our other function attributes are related to how out-of-line copies + should be compiled or called. They don't in themselves prevent inlining. */ + +static bool +mips_function_attr_inlinable_p (const_tree decl) +{ + return !mips_use_hazard_barrier_return_p (decl); +} + /* Handle an "interrupt" attribute with an optional argument. */ static tree @@ -7921,6 +7945,11 @@ mips_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED) && !targetm.binds_local_p (decl)) return false; + /* Can't generate sibling calls if returning from current function using + hazard barrier return. */ + if (mips_use_hazard_barrier_return_p (current_function_decl)) + return false; + /* Otherwise OK. */ return true; } @@ -11008,6 +11037,17 @@ mips_compute_frame_info (void) } } + /* Determine whether to use hazard barrier return or not. */ + if (mips_use_hazard_barrier_return_p (current_function_decl)) + { + if (mips_isa_rev < 2) + error ("hazard barrier returns require a MIPS32r2 processor or greater"); + else if (TARGET_MIPS16) + error ("hazard barrier returns are not supported for MIPS16 functions"); + else + cfun->machine->use_hazard_barrier_return_p = true; + } + frame = &cfun->machine->frame; memset (frame, 0, sizeof (*frame)); size = get_frame_size (); @@ -12671,7 +12711,8 @@ mips_expand_epilogue (bool sibcall_p) && !crtl->calls_eh_return && !sibcall_p && step2 > 0 - && mips_unsigned_immediate_p (step2, 5, 2)) + && mips_unsigned_immediate_p (step2, 5, 2) + && !cfun->machine->use_hazard_barrier_return_p) use_jraddiusp_p = true; else /* Deallocate the final bit of the frame. */ @@ -12712,6 +12753,11 @@ mips_expand_epilogue (bool sibcall_p) else emit_jump_insn (gen_mips_eret ()); } + else if (cfun->machine->use_hazard_barrier_return_p) + { + rtx reg = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM); + emit_jump_insn (gen_mips_hb_return_internal (reg)); + } else { rtx pat; @@ -12770,6 +12816,11 @@ mips_can_use_return_insn (void) if (cfun->machine->interrupt_handler_p) return false; + /* Even if the function has a null epilogue, generating hazard barrier return + in epilogue handler is a lot cleaner and more manageable. */ + if (cfun->machine->use_hazard_barrier_return_p) + return false; + if (!reload_completed) return false; @@ -22777,10 +22828,9 @@ mips_asm_file_end (void) #undef TARGET_ATTRIBUTE_TABLE #define TARGET_ATTRIBUTE_TABLE mips_attribute_table -/* All our function attributes are related to how out-of-line copies should - be compiled or called. They don't in themselves prevent inlining. */ + #undef TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P -#define TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P hook_bool_const_tree_true +#define TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P mips_function_attr_inlinable_p #undef TARGET_EXTRA_LIVE_ON_ENTRY #define TARGET_EXTRA_LIVE_ON_ENTRY mips_extra_live_on_entry diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index 47aac9d3d61..bae9ffe9b3c 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -3376,6 +3376,9 @@ struct GTY(()) machine_function { /* True if GCC stored callee saved registers in the frame header. */ bool use_frame_header_for_callee_saved_regs; + + /* True if the function should generate hazard barrier return. */ + bool use_hazard_barrier_return_p; }; #endif diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index 455b9b802f6..dee71dc1fb0 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -159,6 +159,7 @@ ;; The `.insn' pseudo-op. UNSPEC_INSN_PSEUDO + UNSPEC_JRHB ]) (define_constants @@ -6660,6 +6661,20 @@ [(set_attr "type" "jump") (set_attr "mode" "none")]) +;; Insn to clear execution and instruction hazards while returning. +;; However, it doesn't clear hazards created by the insn in its delay slot. +;; Thus, explicitly place a nop in its delay slot. + +(define_insn "mips_hb_return_internal" + [(return) + (unspec_volatile [(match_operand 0 "pmode_register_operand" "")] + UNSPEC_JRHB)] + "" + { + return "%(jr.hb\t$31%/%)"; + } + [(set_attr "insn_count" "2")]) + ;; Normal return. (define_insn "<optab>_internal" diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 49df8e6dc38..8d2a0a23af6 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -5540,6 +5540,12 @@ On MIPS targets, you can use the @code{nocompression} function attribute to locally turn off MIPS16 and microMIPS code generation. This attribute overrides the @option{-mips16} and @option{-mmicromips} options on the command line (@pxref{MIPS Options}). + +@item use_hazard_barrier_return +@cindex @code{use_hazard_barrier_return} function attribute, MIPS +This function attribute instructs the compiler to generate a hazard barrier +return that clears all execution and instruction hazards while returning, +instead of generating a normal return instruction. @end table @node MSP430 Function Attributes diff --git a/gcc/testsuite/gcc.target/mips/hazard-barrier-return-attribute.c b/gcc/testsuite/gcc.target/mips/hazard-barrier-return-attribute.c new file mode 100644 index 00000000000..3575af44dcd --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/hazard-barrier-return-attribute.c @@ -0,0 +1,20 @@ +/* Test attribute for clearing hazards while returning. */ +/* { dg-do compile } */ +/* { dg-options "isa_rev>=2 -mno-mips16" } */ + +extern int bar (); + +static int __attribute__ ((use_hazard_barrier_return)) +foo0 () +{ + return bar (); +} + +int +foo1 () +{ + return foo0 (); +} + +/* { dg-final { scan-assembler "foo0:" } } */ +/* { dg-final { scan-assembler-times "\tjr.hb\t\\\$31\n\tnop\\n" 1 } } */ -- 2.17.1