static void macho_branch_islands (void);
static tree get_prev_label (tree);
#endif
-static rtx rs6000_legitimize_reload_address (rtx, machine_mode, int, int,
- int, int *);
-static rtx rs6000_debug_legitimize_reload_address (rtx, machine_mode, int,
- int, int, int *);
static bool rs6000_mode_dependent_address (const_rtx);
static bool rs6000_debug_mode_dependent_address (const_rtx);
static bool rs6000_offsettable_memref_p (rtx, machine_mode, bool);
static bool rs6000_save_toc_in_prologue_p (void);
static rtx rs6000_internal_arg_pointer (void);
-rtx (*rs6000_legitimize_reload_address_ptr) (rtx, machine_mode, int, int,
- int, int *)
- = rs6000_legitimize_reload_address;
-
static bool (*rs6000_mode_dependent_address_ptr) (const_rtx)
= rs6000_mode_dependent_address;
/* Default register names. */
char rs6000_reg_names[][8] =
{
+ /* GPRs */
"0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "10", "11", "12", "13", "14", "15",
"16", "17", "18", "19", "20", "21", "22", "23",
"24", "25", "26", "27", "28", "29", "30", "31",
+ /* FPRs */
"0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "10", "11", "12", "13", "14", "15",
"16", "17", "18", "19", "20", "21", "22", "23",
"24", "25", "26", "27", "28", "29", "30", "31",
- "mq", "lr", "ctr","ap",
+ /* VRs */
"0", "1", "2", "3", "4", "5", "6", "7",
- "ca",
- /* AltiVec registers. */
- "0", "1", "2", "3", "4", "5", "6", "7",
- "8", "9", "10", "11", "12", "13", "14", "15",
- "16", "17", "18", "19", "20", "21", "22", "23",
- "24", "25", "26", "27", "28", "29", "30", "31",
- "vrsave", "vscr",
- /* Soft frame pointer. */
- "sfp",
- /* HTM SPR registers. */
- "tfhar", "tfiar", "texasr"
+ "8", "9", "10", "11", "12", "13", "14", "15",
+ "16", "17", "18", "19", "20", "21", "22", "23",
+ "24", "25", "26", "27", "28", "29", "30", "31",
+ /* lr ctr ca ap */
+ "lr", "ctr", "ca", "ap",
+ /* cr0..cr7 */
+ "0", "1", "2", "3", "4", "5", "6", "7",
+ /* vrsave vscr sfp */
+ "vrsave", "vscr", "sfp",
};
#ifdef TARGET_REGNAMES
static const char alt_reg_names[][8] =
{
- "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7",
- "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
- "%r16", "%r17", "%r18", "%r19", "%r20", "%r21", "%r22", "%r23",
- "%r24", "%r25", "%r26", "%r27", "%r28", "%r29", "%r30", "%r31",
- "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
- "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15",
- "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23",
- "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31",
- "mq", "lr", "ctr", "ap",
- "%cr0", "%cr1", "%cr2", "%cr3", "%cr4", "%cr5", "%cr6", "%cr7",
- "ca",
- /* AltiVec registers. */
- "%v0", "%v1", "%v2", "%v3", "%v4", "%v5", "%v6", "%v7",
+ /* GPRs */
+ "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7",
+ "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
+ "%r16", "%r17", "%r18", "%r19", "%r20", "%r21", "%r22", "%r23",
+ "%r24", "%r25", "%r26", "%r27", "%r28", "%r29", "%r30", "%r31",
+ /* FPRs */
+ "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
+ "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15",
+ "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23",
+ "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31",
+ /* VRs */
+ "%v0", "%v1", "%v2", "%v3", "%v4", "%v5", "%v6", "%v7",
"%v8", "%v9", "%v10", "%v11", "%v12", "%v13", "%v14", "%v15",
"%v16", "%v17", "%v18", "%v19", "%v20", "%v21", "%v22", "%v23",
"%v24", "%v25", "%v26", "%v27", "%v28", "%v29", "%v30", "%v31",
- "vrsave", "vscr",
- /* Soft frame pointer. */
- "sfp",
- /* HTM SPR registers. */
- "tfhar", "tfiar", "texasr"
+ /* lr ctr ca ap */
+ "lr", "ctr", "ca", "ap",
+ /* cr0..cr7 */
+ "%cr0", "%cr1", "%cr2", "%cr3", "%cr4", "%cr5", "%cr6", "%cr7",
+ /* vrsave vscr sfp */
+ "vrsave", "vscr", "sfp",
};
#endif
#define TARGET_REGISTER_MOVE_COST rs6000_register_move_cost
#undef TARGET_MEMORY_MOVE_COST
#define TARGET_MEMORY_MOVE_COST rs6000_memory_move_cost
+#undef TARGET_IRA_CHANGE_PSEUDO_ALLOCNO_CLASS
+#define TARGET_IRA_CHANGE_PSEUDO_ALLOCNO_CLASS \
+ rs6000_ira_change_pseudo_allocno_class
#undef TARGET_CANNOT_COPY_INSN_P
#define TARGET_CANNOT_COPY_INSN_P rs6000_cannot_copy_insn_p
#undef TARGET_RTX_COSTS
"f reg_class = %s\n"
"v reg_class = %s\n"
"wa reg_class = %s\n"
- "wb reg_class = %s\n"
"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"
- "wo reg_class = %s\n"
"wp reg_class = %s\n"
"wq reg_class = %s\n"
"wr reg_class = %s\n"
"ws reg_class = %s\n"
"wt reg_class = %s\n"
- "wu reg_class = %s\n"
"wv reg_class = %s\n"
"ww reg_class = %s\n"
"wx reg_class = %s\n"
- "wy reg_class = %s\n"
- "wz reg_class = %s\n"
"wA reg_class = %s\n"
- "wH reg_class = %s\n"
- "wI reg_class = %s\n"
- "wJ reg_class = %s\n"
- "wK reg_class = %s\n"
"\n",
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_d]],
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_f]],
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_v]],
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wa]],
- reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wb]],
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_wo]],
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_ws]],
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wt]],
- reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wu]],
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_wy]],
- reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wz]],
- reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wA]],
- 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_wA]]);
nl = "\n";
for (m = 0; m < NUM_MACHINE_MODES; ++m)
rs6000_regno_regclass[CA_REGNO] = NO_REGS;
rs6000_regno_regclass[VRSAVE_REGNO] = VRSAVE_REGS;
rs6000_regno_regclass[VSCR_REGNO] = VRSAVE_REGS;
- rs6000_regno_regclass[TFHAR_REGNO] = SPR_REGS;
- rs6000_regno_regclass[TFIAR_REGNO] = SPR_REGS;
- rs6000_regno_regclass[TEXASR_REGNO] = SPR_REGS;
rs6000_regno_regclass[ARG_POINTER_REGNUM] = BASE_REGS;
rs6000_regno_regclass[FRAME_POINTER_REGNUM] = BASE_REGS;
below. */
gcc_assert ((int)VECTOR_NONE == 0);
memset ((void *) &rs6000_vector_unit[0], '\0', sizeof (rs6000_vector_unit));
- memset ((void *) &rs6000_vector_mem[0], '\0', sizeof (rs6000_vector_unit));
+ memset ((void *) &rs6000_vector_mem[0], '\0', sizeof (rs6000_vector_mem));
gcc_assert ((int)CODE_FOR_nothing == 0);
memset ((void *) ®_addr[0], '\0', sizeof (reg_addr));
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.
- wu - Altivec register for ISA 2.07 VSX SF/SI load/stores.
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.
- wy - Register class to do ISA 2.07 SF operations.
- wz - Float register if we can do 32-bit unsigned int loads.
- wH - Altivec register if SImode is allowed in VSX registers.
- wI - VSX register if SImode is allowed in VSX registers.
- wJ - VSX register if QImode/HImode are allowed in VSX registers.
- wK - Altivec register if QImode/HImode are allowed in VSX registers. */
+ 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_P8_VECTOR) /* SFmode */
- {
- rs6000_constraints[RS6000_CONSTRAINT_wu] = ALTIVEC_REGS;
- rs6000_constraints[RS6000_CONSTRAINT_wy] = VSX_REGS;
- rs6000_constraints[RS6000_CONSTRAINT_ww] = VSX_REGS;
- }
+ rs6000_constraints[RS6000_CONSTRAINT_ww] = VSX_REGS;
else if (TARGET_VSX)
rs6000_constraints[RS6000_CONSTRAINT_ww] = FLOAT_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_constraints[RS6000_CONSTRAINT_wp] = VSX_REGS; /* TFmode */
}
- if (TARGET_P9_VECTOR)
- {
- /* Support for new D-form instructions. */
- rs6000_constraints[RS6000_CONSTRAINT_wb] = ALTIVEC_REGS;
-
- /* Support for ISA 3.0 (power9) vectors. */
- rs6000_constraints[RS6000_CONSTRAINT_wo] = VSX_REGS;
- }
-
/* Support for new direct moves (ISA 3.0 + 64bit). */
if (TARGET_DIRECT_MOVE_128)
rs6000_constraints[RS6000_CONSTRAINT_we] = VSX_REGS;
- /* Support small integers in VSX registers. */
- if (TARGET_P8_VECTOR)
- {
- rs6000_constraints[RS6000_CONSTRAINT_wH] = ALTIVEC_REGS;
- rs6000_constraints[RS6000_CONSTRAINT_wI] = FLOAT_REGS;
- if (TARGET_P9_VECTOR)
- {
- rs6000_constraints[RS6000_CONSTRAINT_wJ] = FLOAT_REGS;
- rs6000_constraints[RS6000_CONSTRAINT_wK] = ALTIVEC_REGS;
- }
- }
-
/* Set up the reload helper and direct move functions. */
if (TARGET_VSX || TARGET_ALTIVEC)
{
for (r = 0; HARD_REGISTER_NUM_P (r); ++r)
for (m = 0; m < NUM_MACHINE_MODES; ++m)
rs6000_hard_regno_nregs[m][r]
- = rs6000_hard_regno_nregs_internal (r, (machine_mode)m);
+ = rs6000_hard_regno_nregs_internal (r, (machine_mode) m);
/* Precalculate TARGET_HARD_REGNO_MODE_OK. */
for (r = 0; HARD_REGISTER_NUM_P (r); ++r)
for (m = 0; m < NUM_MACHINE_MODES; ++m)
- if (rs6000_hard_regno_mode_ok_uncached (r, (machine_mode)m))
- rs6000_hard_regno_mode_ok_p[m][r] = true;
+ rs6000_hard_regno_mode_ok_p[m][r]
+ = rs6000_hard_regno_mode_ok_uncached (r, (machine_mode) m);
/* Precalculate CLASS_MAX_NREGS sizes. */
for (c = 0; c < LIM_REG_CLASSES; ++c)
if (main_target_opt != NULL
&& (main_target_opt->x_rs6000_long_double_type_size
!= default_long_double_size))
- error ("target attribute or pragma changes long double size");
+ error ("target attribute or pragma changes %<long double%> size");
else
rs6000_long_double_type_size = default_long_double_size;
}
{
warned_change_long_double = true;
if (TARGET_IEEEQUAD)
- warning (OPT_Wpsabi, "Using IEEE extended precision long double");
+ warning (OPT_Wpsabi, "Using IEEE extended precision "
+ "%<long double%>");
else
- warning (OPT_Wpsabi, "Using IBM extended precision long double");
+ warning (OPT_Wpsabi, "Using IBM extended precision "
+ "%<long double%>");
}
}
}
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_debug_can_change_mode_class;
rs6000_preferred_reload_class_ptr
= rs6000_debug_preferred_reload_class;
- rs6000_legitimize_reload_address_ptr
- = rs6000_debug_legitimize_reload_address;
rs6000_mode_dependent_address_ptr
= rs6000_debug_mode_dependent_address;
}
&& 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)
default:
break;
case E_V1TImode:
- gcc_assert (INTVAL (elt) == 0 && inner_mode == TImode);
emit_move_insn (target, gen_lowpart (TImode, vec));
break;
case E_V2DFmode:
switch (mode)
{
+ case E_V1TImode:
+ emit_move_insn (target, gen_lowpart (TImode, vec));
+ return;
+
case E_V2DFmode:
emit_insn (gen_vsx_extract_v2df_var (target, vec, elt));
return;
}
}
- gcc_assert (CONST_INT_P (elt));
-
/* Allocate mode-sized buffer. */
mem = assign_stack_temp (mode, GET_MODE_SIZE (mode));
emit_move_insn (mem, vec);
+ if (CONST_INT_P (elt))
+ {
+ int modulo_elt = INTVAL (elt) % GET_MODE_NUNITS (mode);
- /* Add offset to field within buffer matching vector element. */
- mem = adjust_address_nv (mem, inner_mode,
- INTVAL (elt) * GET_MODE_SIZE (inner_mode));
+ /* Add offset to field within buffer matching vector element. */
+ mem = adjust_address_nv (mem, inner_mode,
+ modulo_elt * GET_MODE_SIZE (inner_mode));
+ emit_move_insn (target, adjust_address_nv (mem, inner_mode, 0));
+ }
+ else
+ {
+ unsigned int ele_size = GET_MODE_SIZE (inner_mode);
+ rtx num_ele_m1 = GEN_INT (GET_MODE_NUNITS (mode) - 1);
+ rtx new_addr = gen_reg_rtx (Pmode);
- emit_move_insn (target, adjust_address_nv (mem, inner_mode, 0));
+ elt = gen_rtx_AND (Pmode, elt, num_ele_m1);
+ if (ele_size > 1)
+ elt = gen_rtx_MULT (Pmode, elt, GEN_INT (ele_size));
+ new_addr = gen_rtx_PLUS (Pmode, XEXP (mem, 0), elt);
+ new_addr = change_address (mem, inner_mode, new_addr);
+ emit_move_insn (target, new_addr);
+ }
}
/* Adjust a memory address (MEM) of a vector type to point to a scalar field
rtx tmp_altivec)
{
machine_mode mode = GET_MODE (src);
- machine_mode scalar_mode = GET_MODE (dest);
+ machine_mode scalar_mode = GET_MODE_INNER (GET_MODE (src));
unsigned scalar_size = GET_MODE_SIZE (scalar_mode);
int byte_shift = exact_log2 (scalar_size);
systems. */
if (MEM_P (src))
{
+ int num_elements = GET_MODE_NUNITS (mode);
+ rtx num_ele_m1 = GEN_INT (num_elements - 1);
+
+ emit_insn (gen_anddi3 (element, element, num_ele_m1));
gcc_assert (REG_P (tmp_gpr));
emit_move_insn (dest, rs6000_adjust_vec_address (dest, src, element,
tmp_gpr, scalar_mode));
else if (REG_P (src) || SUBREG_P (src))
{
- int bit_shift = byte_shift + 3;
+ int num_elements = GET_MODE_NUNITS (mode);
+ int bits_in_element = mode_to_bits (GET_MODE_INNER (mode));
+ int bit_shift = 7 - exact_log2 (num_elements);
rtx element2;
unsigned int dest_regno = reg_or_subregno (dest);
unsigned int src_regno = reg_or_subregno (src);
{
if (!BYTES_BIG_ENDIAN)
{
- rtx num_ele_m1 = GEN_INT (GET_MODE_NUNITS (mode) - 1);
+ rtx num_ele_m1 = GEN_INT (num_elements - 1);
emit_insn (gen_anddi3 (tmp_gpr, element, num_ele_m1));
emit_insn (gen_subdi3 (tmp_gpr, num_ele_m1, tmp_gpr));
emit_insn (gen_vsx_vslo_v2di (tmp_altivec_di, src_v2di,
tmp_altivec));
emit_move_insn (tmp_gpr_di, tmp_altivec_di);
- emit_insn (gen_ashrdi3 (tmp_gpr_di, tmp_gpr_di,
- GEN_INT (64 - (8 * scalar_size))));
+ emit_insn (gen_lshrdi3 (tmp_gpr_di, tmp_gpr_di,
+ GEN_INT (64 - bits_in_element)));
return;
}
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;
}
Accept direct, indexed, offset, lo_sum and tocref. Since this is
a constraint function we know the operand has satisfied a suitable
- memory predicate. Also accept some odd rtl generated by reload
- (see rs6000_legitimize_reload_address for various forms). It is
- important that reload rtl be accepted by appropriate constraints
- but not by the operand predicate.
+ memory predicate.
Offsetting a lo_sum should not be allowed, except where we know by
- alignment that a 32k boundary is not crossed, but see the ???
- comment in rs6000_legitimize_reload_address. Note that by
+ alignment that a 32k boundary is not crossed. Note that by
"offsetting" here we mean a further offset to access parts of the
MEM. It's fine to have a lo_sum where the inner address is offset
from a sym, since the same sym+offset will appear in the high part
function says opposite. In most cases, LRA through different
transformations can generate correct code for address reloads.
It cannot manage only some LO_SUM cases. So we need to add
- code analogous to one in rs6000_legitimize_reload_address for
- LOW_SUM here saying that some addresses are still valid. */
+ code here saying that some addresses are still valid. */
large_toc_ok = (lra_in_progress && TARGET_CMODEL != CMODEL_SMALL
&& small_toc_ref (x, VOIDmode));
if (TARGET_TOC && ! large_toc_ok)
else
emit_library_call_value (tga, dest, LCT_CONST, Pmode);
global_tlsarg = NULL_RTX;
+
+ /* Make a note so that the result of this call can be CSEd. */
+ rtvec vec = gen_rtvec (1, copy_rtx (arg));
+ rtx uns = gen_rtx_UNSPEC (Pmode, vec, UNSPEC_TLS_GET_ADDR);
+ set_unique_reg_note (get_last_insn (), REG_EQUAL, uns);
}
else if (model == TLS_MODEL_LOCAL_DYNAMIC)
{
emit_library_call_value (tga, tmp1, LCT_CONST, Pmode);
global_tlsarg = NULL_RTX;
+ /* Make a note so that the result of this call can be CSEd. */
+ rtvec vec = gen_rtvec (1, copy_rtx (arg));
+ rtx uns = gen_rtx_UNSPEC (Pmode, vec, UNSPEC_TLS_GET_ADDR);
+ set_unique_reg_note (get_last_insn (), REG_EQUAL, uns);
+
if (rs6000_tls_size == 16)
{
if (TARGET_64BIT)
&& GET_MODE_SIZE (mode) <= POWERPC64_TOC_POINTER_ALIGNMENT));
}
-/* Our implementation of LEGITIMIZE_RELOAD_ADDRESS. Returns a value to
- replace the input X, or the original X if no replacement is called for.
- The output parameter *WIN is 1 if the calling macro should goto WIN,
- 0 if it should not.
-
- For RS/6000, we wish to handle large displacements off a base
- register by splitting the addend across an addiu/addis and the mem insn.
- This cuts number of extra insns needed from 3 to 1.
-
- On Darwin, we use this to generate code for floating point constants.
- A movsf_low is generated so we wind up with 2 instructions rather than 3.
- The Darwin code is inside #if TARGET_MACHO because only then are the
- machopic_* functions defined. */
-static rtx
-rs6000_legitimize_reload_address (rtx x, machine_mode mode,
- int opnum, int type,
- int ind_levels ATTRIBUTE_UNUSED, int *win)
-{
- bool reg_offset_p = reg_offset_addressing_ok_p (mode);
- bool quad_offset_p = mode_supports_dq_form (mode);
-
- /* Nasty hack for vsx_splat_v2df/v2di load from mem, which takes a
- DFmode/DImode MEM. Ditto for ISA 3.0 vsx_splat_v4sf/v4si. */
- if (reg_offset_p
- && opnum == 1
- && ((mode == DFmode && recog_data.operand_mode[0] == V2DFmode)
- || (mode == DImode && recog_data.operand_mode[0] == V2DImode)
- || (mode == SFmode && recog_data.operand_mode[0] == V4SFmode
- && TARGET_P9_VECTOR)
- || (mode == SImode && recog_data.operand_mode[0] == V4SImode
- && TARGET_P9_VECTOR)))
- reg_offset_p = false;
-
- /* We must recognize output that we have already generated ourselves. */
- if (GET_CODE (x) == PLUS
- && GET_CODE (XEXP (x, 0)) == PLUS
- && REG_P (XEXP (XEXP (x, 0), 0))
- && CONST_INT_P (XEXP (XEXP (x, 0), 1))
- && CONST_INT_P (XEXP (x, 1)))
- {
- if (TARGET_DEBUG_ADDR)
- {
- fprintf (stderr, "\nlegitimize_reload_address push_reload #1:\n");
- debug_rtx (x);
- }
- push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
- BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
- opnum, (enum reload_type) type);
- *win = 1;
- return x;
- }
-
- /* Likewise for (lo_sum (high ...) ...) output we have generated. */
- if (GET_CODE (x) == LO_SUM
- && GET_CODE (XEXP (x, 0)) == HIGH)
- {
- if (TARGET_DEBUG_ADDR)
- {
- fprintf (stderr, "\nlegitimize_reload_address push_reload #2:\n");
- debug_rtx (x);
- }
- push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
- BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
- opnum, (enum reload_type) type);
- *win = 1;
- return x;
- }
-
-#if TARGET_MACHO
- if (DEFAULT_ABI == ABI_DARWIN && flag_pic
- && GET_CODE (x) == LO_SUM
- && GET_CODE (XEXP (x, 0)) == PLUS
- && XEXP (XEXP (x, 0), 0) == pic_offset_table_rtx
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == HIGH
- && XEXP (XEXP (XEXP (x, 0), 1), 0) == XEXP (x, 1)
- && machopic_operand_p (XEXP (x, 1)))
- {
- /* Result of previous invocation of this function on Darwin
- floating point constant. */
- push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
- BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
- opnum, (enum reload_type) type);
- *win = 1;
- return x;
- }
-#endif
-
- if (TARGET_CMODEL != CMODEL_SMALL
- && reg_offset_p
- && !quad_offset_p
- && small_toc_ref (x, VOIDmode))
- {
- rtx hi = gen_rtx_HIGH (Pmode, copy_rtx (x));
- x = gen_rtx_LO_SUM (Pmode, hi, x);
- if (TARGET_DEBUG_ADDR)
- {
- fprintf (stderr, "\nlegitimize_reload_address push_reload #3:\n");
- debug_rtx (x);
- }
- push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
- BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
- opnum, (enum reload_type) type);
- *win = 1;
- return x;
- }
-
- if (GET_CODE (x) == PLUS
- && REG_P (XEXP (x, 0))
- && HARD_REGISTER_P (XEXP (x, 0))
- && INT_REG_OK_FOR_BASE_P (XEXP (x, 0), 1)
- && CONST_INT_P (XEXP (x, 1))
- && reg_offset_p
- && (quad_offset_p || !VECTOR_MODE_P (mode) || VECTOR_MEM_NONE_P (mode)))
- {
- HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
- HOST_WIDE_INT low = ((val & 0xffff) ^ 0x8000) - 0x8000;
- HOST_WIDE_INT high
- = (((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000;
-
- /* Check for 32-bit overflow or quad addresses with one of the
- four least significant bits set. */
- if (high + low != val
- || (quad_offset_p && (low & 0xf)))
- {
- *win = 0;
- return x;
- }
-
- /* Reload the high part into a base reg; leave the low part
- in the mem directly. */
-
- x = gen_rtx_PLUS (GET_MODE (x),
- gen_rtx_PLUS (GET_MODE (x), XEXP (x, 0),
- GEN_INT (high)),
- GEN_INT (low));
-
- if (TARGET_DEBUG_ADDR)
- {
- fprintf (stderr, "\nlegitimize_reload_address push_reload #4:\n");
- debug_rtx (x);
- }
- push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
- BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
- opnum, (enum reload_type) type);
- *win = 1;
- return x;
- }
-
- if (SYMBOL_REF_P (x)
- && reg_offset_p
- && !quad_offset_p
- && (!VECTOR_MODE_P (mode) || VECTOR_MEM_NONE_P (mode))
-#if TARGET_MACHO
- && DEFAULT_ABI == ABI_DARWIN
- && (flag_pic || MACHO_DYNAMIC_NO_PIC_P)
- && machopic_symbol_defined_p (x)
-#else
- && DEFAULT_ABI == ABI_V4
- && !flag_pic
-#endif
- /* Don't do this for TFmode or TDmode, since the result isn't offsettable.
- The same goes for DImode without 64-bit gprs and DFmode and DDmode
- without fprs.
- ??? Assume floating point reg based on mode? This assumption is
- violated by eg. powerpc-linux -m32 compile of gcc.dg/pr28796-2.c
- where reload ends up doing a DFmode load of a constant from
- mem using two gprs. Unfortunately, at this point reload
- hasn't yet selected regs so poking around in reload data
- won't help and even if we could figure out the regs reliably,
- we'd still want to allow this transformation when the mem is
- naturally aligned. Since we say the address is good here, we
- can't disable offsets from LO_SUMs in mem_operand_gpr.
- FIXME: Allow offset from lo_sum for other modes too, when
- mem is sufficiently aligned.
-
- Also disallow this if the type can go in VMX/Altivec registers, since
- those registers do not have d-form (reg+offset) address modes. */
- && !reg_addr[mode].scalar_in_vmx_p
- && mode != TFmode
- && mode != TDmode
- && mode != IFmode
- && mode != KFmode
- && (mode != TImode || !TARGET_VSX)
- && mode != PTImode
- && (mode != DImode || TARGET_POWERPC64)
- && ((mode != DFmode && mode != DDmode) || TARGET_POWERPC64
- || TARGET_HARD_FLOAT))
- {
-#if TARGET_MACHO
- if (flag_pic)
- {
- rtx offset = machopic_gen_offset (x);
- x = gen_rtx_LO_SUM (GET_MODE (x),
- gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
- gen_rtx_HIGH (Pmode, offset)), offset);
- }
- else
-#endif
- x = gen_rtx_LO_SUM (GET_MODE (x),
- gen_rtx_HIGH (Pmode, x), x);
-
- if (TARGET_DEBUG_ADDR)
- {
- fprintf (stderr, "\nlegitimize_reload_address push_reload #5:\n");
- debug_rtx (x);
- }
- push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
- BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
- opnum, (enum reload_type) type);
- *win = 1;
- return x;
- }
-
- /* Reload an offset address wrapped by an AND that represents the
- masking of the lower bits. Strip the outer AND and let reload
- convert the offset address into an indirect address. For VSX,
- force reload to create the address with an AND in a separate
- register, because we can't guarantee an altivec register will
- be used. */
- if (VECTOR_MEM_ALTIVEC_P (mode)
- && GET_CODE (x) == AND
- && GET_CODE (XEXP (x, 0)) == PLUS
- && REG_P (XEXP (XEXP (x, 0), 0))
- && CONST_INT_P (XEXP (XEXP (x, 0), 1))
- && CONST_INT_P (XEXP (x, 1))
- && INTVAL (XEXP (x, 1)) == -16)
- {
- x = XEXP (x, 0);
- *win = 1;
- return x;
- }
-
- if (TARGET_TOC
- && reg_offset_p
- && !quad_offset_p
- && SYMBOL_REF_P (x)
- && use_toc_relative_ref (x, mode))
- {
- x = create_TOC_reference (x, NULL_RTX);
- if (TARGET_CMODEL != CMODEL_SMALL)
- {
- if (TARGET_DEBUG_ADDR)
- {
- fprintf (stderr, "\nlegitimize_reload_address push_reload #6:\n");
- debug_rtx (x);
- }
- push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
- BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
- opnum, (enum reload_type) type);
- }
- *win = 1;
- return x;
- }
- *win = 0;
- return x;
-}
-
-/* Debug version of rs6000_legitimize_reload_address. */
-static rtx
-rs6000_debug_legitimize_reload_address (rtx x, machine_mode mode,
- int opnum, int type,
- int ind_levels, int *win)
-{
- rtx ret = rs6000_legitimize_reload_address (x, mode, opnum, type,
- ind_levels, win);
- fprintf (stderr,
- "\nrs6000_legitimize_reload_address: mode = %s, opnum = %d, "
- "type = %d, ind_levels = %d, win = %d, original addr:\n",
- GET_MODE_NAME (mode), opnum, type, ind_levels, *win);
- debug_rtx (x);
-
- if (x == ret)
- fprintf (stderr, "Same address returned\n");
- else if (!ret)
- fprintf (stderr, "NULL returned\n");
- else
- {
- fprintf (stderr, "New address:\n");
- debug_rtx (ret);
- }
-
- return ret;
-}
-
/* TARGET_LEGITIMATE_ADDRESS_P recognizes an RTL expression
that is a valid memory address for an instruction.
The MODE argument is the machine mode for the MEM expression
{
case PROCESSOR_POWER8:
case PROCESSOR_POWER9:
+ case PROCESSOR_FUTURE:
if (DECIMAL_FLOAT_MODE_P (mode))
return 1;
if (VECTOR_MODE_P (mode))
if (TARGET_DEBUG_TARGET)
fprintf (stderr, "rs6000_conditional_register_usage called\n");
- /* Set MQ register fixed (already call_used) so that it will not be
- allocated. */
- fixed_regs[64] = 1;
-
/* 64-bit AIX and Linux reserve GPR13 for thread-private data. */
if (TARGET_64BIT)
fixed_regs[13] = call_used_regs[13]
{
warned = true;
inform (input_location,
- "the ABI of passing homogeneous float aggregates"
+ "the ABI of passing homogeneous %<float%> aggregates"
" has changed in GCC 5");
}
}
/* Builtin not supported in 32-bit mode. */
fatal_error (input_location,
"%<__builtin_set_fpscr_drn%> is not supported "
- "in 32-bit mode.");
+ "in 32-bit mode");
if (rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT)
{
return TEXASRU_SPR;
}
-/* Return the appropriate SPR regno associated with the given builtin. */
-static inline HOST_WIDE_INT
-htm_spr_regno (enum rs6000_builtins code)
-{
- if (code == HTM_BUILTIN_GET_TFHAR
- || code == HTM_BUILTIN_SET_TFHAR)
- return TFHAR_REGNO;
- else if (code == HTM_BUILTIN_GET_TFIAR
- || code == HTM_BUILTIN_SET_TFIAR)
- return TFIAR_REGNO;
- gcc_assert (code == HTM_BUILTIN_GET_TEXASR
- || code == HTM_BUILTIN_SET_TEXASR
- || code == HTM_BUILTIN_GET_TEXASRU
- || code == HTM_BUILTIN_SET_TEXASRU);
- return TEXASR_REGNO;
-}
-
/* Return the correct ICODE value depending on whether we are
setting or reading the HTM SPRs. */
static inline enum insn_code
{
machine_mode mode = (TARGET_POWERPC64) ? DImode : SImode;
op[nopnds++] = gen_rtx_CONST_INT (mode, htm_spr_num (fcode));
- op[nopnds++] = gen_rtx_REG (mode, htm_spr_regno (fcode));
}
/* If this builtin accesses a CR, then pass in a scratch
CR as the last operand. */
if (!(attr & RS6000_BTC_VOID))
expected_nopnds += 1;
if (uses_spr)
- expected_nopnds += 2;
+ expected_nopnds += 1;
gcc_assert (nopnds == expected_nopnds
&& nopnds <= MAX_HTM_OPERANDS);
if (TREE_CODE (arg2) != INTEGER_CST
|| wi::geu_p (wi::to_wide (arg2), 16))
{
- error ("argument 3 must be in the range 0..15");
+ error ("argument 3 must be in the range [0, 15]");
return CONST0_RTX (tmode);
}
}
if (!tree_fits_uhwi_p (arg)
|| (elt = tree_to_uhwi (arg), elt > max))
{
- error ("selector must be an integer constant in the range 0..%wi", max);
+ error ("selector must be an integer constant in the range [0, %wi]", max);
return 0;
}
op0 = expand_normal (arg0);
op1 = expand_normal (arg1);
- /* Call get_element_number to validate arg1 if it is a constant. */
if (TREE_CODE (arg1) == INTEGER_CST)
- (void) get_element_number (TREE_TYPE (arg0), arg1);
+ {
+ unsigned HOST_WIDE_INT elt;
+ unsigned HOST_WIDE_INT size = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0));
+ unsigned int truncated_selector;
+ /* Even if !tree_fits_uhwi_p (arg1)), TREE_INT_CST_LOW (arg0)
+ returns low-order bits of INTEGER_CST for modulo indexing. */
+ elt = TREE_INT_CST_LOW (arg1);
+ truncated_selector = elt % size;
+ op1 = GEN_INT (truncated_selector);
+ }
tmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0)));
mode0 = TYPE_MODE (TREE_TYPE (arg0));
if (TREE_CODE (arg1) != INTEGER_CST || TREE_INT_CST_LOW (arg1) > 12)
{
- error ("second argument to %qs must be 0..12", "vec_vextract4b");
+ error ("second argument to %qs must be [0, 12]", "vec_vextract4b");
return expand_call (exp, target, false);
}
break;
if (TREE_CODE (arg2) != INTEGER_CST || TREE_INT_CST_LOW (arg2) > 12)
{
- error ("third argument to %qs must be 0..12", "vec_vinsert4b");
+ error ("third argument to %qs must be [0, 12]", "vec_vinsert4b");
return expand_call (exp, target, false);
}
break;
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)
return NO_REGS;
}
- if (GET_MODE_CLASS (mode) == MODE_INT && rclass == NON_SPECIAL_REGS)
+ if (GET_MODE_CLASS (mode) == MODE_INT && rclass == GEN_OR_FLOAT_REGS)
return GENERAL_REGS;
return rclass;
/* Constants, memory, and FP registers can go into FP registers. */
if ((regno == -1 || FP_REGNO_P (regno))
- && (rclass == FLOAT_REGS || rclass == NON_SPECIAL_REGS))
+ && (rclass == FLOAT_REGS || rclass == GEN_OR_FLOAT_REGS))
return (mode != SDmode || lra_in_progress) ? NO_REGS : GENERAL_REGS;
/* Memory, and AltiVec registers can go into AltiVec registers. */
{
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. */
emit_insn (TARGET_32BIT
? (TARGET_POWERPC64
? gen_movdi_si_update (breg, breg, delta_rtx, nsrc)
- : gen_movsi_update (breg, breg, delta_rtx, nsrc))
+ : gen_movsi_si_update (breg, breg, delta_rtx, nsrc))
: gen_movdi_di_update (breg, breg, delta_rtx, nsrc));
used_update = true;
}
fprintf (stderr, "\tsave-strategy = %04x\n", info->savres_strategy);
+ if (info->abi == ABI_DARWIN)
+ fprintf (stderr, "\tWORLD_SAVE_P = %5d\n", WORLD_SAVE_P(info));
+
fprintf (stderr, "\n");
}
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);
size_rtx = tmp_reg;
}
- if (Pmode == SImode)
+ if (TARGET_32BIT)
insn = emit_insn (gen_movsi_update_stack (stack_pointer_rtx,
stack_pointer_rtx,
size_rtx,
orig_sp));
else
- insn = emit_insn (gen_movdi_di_update_stack (stack_pointer_rtx,
- stack_pointer_rtx,
- size_rtx,
- orig_sp));
+ insn = emit_insn (gen_movdi_update_stack (stack_pointer_rtx,
+ stack_pointer_rtx,
+ size_rtx,
+ orig_sp));
rtx par = PATTERN (insn);
gcc_assert (GET_CODE (par) == PARALLEL);
rtx set = XVECEXP (par, 0, 0);
/* 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. */
/* Reload CR from REG. */
static void
-restore_saved_cr (rtx reg, int using_mfcr_multiple, bool exit_func)
+restore_saved_cr (rtx reg, bool using_mfcr_multiple, bool exit_func)
{
int count = 0;
int i;
/* Emit function epilogue as insns. */
void
-rs6000_emit_epilogue (int sibcall)
-{
- rs6000_stack_t *info;
- int restoring_GPRs_inline;
- int restoring_FPRs_inline;
- int using_load_multiple;
- int using_mtcr_multiple;
- int use_backchain_to_restore_sp;
- int restore_lr;
- int strategy;
+rs6000_emit_epilogue (enum epilogue_type epilogue_type)
+{
HOST_WIDE_INT frame_off = 0;
rtx sp_reg_rtx = gen_rtx_REG (Pmode, 1);
rtx frame_reg_rtx = sp_reg_rtx;
machine_mode fp_reg_mode = TARGET_HARD_FLOAT ? DFmode : SFmode;
int fp_reg_size = 8;
int i;
- bool exit_func;
unsigned ptr_regno;
- info = rs6000_stack_info ();
+ rs6000_stack_t *info = rs6000_stack_info ();
+
+ if (epilogue_type == EPILOGUE_TYPE_NORMAL && crtl->calls_eh_return)
+ epilogue_type = EPILOGUE_TYPE_EH_RETURN;
+
+ int strategy = info->savres_strategy;
+ bool using_load_multiple = !!(strategy & REST_MULTIPLE);
+ bool restoring_GPRs_inline = !!(strategy & REST_INLINE_GPRS);
+ bool restoring_FPRs_inline = !!(strategy & REST_INLINE_FPRS);
+ if (epilogue_type == EPILOGUE_TYPE_SIBCALL)
+ {
+ restoring_GPRs_inline = true;
+ restoring_FPRs_inline = true;
+ }
+
+ bool using_mtcr_multiple = (rs6000_tune == PROCESSOR_PPC601
+ || rs6000_tune == PROCESSOR_PPC603
+ || rs6000_tune == PROCESSOR_PPC750
+ || optimize_size);
- strategy = info->savres_strategy;
- using_load_multiple = strategy & REST_MULTIPLE;
- restoring_FPRs_inline = sibcall || (strategy & REST_INLINE_FPRS);
- restoring_GPRs_inline = sibcall || (strategy & REST_INLINE_GPRS);
- using_mtcr_multiple = (rs6000_tune == PROCESSOR_PPC601
- || rs6000_tune == PROCESSOR_PPC603
- || rs6000_tune == PROCESSOR_PPC750
- || optimize_size);
/* Restore via the backchain when we have a large frame, since this
is more efficient than an addis, addi pair. The second condition
here will not trigger at the moment; We don't actually need a
frame pointer for alloca, but the generic parts of the compiler
give us one anyway. */
- use_backchain_to_restore_sp = (info->total_size + (info->lr_save_p
- ? info->lr_save_offset
- : 0) > 32767
- || (cfun->calls_alloca
- && !frame_pointer_needed));
- restore_lr = (info->lr_save_p
+ bool use_backchain_to_restore_sp
+ = (info->total_size + (info->lr_save_p ? info->lr_save_offset : 0) > 32767
+ || (cfun->calls_alloca && !frame_pointer_needed));
+
+ bool restore_lr = (info->lr_save_p
&& (restoring_FPRs_inline
|| (strategy & REST_NOINLINE_FPRS_DOESNT_RESTORE_LR))
&& (restoring_GPRs_inline
if (WORLD_SAVE_P (info))
{
- int i, j;
- char rname[30];
- const char *alloc_rname;
- rtvec p;
+ gcc_assert (epilogue_type != EPILOGUE_TYPE_SIBCALL);
/* eh_rest_world_r10 will return to the location saved in the LR
stack slot (which is not likely to be our caller.)
The exception-handling stuff that was here in 2.95 is no
longer necessary. */
+ rtvec p;
p = rtvec_alloc (9
+ 32 - info->first_gp_reg_save
+ LAST_ALTIVEC_REGNO + 1 - info->first_altivec_reg_save
+ 63 + 1 - info->first_fp_reg_save);
- strcpy (rname, ((crtl->calls_eh_return) ?
- "*eh_rest_world_r10" : "*rest_world"));
- alloc_rname = ggc_strdup (rname);
+ const char *rname;
+ switch (epilogue_type)
+ {
+ case EPILOGUE_TYPE_NORMAL:
+ rname = ggc_strdup ("*rest_world");
+ break;
- j = 0;
+ case EPILOGUE_TYPE_EH_RETURN:
+ rname = ggc_strdup ("*eh_rest_world_r10");
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ int j = 0;
RTVEC_ELT (p, j++) = ret_rtx;
RTVEC_ELT (p, j++)
- = gen_rtx_USE (VOIDmode, gen_rtx_SYMBOL_REF (Pmode, alloc_rname));
+ = gen_rtx_USE (VOIDmode, gen_rtx_SYMBOL_REF (Pmode, rname));
/* The instruction pattern requires a clobber here;
it is shared with the restVEC helper. */
RTVEC_ELT (p, j++) = gen_hard_reg_clobber (Pmode, 11);
}
}
+ int i;
for (i = 0; i < 32 - info->first_gp_reg_save; i++)
{
rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
}
else if (info->push_p
&& DEFAULT_ABI != ABI_V4
- && !crtl->calls_eh_return)
+ && epilogue_type != EPILOGUE_TYPE_EH_RETURN)
{
/* Prevent reordering memory accesses against stack pointer restore. */
if (cfun->calls_alloca
function will deallocate the stack, so we don't need to worry
about the unwinder restoring cr from an invalid stack frame
location. */
- exit_func = (!restoring_FPRs_inline
- || (!restoring_GPRs_inline
- && info->first_fp_reg_save == 64));
+ bool exit_func = (!restoring_FPRs_inline
+ || (!restoring_GPRs_inline
+ && info->first_fp_reg_save == 64));
/* In the ELFv2 ABI we need to restore all call-saved CR fields from
*separate* slots if the routine calls __builtin_eh_return, so
restore_saved_lr (0, exit_func);
/* Load exception handler data registers, if needed. */
- if (crtl->calls_eh_return)
+ if (epilogue_type == EPILOGUE_TYPE_EH_RETURN)
{
unsigned int i, regno;
RTX_FRAME_RELATED_P (insn) = 1;
}
- if (crtl->calls_eh_return)
+ if (epilogue_type == EPILOGUE_TYPE_EH_RETURN)
{
rtx sa = EH_RETURN_STACKADJ_RTX;
emit_insn (gen_add3_insn (sp_reg_rtx, sp_reg_rtx, sa));
}
- if (!sibcall && restoring_FPRs_inline)
+ if (epilogue_type != EPILOGUE_TYPE_SIBCALL && restoring_FPRs_inline)
{
if (cfa_restores)
{
emit_jump_insn (targetm.gen_simple_return ());
}
- if (!sibcall && !restoring_FPRs_inline)
+ if (epilogue_type != EPILOGUE_TYPE_SIBCALL && !restoring_FPRs_inline)
{
bool lr = (strategy & REST_NOINLINE_FPRS_DOESNT_RESTORE_LR) == 0;
rtvec p = rtvec_alloc (3 + !!lr + 64 - info->first_fp_reg_save);
if (cfa_restores)
{
- if (sibcall)
+ if (epilogue_type == EPILOGUE_TYPE_SIBCALL)
/* Ensure the cfa_restores are hung off an insn that won't
be reordered above other restores. */
emit_insn (gen_blockage ());
HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
tree function)
{
+ const char *fnname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk_fndecl));
rtx this_rtx, funexp;
rtx_insn *insn;
/* 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);
final_start_function (insn, file, 1);
final (insn, file, 1);
final_end_function ();
+ assemble_end_function (thunk_fndecl, fnname);
reload_completed = 0;
epilogue_completed = 0;
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)
}
else
{
- strcat (tmp_buf, ":\nlis r12,hi16(");
+ strcat (tmp_buf, ":\n\tlis r12,hi16(");
strcat (tmp_buf, name_buf);
strcat (tmp_buf, ")\n\tori r12,r12,lo16(");
strcat (tmp_buf, name_buf);
unsigned int length;
char *symbol_name, *lazy_ptr_name;
char *local_label_0;
- static int label = 0;
+ static unsigned label = 0;
/* Lose our funky encoding stuff so it doesn't contaminate the stub. */
symb = (*targetm.strip_name_encoding) (symb);
fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
label++;
- local_label_0 = XALLOCAVEC (char, sizeof ("\"L00000000000$spb\""));
- sprintf (local_label_0, "\"L%011d$spb\"", label);
+ local_label_0 = XALLOCAVEC (char, 16);
+ sprintf (local_label_0, "L%u$spb", label);
fprintf (file, "\tmflr r0\n");
if (TARGET_LINK_STACK)
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];
rs6000_xcoff_output_readwrite_section_asm_op,
&xcoff_private_data_section_name);
+ read_only_private_data_section
+ = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
+ &xcoff_private_rodata_section_name);
+
tls_data_section
= get_unnamed_section (SECTION_TLS,
rs6000_xcoff_output_tls_section_asm_op,
rs6000_xcoff_output_tls_section_asm_op,
&xcoff_private_data_section_name);
- read_only_private_data_section
- = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
- &xcoff_private_data_section_name);
-
toc_section
= get_unnamed_section (0, rs6000_xcoff_output_toc_section_asm_op, NULL);
main_input_filename, ".bss_");
rs6000_gen_section_name (&xcoff_private_data_section_name,
main_input_filename, ".rw_");
+ rs6000_gen_section_name (&xcoff_private_rodata_section_name,
+ main_input_filename, ".rop_");
rs6000_gen_section_name (&xcoff_read_only_section_name,
main_input_filename, ".ro_");
rs6000_gen_section_name (&xcoff_tls_data_section_name,
reg_class_t from, reg_class_t to)
{
int ret;
+ reg_class_t rclass;
if (TARGET_DEBUG_COST)
dbg_cost_ctrl++;
+ /* If we have VSX, we can easily move between FPR or Altivec registers,
+ otherwise we can only easily move within classes.
+ Do this first so we give best-case answers for union classes
+ containing both gprs and vsx regs. */
+ HARD_REG_SET to_vsx, from_vsx;
+ COPY_HARD_REG_SET (to_vsx, reg_class_contents[to]);
+ AND_HARD_REG_SET (to_vsx, reg_class_contents[VSX_REGS]);
+ COPY_HARD_REG_SET (from_vsx, reg_class_contents[from]);
+ AND_HARD_REG_SET (from_vsx, reg_class_contents[VSX_REGS]);
+ if (!hard_reg_set_empty_p (to_vsx)
+ && !hard_reg_set_empty_p (from_vsx)
+ && (TARGET_VSX
+ || hard_reg_set_intersect_p (to_vsx, from_vsx)))
+ {
+ int reg = FIRST_FPR_REGNO;
+ if (TARGET_VSX
+ || (TEST_HARD_REG_BIT (to_vsx, FIRST_ALTIVEC_REGNO)
+ && TEST_HARD_REG_BIT (from_vsx, FIRST_ALTIVEC_REGNO)))
+ reg = FIRST_ALTIVEC_REGNO;
+ ret = 2 * hard_regno_nregs (reg, mode);
+ }
+
/* Moves from/to GENERAL_REGS. */
- if (reg_classes_intersect_p (to, GENERAL_REGS)
- || reg_classes_intersect_p (from, GENERAL_REGS))
+ else if ((rclass = from, reg_classes_intersect_p (to, GENERAL_REGS))
+ || (rclass = to, reg_classes_intersect_p (from, GENERAL_REGS)))
{
- reg_class_t rclass = from;
-
- if (! reg_classes_intersect_p (to, GENERAL_REGS))
- rclass = to;
-
if (rclass == FLOAT_REGS || rclass == ALTIVEC_REGS || rclass == VSX_REGS)
- ret = (rs6000_memory_move_cost (mode, rclass, false)
- + rs6000_memory_move_cost (mode, GENERAL_REGS, false));
+ {
+ if (TARGET_DIRECT_MOVE)
+ {
+ /* 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
+ and vsx. */
+ if (mode == SFmode)
+ ret += 2;
+ }
+ else
+ ret = (rs6000_memory_move_cost (mode, rclass, false)
+ + rs6000_memory_move_cost (mode, GENERAL_REGS, false));
+ }
/* It's more expensive to move CR_REGS than CR0_REGS because of the
shift. */
|| rs6000_tune == PROCESSOR_POWER7
|| rs6000_tune == PROCESSOR_POWER8
|| rs6000_tune == PROCESSOR_POWER9)
- && reg_classes_intersect_p (rclass, LINK_OR_CTR_REGS))
- ret = 6 * hard_regno_nregs (0, mode);
+ && reg_class_subset_p (rclass, SPECIAL_REGS))
+ ret = 6 * hard_regno_nregs (FIRST_GPR_REGNO, mode);
else
/* A move will cost one instruction per GPR moved. */
- ret = 2 * hard_regno_nregs (0, mode);
+ ret = 2 * hard_regno_nregs (FIRST_GPR_REGNO, mode);
}
- /* If we have VSX, we can easily move between FPR or Altivec registers. */
- else if (VECTOR_MEM_VSX_P (mode)
- && reg_classes_intersect_p (to, VSX_REGS)
- && reg_classes_intersect_p (from, VSX_REGS))
- ret = 2 * hard_regno_nregs (FIRST_FPR_REGNO, mode);
-
- /* Moving between two similar registers is just one instruction. */
- else if (reg_classes_intersect_p (to, from))
- ret = (FLOAT128_2REG_P (mode)) ? 4 : 2;
-
/* Everything else has to go through GENERAL_REGS. */
else
ret = (rs6000_register_move_cost (mode, GENERAL_REGS, to)
{
if (dbg_cost_ctrl == 1)
fprintf (stderr,
- "rs6000_register_move_cost:, ret=%d, mode=%s, from=%s, to=%s\n",
+ "rs6000_register_move_cost: ret=%d, mode=%s, from=%s, to=%s\n",
ret, GET_MODE_NAME (mode), reg_class_names[from],
reg_class_names[to]);
dbg_cost_ctrl--;
return ret;
}
+/* Implement TARGET_IRA_CHANGE_PSEUDO_ALLOCNO_CLASS.
+
+ The register allocator chooses GEN_OR_VSX_REGS for the allocno
+ class if GENERAL_REGS and VSX_REGS cost is lower than the memory
+ cost. This happens a lot when TARGET_DIRECT_MOVE makes the register
+ move cost between GENERAL_REGS and VSX_REGS low.
+
+ It might seem reasonable to use a union class. After all, if usage
+ of vsr is low and gpr high, it might make sense to spill gpr to vsr
+ rather than memory. However, in cases where register pressure of
+ both is high, like the cactus_adm spec test, allowing
+ GEN_OR_VSX_REGS as the allocno class results in bad decisions in
+ the first scheduling pass. This is partly due to an allocno of
+ GEN_OR_VSX_REGS wrongly contributing to the GENERAL_REGS pressure
+ class, which gives too high a pressure for GENERAL_REGS and too low
+ for VSX_REGS. So, force a choice of the subclass here.
+
+ The best class is also the union if GENERAL_REGS and VSX_REGS have
+ the same cost. In that case we do use GEN_OR_VSX_REGS as the
+ allocno class, since trying to narrow down the class by regno mode
+ is prone to error. For example, SImode is allowed in VSX regs and
+ in some cases (eg. gcc.target/powerpc/p9-xxbr-3.c do_bswap32_vect)
+ it would be wrong to choose an allocno of GENERAL_REGS based on
+ SImode. */
+
+static reg_class_t
+rs6000_ira_change_pseudo_allocno_class (int regno ATTRIBUTE_UNUSED,
+ reg_class_t allocno_class,
+ reg_class_t best_class)
+{
+ switch (allocno_class)
+ {
+ case GEN_OR_VSX_REGS:
+ /* best_class must be a subset of allocno_class. */
+ gcc_checking_assert (best_class == GEN_OR_VSX_REGS
+ || best_class == GEN_OR_FLOAT_REGS
+ || best_class == VSX_REGS
+ || best_class == ALTIVEC_REGS
+ || best_class == FLOAT_REGS
+ || best_class == GENERAL_REGS
+ || best_class == BASE_REGS);
+ /* Use best_class but choose wider classes when copying from the
+ wider class to best_class is cheap. This mimics IRA choice
+ of allocno class. */
+ if (best_class == BASE_REGS)
+ return GENERAL_REGS;
+ if (TARGET_VSX
+ && (best_class == FLOAT_REGS || best_class == ALTIVEC_REGS))
+ return VSX_REGS;
+ return best_class;
+
+ default:
+ break;
+ }
+
+ return allocno_class;
+}
+
/* Returns a code for a target-specific builtin that implements
reciprocal of the function, or NULL_TREE if not available. */
}
/* Compute register pressure classes. We implement the target hook to avoid
- IRA picking something like NON_SPECIAL_REGS as a pressure class, which can
+ IRA picking something like GEN_OR_FLOAT_REGS as a pressure class, which can
lead to incorrect estimates of number of available registers and therefor
increased register pressure/spill. */
static int
unsigned int
rs6000_dbx_register_number (unsigned int regno, unsigned int format)
{
- /* Except for the above, we use the internal number for non-DWARF
- debug information, and also for .eh_frame. */
- if ((format == 0 && write_symbols != DWARF2_DEBUG) || format == 2)
- return regno;
-
/* On some platforms, we use the standard DWARF register
numbering for .debug_info and .debug_frame. */
+ if ((format == 0 && write_symbols == DWARF2_DEBUG) || format == 1)
+ {
#ifdef RS6000_USE_DWARF_NUMBERING
- if (regno <= 63)
+ if (regno <= 31)
+ return regno;
+ if (FP_REGNO_P (regno))
+ return regno - FIRST_FPR_REGNO + 32;
+ if (ALTIVEC_REGNO_P (regno))
+ return regno - FIRST_ALTIVEC_REGNO + 1124;
+ if (regno == LR_REGNO)
+ return 108;
+ if (regno == CTR_REGNO)
+ return 109;
+ if (regno == CA_REGNO)
+ return 101; /* XER */
+ /* Special handling for CR for .debug_frame: rs6000_emit_prologue has
+ translated any combination of CR2, CR3, CR4 saves to a save of CR2.
+ The actual code emitted saves the whole of CR, so we map CR2_REGNO
+ to the DWARF reg for CR. */
+ if (format == 1 && regno == CR2_REGNO)
+ return 64;
+ if (CR_REGNO_P (regno))
+ return regno - CR0_REGNO + 86;
+ if (regno == VRSAVE_REGNO)
+ return 356;
+ if (regno == VSCR_REGNO)
+ return 67;
+
+ /* These do not make much sense. */
+ if (regno == FRAME_POINTER_REGNUM)
+ return 111;
+ if (regno == ARG_POINTER_REGNUM)
+ return 67;
+ if (regno == 64)
+ return 100;
+
+ gcc_unreachable ();
+#endif
+ }
+
+ /* We use the GCC 7 (and before) internal number for non-DWARF debug
+ information, and also for .eh_frame. */
+ /* Translate the regnos to their numbers in GCC 7 (and before). */
+ if (regno <= 31)
return regno;
+ if (FP_REGNO_P (regno))
+ return regno - FIRST_FPR_REGNO + 32;
+ if (ALTIVEC_REGNO_P (regno))
+ return regno - FIRST_ALTIVEC_REGNO + 77;
if (regno == LR_REGNO)
- return 108;
+ return 65;
if (regno == CTR_REGNO)
- return 109;
- /* Special handling for CR for .debug_frame: rs6000_emit_prologue has
- translated any combination of CR2, CR3, CR4 saves to a save of CR2.
- The actual code emitted saves the whole of CR, so we map CR2_REGNO
- to the DWARF reg for CR. */
- if (format == 1 && regno == CR2_REGNO)
- return 64;
- if (CR_REGNO_P (regno))
- return regno - CR0_REGNO + 86;
+ return 66;
if (regno == CA_REGNO)
- return 101; /* XER */
- if (ALTIVEC_REGNO_P (regno))
- return regno - FIRST_ALTIVEC_REGNO + 1124;
+ return 76; /* XER */
+ if (CR_REGNO_P (regno))
+ return regno - CR0_REGNO + 68;
if (regno == VRSAVE_REGNO)
- return 356;
+ return 109;
if (regno == VSCR_REGNO)
+ return 110;
+
+ if (regno == FRAME_POINTER_REGNUM)
+ return 111;
+ if (regno == ARG_POINTER_REGNUM)
return 67;
-#endif
- return regno;
+ if (regno == 64)
+ return 64;
+
+ gcc_unreachable ();
}
/* target hook eh_return_filter_mode */
{ "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 },
#ifndef TARGET_LIBC_PROVIDES_HWCAP_IN_TCB
error_at (DECL_SOURCE_LOCATION (default_node->decl),
- "target_clones attribute needs GLIBC (2.23 and newer) that "
+ "%<target_clones%> attribute needs GLIBC (2.23 and newer) that "
"exports hardware capability bits");
#else
/* Build result decl and add to function_decl. */
tree t = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, ptr_type_node);
+ DECL_CONTEXT (t) = decl;
DECL_ARTIFICIAL (t) = 1;
DECL_IGNORED_P (t) = 1;
DECL_RESULT (decl) = t;
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