"wd reg_class = %s\n"
"we reg_class = %s\n"
"wf reg_class = %s\n"
- "wg reg_class = %s\n"
- "wh reg_class = %s\n"
"wi reg_class = %s\n"
- "wj reg_class = %s\n"
- "wk reg_class = %s\n"
- "wl reg_class = %s\n"
- "wm reg_class = %s\n"
"wp reg_class = %s\n"
"wq reg_class = %s\n"
"wr reg_class = %s\n"
"wv reg_class = %s\n"
"ww reg_class = %s\n"
"wx reg_class = %s\n"
- "wz reg_class = %s\n"
"wA reg_class = %s\n"
"\n",
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_d]],
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wd]],
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_we]],
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wf]],
- reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wg]],
- reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wh]],
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wi]],
- reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wj]],
- reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wk]],
- reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wl]],
- reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wm]],
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wp]],
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wq]],
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wr]],
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wv]],
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_ww]],
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wx]],
- reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wz]],
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wA]]);
nl = "\n";
wc - Reserved to represent individual CR bits (used in LLVM).
wd - Preferred register class for V2DFmode.
wf - Preferred register class for V4SFmode.
- wg - Float register for power6x move insns.
- wh - FP register for direct move instructions.
wi - FP or VSX register to hold 64-bit integers for VSX insns.
- wj - FP or VSX register to hold 64-bit integers for direct moves.
- wk - FP or VSX register to hold 64-bit doubles for direct moves.
- wl - Float register if we can do 32-bit signed int loads.
- wm - VSX register for ISA 2.07 direct move operations.
wn - always NO_REGS.
wr - GPR if 64-bit mode is permitted.
ws - Register class to do ISA 2.06 DF operations.
wt - VSX register for TImode in VSX registers.
wv - Altivec register for ISA 2.06 VSX DF/DI load/stores.
ww - Register class to do SF conversions in with VSX operations.
- wx - Float register if we can do 32-bit int stores.
- wz - Float register if we can do 32-bit unsigned int loads. */
+ wx - Float register if we can do 32-bit int stores. */
if (TARGET_HARD_FLOAT)
{
if (TARGET_ALTIVEC)
rs6000_constraints[RS6000_CONSTRAINT_v] = ALTIVEC_REGS;
- if (TARGET_MFPGPR) /* DFmode */
- rs6000_constraints[RS6000_CONSTRAINT_wg] = FLOAT_REGS;
-
- if (TARGET_LFIWAX)
- rs6000_constraints[RS6000_CONSTRAINT_wl] = FLOAT_REGS; /* DImode */
-
- if (TARGET_DIRECT_MOVE)
- {
- rs6000_constraints[RS6000_CONSTRAINT_wh] = FLOAT_REGS;
- rs6000_constraints[RS6000_CONSTRAINT_wj] /* DImode */
- = rs6000_constraints[RS6000_CONSTRAINT_wi];
- rs6000_constraints[RS6000_CONSTRAINT_wk] /* DFmode */
- = rs6000_constraints[RS6000_CONSTRAINT_ws];
- rs6000_constraints[RS6000_CONSTRAINT_wm] = VSX_REGS;
- }
-
if (TARGET_POWERPC64)
{
rs6000_constraints[RS6000_CONSTRAINT_wr] = GENERAL_REGS;
if (TARGET_STFIWX)
rs6000_constraints[RS6000_CONSTRAINT_wx] = FLOAT_REGS; /* DImode */
- if (TARGET_LFIWZX)
- rs6000_constraints[RS6000_CONSTRAINT_wz] = FLOAT_REGS; /* DImode */
-
if (TARGET_FLOAT128_TYPE)
{
rs6000_constraints[RS6000_CONSTRAINT_wq] = VSX_REGS; /* KFmode */
rs6000_isa_flags &= ~OPTION_MASK_FLOAT128_HW;
}
+ /* -mpcrel requires prefixed load/store addressing. */
+ if (TARGET_PCREL && !TARGET_PREFIXED_ADDR)
+ {
+ if ((rs6000_isa_flags_explicit & OPTION_MASK_PCREL) != 0)
+ error ("%qs requires %qs", "-mpcrel", "-mprefixed-addr");
+
+ rs6000_isa_flags &= ~OPTION_MASK_PCREL;
+ }
+
+ /* -mprefixed-addr (and hence -mpcrel) requires -mcpu=future. */
+ if (TARGET_PREFIXED_ADDR && !TARGET_FUTURE)
+ {
+ if ((rs6000_isa_flags_explicit & OPTION_MASK_PCREL) != 0)
+ error ("%qs requires %qs", "-mprefixed-addr", "-mcpu=future");
+
+ rs6000_isa_flags &= ~(OPTION_MASK_PCREL | OPTION_MASK_PREFIXED_ADDR);
+ }
+
/* Print the options after updating the defaults. */
if (TARGET_DEBUG_REG || TARGET_DEBUG_TARGET)
rs6000_print_isa_options (stderr, 0, "after defaults", rs6000_isa_flags);
&& rs6000_tune != PROCESSOR_POWER7
&& rs6000_tune != PROCESSOR_POWER8
&& rs6000_tune != PROCESSOR_POWER9
+ && rs6000_tune != PROCESSOR_FUTURE
&& rs6000_tune != PROCESSOR_PPCA2
&& rs6000_tune != PROCESSOR_CELL
&& rs6000_tune != PROCESSOR_PPC476);
|| rs6000_tune == PROCESSOR_POWER7
|| rs6000_tune == PROCESSOR_POWER8
|| rs6000_tune == PROCESSOR_POWER9
+ || rs6000_tune == PROCESSOR_FUTURE
|| rs6000_tune == PROCESSOR_PPCE500MC
|| rs6000_tune == PROCESSOR_PPCE500MC64
|| rs6000_tune == PROCESSOR_PPCE5500
break;
case PROCESSOR_POWER9:
+ case PROCESSOR_FUTURE:
rs6000_cost = &power9_cost;
break;
/* Default CPU string for rs6000*_file_start functions. */
static const char *rs6000_default_cpu;
+#ifdef USING_ELFOS_H
+static const char *rs6000_machine;
+
+static const char *
+rs6000_machine_from_flags (void)
+{
+ if ((rs6000_isa_flags & (ISA_FUTURE_MASKS_SERVER & ~ISA_3_0_MASKS_SERVER))
+ != 0)
+ return "future";
+ if ((rs6000_isa_flags & (ISA_3_0_MASKS_SERVER & ~ISA_2_7_MASKS_SERVER)) != 0)
+ return "power9";
+ if ((rs6000_isa_flags & (ISA_2_7_MASKS_SERVER & ~ISA_2_6_MASKS_SERVER)) != 0)
+ return "power8";
+ if ((rs6000_isa_flags & (ISA_2_6_MASKS_SERVER & ~ISA_2_5_MASKS_SERVER)) != 0)
+ return "power7";
+ if ((rs6000_isa_flags & (ISA_2_5_MASKS_SERVER & ~ISA_2_4_MASKS)) != 0)
+ return "power6";
+ if ((rs6000_isa_flags & (ISA_2_4_MASKS & ~ISA_2_1_MASKS)) != 0)
+ return "power5";
+ if ((rs6000_isa_flags & ISA_2_1_MASKS) != 0)
+ return "power4";
+ if ((rs6000_isa_flags & OPTION_MASK_POWERPC64) != 0)
+ return "ppc64";
+ return "ppc";
+}
+
+static void
+emit_asm_machine (void)
+{
+ fprintf (asm_out_file, "\t.machine %s\n", rs6000_machine);
+}
+#endif
+
/* Do anything needed at the start of the asm file. */
static void
}
#ifdef USING_ELFOS_H
+ rs6000_machine = rs6000_machine_from_flags ();
if (!(rs6000_default_cpu && rs6000_default_cpu[0])
&& !global_options_set.x_rs6000_cpu_index)
- {
- fputs ("\t.machine ", asm_out_file);
- if ((rs6000_isa_flags & OPTION_MASK_MODULO) != 0)
- fputs ("power9\n", asm_out_file);
- else if ((rs6000_isa_flags & OPTION_MASK_DIRECT_MOVE) != 0)
- fputs ("power8\n", asm_out_file);
- else if ((rs6000_isa_flags & OPTION_MASK_POPCNTD) != 0)
- fputs ("power7\n", asm_out_file);
- else if ((rs6000_isa_flags & OPTION_MASK_CMPB) != 0)
- fputs ("power6\n", asm_out_file);
- else if ((rs6000_isa_flags & OPTION_MASK_POPCNTB) != 0)
- fputs ("power5\n", asm_out_file);
- else if ((rs6000_isa_flags & OPTION_MASK_MFCRF) != 0)
- fputs ("power4\n", asm_out_file);
- else if ((rs6000_isa_flags & OPTION_MASK_POWERPC64) != 0)
- fputs ("ppc64\n", asm_out_file);
- else
- fputs ("ppc\n", asm_out_file);
- }
+ emit_asm_machine ();
#endif
if (DEFAULT_ABI == ABI_ELFv2)
bool
direct_move_p (rtx op0, rtx op1)
{
- int regno0, regno1;
-
if (!REG_P (op0) || !REG_P (op1))
return false;
- if (!TARGET_DIRECT_MOVE && !TARGET_MFPGPR)
+ if (!TARGET_DIRECT_MOVE)
return false;
- regno0 = REGNO (op0);
- regno1 = REGNO (op1);
+ int regno0 = REGNO (op0);
+ int regno1 = REGNO (op1);
if (!HARD_REGISTER_NUM_P (regno0) || !HARD_REGISTER_NUM_P (regno1))
return false;
- if (INT_REGNO_P (regno0))
- return (TARGET_DIRECT_MOVE) ? VSX_REGNO_P (regno1) : FP_REGNO_P (regno1);
-
- else if (INT_REGNO_P (regno1))
- {
- if (TARGET_MFPGPR && FP_REGNO_P (regno0))
- return true;
+ if (INT_REGNO_P (regno0) && VSX_REGNO_P (regno1))
+ return true;
- else if (TARGET_DIRECT_MOVE && VSX_REGNO_P (regno0))
- return true;
- }
+ if (VSX_REGNO_P (regno0) && INT_REGNO_P (regno1))
+ return true;
return false;
}
{
case PROCESSOR_POWER8:
case PROCESSOR_POWER9:
+ case PROCESSOR_FUTURE:
if (DECIMAL_FLOAT_MODE_P (mode))
return 1;
if (VECTOR_MODE_P (mode))
return true;
}
- /* Power6+: MFTGPR or MFFGPR. */
- else if (TARGET_MFPGPR && TARGET_POWERPC64 && size == 8
- && ((to_type == GPR_REG_TYPE && from_type == FPR_REG_TYPE)
- || (to_type == FPR_REG_TYPE && from_type == GPR_REG_TYPE)))
- return true;
-
/* Move to/from SPR. */
else if ((size == 4 || (TARGET_POWERPC64 && size == 8))
&& ((to_type == GPR_REG_TYPE && from_type == SPR_REG_TYPE)
{
if (REG_P (x))
fprintf (file, "0(%s)", reg_names[ REGNO (x) ]);
+
+ /* Is it a pc-relative address? */
+ else if (pcrel_address (x, Pmode))
+ {
+ HOST_WIDE_INT offset;
+
+ if (GET_CODE (x) == CONST)
+ x = XEXP (x, 0);
+
+ if (GET_CODE (x) == PLUS)
+ {
+ offset = INTVAL (XEXP (x, 1));
+ x = XEXP (x, 0);
+ }
+ else
+ offset = 0;
+
+ output_addr_const (file, x);
+
+ if (offset)
+ fprintf (file, "%+" PRId64, offset);
+
+ fputs ("@pcrel", file);
+ }
else if (SYMBOL_REF_P (x) || GET_CODE (x) == CONST
|| GET_CODE (x) == LABEL_REF)
{
(DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic == 2
? "+32768" : ""));
- static char str[32]; /* 2 spare */
- if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
+ static char str[32]; /* 1 spare */
+ if (rs6000_pcrel_p (cfun))
+ sprintf (str, "b%s %s@notoc%s", sibcall ? "" : "l", z, arg);
+ else if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
sprintf (str, "b%s %s%s%s", sibcall ? "" : "l", z, arg,
sibcall ? "" : "\n\tnop");
else if (DEFAULT_ABI == ABI_V4)
/* Currently, funop is either 0 or 1. The maximum string is always
a !speculate 64-bit __tls_get_addr call.
+ ABI_ELFv2, pcrel:
+ . 27 .reloc .,R_PPC64_TLSGD,%2\n\t
+ . 35 .reloc .,R_PPC64_PLTSEQ_NOTOC,%z1\n\t
+ . 9 crset 2\n\t
+ . 27 .reloc .,R_PPC64_TLSGD,%2\n\t
+ . 36 .reloc .,R_PPC64_PLTCALL_NOTOC,%z1\n\t
+ . 8 beq%T1l-
+ .---
+ .142
+
ABI_AIX:
. 9 ld 2,%3\n\t
. 27 .reloc .,R_PPC64_TLSGD,%2\n\t
gcc_unreachable ();
}
+ const char *notoc = rs6000_pcrel_p (cfun) ? "_NOTOC" : "";
const char *addend = (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT
&& flag_pic == 2 ? "+32768" : "");
if (!speculate)
{
s += sprintf (s,
- "%s.reloc .,R_PPC%s_PLTSEQ,%%z%u%s\n\t",
- tls, rel64, funop, addend);
+ "%s.reloc .,R_PPC%s_PLTSEQ%s,%%z%u%s\n\t",
+ tls, rel64, notoc, funop, addend);
s += sprintf (s, "crset 2\n\t");
}
s += sprintf (s,
- "%s.reloc .,R_PPC%s_PLTCALL,%%z%u%s\n\t",
- tls, rel64, funop, addend);
+ "%s.reloc .,R_PPC%s_PLTCALL%s,%%z%u%s\n\t",
+ tls, rel64, notoc, funop, addend);
}
else if (!speculate)
s += sprintf (s, "crset 2\n\t");
- if (DEFAULT_ABI == ABI_AIX)
+ if (rs6000_pcrel_p (cfun))
+ {
+ if (speculate)
+ sprintf (s, "b%%T%ul", funop);
+ else
+ sprintf (s, "beq%%T%ul-", funop);
+ }
+ else if (DEFAULT_ABI == ABI_AIX)
{
if (speculate)
sprintf (s,
}
#if HAVE_AS_PLTSEQ
-/* Output indirect call insns.
- WHICH is 0 for tocsave, 1 for plt16_ha, 2 for plt16_lo, 3 for mtctr. */
+/* Output indirect call insns. WHICH identifies the type of sequence. */
const char *
rs6000_pltseq_template (rtx *operands, int which)
{
const char *rel64 = TARGET_64BIT ? "64" : "";
- char tls[28];
+ char tls[30];
tls[0] = 0;
if (TARGET_TLS_MARKERS && GET_CODE (operands[3]) == UNSPEC)
{
+ char off = which == RS6000_PLTSEQ_PLT_PCREL34 ? '8' : '4';
if (XINT (operands[3], 1) == UNSPEC_TLSGD)
- sprintf (tls, ".reloc .,R_PPC%s_TLSGD,%%3\n\t",
- rel64);
+ sprintf (tls, ".reloc .-%c,R_PPC%s_TLSGD,%%3\n\t",
+ off, rel64);
else if (XINT (operands[3], 1) == UNSPEC_TLSLD)
- sprintf (tls, ".reloc .,R_PPC%s_TLSLD,%%&\n\t",
- rel64);
+ sprintf (tls, ".reloc .-%c,R_PPC%s_TLSLD,%%&\n\t",
+ off, rel64);
else
gcc_unreachable ();
}
gcc_assert (DEFAULT_ABI == ABI_ELFv2 || DEFAULT_ABI == ABI_V4);
- static char str[96]; /* 15 spare */
- const char *off = WORDS_BIG_ENDIAN ? "+2" : "";
+ static char str[96]; /* 10 spare */
+ char off = WORDS_BIG_ENDIAN ? '2' : '4';
const char *addend = (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT
&& flag_pic == 2 ? "+32768" : "");
switch (which)
{
- case 0:
+ case RS6000_PLTSEQ_TOCSAVE:
sprintf (str,
- "%s.reloc .,R_PPC%s_PLTSEQ,%%z2\n\t"
- "st%s",
- tls, rel64, TARGET_64BIT ? "d 2,24(1)" : "w 2,12(1)");
+ "st%s\n\t"
+ "%s.reloc .-4,R_PPC%s_PLTSEQ,%%z2",
+ TARGET_64BIT ? "d 2,24(1)" : "w 2,12(1)",
+ tls, rel64);
break;
- case 1:
+ case RS6000_PLTSEQ_PLT16_HA:
if (DEFAULT_ABI == ABI_V4 && !flag_pic)
sprintf (str,
- "%s.reloc .%s,R_PPC%s_PLT16_HA,%%z2\n\t"
- "lis %%0,0",
+ "lis %%0,0\n\t"
+ "%s.reloc .-%c,R_PPC%s_PLT16_HA,%%z2",
tls, off, rel64);
else
sprintf (str,
- "%s.reloc .%s,R_PPC%s_PLT16_HA,%%z2%s\n\t"
- "addis %%0,%%1,0",
+ "addis %%0,%%1,0\n\t"
+ "%s.reloc .-%c,R_PPC%s_PLT16_HA,%%z2%s",
tls, off, rel64, addend);
break;
- case 2:
+ case RS6000_PLTSEQ_PLT16_LO:
sprintf (str,
- "%s.reloc .%s,R_PPC%s_PLT16_LO%s,%%z2%s\n\t"
- "l%s %%0,0(%%1)",
- tls, off, rel64, TARGET_64BIT ? "_DS" : "", addend,
- TARGET_64BIT ? "d" : "wz");
+ "l%s %%0,0(%%1)\n\t"
+ "%s.reloc .-%c,R_PPC%s_PLT16_LO%s,%%z2%s",
+ TARGET_64BIT ? "d" : "wz",
+ tls, off, rel64, TARGET_64BIT ? "_DS" : "", addend);
break;
- case 3:
+ case RS6000_PLTSEQ_MTCTR:
sprintf (str,
- "%s.reloc .,R_PPC%s_PLTSEQ,%%z2%s\n\t"
- "mtctr %%1",
+ "mtctr %%1\n\t"
+ "%s.reloc .-4,R_PPC%s_PLTSEQ,%%z2%s",
tls, rel64, addend);
break;
+ case RS6000_PLTSEQ_PLT_PCREL34:
+ sprintf (str,
+ "pl%s %%0,0(0),1\n\t"
+ "%s.reloc .-8,R_PPC%s_PLT_PCREL34_NOTOC,%%z2",
+ TARGET_64BIT ? "d" : "wz",
+ tls, rel64);
+ break;
default:
gcc_unreachable ();
}
}
#endif
+/* Helper function to return whether a MODE can do prefixed loads/stores.
+ VOIDmode is used when we are loading the pc-relative address into a base
+ register, but we are not using it as part of a memory operation. As modes
+ add support for prefixed memory, they will be added here. */
+
+static bool
+mode_supports_prefixed_address_p (machine_mode mode)
+{
+ return mode == VOIDmode;
+}
+
+/* Function to return true if ADDR is a valid prefixed memory address that uses
+ mode MODE. */
+
+bool
+rs6000_prefixed_address (rtx addr, machine_mode mode)
+{
+ if (!TARGET_PREFIXED_ADDR || !mode_supports_prefixed_address_p (mode))
+ return false;
+
+ /* Check for PC-relative addresses. */
+ if (pcrel_address (addr, Pmode))
+ return true;
+
+ /* Check for prefixed memory addresses that have a large numeric offset,
+ or an offset that can't be used for a DS/DQ-form memory operation. */
+ if (GET_CODE (addr) == PLUS)
+ {
+ rtx op0 = XEXP (addr, 0);
+ rtx op1 = XEXP (addr, 1);
+
+ if (!base_reg_operand (op0, Pmode) || !CONST_INT_P (op1))
+ return false;
+
+ HOST_WIDE_INT value = INTVAL (op1);
+ if (!SIGNED_34BIT_OFFSET_P (value, 0))
+ return false;
+
+ /* Offset larger than 16-bits? */
+ if (!SIGNED_16BIT_OFFSET_P (value, 0))
+ return true;
+
+ /* DQ instruction (bottom 4 bits must be 0) for vectors. */
+ HOST_WIDE_INT mask;
+ if (GET_MODE_SIZE (mode) >= 16)
+ mask = 15;
+
+ /* DS instruction (bottom 2 bits must be 0). For 32-bit integers, we
+ need to use DS instructions if we are sign-extending the value with
+ LWA. For 32-bit floating point, we need DS instructions to load and
+ store values to the traditional Altivec registers. */
+ else if (GET_MODE_SIZE (mode) >= 4)
+ mask = 3;
+
+ /* QImode/HImode has no restrictions. */
+ else
+ return true;
+
+ /* Return true if we must use a prefixed instruction. */
+ return (value & mask) != 0;
+ }
+
+ return false;
+}
+\f
#if defined (HAVE_GAS_HIDDEN) && !TARGET_MACHO
/* Emit an assembler directive to set symbol visibility for DECL to
VISIBILITY_TYPE. */
return get_hard_reg_initial_val (Pmode, LR_REGNO);
}
+/* Helper function for rs6000_function_ok_for_sibcall. */
+
+static bool
+rs6000_decl_ok_for_sibcall (tree decl)
+{
+ /* Sibcalls are always fine for the Darwin ABI. */
+ if (DEFAULT_ABI == ABI_DARWIN)
+ return true;
+
+ if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
+ {
+ /* Under the AIX or ELFv2 ABIs we can't allow calls to non-local
+ functions, because the callee may have a different TOC pointer to
+ the caller and there's no way to ensure we restore the TOC when
+ we return. */
+ if (!decl || DECL_EXTERNAL (decl) || DECL_WEAK (decl)
+ || !(*targetm.binds_local_p) (decl))
+ return false;
+
+ /* Similarly, if the caller preserves the TOC pointer and the callee
+ doesn't (or vice versa), proper TOC setup or restoration will be
+ missed. For example, suppose A, B, and C are in the same binary
+ and A -> B -> C. A and B preserve the TOC pointer but C does not,
+ and B -> C is eligible as a sibcall. A will call B through its
+ local entry point, so A will not restore its TOC itself. B calls
+ C with a sibcall, so it will not restore the TOC. C does not
+ preserve the TOC, so it may clobber r2 with impunity. Returning
+ from C will result in a corrupted TOC for A. */
+ else if (rs6000_fndecl_pcrel_p (decl) != rs6000_pcrel_p (cfun))
+ return false;
+
+ else
+ return true;
+ }
+
+ /* With the secure-plt SYSV ABI we can't make non-local calls when
+ -fpic/PIC because the plt call stubs use r30. */
+ if (DEFAULT_ABI != ABI_V4
+ || (TARGET_SECURE_PLT
+ && flag_pic
+ && (!decl || !((*targetm.binds_local_p) (decl)))))
+ return false;
+
+ return true;
+}
+
/* Say whether a function is a candidate for sibcall handling or not. */
static bool
return false;
}
- /* Under the AIX or ELFv2 ABIs we can't allow calls to non-local
- functions, because the callee may have a different TOC pointer to
- the caller and there's no way to ensure we restore the TOC when
- we return. With the secure-plt SYSV ABI we can't make non-local
- calls when -fpic/PIC because the plt call stubs use r30. */
- if (DEFAULT_ABI == ABI_DARWIN
- || ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
- && decl
- && !DECL_EXTERNAL (decl)
- && !DECL_WEAK (decl)
- && (*targetm.binds_local_p) (decl))
- || (DEFAULT_ABI == ABI_V4
- && (!TARGET_SECURE_PLT
- || !flag_pic
- || (decl
- && (*targetm.binds_local_p) (decl)))))
+ if (rs6000_decl_ok_for_sibcall (decl))
{
tree attr_list = TYPE_ATTRIBUTES (fntype);
/* Return whether we need to emit an ELFv2 global entry point prologue. */
static bool
-rs6000_global_entry_point_needed_p (void)
+rs6000_global_entry_point_prologue_needed_p (void)
{
/* Only needed for the ELFv2 ABI. */
if (DEFAULT_ABI != ABI_ELFv2)
if (TARGET_SINGLE_PIC_BASE)
return false;
+ /* PC-relative functions never generate a global entry point prologue. */
+ if (rs6000_pcrel_p (cfun))
+ return false;
+
/* Ensure we have a global entry point for thunks. ??? We could
avoid that if the target routine doesn't need a global entry point,
but we do not know whether this is the case at this point. */
rs6000_output_function_prologue (FILE *file)
{
if (!cfun->is_thunk)
- rs6000_output_savres_externs (file);
+ {
+ rs6000_output_savres_externs (file);
+#ifdef USING_ELFOS_H
+ const char *curr_machine = rs6000_machine_from_flags ();
+ if (rs6000_machine != curr_machine)
+ {
+ rs6000_machine = curr_machine;
+ emit_asm_machine ();
+ }
+#endif
+ }
/* ELFv2 ABI r2 setup code and local entry point. This must follow
immediately after the global entry point label. */
- if (rs6000_global_entry_point_needed_p ())
+ if (rs6000_global_entry_point_prologue_needed_p ())
{
const char *name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
-
(*targetm.asm_out.internal_label) (file, "LCF", rs6000_pic_labelno);
if (TARGET_CMODEL != CMODEL_LARGE)
fputs ("\n", file);
}
+ else if (rs6000_pcrel_p (cfun))
+ {
+ const char *name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
+ /* All functions compiled to use PC-relative addressing will
+ have a .localentry value of 0 or 1. For now we set it to
+ 1 all the time, indicating that the function may clobber
+ the TOC register r2. Later we may optimize this by setting
+ it to 0 if the function is a leaf and does not clobber r2. */
+ fputs ("\t.localentry\t", file);
+ assemble_name (file, name);
+ fputs (",1\n", file);
+ }
+
/* Output -mprofile-kernel code. This needs to be done here instead of
in output_function_profile since it must go after the ELFv2 ABI
local entry point. */
/* Run just enough of rest_of_compilation to get the insns emitted.
There's not really enough bulk here to make other passes such as
- instruction scheduling worth while. Note that use_thunk calls
- assemble_start_function and assemble_end_function. */
+ instruction scheduling worth while. */
insn = get_insns ();
shorten_branches (insn);
assemble_start_function (thunk_fndecl, fnname);
some cycles later. */
/* Separate a load from a narrower, dependent store. */
- if ((rs6000_sched_groups || rs6000_tune == PROCESSOR_POWER9)
+ if ((rs6000_sched_groups || rs6000_tune == PROCESSOR_POWER9
+ || rs6000_tune == PROCESSOR_FUTURE)
&& GET_CODE (PATTERN (insn)) == SET
&& GET_CODE (PATTERN (dep_insn)) == SET
&& MEM_P (XEXP (PATTERN (insn), 1))
|| rs6000_tune == PROCESSOR_POWER7
|| rs6000_tune == PROCESSOR_POWER8
|| rs6000_tune == PROCESSOR_POWER9
+ || rs6000_tune == PROCESSOR_FUTURE
|| rs6000_tune == PROCESSOR_CELL)
&& recog_memoized (dep_insn)
&& (INSN_CODE (dep_insn) >= 0))
case PROCESSOR_POWER8:
return 7;
case PROCESSOR_POWER9:
+ case PROCESSOR_FUTURE:
return 6;
default:
return 1;
if (TARGET_PLTSEQ)
{
rtx base = const0_rtx;
- int regno;
- if (DEFAULT_ABI == ABI_ELFv2)
+ int regno = 12;
+ if (rs6000_pcrel_p (cfun))
{
- base = gen_rtx_REG (Pmode, TOC_REGISTER);
- regno = 12;
+ rtx reg = gen_rtx_REG (Pmode, regno);
+ rtx u = gen_rtx_UNSPEC (Pmode, gen_rtvec (3, base, call_ref, arg),
+ UNSPEC_PLT_PCREL);
+ emit_insn (gen_rtx_SET (reg, u));
+ return reg;
}
+
+ if (DEFAULT_ABI == ABI_ELFv2)
+ base = gen_rtx_REG (Pmode, TOC_REGISTER);
else
{
if (flag_pic)
ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
- if (TARGET_CMODEL == CMODEL_LARGE && rs6000_global_entry_point_needed_p ())
+ if (TARGET_CMODEL == CMODEL_LARGE
+ && rs6000_global_entry_point_prologue_needed_p ())
{
char buf[256];
{
if (TARGET_DIRECT_MOVE)
{
- if (rs6000_tune == PROCESSOR_POWER9)
- ret = 2 * hard_regno_nregs (FIRST_GPR_REGNO, mode);
+ /* Keep the cost for direct moves above that for within
+ a register class even if the actual processor cost is
+ comparable. We do this because a direct move insn
+ can't be a nop, whereas with ideal register
+ allocation a move within the same class might turn
+ out to be a nop. */
+ if (rs6000_tune == PROCESSOR_POWER9
+ || rs6000_tune == PROCESSOR_FUTURE)
+ ret = 3 * hard_regno_nregs (FIRST_GPR_REGNO, mode);
else
ret = 4 * hard_regno_nregs (FIRST_GPR_REGNO, mode);
/* SFmode requires a conversion when moving between gprs
{ "float128", OPTION_MASK_FLOAT128_KEYWORD, false, true },
{ "float128-hardware", OPTION_MASK_FLOAT128_HW, false, true },
{ "fprnd", OPTION_MASK_FPRND, false, true },
+ { "future", OPTION_MASK_FUTURE, false, true },
{ "hard-dfp", OPTION_MASK_DFP, false, true },
{ "htm", OPTION_MASK_HTM, false, true },
{ "isel", OPTION_MASK_ISEL, false, true },
{ "mfcrf", OPTION_MASK_MFCRF, false, true },
- { "mfpgpr", OPTION_MASK_MFPGPR, false, true },
+ { "mfpgpr", 0, false, true },
{ "modulo", OPTION_MASK_MODULO, false, true },
{ "mulhw", OPTION_MASK_MULHW, false, true },
{ "multiple", OPTION_MASK_MULTIPLE, false, true },
+ { "pcrel", OPTION_MASK_PCREL, false, true },
{ "popcntb", OPTION_MASK_POPCNTB, false, true },
{ "popcntd", OPTION_MASK_POPCNTD, false, true },
{ "power8-fusion", OPTION_MASK_P8_FUSION, false, true },
{ "power9-vector", OPTION_MASK_P9_VECTOR, false, true },
{ "powerpc-gfxopt", OPTION_MASK_PPC_GFXOPT, false, true },
{ "powerpc-gpopt", OPTION_MASK_PPC_GPOPT, false, true },
+ { "prefixed-addr", OPTION_MASK_PREFIXED_ADDR, false, true },
{ "quad-memory", OPTION_MASK_QUAD_MEMORY, false, true },
{ "quad-memory-atomic", OPTION_MASK_QUAD_MEMORY_ATOMIC, false, true },
{ "recip-precision", OPTION_MASK_RECIP_PRECISION, false, true },
if (!SYMBOL_REF_P (func)
|| (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (func)))
{
- /* Save the TOC into its reserved slot before the call,
- and prepare to restore it after the call. */
- rtx stack_toc_offset = GEN_INT (RS6000_TOC_SAVE_SLOT);
- rtx stack_toc_unspec = gen_rtx_UNSPEC (Pmode,
- gen_rtvec (1, stack_toc_offset),
- UNSPEC_TOCSLOT);
- toc_restore = gen_rtx_SET (toc_reg, stack_toc_unspec);
-
- /* Can we optimize saving the TOC in the prologue or
- do we need to do it at every call? */
- if (TARGET_SAVE_TOC_INDIRECT && !cfun->calls_alloca)
- cfun->machine->save_toc_in_prologue = true;
- else
+ if (!rs6000_pcrel_p (cfun))
{
- rtx stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
- rtx stack_toc_mem = gen_frame_mem (Pmode,
- gen_rtx_PLUS (Pmode, stack_ptr,
- stack_toc_offset));
- MEM_VOLATILE_P (stack_toc_mem) = 1;
- if (is_pltseq_longcall)
+ /* Save the TOC into its reserved slot before the call,
+ and prepare to restore it after the call. */
+ rtx stack_toc_offset = GEN_INT (RS6000_TOC_SAVE_SLOT);
+ rtx stack_toc_unspec = gen_rtx_UNSPEC (Pmode,
+ gen_rtvec (1, stack_toc_offset),
+ UNSPEC_TOCSLOT);
+ toc_restore = gen_rtx_SET (toc_reg, stack_toc_unspec);
+
+ /* Can we optimize saving the TOC in the prologue or
+ do we need to do it at every call? */
+ if (TARGET_SAVE_TOC_INDIRECT && !cfun->calls_alloca)
+ cfun->machine->save_toc_in_prologue = true;
+ else
{
- /* Use USPEC_PLTSEQ here to emit every instruction in an
- inline PLT call sequence with a reloc, enabling the
- linker to edit the sequence back to a direct call
- when that makes sense. */
- rtvec v = gen_rtvec (3, toc_reg, func_desc, tlsarg);
- rtx mark_toc_reg = gen_rtx_UNSPEC (Pmode, v, UNSPEC_PLTSEQ);
- emit_insn (gen_rtx_SET (stack_toc_mem, mark_toc_reg));
+ rtx stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
+ rtx stack_toc_mem = gen_frame_mem (Pmode,
+ gen_rtx_PLUS (Pmode, stack_ptr,
+ stack_toc_offset));
+ MEM_VOLATILE_P (stack_toc_mem) = 1;
+ if (is_pltseq_longcall)
+ {
+ rtvec v = gen_rtvec (3, toc_reg, func_desc, tlsarg);
+ rtx mark_toc_reg = gen_rtx_UNSPEC (Pmode, v, UNSPEC_PLTSEQ);
+ emit_insn (gen_rtx_SET (stack_toc_mem, mark_toc_reg));
+ }
+ else
+ emit_move_insn (stack_toc_mem, toc_reg);
}
- else
- emit_move_insn (stack_toc_mem, toc_reg);
}
if (DEFAULT_ABI == ABI_ELFv2)
}
else
{
- /* Direct calls use the TOC: for local calls, the callee will
- assume the TOC register is set; for non-local calls, the
- PLT stub needs the TOC register. */
- abi_reg = toc_reg;
+ /* No TOC register needed for calls from PC-relative callers. */
+ if (!rs6000_pcrel_p (cfun))
+ /* Direct calls use the TOC: for local calls, the callee will
+ assume the TOC register is set; for non-local calls, the
+ PLT stub needs the TOC register. */
+ abi_reg = toc_reg;
func_addr = func;
}
insn = emit_call_insn (insn);
/* Note use of the TOC register. */
- use_reg (&CALL_INSN_FUNCTION_USAGE (insn), gen_rtx_REG (Pmode, TOC_REGNUM));
+ if (!rs6000_pcrel_p (cfun))
+ use_reg (&CALL_INSN_FUNCTION_USAGE (insn),
+ gen_rtx_REG (Pmode, TOC_REGNUM));
}
/* Expand code to perform a call under the SYSV4 ABI. */
return (cfun && cfun->machine && cfun->machine->save_toc_in_prologue);
}
+/* Return whether we should generate PC-relative code for FNDECL. */
+bool
+rs6000_fndecl_pcrel_p (const_tree fndecl)
+{
+ if (DEFAULT_ABI != ABI_ELFv2)
+ return false;
+
+ struct cl_target_option *opts = target_opts_for_fn (fndecl);
+
+ return ((opts->x_rs6000_isa_flags & OPTION_MASK_PCREL) != 0
+ && TARGET_CMODEL == CMODEL_MEDIUM);
+}
+
+/* Return whether we should generate PC-relative code for *FN. */
+bool
+rs6000_pcrel_p (struct function *fn)
+{
+ if (DEFAULT_ABI != ABI_ELFv2)
+ return false;
+
+ /* Optimize usual case. */
+ if (fn == cfun)
+ return ((rs6000_isa_flags & OPTION_MASK_PCREL) != 0
+ && TARGET_CMODEL == CMODEL_MEDIUM);
+
+ return rs6000_fndecl_pcrel_p (fn->decl);
+}
+
#ifdef HAVE_GAS_HIDDEN
# define USE_HIDDEN_LINKONCE 1
#else