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;
= 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;
}
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)
&& 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