#undef TARGET_LEGITIMATE_CONSTANT_P
#define TARGET_LEGITIMATE_CONSTANT_P rs6000_legitimate_constant_p
-struct gcc_target targetm = TARGET_INITIALIZER;
\f
/* Simplifications for entries below. */
target_option_default_node = target_option_current_node
= build_target_option_node ();
+ /* If not explicitly specified via option, decide whether to generate the
+ extra blr's required to preserve the link stack on some cpus (eg, 476). */
+ if (TARGET_LINK_STACK == -1)
+ SET_TARGET_LINK_STACK (rs6000_cpu == PROCESSOR_PPC476 && flag_pic);
+
return ret;
}
lab = gen_label_rtx ();
emit_insn (gen_load_toc_v4_PIC_1b (gsym, lab));
emit_move_insn (tmp1, gen_rtx_REG (Pmode, LR_REGNO));
+ if (TARGET_LINK_STACK)
+ emit_insn (gen_addsi3 (tmp1, tmp1, GEN_INT (4)));
emit_move_insn (tmp2, mem);
last = emit_insn (gen_addsi3 (got, tmp1, tmp2));
set_unique_reg_note (last, REG_EQUAL, gsym);
lab = gen_label_rtx ();
emit_insn (gen_load_toc_v4_PIC_1b (tocsym, lab));
emit_move_insn (dest, gen_rtx_REG (Pmode, LR_REGNO));
+ if (TARGET_LINK_STACK)
+ emit_insn (gen_addsi3 (dest, dest, GEN_INT (4)));
emit_move_insn (temp0, gen_rtx_MEM (Pmode, dest));
}
emit_insn (gen_addsi3 (dest, temp0, dest));
}
else if (TARGET_SECURE_PLT && flag_pic)
{
- asm_fprintf (file, "\tbcl 20,31,1f\n1:\n\t{st|stw} %s,4(%s)\n",
+ if (TARGET_LINK_STACK)
+ {
+ char name[32];
+ get_ppc476_thunk_name (name);
+ asm_fprintf (file, "\tbl %s\n", name);
+ }
+ else
+ asm_fprintf (file, "\tbcl 20,31,1f\n1:\n");
+ asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
reg_names[0], reg_names[1]);
asm_fprintf (file, "\tmflr %s\n", reg_names[12]);
asm_fprintf (file, "\t{cau|addis} %s,%s,",
asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
reg_names[0], reg_names[1]);
/* Now, we need to get the address of the label. */
- fputs ("\tbcl 20,31,1f\n\t.long ", file);
- assemble_name (file, buf);
- fputs ("-.\n1:", file);
- asm_fprintf (file, "\tmflr %s\n", reg_names[11]);
+ if (TARGET_LINK_STACK)
+ {
+ char name[32];
+ get_ppc476_thunk_name (name);
+ asm_fprintf (file, "\tbl %s\n\tb 1f\n\t.long ", name);
+ assemble_name (file, buf);
+ fputs ("-.\n1:", file);
+ asm_fprintf (file, "\tmflr %s\n", reg_names[11]);
+ asm_fprintf (file, "\taddi %s,%s,4\n",
+ reg_names[11], reg_names[11]);
+ }
+ else
+ {
+ fputs ("\tbcl 20,31,1f\n\t.long ", file);
+ assemble_name (file, buf);
+ fputs ("-.\n1:", file);
+ asm_fprintf (file, "\tmflr %s\n", reg_names[11]);
+ }
asm_fprintf (file, "\t{l|lwz} %s,0(%s)\n",
reg_names[0], reg_names[11]);
asm_fprintf (file, "\t{cax|add} %s,%s,%s\n",
#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
if (flag_pic)
{
- strcat (tmp_buf, ":\n\tmflr r0\n\tbcl 20,31,");
- strcat (tmp_buf, label);
- strcat (tmp_buf, "_pic\n");
- strcat (tmp_buf, label);
- strcat (tmp_buf, "_pic:\n\tmflr r11\n");
+ if (TARGET_LINK_STACK)
+ {
+ char name[32];
+ get_ppc64_thunk_name (name);
+ strcat (tmp_buf, ":\n\tmflr r0\n\tbl ");
+ strcat (tmp_buf, name);
+ strcat (tmp_buf, "\n");
+ strcat (tmp_buf, label);
+ strcat (tmp_buf, "_pic:\n\tmflr r11\n");
+ }
+ else
+ {
+ strcat (tmp_buf, ":\n\tmflr r0\n\tbcl 20,31,");
+ strcat (tmp_buf, label);
+ strcat (tmp_buf, "_pic\n");
+ strcat (tmp_buf, label);
+ strcat (tmp_buf, "_pic:\n\tmflr r11\n");
+ }
strcat (tmp_buf, "\taddis r11,r11,ha16(");
strcat (tmp_buf, name_buf);
sprintf (local_label_0, "\"L%011d$spb\"", label);
fprintf (file, "\tmflr r0\n");
- fprintf (file, "\tbcl 20,31,%s\n", local_label_0);
- fprintf (file, "%s:\n\tmflr r11\n", local_label_0);
+ if (TARGET_LINK_STACK)
+ {
+ char name[32];
+ get_ppc476_thunk_name (name);
+ fprintf (file, "\tbl %s\n", name);
+ fprintf (file, "%s:\n\tmflr r11\n", local_label_0);
+ }
+ else
+ {
+ fprintf (file, "\tbcl 20,31,%s\n", local_label_0);
+ fprintf (file, "%s:\n\tmflr r11\n", local_label_0);
+ }
fprintf (file, "\taddis r11,r11,ha16(%s-%s)\n",
lazy_ptr_name, local_label_0);
fprintf (file, "\tmtlr r0\n");
return (cfun && cfun->machine && cfun->machine->save_toc_in_prologue);
}
+/* Fills in the label name that should be used for a 476 link stack thunk. */
+
+void
+get_ppc476_thunk_name (char name[32])
+{
+ gcc_assert (TARGET_LINK_STACK);
+
+ if (HAVE_GAS_HIDDEN)
+ sprintf (name, "__ppc476.get_thunk");
+ else
+ ASM_GENERATE_INTERNAL_LABEL (name, "LPPC476_", 0);
+}
+
+/* This function emits the simple thunk routine that is used to preserve
+ the link stack on the 476 cpu. */
+
+static void
+rs6000_code_end (void)
+{
+ char name[32];
+ tree decl;
+
+ if (!TARGET_LINK_STACK)
+ return;
+
+ get_ppc476_thunk_name (name);
+
+ decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, get_identifier (name),
+ 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;
+
+ if (HAVE_GAS_HIDDEN)
+ {
+ DECL_COMDAT_GROUP (decl) = DECL_ASSEMBLER_NAME (decl);
+ targetm.asm_out.unique_section (decl, 0);
+ switch_to_section (get_named_section (decl, NULL, 0));
+ DECL_WEAK (decl) = 1;
+ ASM_WEAKEN_DECL (asm_out_file, decl, name, 0);
+ targetm.asm_out.globalize_label (asm_out_file, name);
+ targetm.asm_out.assemble_visibility (decl, VISIBILITY_HIDDEN);
+ ASM_DECLARE_FUNCTION_NAME (asm_out_file, name, decl);
+ }
+ else
+ {
+ switch_to_section (text_section);
+ ASM_OUTPUT_LABEL (asm_out_file, name);
+ }
+
+ DECL_INITIAL (decl) = make_node (BLOCK);
+ current_function_decl = decl;
+ init_function_start (decl);
+ first_function_block_is_cold = false;
+ /* Make sure unwind info is emitted for the thunk if needed. */
+ final_start_function (emit_barrier (), asm_out_file, 1);
+
+ fputs ("\tblr\n", asm_out_file);
+
+ final_end_function ();
+ init_insn_lengths ();
+ free_after_compilation (cfun);
+ set_cfun (NULL);
+ current_function_decl = NULL;
+}
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+
#include "gt-rs6000.h"
[(set_attr "type" "branch")
(set_attr "length" "4")])
-(define_insn "load_toc_v4_PIC_1"
+(define_expand "load_toc_v4_PIC_1"
+ [(parallel [(set (reg:SI LR_REGNO)
+ (match_operand:SI 0 "immediate_operand" "s"))
+ (use (unspec [(match_dup 0)] UNSPEC_TOC))])]
+ "TARGET_ELF && DEFAULT_ABI != ABI_AIX
+ && (flag_pic == 2 || (flag_pic && TARGET_SECURE_PLT))"
+ "")
+
+(define_insn "load_toc_v4_PIC_1_normal"
[(set (reg:SI LR_REGNO)
(match_operand:SI 0 "immediate_operand" "s"))
(use (unspec [(match_dup 0)] UNSPEC_TOC))]
- "TARGET_ELF && DEFAULT_ABI != ABI_AIX
+ "!TARGET_LINK_STACK && TARGET_ELF && DEFAULT_ABI != ABI_AIX
&& (flag_pic == 2 || (flag_pic && TARGET_SECURE_PLT))"
"bcl 20,31,%0\\n%0:"
[(set_attr "type" "branch")
(set_attr "length" "4")])
-(define_insn "load_toc_v4_PIC_1b"
+(define_insn "load_toc_v4_PIC_1_476"
+ [(set (reg:SI LR_REGNO)
+ (match_operand:SI 0 "immediate_operand" "s"))
+ (use (unspec [(match_dup 0)] UNSPEC_TOC))]
+ "TARGET_LINK_STACK && TARGET_ELF && DEFAULT_ABI != ABI_AIX
+ && (flag_pic == 2 || (flag_pic && TARGET_SECURE_PLT))"
+ "*
+{
+ char name[32];
+ static char templ[32];
+
+ get_ppc476_thunk_name (name);
+ sprintf (templ, \"bl %s\\n%%0:\", name);
+ return templ;
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4")])
+
+(define_expand "load_toc_v4_PIC_1b"
+ [(parallel [(set (reg:SI LR_REGNO)
+ (unspec:SI [(match_operand:SI 0 "immediate_operand" "s")
+ (label_ref (match_operand 1 "" ""))]
+ UNSPEC_TOCPTR))
+ (match_dup 1)])]
+ "TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2"
+ "")
+
+(define_insn "load_toc_v4_PIC_1b_normal"
[(set (reg:SI LR_REGNO)
(unspec:SI [(match_operand:SI 0 "immediate_operand" "s")
(label_ref (match_operand 1 "" ""))]
UNSPEC_TOCPTR))
(match_dup 1)]
- "TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2"
+ "!TARGET_LINK_STACK && TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2"
"bcl 20,31,$+8\;.long %0-$"
[(set_attr "type" "branch")
(set_attr "length" "8")])
+(define_insn "load_toc_v4_PIC_1b_476"
+ [(set (reg:SI LR_REGNO)
+ (unspec:SI [(match_operand:SI 0 "immediate_operand" "s")
+ (label_ref (match_operand 1 "" ""))]
+ UNSPEC_TOCPTR))
+ (match_dup 1)]
+ "TARGET_LINK_STACK && TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2"
+ "*
+{
+ char name[32];
+ static char templ[32];
+
+ get_ppc476_thunk_name (name);
+ sprintf (templ, \"bl %s\\n\\tb $+8\\n\\t.long %%0-$\", name);
+ return templ;
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "16")])
+
(define_insn "load_toc_v4_PIC_2"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(mem:SI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "b")