diff --git a/SOURCES/gcc48-rh1552021.patch b/SOURCES/gcc48-rh1552021.patch new file mode 100644 index 0000000..c931115 --- /dev/null +++ b/SOURCES/gcc48-rh1552021.patch @@ -0,0 +1,1966 @@ +diff -Nrup gcc/config/s390/s390.c gcc/config/s390/s390.c +--- gcc/config/s390/s390.c 2018-03-27 09:33:20.158140823 -0600 ++++ gcc/config/s390/s390.c 2018-03-27 09:33:58.826861609 -0600 +@@ -958,6 +958,35 @@ s390_expand_builtin (tree exp, rtx targe + } + + ++/* Masks per jump target register indicating which thunk need to be ++ generated. */ ++static GTY(()) int indirect_branch_prez10thunk_mask = 0; ++static GTY(()) int indirect_branch_z10thunk_mask = 0; ++ ++#define INDIRECT_BRANCH_NUM_OPTIONS 4 ++ ++enum s390_indirect_branch_option ++ { ++ s390_opt_indirect_branch_jump = 0, ++ s390_opt_indirect_branch_call, ++ s390_opt_function_return_reg, ++ s390_opt_function_return_mem ++ }; ++ ++static GTY(()) int indirect_branch_table_label_no[INDIRECT_BRANCH_NUM_OPTIONS] = { 0 }; ++const char *indirect_branch_table_label[INDIRECT_BRANCH_NUM_OPTIONS] = \ ++ { "LJUMP", "LCALL", "LRETREG", "LRETMEM" }; ++const char *indirect_branch_table_name[INDIRECT_BRANCH_NUM_OPTIONS] = \ ++ { ".s390_indirect_jump", ".s390_indirect_call", ++ ".s390_return_reg", ".s390_return_mem" }; ++ ++bool ++s390_return_addr_from_memory () ++{ ++ return (cfun_frame_layout.first_save_gpr <= RETURN_REGNUM ++ && cfun_frame_layout.last_save_gpr >= RETURN_REGNUM); ++} ++ + static const int s390_hotpatch_hw_max = 1000000; + static int s390_hotpatch_hw_before_label = 0; + static int s390_hotpatch_hw_after_label = 0; +@@ -2669,6 +2698,34 @@ s390_option_override (void) + if (TARGET_64BIT && !TARGET_ZARCH) + error ("64-bit ABI not supported in ESA/390 mode"); + ++ if (s390_indirect_branch != indirect_branch_keep) ++ { ++ if (!global_options_set.x_s390_indirect_branch_call) ++ s390_indirect_branch_call = s390_indirect_branch; ++ ++ if (!global_options_set.x_s390_indirect_branch_jump) ++ s390_indirect_branch_jump = s390_indirect_branch; ++ } ++ ++ if (s390_function_return != indirect_branch_keep) ++ { ++ if (!global_options_set.x_s390_function_return_reg) ++ s390_function_return_reg = s390_function_return; ++ ++ if (!global_options_set.x_s390_function_return_mem) ++ s390_function_return_mem = s390_function_return; ++ } ++ ++ if (!TARGET_CPU_ZARCH) ++ { ++ if (s390_indirect_branch_call != indirect_branch_keep ++ || s390_indirect_branch_jump != indirect_branch_keep) ++ error ("-mindirect-branch* options require -march=z900 or higher"); ++ if (s390_function_return_reg != indirect_branch_keep ++ || s390_function_return_mem != indirect_branch_keep) ++ error ("-mfunction-return* options require -march=z900 or higher"); ++ } ++ + /* Use hardware DFP if available and not explicitly disabled by + user. E.g. with -m31 -march=z10 -mzarch */ + if (!(target_flags_explicit & MASK_HARD_DFP) && TARGET_DFP) +@@ -10873,7 +10930,6 @@ s390_emit_epilogue (bool sibcall) + rtx frame_pointer, return_reg, cfa_restores = NULL_RTX; + int area_bottom, area_top, offset = 0; + int next_offset; +- rtvec p; + int i; + + if (TARGET_TPF_PROFILING) +@@ -11023,8 +11079,14 @@ s390_emit_epilogue (bool sibcall) + && cfun_frame_layout.last_restore_gpr > RETURN_REGNUM)) + { + int return_regnum = find_unused_clobbered_reg(); +- if (!return_regnum) +- return_regnum = 4; ++ if (!return_regnum ++ || (TARGET_INDIRECT_BRANCH_NOBP_RET_OPTION ++ && !TARGET_CPU_Z10 ++ && return_regnum == INDIRECT_BRANCH_THUNK_REGNUM)) ++ { ++ gcc_assert (INDIRECT_BRANCH_THUNK_REGNUM != 4); ++ return_regnum = 4; ++ } + return_reg = gen_rtx_REG (Pmode, return_regnum); + + addr = plus_constant (Pmode, frame_pointer, +@@ -11054,16 +11116,7 @@ s390_emit_epilogue (bool sibcall) + } + + if (! sibcall) +- { +- +- /* Return to caller. */ +- +- p = rtvec_alloc (2); +- +- RTVEC_ELT (p, 0) = ret_rtx; +- RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode, return_reg); +- emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p)); +- } ++ emit_jump_insn (gen_return_use (return_reg)); + } + + +@@ -12371,6 +12424,84 @@ s390_output_mi_thunk (FILE *file, tree t + final_end_function (); + } + ++/* Output either an indirect jump or a an indirect call ++ (RETURN_ADDR_REGNO != INVALID_REGNUM) with target register REGNO ++ using a branch trampoline disabling branch target prediction. */ ++ ++void ++s390_indirect_branch_via_thunk (unsigned int regno, ++ unsigned int return_addr_regno, ++ rtx comparison_operator, ++ enum s390_indirect_branch_type type) ++{ ++ enum s390_indirect_branch_option option; ++ ++ if (type == s390_indirect_branch_type_return) ++ { ++ if (s390_function_return_reg != indirect_branch_keep ++ && !s390_return_addr_from_memory ()) ++ option = s390_opt_function_return_reg; ++ ++ if (s390_function_return_mem != indirect_branch_keep ++ && s390_return_addr_from_memory ()) ++ option = s390_opt_function_return_mem; ++ } ++ else if (type == s390_indirect_branch_type_jump) ++ option = s390_opt_indirect_branch_jump; ++ else if (type == s390_indirect_branch_type_call) ++ option = s390_opt_indirect_branch_call; ++ else ++ gcc_unreachable (); ++ ++ if (TARGET_INDIRECT_BRANCH_TABLE) ++ { ++ char label[32]; ++ ++ ASM_GENERATE_INTERNAL_LABEL (label, ++ indirect_branch_table_label[option], ++ indirect_branch_table_label_no[option]++); ++ ASM_OUTPUT_LABEL (asm_out_file, label); ++ } ++ ++ if (return_addr_regno != INVALID_REGNUM) ++ { ++ gcc_assert (comparison_operator == NULL_RTX); ++ fprintf (asm_out_file, " \tbrasl\t%%r%d,", return_addr_regno); ++ } ++ else ++ { ++ fputs (" \tjg", asm_out_file); ++ if (comparison_operator != NULL_RTX) ++ print_operand (asm_out_file, comparison_operator, 'C'); ++ ++ fputs ("\t", asm_out_file); ++ } ++ ++ if (TARGET_CPU_Z10) ++ fprintf (asm_out_file, ++ TARGET_INDIRECT_BRANCH_THUNK_NAME_EXRL "\n", ++ regno); ++ else ++ fprintf (asm_out_file, ++ TARGET_INDIRECT_BRANCH_THUNK_NAME_EX "\n", ++ INDIRECT_BRANCH_THUNK_REGNUM, regno); ++ ++ if ((option == s390_opt_indirect_branch_jump ++ && s390_indirect_branch_jump == indirect_branch_thunk) ++ || (option == s390_opt_indirect_branch_call ++ && s390_indirect_branch_call == indirect_branch_thunk) ++ || (option == s390_opt_function_return_reg ++ && s390_function_return_reg == indirect_branch_thunk) ++ || (option == s390_opt_function_return_mem ++ && s390_function_return_mem == indirect_branch_thunk)) ++ { ++ if (TARGET_CPU_Z10) ++ indirect_branch_z10thunk_mask |= (1 << regno); ++ else ++ indirect_branch_prez10thunk_mask |= (1 << regno); ++ } ++} ++ + static bool + s390_valid_pointer_mode (enum machine_mode mode) + { +@@ -12476,6 +12607,14 @@ s390_function_ok_for_sibcall (tree decl, + if (!TARGET_64BIT && flag_pic && decl && !targetm.binds_local_p (decl)) + return false; + ++ /* The thunks for indirect branches require r1 if no exrl is ++ available. r1 might not be available when doing a sibling ++ call. */ ++ if (TARGET_INDIRECT_BRANCH_NOBP_CALL ++ && !TARGET_CPU_Z10 ++ && !decl) ++ return false; ++ + /* Register 6 on s390 is available as an argument register but unfortunately + "caller saved". This makes functions needing this register for arguments + not suitable for sibcalls. */ +@@ -12509,9 +12648,13 @@ s390_emit_call (rtx addr_location, rtx t + { + bool plt_call = false; + rtx insn; +- rtx call; +- rtx clobber; +- rtvec vec; ++ rtx vec[4] = { NULL_RTX }; ++ int elts = 0; ++ rtx *call = &vec[0]; ++ rtx *clobber_ret_reg = &vec[1]; ++ rtx *use = &vec[2]; ++ rtx *clobber_thunk_reg = &vec[3]; ++ int i; + + /* Direct function calls need special treatment. */ + if (GET_CODE (addr_location) == SYMBOL_REF) +@@ -12520,7 +12663,7 @@ s390_emit_call (rtx addr_location, rtx t + replace the symbol itself with the PLT stub. */ + if (flag_pic && !SYMBOL_REF_LOCAL_P (addr_location)) + { +- if (retaddr_reg != NULL_RTX) ++ if (TARGET_64BIT || retaddr_reg != NULL_RTX) + { + addr_location = gen_rtx_UNSPEC (Pmode, + gen_rtvec (1, addr_location), +@@ -12563,26 +12706,57 @@ s390_emit_call (rtx addr_location, rtx t + addr_location = gen_rtx_REG (Pmode, SIBCALL_REGNUM); + } + ++ if (TARGET_INDIRECT_BRANCH_NOBP_CALL ++ && GET_CODE (addr_location) != SYMBOL_REF ++ && !plt_call) ++ { ++ /* Indirect branch thunks require the target to be a single GPR. */ ++ addr_location = force_reg (Pmode, addr_location); ++ ++ /* Without exrl the indirect branch thunks need an additional ++ register for larl;ex */ ++ if (!TARGET_CPU_Z10) ++ { ++ *clobber_thunk_reg = gen_rtx_REG (Pmode, INDIRECT_BRANCH_THUNK_REGNUM); ++ *clobber_thunk_reg = gen_rtx_CLOBBER (VOIDmode, *clobber_thunk_reg); ++ } ++ } ++ + addr_location = gen_rtx_MEM (QImode, addr_location); +- call = gen_rtx_CALL (VOIDmode, addr_location, const0_rtx); ++ *call = gen_rtx_CALL (VOIDmode, addr_location, const0_rtx); + + if (result_reg != NULL_RTX) +- call = gen_rtx_SET (VOIDmode, result_reg, call); ++ *call = gen_rtx_SET (VOIDmode, result_reg, *call); + + if (retaddr_reg != NULL_RTX) + { +- clobber = gen_rtx_CLOBBER (VOIDmode, retaddr_reg); ++ *clobber_ret_reg = gen_rtx_CLOBBER (VOIDmode, retaddr_reg); + + if (tls_call != NULL_RTX) +- vec = gen_rtvec (3, call, clobber, +- gen_rtx_USE (VOIDmode, tls_call)); +- else +- vec = gen_rtvec (2, call, clobber); ++ *use = gen_rtx_USE (VOIDmode, tls_call); ++ } ++ ++ for (i = 0; i < 4; i++) ++ if (vec[i] != NULL_RTX) ++ elts++; + +- call = gen_rtx_PARALLEL (VOIDmode, vec); ++ if (elts > 1) ++ { ++ rtvec v; ++ int e = 0; ++ ++ v = rtvec_alloc (elts); ++ for (i = 0; i < 4; i++) ++ if (vec[i] != NULL_RTX) ++ { ++ RTVEC_ELT (v, e) = vec[i]; ++ e++; ++ } ++ ++ *call = gen_rtx_PARALLEL (VOIDmode, v); + } + +- insn = emit_call_insn (call); ++ insn = emit_call_insn (*call); + + /* 31-bit PLT stubs and tls calls use the GOT register implicitly. */ + if ((!TARGET_64BIT && plt_call) || tls_call != NULL_RTX) +@@ -13819,6 +13993,190 @@ s390_asm_file_end (void) + file_end_indicate_exec_stack (); + } + ++#ifdef HAVE_GAS_HIDDEN ++# define USE_HIDDEN_LINKONCE 1 ++#else ++# define USE_HIDDEN_LINKONCE 0 ++#endif ++ ++/* Output an indirect branch trampoline for target register REGNO. */ ++ ++static void ++s390_output_indirect_thunk_function (unsigned int regno, bool z10_p) ++{ ++ tree decl; ++ char thunk_label[32]; ++ ++ int i; ++ ++ if (z10_p) ++ sprintf (thunk_label, TARGET_INDIRECT_BRANCH_THUNK_NAME_EXRL, regno); ++ else ++ sprintf (thunk_label, TARGET_INDIRECT_BRANCH_THUNK_NAME_EX, ++ INDIRECT_BRANCH_THUNK_REGNUM, regno); ++ ++ decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, ++ get_identifier (thunk_label), ++ build_function_type_list (void_type_node, NULL_TREE)); ++ DECL_RESULT (decl) = build_decl (BUILTINS_LOCATION, RESULT_DECL, ++ NULL_TREE, void_type_node); ++ TREE_PUBLIC (decl) = 1; ++ TREE_STATIC (decl) = 1; ++ DECL_IGNORED_P (decl) = 1; ++ ++ if (USE_HIDDEN_LINKONCE) ++ { ++ DECL_COMDAT_GROUP (decl) = DECL_ASSEMBLER_NAME (decl); ++ ++ targetm.asm_out.unique_section (decl, 0); ++ switch_to_section (get_named_section (decl, NULL, 0)); ++ ++ targetm.asm_out.globalize_label (asm_out_file, thunk_label); ++ fputs ("\t.hidden\t", asm_out_file); ++ assemble_name (asm_out_file, thunk_label); ++ putc ('\n', asm_out_file); ++ ASM_DECLARE_FUNCTION_NAME (asm_out_file, thunk_label, decl); ++ } ++ else ++ { ++ switch_to_section (text_section); ++ ASM_OUTPUT_LABEL (asm_out_file, thunk_label); ++ } ++ ++ DECL_INITIAL (decl) = make_node (BLOCK); ++ current_function_decl = decl; ++ allocate_struct_function (decl, false); ++ init_function_start (decl); ++ cfun->is_thunk = true; ++ first_function_block_is_cold = false; ++ final_start_function (emit_barrier (), asm_out_file, 1); ++ ++ /* This makes CFI at least usable for indirect jumps. ++ ++ jumps: stopping in the thunk: backtrace will point to the thunk ++ target is if it was interrupted by a signal ++ ++ calls: Instead of caller->thunk the backtrace will be ++ caller->callee->thunk */ ++ if (flag_asynchronous_unwind_tables) ++ { ++ fputs ("\t.cfi_signal_frame\n", asm_out_file); ++ fprintf (asm_out_file, "\t.cfi_return_column %d\n", regno); ++ for (i = 0; i < FPR15_REGNUM; i++) ++ fprintf (asm_out_file, "\t.cfi_same_value %s\n", reg_names[i]); ++ } ++ ++ if (z10_p) ++ { ++ /* exrl 0,1f */ ++ ++ /* We generate a thunk for z10 compiled code although z10 is ++ currently not enabled. Tell the assembler to accept the ++ instruction. */ ++ if (!TARGET_CPU_Z10) ++ { ++ fputs ("\t.machine push\n", asm_out_file); ++ fputs ("\t.machine z10\n", asm_out_file); ++ } ++ /* We use exrl even if -mzarch hasn't been specified on the ++ command line so we have to tell the assembler to accept ++ it. */ ++ if (!TARGET_ZARCH) ++ fputs ("\t.machinemode zarch\n", asm_out_file); ++ ++ fputs ("\texrl\t0,1f\n", asm_out_file); ++ ++ if (!TARGET_ZARCH) ++ fputs ("\t.machinemode esa\n", asm_out_file); ++ ++ if (!TARGET_CPU_Z10) ++ fputs ("\t.machine pop\n", asm_out_file); ++ } ++ else if (TARGET_CPU_ZARCH) ++ { ++ /* larl %r1,1f */ ++ fprintf (asm_out_file, "\tlarl\t%%r%d,1f\n", ++ INDIRECT_BRANCH_THUNK_REGNUM); ++ ++ /* ex 0,0(%r1) */ ++ fprintf (asm_out_file, "\tex\t0,0(%%r%d)\n", ++ INDIRECT_BRANCH_THUNK_REGNUM); ++ } ++ else ++ gcc_unreachable (); ++ ++ /* 0: j 0b */ ++ fputs ("0:\tj\t0b\n", asm_out_file); ++ ++ /* 1: br */ ++ fprintf (asm_out_file, "1:\tbr\t%%r%d\n", regno); ++ ++ final_end_function (); ++ init_insn_lengths (); ++ free_after_compilation (cfun); ++ set_cfun (NULL); ++ current_function_decl = NULL; ++} ++ ++/* Implement the asm.code_end target hook. */ ++ ++static void ++s390_code_end (void) ++{ ++ int i; ++ ++ for (i = 1; i < 16; i++) ++ { ++ if (indirect_branch_z10thunk_mask & (1 << i)) ++ s390_output_indirect_thunk_function (i, true); ++ ++ if (indirect_branch_prez10thunk_mask & (1 << i)) ++ s390_output_indirect_thunk_function (i, false); ++ } ++ ++ if (TARGET_INDIRECT_BRANCH_TABLE) ++ { ++ int o; ++ int i; ++ ++ for (o = 0; o < INDIRECT_BRANCH_NUM_OPTIONS; o++) ++ { ++ if (indirect_branch_table_label_no[o] == 0) ++ continue; ++ ++ switch_to_section (get_section (indirect_branch_table_name[o], ++ 0, ++ NULL_TREE)); ++ for (i = 0; i < indirect_branch_table_label_no[o]; i++) ++ { ++ char label_start[32]; ++ ++ ASM_GENERATE_INTERNAL_LABEL (label_start, ++ indirect_branch_table_label[o], i); ++ ++ fputs ("\t.long\t", asm_out_file); ++ assemble_name_raw (asm_out_file, label_start); ++ fputs ("-.\n", asm_out_file); ++ } ++ switch_to_section (current_function_section ()); ++ } ++ } ++} ++ ++/* Implement the TARGET_CASE_VALUES_THRESHOLD target hook. */ ++ ++unsigned int ++s390_case_values_threshold (void) ++{ ++ /* Disabling branch prediction for indirect jumps makes jump table ++ much more expensive. */ ++ if (TARGET_INDIRECT_BRANCH_NOBP_JUMP) ++ return 20; ++ ++ return default_case_values_threshold (); ++} ++ ++ + /* Initialize GCC target structure. */ + + #undef TARGET_ASM_ALIGNED_HI_OP +@@ -14015,6 +14373,12 @@ s390_asm_file_end (void) + #undef TARGET_ASM_FILE_END + #define TARGET_ASM_FILE_END s390_asm_file_end + ++#undef TARGET_ASM_CODE_END ++#define TARGET_ASM_CODE_END s390_code_end ++ ++#undef TARGET_CASE_VALUES_THRESHOLD ++#define TARGET_CASE_VALUES_THRESHOLD s390_case_values_threshold ++ + struct gcc_target targetm = TARGET_INITIALIZER; + + #include "gt-s390.h" +diff -Nrup gcc/config/s390/s390.h gcc/config/s390/s390.h +--- gcc/config/s390/s390.h 2018-03-27 09:33:19.762143683 -0600 ++++ gcc/config/s390/s390.h 2018-03-27 09:33:58.827861602 -0600 +@@ -1006,4 +1006,37 @@ extern const int processor_flags_table[] + s390_register_target_pragmas (); \ + } while (0) + ++ ++#define TARGET_INDIRECT_BRANCH_NOBP_RET_OPTION \ ++ (s390_function_return_reg != indirect_branch_keep \ ++ || s390_function_return_mem != indirect_branch_keep) ++ ++#define TARGET_INDIRECT_BRANCH_NOBP_RET \ ++ ((s390_function_return_reg != indirect_branch_keep \ ++ && !s390_return_addr_from_memory ()) \ ++ || (s390_function_return_mem != indirect_branch_keep \ ++ && s390_return_addr_from_memory ())) ++ ++#define TARGET_INDIRECT_BRANCH_NOBP_JUMP \ ++ (s390_indirect_branch_jump != indirect_branch_keep) ++ ++#define TARGET_INDIRECT_BRANCH_NOBP_JUMP_THUNK \ ++ (s390_indirect_branch_jump == indirect_branch_thunk \ ++ || s390_indirect_branch_jump == indirect_branch_thunk_extern) ++ ++#define TARGET_INDIRECT_BRANCH_NOBP_JUMP_INLINE_THUNK \ ++ (s390_indirect_branch_jump == indirect_branch_thunk_inline) ++ ++#define TARGET_INDIRECT_BRANCH_NOBP_CALL \ ++ (s390_indirect_branch_call != indirect_branch_keep) ++ ++#ifndef TARGET_DEFAULT_INDIRECT_BRANCH_TABLE ++#define TARGET_DEFAULT_INDIRECT_BRANCH_TABLE 0 ++#endif ++ ++#define TARGET_INDIRECT_BRANCH_THUNK_NAME_EXRL "__s390_indirect_jump_r%d" ++#define TARGET_INDIRECT_BRANCH_THUNK_NAME_EX "__s390_indirect_jump_r%duse_r%d" ++ ++#define TARGET_INDIRECT_BRANCH_TABLE s390_indirect_branch_table ++ + #endif /* S390_H */ +diff -Nrup gcc/config/s390/s390.md gcc/config/s390/s390.md +--- gcc/config/s390/s390.md 2018-03-27 09:33:19.763143675 -0600 ++++ gcc/config/s390/s390.md 2018-03-27 09:33:58.831861573 -0600 +@@ -285,6 +285,8 @@ + [ + ; Sibling call register. + (SIBCALL_REGNUM 1) ++ ; A call-clobbered reg which can be used in indirect branch thunks ++ (INDIRECT_BRANCH_THUNK_REGNUM 1) + ; Literal pool base register. + (BASE_REGNUM 13) + ; Return address register. +@@ -304,6 +306,7 @@ + ; Floating point registers. + (FPR0_REGNUM 16) + (FPR2_REGNUM 18) ++ (FPR15_REGNUM 31) + (VR0_REGNUM 16) + (VR16_REGNUM 38) + (VR23_REGNUM 45) +@@ -402,7 +405,10 @@ + z196_cracked" + (const_string "none")) + +-(define_attr "mnemonic" "bcr_flush,unknown" (const_string "unknown")) ++; mnemonics which only get defined through if_then_else currently ++; don't get added to the list values automatically and hence need to ++; be listed here. ++(define_attr "mnemonic" "b,br,bas,bc,bcr,bcr_flush,unknown" (const_string "unknown")) + + ;; Length in bytes. + +@@ -8436,7 +8442,7 @@ + (match_operator 1 "s390_comparison" [(reg CC_REGNUM) (const_int 0)]) + (match_operand 0 "address_operand" "ZQZR") + (pc)))] +- "" ++ "!TARGET_INDIRECT_BRANCH_NOBP_JUMP" + { + if (get_attr_op_type (insn) == OP_TYPE_RR) + return "b%C1r\t%0"; +@@ -8446,6 +8452,9 @@ + [(set (attr "op_type") + (if_then_else (match_operand 0 "register_operand" "") + (const_string "RR") (const_string "RX"))) ++ (set (attr "mnemonic") ++ (if_then_else (match_operand 0 "register_operand" "") ++ (const_string "bcr") (const_string "bc"))) + (set_attr "type" "branch") + (set_attr "atype" "agen")]) + +@@ -8499,7 +8508,7 @@ + (match_operator 1 "s390_comparison" [(reg CC_REGNUM) (const_int 0)]) + (pc) + (match_operand 0 "address_operand" "ZQZR")))] +- "" ++ "!TARGET_INDIRECT_BRANCH_NOBP_JUMP" + { + if (get_attr_op_type (insn) == OP_TYPE_RR) + return "b%D1r\t%0"; +@@ -8509,6 +8518,9 @@ + [(set (attr "op_type") + (if_then_else (match_operand 0 "register_operand" "") + (const_string "RR") (const_string "RX"))) ++ (set (attr "mnemonic") ++ (if_then_else (match_operand 0 "register_operand" "") ++ (const_string "bcr") (const_string "bc"))) + (set_attr "type" "branch") + (set_attr "atype" "agen")]) + +@@ -9005,29 +9017,125 @@ + ; indirect-jump instruction pattern(s). + ; + +-(define_insn "indirect_jump" +- [(set (pc) (match_operand 0 "address_operand" "ZQZR"))] +- "" ++(define_expand "indirect_jump" ++ [(set (pc) (match_operand 0 "address_operand" "ZQZR"))] ++ "" ++{ ++ if (TARGET_INDIRECT_BRANCH_NOBP_JUMP_THUNK) ++ { ++ operands[0] = force_reg (Pmode, operands[0]); ++ if (TARGET_CPU_Z10) ++ { ++ if (TARGET_64BIT) ++ emit_jump_insn (gen_indirect_jump_via_thunkdi_z10 (operands[0])); ++ else ++ emit_jump_insn (gen_indirect_jump_via_thunksi_z10 (operands[0])); ++ } ++ else ++ { ++ if (TARGET_64BIT) ++ emit_jump_insn (gen_indirect_jump_via_thunkdi (operands[0])); ++ else ++ emit_jump_insn (gen_indirect_jump_via_thunksi (operands[0])); ++ } ++ DONE; ++ } ++}) ++ ++(define_insn "*indirect_jump" ++ [(set (pc) ++ (match_operand 0 "address_operand" "ZR"))] ++ "!TARGET_INDIRECT_BRANCH_NOBP_JUMP_THUNK" + { + if (get_attr_op_type (insn) == OP_TYPE_RR) + return "br\t%0"; + else + return "b\t%a0"; + } +- [(set (attr "op_type") +- (if_then_else (match_operand 0 "register_operand" "") +- (const_string "RR") (const_string "RX"))) +- (set_attr "type" "branch") +- (set_attr "atype" "agen")]) ++ [(set (attr "op_type") ++ (if_then_else (match_operand 0 "register_operand" "") ++ (const_string "RR") (const_string "RX"))) ++ (set (attr "mnemonic") ++ (if_then_else (match_operand 0 "register_operand" "") ++ (const_string "br") (const_string "b"))) ++ (set_attr "type" "branch") ++ (set_attr "atype" "agen")]) ++ ++(define_insn "indirect_jump_via_thunk_z10" ++ [(set (pc) ++ (match_operand:P 0 "register_operand" "a"))] ++ "TARGET_INDIRECT_BRANCH_NOBP_JUMP_THUNK ++ && TARGET_CPU_Z10" ++{ ++ s390_indirect_branch_via_thunk (REGNO (operands[0]), ++ INVALID_REGNUM, ++ NULL_RTX, ++ s390_indirect_branch_type_jump); ++ return ""; ++} ++ [(set_attr "op_type" "RIL") ++ (set_attr "mnemonic" "jg") ++ (set_attr "type" "branch") ++ (set_attr "atype" "agen")]) ++ ++(define_insn "indirect_jump_via_thunk" ++ [(set (pc) ++ (match_operand:P 0 "register_operand" " a")) ++ (clobber (reg:P INDIRECT_BRANCH_THUNK_REGNUM))] ++ "TARGET_INDIRECT_BRANCH_NOBP_JUMP_THUNK ++ && !TARGET_CPU_Z10" ++{ ++ s390_indirect_branch_via_thunk (REGNO (operands[0]), ++ INVALID_REGNUM, ++ NULL_RTX, ++ s390_indirect_branch_type_jump); ++ return ""; ++} ++ [(set_attr "op_type" "RIL") ++ (set_attr "mnemonic" "jg") ++ (set_attr "type" "branch") ++ (set_attr "atype" "agen")]) + + ; + ; casesi instruction pattern(s). + ; + +-(define_insn "casesi_jump" +- [(set (pc) (match_operand 0 "address_operand" "ZQZR")) +- (use (label_ref (match_operand 1 "" "")))] +- "" ++(define_expand "casesi_jump" ++ [(parallel ++ [(set (pc) (match_operand 0 "address_operand")) ++ (use (label_ref (match_operand 1 "")))])] ++ "" ++{ ++ if (TARGET_INDIRECT_BRANCH_NOBP_JUMP_THUNK) ++ { ++ operands[0] = force_reg (GET_MODE (operands[0]), operands[0]); ++ ++ if (TARGET_CPU_Z10) ++ { ++ if (TARGET_64BIT) ++ emit_jump_insn (gen_casesi_jump_via_thunkdi_z10 (operands[0], ++ operands[1])); ++ else ++ emit_jump_insn (gen_casesi_jump_via_thunksi_z10 (operands[0], ++ operands[1])); ++ } ++ else ++ { ++ if (TARGET_64BIT) ++ emit_jump_insn (gen_casesi_jump_via_thunkdi (operands[0], ++ operands[1])); ++ else ++ emit_jump_insn (gen_casesi_jump_via_thunksi (operands[0], ++ operands[1])); ++ } ++ DONE; ++ } ++}) ++ ++(define_insn "*casesi_jump" ++ [(set (pc) (match_operand 0 "address_operand" "ZR")) ++ (use (label_ref (match_operand 1 "" "")))] ++ "!TARGET_INDIRECT_BRANCH_NOBP_JUMP_THUNK" + { + if (get_attr_op_type (insn) == OP_TYPE_RR) + return "br\t%0"; +@@ -9035,11 +9143,50 @@ + return "b\t%a0"; + } + [(set (attr "op_type") ++ (if_then_else (match_operand 0 "register_operand" "") ++ (const_string "RR") (const_string "RX"))) ++ (set (attr "mnemonic") + (if_then_else (match_operand 0 "register_operand" "") +- (const_string "RR") (const_string "RX"))) ++ (const_string "br") (const_string "b"))) ++ (set_attr "type" "branch") ++ (set_attr "atype" "agen")]) ++ ++(define_insn "casesi_jump_via_thunk_z10" ++ [(set (pc) (match_operand:P 0 "register_operand" "a")) ++ (use (label_ref (match_operand 1 "" "")))] ++ "TARGET_INDIRECT_BRANCH_NOBP_JUMP_THUNK ++ && TARGET_CPU_Z10" ++{ ++ s390_indirect_branch_via_thunk (REGNO (operands[0]), ++ INVALID_REGNUM, ++ NULL_RTX, ++ s390_indirect_branch_type_jump); ++ return ""; ++} ++ [(set_attr "op_type" "RIL") ++ (set_attr "mnemonic" "jg") + (set_attr "type" "branch") + (set_attr "atype" "agen")]) + ++(define_insn "casesi_jump_via_thunk" ++ [(set (pc) (match_operand:P 0 "register_operand" "a")) ++ (use (label_ref (match_operand 1 "" ""))) ++ (clobber (reg:P INDIRECT_BRANCH_THUNK_REGNUM))] ++ "TARGET_INDIRECT_BRANCH_NOBP_JUMP_THUNK ++ && !TARGET_CPU_Z10" ++{ ++ s390_indirect_branch_via_thunk (REGNO (operands[0]), ++ INVALID_REGNUM, ++ NULL_RTX, ++ s390_indirect_branch_type_jump); ++ return ""; ++} ++ [(set_attr "op_type" "RIL") ++ (set_attr "mnemonic" "jg") ++ (set_attr "type" "branch") ++ (set_attr "atype" "agen")]) ++ ++ + (define_expand "casesi" + [(match_operand:SI 0 "general_operand" "") + (match_operand:SI 1 "general_operand" "") +@@ -9141,11 +9288,30 @@ + + (define_insn "*sibcall_br" + [(call (mem:QI (reg SIBCALL_REGNUM)) +- (match_operand 0 "const_int_operand" "n"))] ++ (match_operand 0 "const_int_operand" "n"))] + "SIBLING_CALL_P (insn) +- && GET_MODE (XEXP (XEXP (PATTERN (insn), 0), 0)) == Pmode" +- "br\t%%r1" +- [(set_attr "op_type" "RR") ++ && GET_MODE (XEXP (XEXP (PATTERN (insn), 0), 0)) == Pmode" ++{ ++ if (TARGET_INDIRECT_BRANCH_NOBP_CALL) ++ { ++ gcc_assert (TARGET_CPU_Z10); ++ s390_indirect_branch_via_thunk (SIBCALL_REGNUM, ++ INVALID_REGNUM, ++ NULL_RTX, ++ s390_indirect_branch_type_call); ++ return ""; ++ } ++ else ++ return "br\t%%r1"; ++} ++ [(set (attr "op_type") ++ (if_then_else (match_test "TARGET_INDIRECT_BRANCH_NOBP_CALL") ++ (const_string "RIL") ++ (const_string "RR"))) ++ (set (attr "mnemonic") ++ (if_then_else (match_test "TARGET_INDIRECT_BRANCH_NOBP_CALL") ++ (const_string "jg") ++ (const_string "br"))) + (set_attr "type" "branch") + (set_attr "atype" "agen")]) + +@@ -9185,8 +9351,27 @@ + (match_operand 1 "const_int_operand" "n")))] + "SIBLING_CALL_P (insn) + && GET_MODE (XEXP (XEXP (XEXP (PATTERN (insn), 1), 0), 0)) == Pmode" +- "br\t%%r1" +- [(set_attr "op_type" "RR") ++{ ++ if (TARGET_INDIRECT_BRANCH_NOBP_CALL) ++ { ++ gcc_assert (TARGET_CPU_Z10); ++ s390_indirect_branch_via_thunk (SIBCALL_REGNUM, ++ INVALID_REGNUM, ++ NULL_RTX, ++ s390_indirect_branch_type_call); ++ return ""; ++ } ++ else ++ return "br\t%%r1"; ++} ++ [(set (attr "op_type") ++ (if_then_else (match_test "TARGET_INDIRECT_BRANCH_NOBP_CALL") ++ (const_string "RIL") ++ (const_string "RR"))) ++ (set (attr "mnemonic") ++ (if_then_else (match_test "TARGET_INDIRECT_BRANCH_NOBP_CALL") ++ (const_string "jg") ++ (const_string "br"))) + (set_attr "type" "branch") + (set_attr "atype" "agen")]) + +@@ -9252,7 +9437,9 @@ + [(call (mem:QI (match_operand 0 "address_operand" "ZQZR")) + (match_operand 1 "const_int_operand" "n")) + (clobber (match_operand 2 "register_operand" "=r"))] +- "!SIBLING_CALL_P (insn) && GET_MODE (operands[2]) == Pmode" ++ "!TARGET_INDIRECT_BRANCH_NOBP_CALL ++ && !SIBLING_CALL_P (insn) ++ && GET_MODE (operands[2]) == Pmode" + { + if (get_attr_op_type (insn) == OP_TYPE_RR) + return "basr\t%2,%0"; +@@ -9262,6 +9449,50 @@ + [(set (attr "op_type") + (if_then_else (match_operand 0 "register_operand" "") + (const_string "RR") (const_string "RX"))) ++ (set (attr "mnemonic") ++ (if_then_else (match_operand 0 "register_operand" "") ++ (const_string "basr") (const_string "bas"))) ++ (set_attr "type" "jsr") ++ (set_attr "atype" "agen") ++ (set_attr "z196prop" "z196_cracked")]) ++ ++(define_insn "*basr_via_thunk_z10" ++ [(call (mem:QI (match_operand:P 0 "register_operand" "a")) ++ (match_operand 1 "const_int_operand" "n")) ++ (clobber (match_operand:P 2 "register_operand" "=&r"))] ++ "TARGET_INDIRECT_BRANCH_NOBP_CALL ++ && TARGET_CPU_Z10 ++ && !SIBLING_CALL_P (insn)" ++{ ++ s390_indirect_branch_via_thunk (REGNO (operands[0]), ++ REGNO (operands[2]), ++ NULL_RTX, ++ s390_indirect_branch_type_call); ++ return ""; ++} ++ [(set_attr "op_type" "RIL") ++ (set_attr "mnemonic" "brasl") ++ (set_attr "type" "jsr") ++ (set_attr "atype" "agen") ++ (set_attr "z196prop" "z196_cracked")]) ++ ++(define_insn "*basr_via_thunk" ++ [(call (mem:QI (match_operand:P 0 "register_operand" "a")) ++ (match_operand 1 "const_int_operand" "n")) ++ (clobber (match_operand:P 2 "register_operand" "=&r")) ++ (clobber (reg:P INDIRECT_BRANCH_THUNK_REGNUM))] ++ "TARGET_INDIRECT_BRANCH_NOBP_CALL ++ && !TARGET_CPU_Z10 ++ && !SIBLING_CALL_P (insn)" ++{ ++ s390_indirect_branch_via_thunk (REGNO (operands[0]), ++ REGNO (operands[2]), ++ NULL_RTX, ++ s390_indirect_branch_type_call); ++ return ""; ++} ++ [(set_attr "op_type" "RIL") ++ (set_attr "mnemonic" "brasl") + (set_attr "type" "jsr") + (set_attr "atype" "agen") + (set_attr "z196prop" "z196_cracked")]) +@@ -9313,7 +9544,10 @@ + (call (mem:QI (match_operand 1 "address_operand" "ZQZR")) + (match_operand 2 "const_int_operand" "n"))) + (clobber (match_operand 3 "register_operand" "=r"))] +- "!SIBLING_CALL_P (insn) && GET_MODE (operands[3]) == Pmode" ++ "!TARGET_INDIRECT_BRANCH_NOBP_CALL ++ && !SIBLING_CALL_P (insn) ++ && GET_MODE (operands[3]) == Pmode" ++ + { + if (get_attr_op_type (insn) == OP_TYPE_RR) + return "basr\t%3,%1"; +@@ -9323,6 +9557,54 @@ + [(set (attr "op_type") + (if_then_else (match_operand 1 "register_operand" "") + (const_string "RR") (const_string "RX"))) ++ (set (attr "mnemonic") ++ (if_then_else (match_operand 1 "register_operand" "") ++ (const_string "basr") (const_string "bas"))) ++ (set_attr "type" "jsr") ++ (set_attr "atype" "agen") ++ (set_attr "z196prop" "z196_cracked")]) ++ ++(define_insn "*basr_r_via_thunk_z10" ++ [(set (match_operand 0 "" "") ++ (call (mem:QI (match_operand 1 "register_operand" "a")) ++ (match_operand 2 "const_int_operand" "n"))) ++ (clobber (match_operand 3 "register_operand" "=&r"))] ++ "TARGET_INDIRECT_BRANCH_NOBP_CALL ++ && TARGET_CPU_Z10 ++ && !SIBLING_CALL_P (insn) ++ && GET_MODE (operands[3]) == Pmode" ++{ ++ s390_indirect_branch_via_thunk (REGNO (operands[1]), ++ REGNO (operands[3]), ++ NULL_RTX, ++ s390_indirect_branch_type_call); ++ return ""; ++} ++ [(set_attr "op_type" "RIL") ++ (set_attr "mnemonic" "brasl") ++ (set_attr "type" "jsr") ++ (set_attr "atype" "agen") ++ (set_attr "z196prop" "z196_cracked")]) ++ ++(define_insn "*basr_r_via_thunk" ++ [(set (match_operand 0 "" "") ++ (call (mem:QI (match_operand 1 "register_operand" "a")) ++ (match_operand 2 "const_int_operand" "n"))) ++ (clobber (match_operand 3 "register_operand" "=&r")) ++ (clobber (reg:P INDIRECT_BRANCH_THUNK_REGNUM))] ++ "TARGET_INDIRECT_BRANCH_NOBP_CALL ++ && !TARGET_CPU_Z10 ++ && !SIBLING_CALL_P (insn) ++ && GET_MODE (operands[3]) == Pmode" ++{ ++ s390_indirect_branch_via_thunk (REGNO (operands[1]), ++ REGNO (operands[3]), ++ NULL_RTX, ++ s390_indirect_branch_type_call); ++ return ""; ++} ++ [(set_attr "op_type" "RIL") ++ (set_attr "mnemonic" "brasl") + (set_attr "type" "jsr") + (set_attr "atype" "agen") + (set_attr "z196prop" "z196_cracked")]) +@@ -10056,15 +10338,78 @@ + "" + "s390_emit_epilogue (true); DONE;") + +-(define_insn "*return" ++(define_expand "return_use" ++ [(parallel ++ [(return) ++ (use (match_operand 0 "register_operand" "a"))])] ++ "" ++{ ++ if (!TARGET_CPU_Z10 ++ && TARGET_INDIRECT_BRANCH_NOBP_RET_OPTION) ++ { ++ if (TARGET_64BIT) ++ emit_jump_insn (gen_returndi_prez10 (operands[0])); ++ else ++ emit_jump_insn (gen_returnsi_prez10 (operands[0])); ++ DONE; ++ } ++}) ++ ++(define_insn "*return" + [(return) +- (use (match_operand 0 "register_operand" "a"))] +- "GET_MODE (operands[0]) == Pmode" +- "br\t%0" +- [(set_attr "op_type" "RR") ++ (use (match_operand:P 0 "register_operand" "a"))] ++ "TARGET_CPU_Z10 || !TARGET_INDIRECT_BRANCH_NOBP_RET_OPTION" ++{ ++ if (TARGET_INDIRECT_BRANCH_NOBP_RET) ++ { ++ s390_indirect_branch_via_thunk (REGNO (operands[0]), ++ INVALID_REGNUM, ++ NULL_RTX, ++ s390_indirect_branch_type_return); ++ return ""; ++ } ++ else ++ return "br\t%0"; ++} ++ [(set (attr "op_type") ++ (if_then_else (match_test "TARGET_INDIRECT_BRANCH_NOBP_RET") ++ (const_string "RIL") ++ (const_string "RR"))) ++ (set (attr "mnemonic") ++ (if_then_else (match_test "TARGET_INDIRECT_BRANCH_NOBP_RET") ++ (const_string "jg") ++ (const_string "br"))) + (set_attr "type" "jsr") + (set_attr "atype" "agen")]) + ++(define_insn "return_prez10" ++ [(return) ++ (use (match_operand:P 0 "register_operand" "a")) ++ (clobber (reg:P INDIRECT_BRANCH_THUNK_REGNUM))] ++ "!TARGET_CPU_Z10 && TARGET_INDIRECT_BRANCH_NOBP_RET_OPTION" ++{ ++ if (TARGET_INDIRECT_BRANCH_NOBP_RET) ++ { ++ s390_indirect_branch_via_thunk (REGNO (operands[0]), ++ INVALID_REGNUM, ++ NULL_RTX, ++ s390_indirect_branch_type_return); ++ return ""; ++ } ++ else ++ return "br\t%0"; ++} ++ [(set (attr "op_type") ++ (if_then_else (match_test "TARGET_INDIRECT_BRANCH_NOBP_RET") ++ (const_string "RIL") ++ (const_string "RR"))) ++ (set (attr "mnemonic") ++ (if_then_else (match_test "TARGET_INDIRECT_BRANCH_NOBP_RET") ++ (const_string "jg") ++ (const_string "br"))) ++ (set_attr "type" "jsr") ++ (set_attr "atype" "agen")]) ++ + + ;; Instruction definition to extend a 31-bit pointer into a 64-bit + ;; pointer. This is used for compatibility. +diff -Nrup gcc/config/s390/s390.opt gcc/config/s390/s390.opt +--- gcc/config/s390/s390.opt 2018-03-27 09:33:19.763143675 -0600 ++++ gcc/config/s390/s390.opt 2018-03-27 09:33:58.832861566 -0600 +@@ -175,3 +175,59 @@ Target Report Joined RejectNegative UInt + Set the branch costs for conditional branch instructions. Reasonable + values are small, non-negative integers. The default branch cost is + 1. ++ ++mindirect-branch= ++Target Report RejectNegative Joined Enum(indirect_branch) Var(s390_indirect_branch) Init(indirect_branch_keep) ++Wrap all indirect branches into execute in order to disable branch ++prediction. ++ ++mindirect-branch-jump= ++Target Report RejectNegative Joined Enum(indirect_branch) Var(s390_indirect_branch_jump) Init(indirect_branch_keep) ++Wrap indirect table jumps and computed gotos into execute in order to ++disable branch prediction. Using thunk or thunk-extern with this ++option requires the thunks to be considered signal handlers to order to ++generate correct CFI. For environments where unwinding (e.g. for ++exceptions) is required please use thunk-inline instead. ++ ++mindirect-branch-call= ++Target Report RejectNegative Joined Enum(indirect_branch) Var(s390_indirect_branch_call) Init(indirect_branch_keep) ++Wrap all indirect calls into execute in order to disable branch prediction. ++ ++mfunction-return= ++Target Report RejectNegative Joined Enum(indirect_branch) Var(s390_function_return) Init(indirect_branch_keep) ++Wrap all indirect return branches into execute in order to disable branch ++prediction. ++ ++mfunction-return-mem= ++Target Report RejectNegative Joined Enum(indirect_branch) Var(s390_function_return_mem) Init(indirect_branch_keep) ++Wrap indirect return branches into execute in order to disable branch ++prediction. This affects only branches where the return address is ++going to be restored from memory. ++ ++mfunction-return-reg= ++Target Report RejectNegative Joined Enum(indirect_branch) Var(s390_function_return_reg) Init(indirect_branch_keep) ++Wrap indirect return branches into execute in order to disable branch ++prediction. This affects only branches where the return address ++doesn't need to be restored from memory. ++ ++Enum ++Name(indirect_branch) Type(enum indirect_branch) ++Known indirect branch choices (for use with the -mindirect-branch=/-mfunction-return= options): ++ ++EnumValue ++Enum(indirect_branch) String(keep) Value(indirect_branch_keep) ++ ++EnumValue ++Enum(indirect_branch) String(thunk) Value(indirect_branch_thunk) ++ ++EnumValue ++Enum(indirect_branch) String(thunk-extern) Value(indirect_branch_thunk_extern) ++ ++mindirect-branch-table ++Target Report Var(s390_indirect_branch_table) Init(TARGET_DEFAULT_INDIRECT_BRANCH_TABLE) ++Generate sections .s390_indirect_jump, .s390_indirect_call, ++.s390_return_reg, and .s390_return_mem to contain the indirect branch ++locations which have been patched as part of using one of the ++-mindirect-branch* or -mfunction-return* options. The sections ++consist of an array of 32 bit elements. Each entry holds the offset ++from the entry to the patched location. +diff -Nrup gcc/config/s390/s390-opts.h gcc/config/s390/s390-opts.h +--- gcc/config/s390/s390-opts.h 2018-03-27 09:33:19.764143668 -0600 ++++ gcc/config/s390/s390-opts.h 2018-03-27 09:33:58.821861645 -0600 +@@ -39,4 +39,12 @@ enum processor_type + PROCESSOR_max + }; + ++/* Values for -mindirect-branch and -mfunction-return options. */ ++enum indirect_branch { ++ indirect_branch_unset = 0, ++ indirect_branch_keep, ++ indirect_branch_thunk, ++ indirect_branch_thunk_extern ++}; ++ + #endif +diff -Nrup gcc/config/s390/s390-protos.h gcc/config/s390/s390-protos.h +--- gcc/config/s390/s390-protos.h 2018-03-27 09:33:19.764143668 -0600 ++++ gcc/config/s390/s390-protos.h 2018-03-27 09:33:58.821861645 -0600 +@@ -41,6 +41,7 @@ extern void s390_set_has_landing_pad_p ( + extern bool s390_hard_regno_mode_ok (unsigned int, enum machine_mode); + extern bool s390_hard_regno_rename_ok (unsigned int, unsigned int); + extern int s390_class_max_nregs (enum reg_class, enum machine_mode); ++extern bool s390_return_addr_from_memory(void); + extern int s390_cannot_change_mode_class (enum machine_mode, enum machine_mode, + enum reg_class); + extern bool s390_function_arg_vector (enum machine_mode, const_tree); +@@ -124,6 +125,18 @@ extern int s390_compare_and_branch_condi + extern bool s390_extzv_shift_ok (int, int, unsigned HOST_WIDE_INT); + extern void s390_asm_output_function_label (FILE *, const char *, tree); + ++enum s390_indirect_branch_type ++ { ++ s390_indirect_branch_type_jump = 0, ++ s390_indirect_branch_type_call, ++ s390_indirect_branch_type_return ++ }; ++extern void s390_indirect_branch_via_thunk (unsigned int regno, ++ unsigned int return_addr_regno, ++ rtx comparison_operator, ++ enum s390_indirect_branch_type type); ++extern void s390_indirect_branch_via_inline_thunk (rtx execute_target); ++ + #endif /* RTX_CODE */ + + /* s390-c.c routines */ +diff -Nrup gcc/testsuite/gcc.target/s390/nobp-function-pointer-nothunk.c gcc/testsuite/gcc.target/s390/nobp-function-pointer-nothunk.c +--- gcc/testsuite/gcc.target/s390/nobp-function-pointer-nothunk.c 1969-12-31 17:00:00.000000000 -0700 ++++ gcc/testsuite/gcc.target/s390/nobp-function-pointer-nothunk.c 2018-03-27 09:33:58.832861566 -0600 +@@ -0,0 +1,59 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O3 -march=z10 --save-temps -mindirect-branch-call=thunk-extern -mindirect-branch-table" } */ ++ ++int gl; ++ ++void __attribute__((noinline,noclone)) ++foo (int a) ++{ ++ gl = a + 40; ++} ++ ++int __attribute__((noinline,noclone)) ++foo_value (int a) ++{ ++ return a + 40; ++} ++ ++void* __attribute__((noinline,noclone)) ++get_fptr (int a) ++{ ++ switch (a) ++ { ++ case 0: return &foo; break; ++ case 1: return &foo_value; break; ++ default: __builtin_abort (); ++ } ++} ++ ++void (*f) (int); ++int (*g) (int); ++ ++int ++main () ++{ ++ int res; ++ ++ f = get_fptr(0); ++ f (2); ++ if (gl != 42) ++ __builtin_abort (); ++ ++ g = get_fptr(1); ++ if (g (2) != 42) ++ __builtin_abort (); ++ ++ return 0; ++} ++ ++/* 2 x main ++/* { dg-final { scan-assembler-times "brasl\t%r\[0-9\]*,__s390_indirect_jump" 2 } } */ ++ ++/* No thunks due to thunk-extern. */ ++/* { dg-final { scan-assembler-not "exrl" } } */ ++/* { dg-final { scan-assembler-not ".globl __s390_indirect_jump" } } */ ++ ++/* { dg-final { scan-assembler-not "section\t.s390_indirect_jump" } } */ ++/* { dg-final { scan-assembler "section\t.s390_indirect_call" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_return_reg" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_return_mem" } } */ +diff -Nrup gcc/testsuite/gcc.target/s390/nobp-function-pointer-z10.c gcc/testsuite/gcc.target/s390/nobp-function-pointer-z10.c +--- gcc/testsuite/gcc.target/s390/nobp-function-pointer-z10.c 1969-12-31 17:00:00.000000000 -0700 ++++ gcc/testsuite/gcc.target/s390/nobp-function-pointer-z10.c 2018-03-27 09:33:58.833861558 -0600 +@@ -0,0 +1,56 @@ ++/* { dg-do run } */ ++/* { dg-options "-O3 -march=z10 --save-temps -mindirect-branch-call=thunk -mindirect-branch-table" } */ ++ ++int gl; ++ ++void __attribute__((noinline,noclone)) ++foo (int a) ++{ ++ gl = a + 40; ++} ++ ++int __attribute__((noinline,noclone)) ++foo_value (int a) ++{ ++ return a + 40; ++} ++ ++void* __attribute__((noinline,noclone)) ++get_fptr (int a) ++{ ++ switch (a) ++ { ++ case 0: return &foo; break; ++ case 1: return &foo_value; break; ++ default: __builtin_abort (); ++ } ++} ++ ++void (*f) (int); ++int (*g) (int); ++ ++int ++main () ++{ ++ int res; ++ ++ f = get_fptr(0); ++ f (2); ++ if (gl != 42) ++ __builtin_abort (); ++ ++ g = get_fptr(1); ++ if (g (2) != 42) ++ __builtin_abort (); ++ ++ return 0; ++} ++ ++/* 2 x main ++/* { dg-final { scan-assembler-times "brasl\t%r\[0-9\]*,__s390_indirect_jump" 2 } } */ ++/* { dg-final { scan-assembler "exrl" } } */ ++ ++/* { dg-final { scan-assembler-not "section\t.s390_indirect_jump" } } */ ++/* { dg-final { scan-assembler "section\t.s390_indirect_call" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_return_reg" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_return_mem" } } */ +diff -Nrup gcc/testsuite/gcc.target/s390/nobp-function-pointer-z900.c gcc/testsuite/gcc.target/s390/nobp-function-pointer-z900.c +--- gcc/testsuite/gcc.target/s390/nobp-function-pointer-z900.c 1969-12-31 17:00:00.000000000 -0700 ++++ gcc/testsuite/gcc.target/s390/nobp-function-pointer-z900.c 2018-03-27 09:33:58.833861558 -0600 +@@ -0,0 +1,56 @@ ++/* { dg-do run } */ ++/* { dg-options "-O3 -march=z900 --save-temps -mindirect-branch-call=thunk -mindirect-branch-table" } */ ++ ++int gl; ++ ++void __attribute__((noinline,noclone)) ++foo (int a) ++{ ++ gl = a + 40; ++} ++ ++int __attribute__((noinline,noclone)) ++foo_value (int a) ++{ ++ return a + 40; ++} ++ ++void* __attribute__((noinline,noclone)) ++get_fptr (int a) ++{ ++ switch (a) ++ { ++ case 0: return &foo; break; ++ case 1: return &foo_value; break; ++ default: __builtin_abort (); ++ } ++} ++ ++void (*f) (int); ++int (*g) (int); ++ ++int ++main () ++{ ++ int res; ++ ++ f = get_fptr(0); ++ f (2); ++ if (gl != 42) ++ __builtin_abort (); ++ ++ g = get_fptr(1); ++ if (g (2) != 42) ++ __builtin_abort (); ++ ++ return 0; ++} ++ ++/* 2 x main ++/* { dg-final { scan-assembler-times "brasl\t%r\[0-9\]*,__s390_indirect_jump" 2 } } */ ++/* { dg-final { scan-assembler "ex\t" } } */ ++ ++/* { dg-final { scan-assembler-not "section\t.s390_indirect_jump" } } */ ++/* { dg-final { scan-assembler "section\t.s390_indirect_call" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_return_reg" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_return_mem" } } */ +diff -Nrup gcc/testsuite/gcc.target/s390/nobp-indirect-jump-nothunk.c gcc/testsuite/gcc.target/s390/nobp-indirect-jump-nothunk.c +--- gcc/testsuite/gcc.target/s390/nobp-indirect-jump-nothunk.c 1969-12-31 17:00:00.000000000 -0700 ++++ gcc/testsuite/gcc.target/s390/nobp-indirect-jump-nothunk.c 2018-03-27 09:33:58.833861558 -0600 +@@ -0,0 +1,45 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O3 -march=z10 --save-temps -mindirect-branch-jump=thunk-extern -mindirect-branch-table" } */ ++ ++/* This is a copy of the gcc.c-torture/execute/20040302-1.c ++ testcase. */ ++ ++int code[]={0,0,0,0,1}; ++ ++void ++foo(int x) { ++ volatile int b; ++ b = 0xffffffff; ++} ++ ++void ++bar(int *pc) { ++ static const void *l[] = {&&lab0, &&end}; ++ ++ foo(0); ++ goto *l[*pc]; ++ lab0: ++ foo(0); ++ pc++; ++ goto *l[*pc]; ++ end: ++ return; ++} ++ ++int ++main() { ++ bar(code); ++ return 0; ++} ++ ++/* 2 x bar ++/* { dg-final { scan-assembler-times "jg\t__s390_indirect_jump" 2 } } */ ++ ++/* No thunks due to thunk-extern. */ ++/* { dg-final { scan-assembler-not "exrl" } } */ ++/* { dg-final { scan-assembler-not ".globl __s390_indirect_jump" } } */ ++ ++/* { dg-final { scan-assembler "section\t.s390_indirect_jump" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_indirect_call" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_return_reg" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_return_mem" } } */ +diff -Nrup gcc/testsuite/gcc.target/s390/nobp-indirect-jump-z10.c gcc/testsuite/gcc.target/s390/nobp-indirect-jump-z10.c +--- gcc/testsuite/gcc.target/s390/nobp-indirect-jump-z10.c 1969-12-31 17:00:00.000000000 -0700 ++++ gcc/testsuite/gcc.target/s390/nobp-indirect-jump-z10.c 2018-03-27 09:33:58.834861551 -0600 +@@ -0,0 +1,42 @@ ++/* { dg-do run } */ ++/* { dg-options "-O3 -march=z10 --save-temps -mindirect-branch-jump=thunk -mindirect-branch-table" } */ ++ ++/* This is a copy of the gcc.c-torture/execute/20040302-1.c ++ testcase. */ ++ ++int code[]={0,0,0,0,1}; ++ ++void ++foo(int x) { ++ volatile int b; ++ b = 0xffffffff; ++} ++ ++void ++bar(int *pc) { ++ static const void *l[] = {&&lab0, &&end}; ++ ++ foo(0); ++ goto *l[*pc]; ++ lab0: ++ foo(0); ++ pc++; ++ goto *l[*pc]; ++ end: ++ return; ++} ++ ++int ++main() { ++ bar(code); ++ return 0; ++} ++ ++/* 2x bar */ ++/* { dg-final { scan-assembler-times "jg\t__s390_indirect_jump" 2 } } */ ++/* { dg-final { scan-assembler "exrl" } } */ ++ ++/* { dg-final { scan-assembler "section\t.s390_indirect_jump" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_indirect_call" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_return_reg" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_return_mem" } } */ +diff -Nrup gcc/testsuite/gcc.target/s390/nobp-indirect-jump-z900.c gcc/testsuite/gcc.target/s390/nobp-indirect-jump-z900.c +--- gcc/testsuite/gcc.target/s390/nobp-indirect-jump-z900.c 1969-12-31 17:00:00.000000000 -0700 ++++ gcc/testsuite/gcc.target/s390/nobp-indirect-jump-z900.c 2018-03-27 09:33:58.834861551 -0600 +@@ -0,0 +1,42 @@ ++/* { dg-do run } */ ++/* { dg-options "-O3 -march=z900 --save-temps -mindirect-branch-jump=thunk -mindirect-branch-table" } */ ++ ++/* This is a copy of the gcc.c-torture/execute/20040302-1.c ++ testcase. */ ++ ++int code[]={0,0,0,0,1}; ++ ++void ++foo(int x) { ++ volatile int b; ++ b = 0xffffffff; ++} ++ ++void ++bar(int *pc) { ++ static const void *l[] = {&&lab0, &&end}; ++ ++ foo(0); ++ goto *l[*pc]; ++ lab0: ++ foo(0); ++ pc++; ++ goto *l[*pc]; ++ end: ++ return; ++} ++ ++int ++main() { ++ bar(code); ++ return 0; ++} ++ ++/* 2 x bar ++/* { dg-final { scan-assembler-times "jg\t__s390_indirect_jump" 2 } } */ ++/* { dg-final { scan-assembler "ex\t" } } */ ++ ++/* { dg-final { scan-assembler "section\t.s390_indirect_jump" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_indirect_call" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_return_reg" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_return_mem" } } */ +diff -Nrup gcc/testsuite/gcc.target/s390/nobp-return-mem-nothunk.c gcc/testsuite/gcc.target/s390/nobp-return-mem-nothunk.c +--- gcc/testsuite/gcc.target/s390/nobp-return-mem-nothunk.c 1969-12-31 17:00:00.000000000 -0700 ++++ gcc/testsuite/gcc.target/s390/nobp-return-mem-nothunk.c 2018-03-27 09:33:58.834861551 -0600 +@@ -0,0 +1,44 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O3 -march=z10 -mzarch --save-temps -mfunction-return-mem=thunk-extern -mindirect-branch-table" } */ ++ ++int gl = 0; ++ ++int __attribute__((noinline,noclone)) ++bar (int a) ++{ ++ return a + 2; ++} ++ ++void __attribute__((noinline,noclone)) ++foo (int a) ++{ ++ int i; ++ ++ if (a == 42) ++ return; ++ ++ for (i = 0; i < a; i++) ++ gl += bar (i); ++} ++ ++int ++main () ++{ ++ foo (3); ++ if (gl != 9) ++ __builtin_abort (); ++ ++ return 0; ++} ++ ++/* 1 x foo, 1 x main ++/* { dg-final { scan-assembler-times "jg\t__s390_indirect_jump" 2 } } */ ++ ++/* No thunks due to thunk-extern. */ ++/* { dg-final { scan-assembler-not "exrl" } } */ ++/* { dg-final { scan-assembler-not ".globl __s390_indirect_jump" } } */ ++ ++/* { dg-final { scan-assembler-not "section\t.s390_indirect_jump" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_indirect_call" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_return_reg" } } */ ++/* { dg-final { scan-assembler "section\t.s390_return_mem" } } */ +diff -Nrup gcc/testsuite/gcc.target/s390/nobp-return-mem-z10.c gcc/testsuite/gcc.target/s390/nobp-return-mem-z10.c +--- gcc/testsuite/gcc.target/s390/nobp-return-mem-z10.c 1969-12-31 17:00:00.000000000 -0700 ++++ gcc/testsuite/gcc.target/s390/nobp-return-mem-z10.c 2018-03-27 09:33:58.835861544 -0600 +@@ -0,0 +1,41 @@ ++/* { dg-do run } */ ++/* { dg-options "-O3 -march=z10 -mzarch --save-temps -mfunction-return-mem=thunk -mindirect-branch-table" } */ ++ ++int gl = 0; ++ ++int __attribute__((noinline,noclone)) ++bar (int a) ++{ ++ return a + 2; ++} ++ ++void __attribute__((noinline,noclone)) ++foo (int a) ++{ ++ int i; ++ ++ if (a == 42) ++ return; ++ ++ for (i = 0; i < a; i++) ++ gl += bar (i); ++} ++ ++int ++main () ++{ ++ foo (3); ++ if (gl != 9) ++ __builtin_abort (); ++ ++ return 0; ++} ++ ++/* 1 x foo, 1 x main ++/* { dg-final { scan-assembler-times "jg\t__s390_indirect_jump" 2 } } */ ++/* { dg-final { scan-assembler "exrl" } } */ ++ ++/* { dg-final { scan-assembler-not "section\t.s390_indirect_jump" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_indirect_call" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_return_reg" } } */ ++/* { dg-final { scan-assembler "section\t.s390_return_mem" } } */ +diff -Nrup gcc/testsuite/gcc.target/s390/nobp-return-mem-z900.c gcc/testsuite/gcc.target/s390/nobp-return-mem-z900.c +--- gcc/testsuite/gcc.target/s390/nobp-return-mem-z900.c 1969-12-31 17:00:00.000000000 -0700 ++++ gcc/testsuite/gcc.target/s390/nobp-return-mem-z900.c 2018-03-27 09:33:58.835861544 -0600 +@@ -0,0 +1,42 @@ ++/* { dg-do run } */ ++/* { dg-options "-O3 -march=z900 --save-temps -mfunction-return-mem=thunk -mindirect-branch-table" } */ ++ ++int gl = 0; ++ ++int __attribute__((noinline,noclone)) ++bar (int a) ++{ ++ return a + 2; ++} ++ ++void __attribute__((noinline,noclone)) ++foo (int a) ++{ ++ int i; ++ ++ if (a == 42) ++ return; ++ ++ for (i = 0; i < a; i++) ++ gl += bar (i); ++} ++ ++int ++main () ++{ ++ foo (3); ++ if (gl != 9) ++ __builtin_abort (); ++ ++ return 0; ++} ++ ++/* 1 x foo, 1 x main ++/* { dg-final { scan-assembler-times "jg\t__s390_indirect_jump" 2 } } */ ++ ++/* { dg-final { scan-assembler "ex\t" } } */ ++ ++/* { dg-final { scan-assembler-not "section\t.s390_indirect_jump" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_indirect_call" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_return_reg" } } */ ++/* { dg-final { scan-assembler "section\t.s390_return_mem" } } */ +diff -Nrup gcc/testsuite/gcc.target/s390/nobp-return-reg-nothunk.c gcc/testsuite/gcc.target/s390/nobp-return-reg-nothunk.c +--- gcc/testsuite/gcc.target/s390/nobp-return-reg-nothunk.c 1969-12-31 17:00:00.000000000 -0700 ++++ gcc/testsuite/gcc.target/s390/nobp-return-reg-nothunk.c 2018-03-27 09:33:58.835861544 -0600 +@@ -0,0 +1,44 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O3 -march=z10 --save-temps -mfunction-return-reg=thunk-extern -mindirect-branch-table" } */ ++ ++int gl = 0; ++ ++int __attribute__((noinline,noclone)) ++bar (int a) ++{ ++ return a + 2; ++} ++ ++void __attribute__((noinline,noclone)) ++foo (int a) ++{ ++ int i; ++ ++ if (a == 42) ++ return; ++ ++ for (i = 0; i < a; i++) ++ gl += bar (i); ++} ++ ++int ++main () ++{ ++ foo (3); ++ if (gl != 9) ++ __builtin_abort (); ++ ++ return 0; ++} ++ ++/* 1 x bar ++/* { dg-final { scan-assembler-times "jg\t__s390_indirect_jump" 1 } } */ ++ ++/* No thunks due to thunk-extern. */ ++/* { dg-final { scan-assembler-not "exrl" } } */ ++/* { dg-final { scan-assembler-not ".globl __s390_indirect_jump" } } */ ++ ++/* { dg-final { scan-assembler-not "section\t.s390_indirect_jump" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_indirect_call" } } */ ++/* { dg-final { scan-assembler "section\t.s390_return_reg" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_return_mem" } } */ +diff -Nrup gcc/testsuite/gcc.target/s390/nobp-return-reg-z10.c gcc/testsuite/gcc.target/s390/nobp-return-reg-z10.c +--- gcc/testsuite/gcc.target/s390/nobp-return-reg-z10.c 1969-12-31 17:00:00.000000000 -0700 ++++ gcc/testsuite/gcc.target/s390/nobp-return-reg-z10.c 2018-03-27 09:33:58.836861537 -0600 +@@ -0,0 +1,41 @@ ++/* { dg-do run } */ ++/* { dg-options "-O3 -march=z10 --save-temps -mfunction-return-reg=thunk -mindirect-branch-table" } */ ++ ++int gl = 0; ++ ++int __attribute__((noinline,noclone)) ++bar (int a) ++{ ++ return a + 2; ++} ++ ++void __attribute__((noinline,noclone)) ++foo (int a) ++{ ++ int i; ++ ++ if (a == 42) ++ return; ++ ++ for (i = 0; i < a; i++) ++ gl += bar (i); ++} ++ ++int ++main () ++{ ++ foo (3); ++ if (gl != 9) ++ __builtin_abort (); ++ ++ return 0; ++} ++ ++/* 1 x bar ++/* { dg-final { scan-assembler-times "jg\t__s390_indirect_jump" 1 } } */ ++/* { dg-final { scan-assembler "exrl" } } */ ++ ++/* { dg-final { scan-assembler-not "section\t.s390_indirect_jump" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_indirect_call" } } */ ++/* { dg-final { scan-assembler "section\t.s390_return_reg" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_return_mem" } } */ +diff -Nrup gcc/testsuite/gcc.target/s390/nobp-return-reg-z900.c gcc/testsuite/gcc.target/s390/nobp-return-reg-z900.c +--- gcc/testsuite/gcc.target/s390/nobp-return-reg-z900.c 1969-12-31 17:00:00.000000000 -0700 ++++ gcc/testsuite/gcc.target/s390/nobp-return-reg-z900.c 2018-03-27 09:33:58.836861537 -0600 +@@ -0,0 +1,41 @@ ++/* { dg-do run } */ ++/* { dg-options "-O3 -march=z900 --save-temps -mfunction-return-reg=thunk -mindirect-branch-table" } */ ++ ++int gl = 0; ++ ++int __attribute__((noinline,noclone)) ++bar (int a) ++{ ++ return a + 2; ++} ++ ++void __attribute__((noinline,noclone)) ++foo (int a) ++{ ++ int i; ++ ++ if (a == 42) ++ return; ++ ++ for (i = 0; i < a; i++) ++ gl += bar (i); ++} ++ ++int ++main () ++{ ++ foo (3); ++ if (gl != 9) ++ __builtin_abort (); ++ ++ return 0; ++} ++ ++/* 1 x bar ++/* { dg-final { scan-assembler-times "jg\t__s390_indirect_jump" 1 } } */ ++/* { dg-final { scan-assembler "ex\t" } } */ ++ ++/* { dg-final { scan-assembler-not "section\t.s390_indirect_jump" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_indirect_call" } } */ ++/* { dg-final { scan-assembler "section\t.s390_return_reg" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_return_mem" } } */ +diff -Nrup gcc/testsuite/gcc.target/s390/nobp-table-jump-z10.c gcc/testsuite/gcc.target/s390/nobp-table-jump-z10.c +--- gcc/testsuite/gcc.target/s390/nobp-table-jump-z10.c 1969-12-31 17:00:00.000000000 -0700 ++++ gcc/testsuite/gcc.target/s390/nobp-table-jump-z10.c 2018-03-27 09:33:58.836861537 -0600 +@@ -0,0 +1,77 @@ ++/* { dg-do run } */ ++/* { dg-options "-O3 -march=z10 -mzarch --save-temps -mindirect-branch-jump=thunk -mindirect-branch-table" } */ ++/* case-values-threshold will be set to 20 by the back-end when jump ++ thunk are requested. */ ++ ++int __attribute__((noinline,noclone)) foo1 (void) { return 1; } ++int __attribute__((noinline,noclone)) foo2 (void) { return 2; } ++int __attribute__((noinline,noclone)) foo3 (void) { return 3; } ++int __attribute__((noinline,noclone)) foo4 (void) { return 4; } ++int __attribute__((noinline,noclone)) foo5 (void) { return 5; } ++int __attribute__((noinline,noclone)) foo6 (void) { return 6; } ++int __attribute__((noinline,noclone)) foo7 (void) { return 7; } ++int __attribute__((noinline,noclone)) foo8 (void) { return 8; } ++int __attribute__((noinline,noclone)) foo9 (void) { return 9; } ++int __attribute__((noinline,noclone)) foo10 (void) { return 10; } ++int __attribute__((noinline,noclone)) foo11 (void) { return 11; } ++int __attribute__((noinline,noclone)) foo12 (void) { return 12; } ++int __attribute__((noinline,noclone)) foo13 (void) { return 13; } ++int __attribute__((noinline,noclone)) foo14 (void) { return 14; } ++int __attribute__((noinline,noclone)) foo15 (void) { return 15; } ++int __attribute__((noinline,noclone)) foo16 (void) { return 16; } ++int __attribute__((noinline,noclone)) foo17 (void) { return 17; } ++int __attribute__((noinline,noclone)) foo18 (void) { return 18; } ++int __attribute__((noinline,noclone)) foo19 (void) { return 19; } ++int __attribute__((noinline,noclone)) foo20 (void) { return 20; } ++ ++ ++int __attribute__((noinline,noclone)) ++bar (int a) ++{ ++ int ret = 0; ++ ++ switch (a) ++ { ++ case 1: ret = foo1 (); break; ++ case 2: ret = foo2 (); break; ++ case 3: ret = foo3 (); break; ++ case 4: ret = foo4 (); break; ++ case 5: ret = foo5 (); break; ++ case 6: ret = foo6 (); break; ++ case 7: ret = foo7 (); break; ++ case 8: ret = foo8 (); break; ++ case 9: ret = foo9 (); break; ++ case 10: ret = foo10 (); break; ++ case 11: ret = foo11 (); break; ++ case 12: ret = foo12 (); break; ++ case 13: ret = foo13 (); break; ++ case 14: ret = foo14 (); break; ++ case 15: ret = foo15 (); break; ++ case 16: ret = foo16 (); break; ++ case 17: ret = foo17 (); break; ++ case 18: ret = foo18 (); break; ++ case 19: ret = foo19 (); break; ++ case 20: ret = foo20 (); break; ++ default: ++ __builtin_abort (); ++ } ++ ++ return ret; ++} ++ ++int ++main () ++{ ++ if (bar (3) != 3) ++ __builtin_abort (); ++ ++ return 0; ++} ++ ++/* 1 x bar ++/* { dg-final { scan-assembler-times "exrl" 1 } } */ ++ ++/* { dg-final { scan-assembler "section\t.s390_indirect_jump" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_indirect_call" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_return_fromreg" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_return_frommem" } } */ +diff -Nrup gcc/testsuite/gcc.target/s390/nobp-table-jump-z900.c gcc/testsuite/gcc.target/s390/nobp-table-jump-z900.c +--- gcc/testsuite/gcc.target/s390/nobp-table-jump-z900.c 1969-12-31 17:00:00.000000000 -0700 ++++ gcc/testsuite/gcc.target/s390/nobp-table-jump-z900.c 2018-03-27 09:33:58.837861529 -0600 +@@ -0,0 +1,78 @@ ++/* { dg-do run } */ ++/* { dg-options "-O3 -march=z900 -mzarch --save-temps -mindirect-branch-jump=thunk -mindirect-branch-table" } */ ++ ++/* case-values-threshold will be set to 20 by the back-end when jump ++ thunk are requested. */ ++ ++int __attribute__((noinline,noclone)) foo1 (void) { return 1; } ++int __attribute__((noinline,noclone)) foo2 (void) { return 2; } ++int __attribute__((noinline,noclone)) foo3 (void) { return 3; } ++int __attribute__((noinline,noclone)) foo4 (void) { return 4; } ++int __attribute__((noinline,noclone)) foo5 (void) { return 5; } ++int __attribute__((noinline,noclone)) foo6 (void) { return 6; } ++int __attribute__((noinline,noclone)) foo7 (void) { return 7; } ++int __attribute__((noinline,noclone)) foo8 (void) { return 8; } ++int __attribute__((noinline,noclone)) foo9 (void) { return 9; } ++int __attribute__((noinline,noclone)) foo10 (void) { return 10; } ++int __attribute__((noinline,noclone)) foo11 (void) { return 11; } ++int __attribute__((noinline,noclone)) foo12 (void) { return 12; } ++int __attribute__((noinline,noclone)) foo13 (void) { return 13; } ++int __attribute__((noinline,noclone)) foo14 (void) { return 14; } ++int __attribute__((noinline,noclone)) foo15 (void) { return 15; } ++int __attribute__((noinline,noclone)) foo16 (void) { return 16; } ++int __attribute__((noinline,noclone)) foo17 (void) { return 17; } ++int __attribute__((noinline,noclone)) foo18 (void) { return 18; } ++int __attribute__((noinline,noclone)) foo19 (void) { return 19; } ++int __attribute__((noinline,noclone)) foo20 (void) { return 20; } ++ ++ ++int __attribute__((noinline,noclone)) ++bar (int a) ++{ ++ int ret = 0; ++ ++ switch (a) ++ { ++ case 1: ret = foo1 (); break; ++ case 2: ret = foo2 (); break; ++ case 3: ret = foo3 (); break; ++ case 4: ret = foo4 (); break; ++ case 5: ret = foo5 (); break; ++ case 6: ret = foo6 (); break; ++ case 7: ret = foo7 (); break; ++ case 8: ret = foo8 (); break; ++ case 9: ret = foo9 (); break; ++ case 10: ret = foo10 (); break; ++ case 11: ret = foo11 (); break; ++ case 12: ret = foo12 (); break; ++ case 13: ret = foo13 (); break; ++ case 14: ret = foo14 (); break; ++ case 15: ret = foo15 (); break; ++ case 16: ret = foo16 (); break; ++ case 17: ret = foo17 (); break; ++ case 18: ret = foo18 (); break; ++ case 19: ret = foo19 (); break; ++ case 20: ret = foo20 (); break; ++ default: ++ __builtin_abort (); ++ } ++ ++ return ret; ++} ++ ++int ++main () ++{ ++ if (bar (3) != 3) ++ __builtin_abort (); ++ ++ return 0; ++} ++ ++/* 1 x bar ++/* { dg-final { scan-assembler-times "ex\t" 1 } } */ ++ ++/* { dg-final { scan-assembler "section\t.s390_indirect_jump" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_indirect_call" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_return_fromreg" } } */ ++/* { dg-final { scan-assembler-not "section\t.s390_return_frommem" } } */ diff --git a/SPECS/gcc.spec b/SPECS/gcc.spec index fb07331..97b73d9 100644 --- a/SPECS/gcc.spec +++ b/SPECS/gcc.spec @@ -79,7 +79,7 @@ Name: gcc %global gcc_version 4.8.5 %endif Version: 4.8.5 -Release: %{gcc_release}%{?dist} +Release: %{gcc_release}%{?dist}.1 %if "%{version}" != "%{gcc_version}" %define gcc_provides %{gcc_version}-16%{?dist} %endif @@ -306,6 +306,7 @@ Patch1403: gcc48-rh1535655-3.patch Patch1404: gcc48-rh1535655-4.patch Patch1405: gcc48-rh1535655-5.patch Patch1406: gcc48-rh1535655-6.patch +Patch1407: gcc48-rh1552021.patch # On ARM EABI systems, we do want -gnueabi to be part of the # target triple. @@ -1136,6 +1137,8 @@ tar xjf %{SOURCE10} %patch1404 -p1 -b .retpolines-4~ %patch1405 -p1 -b .retpolines-5~ %patch1406 -p1 -b .retpolines-6~ +%patch1407 -p0 -b .retpolines-7~ + sed -i -e 's/4\.8\.5/4.8.5/' gcc/BASE-VER echo 'Red Hat %{version}-%{gcc_release}' > gcc/DEV-PHASE @@ -3513,6 +3516,9 @@ fi %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_version}/plugin %changelog +* Tue Mar 27 2018 Jeff Law 4.8.5-29 +- s390 retpoline support for spectre mitigation (#1552021) + * Fri Jan 19 2018 Marek Polacek 4.8.5-28 - Minor testsuite fixes to clean up test results (#1469697) - retpoline support for spectre mitigation (#1535655)