You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1966 lines
60 KiB
1966 lines
60 KiB
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 <regno> */ |
|
+ 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<mode>_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<mode>" |
|
+ [(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<mode>_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<mode>" |
|
+ [(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<mode>_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<mode>" |
|
+ [(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<mode>" |
|
[(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<mode>_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" } } */
|
|
|