#define RELOAD_REG_PRE_INCDEC 0x10 /* PRE_INC/PRE_DEC valid. */
#define RELOAD_REG_PRE_MODIFY 0x20 /* PRE_MODIFY valid. */
#define RELOAD_REG_AND_M16 0x40 /* AND -16 addressing. */
+#define RELOAD_REG_QUAD_OFFSET 0x80 /* quad offset is limited. */
/* Register type masks based on the type, of valid addressing modes. */
struct rs6000_reg_addr {
return ((reg_addr[mode].addr_mask[RELOAD_REG_VMX] & RELOAD_REG_OFFSET) != 0);
}
+/* Return true if we have D-form addressing in VSX registers. This addressing
+ is more limited than normal d-form addressing in that the offset must be
+ aligned on a 16-byte boundary. */
+static inline bool
+mode_supports_vsx_dform_quad (machine_mode mode)
+{
+ return ((reg_addr[mode].addr_mask[RELOAD_REG_ANY] & RELOAD_REG_QUAD_OFFSET)
+ != 0);
+}
+
\f
/* Target cpu costs. */
else if (keep_spaces)
*p++ = ' ';
- if ((mask & RELOAD_REG_OFFSET) != 0)
+ if ((mask & RELOAD_REG_QUAD_OFFSET) != 0)
+ *p++ = 'O';
+ else if ((mask & RELOAD_REG_OFFSET) != 0)
*p++ = 'o';
else if (keep_spaces)
*p++ = ' ';
if (TARGET_LINK_STACK)
fprintf (stderr, DEBUG_FMT_S, "link_stack", "true");
- if (targetm.lra_p ())
- fprintf (stderr, DEBUG_FMT_S, "lra", "true");
+ fprintf (stderr, DEBUG_FMT_S, "lra", TARGET_LRA ? "true" : "false");
if (TARGET_P8_FUSION)
{
}
/* GPR and FPR registers can do REG+OFFSET addressing, except
- possibly for SDmode. ISA 3.0 (i.e. power9) adds D-form
- addressing for scalars to altivec registers. */
+ possibly for SDmode. ISA 3.0 (i.e. power9) adds D-form addressing
+ for 64-bit scalars and 32-bit SFmode to altivec registers. */
if ((addr_mask != 0) && !indexed_only_p
&& msize <= 8
&& (rc == RELOAD_REG_GPR
- || rc == RELOAD_REG_FPR
- || (rc == RELOAD_REG_VMX
- && TARGET_P9_DFORM
- && (m2 == DFmode || m2 == SFmode))))
+ || ((msize == 8 || m2 == SFmode)
+ && (rc == RELOAD_REG_FPR
+ || (rc == RELOAD_REG_VMX
+ && TARGET_P9_DFORM_SCALAR)))))
addr_mask |= RELOAD_REG_OFFSET;
+ /* VSX registers can do REG+OFFSET addresssing if ISA 3.0
+ instructions are enabled. The offset for 128-bit VSX registers is
+ only 12-bits. While GPRs can handle the full offset range, VSX
+ registers can only handle the restricted range. */
+ else if ((addr_mask != 0) && !indexed_only_p
+ && msize == 16 && TARGET_P9_DFORM_VECTOR
+ && (ALTIVEC_OR_VSX_VECTOR_MODE (m2)
+ || (m2 == TImode && TARGET_VSX_TIMODE)))
+ {
+ addr_mask |= RELOAD_REG_OFFSET;
+ if (rc == RELOAD_REG_FPR || rc == RELOAD_REG_VMX)
+ addr_mask |= RELOAD_REG_QUAD_OFFSET;
+ }
+
/* VMX registers can do (REG & -16) and ((REG+REG) & -16)
addressing on 128-bit types. */
if (rc == RELOAD_REG_VMX && msize == 16
}
/* Support for new D-form instructions. */
- if (TARGET_P9_DFORM)
+ if (TARGET_P9_DFORM_SCALAR)
rs6000_constraints[RS6000_CONSTRAINT_wb] = ALTIVEC_REGS;
/* Support for ISA 3.0 (power9) vectors. */
/* For the newer switches (vsx, dfp, etc.) set some of the older options,
unless the user explicitly used the -mno-<option> to disable the code. */
- if (TARGET_P9_VECTOR || TARGET_MODULO || TARGET_P9_DFORM || TARGET_P9_MINMAX)
+ if (TARGET_P9_VECTOR || TARGET_MODULO || TARGET_P9_DFORM_SCALAR
+ || TARGET_P9_DFORM_VECTOR || TARGET_P9_DFORM_BOTH > 0 || TARGET_P9_MINMAX)
rs6000_isa_flags |= (ISA_3_0_MASKS_SERVER & ~rs6000_isa_flags_explicit);
else if (TARGET_P8_VECTOR || TARGET_DIRECT_MOVE || TARGET_CRYPTO)
rs6000_isa_flags |= (ISA_2_7_MASKS_SERVER & ~rs6000_isa_flags_explicit);
&& !(rs6000_isa_flags_explicit & OPTION_MASK_TOC_FUSION))
rs6000_isa_flags |= OPTION_MASK_TOC_FUSION;
+ /* -mpower9-dform turns on both -mpower9-dform-scalar and
+ -mpower9-dform-vector. There are currently problems if
+ -mpower9-dform-vector instructions are enabled when we use the RELOAD
+ register allocator. */
+ if (TARGET_P9_DFORM_BOTH > 0)
+ {
+ if (!(rs6000_isa_flags_explicit & OPTION_MASK_P9_DFORM_VECTOR)
+ && TARGET_LRA)
+ rs6000_isa_flags |= OPTION_MASK_P9_DFORM_VECTOR;
+
+ if (!(rs6000_isa_flags_explicit & OPTION_MASK_P9_DFORM_SCALAR))
+ rs6000_isa_flags |= OPTION_MASK_P9_DFORM_SCALAR;
+ }
+ else if (TARGET_P9_DFORM_BOTH == 0)
+ {
+ if (!(rs6000_isa_flags_explicit & OPTION_MASK_P9_DFORM_VECTOR))
+ rs6000_isa_flags &= ~OPTION_MASK_P9_DFORM_VECTOR;
+
+ if (!(rs6000_isa_flags_explicit & OPTION_MASK_P9_DFORM_SCALAR))
+ rs6000_isa_flags &= ~OPTION_MASK_P9_DFORM_SCALAR;
+ }
+
/* ISA 3.0 D-form instructions require p9-vector and upper-regs. */
- if (TARGET_P9_DFORM && !TARGET_P9_VECTOR)
+ if ((TARGET_P9_DFORM_SCALAR || TARGET_P9_DFORM_VECTOR) && !TARGET_P9_VECTOR)
{
if (rs6000_isa_flags_explicit & OPTION_MASK_P9_VECTOR)
error ("-mpower9-dform requires -mpower9-vector");
- rs6000_isa_flags &= ~OPTION_MASK_P9_DFORM;
+ rs6000_isa_flags &= ~(OPTION_MASK_P9_DFORM_SCALAR
+ | OPTION_MASK_P9_DFORM_VECTOR);
}
- if (TARGET_P9_DFORM && !TARGET_UPPER_REGS_DF)
+ if (TARGET_P9_DFORM_SCALAR && !TARGET_UPPER_REGS_DF)
{
if (rs6000_isa_flags_explicit & OPTION_MASK_UPPER_REGS_DF)
error ("-mpower9-dform requires -mupper-regs-df");
- rs6000_isa_flags &= ~OPTION_MASK_P9_DFORM;
+ rs6000_isa_flags &= ~OPTION_MASK_P9_DFORM_SCALAR;
}
- if (TARGET_P9_DFORM && !TARGET_UPPER_REGS_SF)
+ if (TARGET_P9_DFORM_SCALAR && !TARGET_UPPER_REGS_SF)
{
if (rs6000_isa_flags_explicit & OPTION_MASK_UPPER_REGS_SF)
error ("-mpower9-dform requires -mupper-regs-sf");
- rs6000_isa_flags &= ~OPTION_MASK_P9_DFORM;
+ rs6000_isa_flags &= ~OPTION_MASK_P9_DFORM_SCALAR;
}
/* ISA 3.0 vector instructions include ISA 2.07. */
rs6000_isa_flags &= ~OPTION_MASK_P9_VECTOR;
}
+ /* There have been bugs with both -mvsx-timode and -mpower9-dform-vector that
+ don't show up with -mlra, but do show up with -mno-lra. Given -mlra will
+ become the default once PR 69847 is fixed, turn off the options with
+ problems by default if -mno-lra was used, and warn if the user explicitly
+ asked for the option.
+
+ Enable -mpower9-dform-vector by default if LRA and other power9 options.
+ Enable -mvsx-timode by default if LRA and VSX. */
+ if (!TARGET_LRA)
+ {
+ if (TARGET_VSX_TIMODE)
+ {
+ if ((rs6000_isa_flags_explicit & OPTION_MASK_VSX_TIMODE) != 0)
+ warning (0, "-mvsx-timode might need -mlra");
+
+ else
+ rs6000_isa_flags &= ~OPTION_MASK_VSX_TIMODE;
+ }
+
+ if (TARGET_P9_DFORM_VECTOR)
+ {
+ if ((rs6000_isa_flags_explicit & OPTION_MASK_P9_DFORM_VECTOR) != 0)
+ warning (0, "-mpower9-dform-vector might need -mlra");
+
+ else
+ rs6000_isa_flags &= ~OPTION_MASK_P9_DFORM_VECTOR;
+ }
+ }
+
+ else
+ {
+ if (TARGET_VSX && !TARGET_VSX_TIMODE
+ && (rs6000_isa_flags_explicit & OPTION_MASK_VSX_TIMODE) == 0)
+ rs6000_isa_flags |= OPTION_MASK_VSX_TIMODE;
+
+ if (TARGET_VSX && TARGET_P9_VECTOR && !TARGET_P9_DFORM_VECTOR
+ && TARGET_P9_DFORM_SCALAR && TARGET_P9_DFORM_BOTH < 0
+ && (rs6000_isa_flags_explicit & OPTION_MASK_P9_DFORM_VECTOR) == 0)
+ rs6000_isa_flags |= OPTION_MASK_P9_DFORM_VECTOR;
+ }
+
/* Set -mallow-movmisalign to explicitly on if we have full ISA 2.07
support. If we only have ISA 2.06 support, and the user did not specify
the switch, leave it set to -1 so the movmisalign patterns are enabled,
return false;
}
+/* Return true if the OFFSET is valid for the quad address instructions that
+ use d-form (register + offset) addressing. */
+
+static inline bool
+quad_address_offset_p (HOST_WIDE_INT offset)
+{
+ return (IN_RANGE (offset, -32768, 32767) && ((offset) & 0xf) == 0);
+}
+
+/* Return true if the ADDR is an acceptable address for a quad memory
+ operation of mode MODE (either LQ/STQ for general purpose registers, or
+ LXV/STXV for vector registers under ISA 3.0. GPR_P is true if this address
+ is intended for LQ/STQ. If it is false, the address is intended for the ISA
+ 3.0 LXV/STXV instruction. */
+
+bool
+quad_address_p (rtx addr, machine_mode mode, bool gpr_p)
+{
+ rtx op0, op1;
+
+ if (GET_MODE_SIZE (mode) != 16)
+ return false;
+
+ if (gpr_p)
+ {
+ if (!TARGET_QUAD_MEMORY && !TARGET_SYNC_TI)
+ return false;
+
+ /* LQ/STQ can handle indirect addresses. */
+ if (base_reg_operand (addr, Pmode))
+ return true;
+ }
+
+ else
+ {
+ if (!mode_supports_vsx_dform_quad (mode))
+ return false;
+ }
+
+ if (GET_CODE (addr) != PLUS)
+ return false;
+
+ op0 = XEXP (addr, 0);
+ if (!base_reg_operand (op0, Pmode))
+ return false;
+
+ op1 = XEXP (addr, 1);
+ if (!CONST_INT_P (op1))
+ return false;
+
+ return quad_address_offset_p (INTVAL (op1));
+}
+
/* Return true if this is a load or store quad operation. This function does
not handle the atomic quad memory instructions. */
if (TARGET_POWERPC64 && (offset & 3) != 0)
return false;
+ if (mode_supports_vsx_dform_quad (mode)
+ && !quad_address_offset_p (offset))
+ return false;
+
extra = GET_MODE_SIZE (mode) - UNITS_PER_WORD;
if (extra < 0)
extra = 0;
case TImode:
case TFmode:
case KFmode:
- /* AltiVec/VSX vector modes. Only reg+reg addressing is valid. While
- TImode is not a vector mode, if we want to use the VSX registers to
- move it around, we need to restrict ourselves to reg+reg addressing.
- Similarly for IEEE 128-bit floating point that is passed in a single
- vector register. */
+ /* AltiVec/VSX vector modes. Only reg+reg addressing was valid until the
+ ISA 3.0 vector d-form addressing mode was added. While TImode is not
+ a vector mode, if we want to use the VSX registers to move it around,
+ we need to restrict ourselves to reg+reg addressing. Similarly for
+ IEEE 128-bit floating point that is passed in a single vector
+ register. */
if (VECTOR_MEM_ALTIVEC_OR_VSX_P (mode))
- return false;
+ return mode_supports_vsx_dform_quad (mode);
break;
case V4HImode:
if (GET_CODE (op) != SYMBOL_REF)
return false;
+ /* ISA 3.0 vector d-form addressing is restricted, don't allow
+ SYMBOL_REF. */
+ if (mode_supports_vsx_dform_quad (mode))
+ return false;
+
dsize = GET_MODE_SIZE (mode);
decl = SYMBOL_REF_DECL (op);
if (!decl)
return false;
if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
return false;
+ if (mode_supports_vsx_dform_quad (mode))
+ return (virtual_stack_registers_memory_p (x)
+ || quad_address_p (x, mode, false));
if (!reg_offset_addressing_ok_p (mode))
return virtual_stack_registers_memory_p (x);
if (legitimate_constant_pool_address_p (x, mode, strict || lra_in_progress))
return false;
if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
return false;
+ /* quad word addresses are restricted, and we can't use LO_SUM. */
+ if (mode_supports_vsx_dform_quad (mode))
+ return false;
/* Restrict addressing for DI because of our SUBREG hackery. */
if (TARGET_E500_DOUBLE && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
return false;
if (DEFAULT_ABI == ABI_V4 && flag_pic)
return false;
- /* LRA don't use LEGITIMIZE_RELOAD_ADDRESS as it usually calls
+ /* LRA doesn't use LEGITIMIZE_RELOAD_ADDRESS as it usually calls
push_reload from reload pass code. LEGITIMIZE_RELOAD_ADDRESS
recognizes some LO_SUM addresses as valid although this
function says opposite. In most cases, LRA through different
{
unsigned int extra;
- if (!reg_offset_addressing_ok_p (mode))
+ if (!reg_offset_addressing_ok_p (mode)
+ || mode_supports_vsx_dform_quad (mode))
{
if (virtual_stack_registers_memory_p (x))
return x;
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
&& GET_CODE (XEXP (x, 1)) == CONST_INT)
{
+ 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);
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);
{
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);
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);
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);
{
x = create_TOC_reference (x, NULL_RTX);
if (TARGET_CMODEL != CMODEL_SMALL)
- push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
- BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
- opnum, (enum reload_type) type);
+ {
+ 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;
}
rs6000_legitimate_address_p (machine_mode mode, rtx x, bool reg_ok_strict)
{
bool reg_offset_p = reg_offset_addressing_ok_p (mode);
+ bool quad_offset_p = mode_supports_vsx_dform_quad (mode);
/* If this is an unaligned stvx/ldvx type address, discard the outer AND. */
if (VECTOR_MEM_ALTIVEC_P (mode)
return 1;
if (virtual_stack_registers_memory_p (x))
return 1;
- if (reg_offset_p && legitimate_small_data_p (mode, x))
- return 1;
- if (reg_offset_p
- && legitimate_constant_pool_address_p (x, mode,
+
+ /* Handle restricted vector d-form offsets in ISA 3.0. */
+ if (quad_offset_p)
+ {
+ if (quad_address_p (x, mode, false))
+ return 1;
+ }
+
+ else if (reg_offset_p)
+ {
+ if (legitimate_small_data_p (mode, x))
+ return 1;
+ if (legitimate_constant_pool_address_p (x, mode,
reg_ok_strict || lra_in_progress))
- return 1;
- if (reg_offset_p && reg_addr[mode].fused_toc && GET_CODE (x) == UNSPEC
- && XINT (x, 1) == UNSPEC_FUSION_ADDIS)
- return 1;
+ return 1;
+ if (reg_addr[mode].fused_toc && GET_CODE (x) == UNSPEC
+ && XINT (x, 1) == UNSPEC_FUSION_ADDIS)
+ return 1;
+ }
+
/* For TImode, if we have load/store quad and TImode in VSX registers, only
allow register indirect addresses. This will allow the values to go in
either GPRs or VSX registers without reloading. The vector types would
&& legitimate_indexed_address_p (XEXP (x, 1), reg_ok_strict)))
&& rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
return 1;
- if (reg_offset_p && legitimate_lo_sum_address_p (mode, x, reg_ok_strict))
+ if (reg_offset_p && !quad_offset_p
+ && legitimate_lo_sum_address_p (mode, x, reg_ok_strict))
return 1;
return 0;
}
}
}
+ else if ((addr_mask & RELOAD_REG_QUAD_OFFSET) != 0
+ && CONST_INT_P (plus_arg1))
+ {
+ if (!quad_address_offset_p (INTVAL (plus_arg1)))
+ {
+ extra_cost = 1;
+ type = "vector d-form offset";
+ }
+ }
+
/* Make sure the register class can handle offset addresses. */
else if (rs6000_legitimate_offset_address_p (mode, addr, false, true))
{
if ((addr_mask & RELOAD_REG_OFFSET) == 0)
{
extra_cost = 1;
- type = "offset";
+ type = "offset #2";
}
}
break;
case LO_SUM:
- if (!legitimate_lo_sum_address_p (mode, addr, false))
+ /* Quad offsets are restricted and can't handle normal addresses. */
+ if ((addr_mask & RELOAD_REG_QUAD_OFFSET) != 0)
+ {
+ extra_cost = -1;
+ type = "vector d-form lo_sum";
+ }
+
+ else if (!legitimate_lo_sum_address_p (mode, addr, false))
{
fail_msg = "bad LO_SUM";
extra_cost = -1;
case CONST:
case SYMBOL_REF:
case LABEL_REF:
- type = "address";
- extra_cost = rs6000_secondary_reload_toc_costs (addr_mask);
+ if ((addr_mask & RELOAD_REG_QUAD_OFFSET) != 0)
+ {
+ extra_cost = -1;
+ type = "vector d-form lo_sum #2";
+ }
+
+ else
+ {
+ type = "address";
+ extra_cost = rs6000_secondary_reload_toc_costs (addr_mask);
+ }
break;
/* TOC references look like offsetable memory. */
extra_cost = -1;
}
+ else if ((addr_mask & RELOAD_REG_QUAD_OFFSET) != 0)
+ {
+ extra_cost = -1;
+ type = "vector d-form lo_sum #3";
+ }
+
else if ((addr_mask & RELOAD_REG_OFFSET) == 0)
{
extra_cost = 1;
}
}
+ else if (mode_supports_vsx_dform_quad (mode) && CONST_INT_P (op1))
+ {
+ if (((addr_mask & RELOAD_REG_QUAD_OFFSET) == 0)
+ || !quad_address_p (addr, mode, false))
+ {
+ emit_insn (gen_rtx_SET (scratch, addr));
+ new_addr = scratch;
+ }
+ }
+
/* Make sure the register class can handle offset addresses. */
else if (rs6000_legitimate_offset_address_p (mode, addr, false, true))
{
}
}
+ /* Quad offsets are restricted and can't handle normal addresses. */
+ else if (mode_supports_vsx_dform_quad (mode))
+ {
+ emit_insn (gen_rtx_SET (scratch, addr));
+ new_addr = scratch;
+ }
+
/* Make sure the register class can handle offset addresses. */
else if (legitimate_lo_sum_address_p (mode, addr, false))
{
}
/* D-form addressing can easily reload the value. */
- if (mode_supports_vmx_dform (mode))
+ if (mode_supports_vmx_dform (mode)
+ || mode_supports_vsx_dform_quad (mode))
return rclass;
/* If this is a scalar floating point value and we don't have D-form
else if (TARGET_VSX && dest_vsx_p)
{
- if (mode == V16QImode || mode == V8HImode || mode == V4SImode)
+ if (mode_supports_vsx_dform_quad (mode)
+ && quad_address_p (XEXP (src, 0), mode, false))
+ return "lxv %x0,%1";
+
+ else if (TARGET_P9_VECTOR)
+ return "lxvx %x0,%y1";
+
+ else if (mode == V16QImode || mode == V8HImode || mode == V4SImode)
return "lxvw4x %x0,%y1";
+
else
return "lxvd2x %x0,%y1";
}
else if (TARGET_VSX && src_vsx_p)
{
- if (mode == V16QImode || mode == V8HImode || mode == V4SImode)
+ if (mode_supports_vsx_dform_quad (mode)
+ && quad_address_p (XEXP (dest, 0), mode, false))
+ return "stxv %x1,%0";
+
+ else if (TARGET_P9_VECTOR)
+ return "stxvx %x1,%y0";
+
+ else if (mode == V16QImode || mode == V8HImode || mode == V4SImode)
return "stxvw4x %x1,%y0";
+
else
return "stxvd2x %x1,%y0";
}
if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
{
rtx areg, savereg, mem;
- int offset;
+ HOST_WIDE_INT offset;
offset = (info->altivec_save_offset + frame_off
+ 16 * (i - info->first_altivec_reg_save));
savereg = gen_rtx_REG (V4SImode, i);
- NOT_INUSE (0);
- areg = gen_rtx_REG (Pmode, 0);
- emit_move_insn (areg, GEN_INT (offset));
-
- /* AltiVec addressing mode is [reg+reg]. */
- mem = gen_frame_mem (V4SImode,
- gen_rtx_PLUS (Pmode, frame_reg_rtx, areg));
+ if (TARGET_P9_DFORM_VECTOR && quad_address_offset_p (offset))
+ {
+ mem = gen_frame_mem (V4SImode,
+ gen_rtx_PLUS (Pmode, frame_reg_rtx,
+ GEN_INT (offset)));
+ insn = emit_insn (gen_rtx_SET (mem, savereg));
+ areg = NULL_RTX;
+ }
+ else
+ {
+ NOT_INUSE (0);
+ areg = gen_rtx_REG (Pmode, 0);
+ emit_move_insn (areg, GEN_INT (offset));
- /* Rather than emitting a generic move, force use of the stvx
- instruction, which we always want. In particular we don't
- want xxpermdi/stxvd2x for little endian. */
- insn = emit_insn (gen_altivec_stvx_v4si_internal (mem, savereg));
+ /* AltiVec addressing mode is [reg+reg]. */
+ mem = gen_frame_mem (V4SImode,
+ gen_rtx_PLUS (Pmode, frame_reg_rtx, areg));
+
+ /* Rather than emitting a generic move, force use of the stvx
+ instruction, which we always want on ISA 2.07 (power8) systems.
+ In particular we don't want xxpermdi/stxvd2x for little
+ endian. */
+ insn = emit_insn (gen_altivec_stvx_v4si_internal (mem, savereg));
+ }
rs6000_frame_related (insn, frame_reg_rtx, sp_off - frame_off,
areg, GEN_INT (offset));
for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
{
- rtx addr, areg, mem, reg;
+ rtx addr, areg, mem, insn;
+ rtx reg = gen_rtx_REG (V4SImode, i);
+ HOST_WIDE_INT offset
+ = (info->altivec_save_offset + frame_off
+ + 16 * (i - info->first_altivec_reg_save));
- areg = gen_rtx_REG (Pmode, 0);
- emit_move_insn
- (areg, GEN_INT (info->altivec_save_offset
- + frame_off
- + 16 * (i - info->first_altivec_reg_save)));
+ if (TARGET_P9_DFORM_VECTOR && quad_address_offset_p (offset))
+ {
+ mem = gen_frame_mem (V4SImode,
+ gen_rtx_PLUS (Pmode, frame_reg_rtx,
+ GEN_INT (offset)));
+ insn = gen_rtx_SET (reg, mem);
+ }
+ else
+ {
+ areg = gen_rtx_REG (Pmode, 0);
+ emit_move_insn (areg, GEN_INT (offset));
- /* AltiVec addressing mode is [reg+reg]. */
- addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
- mem = gen_frame_mem (V4SImode, addr);
-
- reg = gen_rtx_REG (V4SImode, i);
- /* Rather than emitting a generic move, force use of the
- lvx instruction, which we always want. In particular
- we don't want lxvd2x/xxpermdi for little endian. */
- (void) emit_insn (gen_altivec_lvx_v4si_internal (reg, mem));
+ /* AltiVec addressing mode is [reg+reg]. */
+ addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
+ mem = gen_frame_mem (V4SImode, addr);
+
+ /* Rather than emitting a generic move, force use of the
+ lvx instruction, which we always want. In particular we
+ don't want lxvd2x/xxpermdi for little endian. */
+ insn = gen_altivec_lvx_v4si_internal (reg, mem);
+ }
+
+ (void) emit_insn (insn);
}
}
for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
{
- rtx addr, areg, mem, reg;
+ rtx addr, areg, mem, insn;
+ rtx reg = gen_rtx_REG (V4SImode, i);
+ HOST_WIDE_INT offset
+ = (info->altivec_save_offset + frame_off
+ + 16 * (i - info->first_altivec_reg_save));
- areg = gen_rtx_REG (Pmode, 0);
- emit_move_insn
- (areg, GEN_INT (info->altivec_save_offset
- + frame_off
- + 16 * (i - info->first_altivec_reg_save)));
+ if (TARGET_P9_DFORM_VECTOR && quad_address_offset_p (offset))
+ {
+ mem = gen_frame_mem (V4SImode,
+ gen_rtx_PLUS (Pmode, frame_reg_rtx,
+ GEN_INT (offset)));
+ insn = gen_rtx_SET (reg, mem);
+ }
+ else
+ {
+ areg = gen_rtx_REG (Pmode, 0);
+ emit_move_insn (areg, GEN_INT (offset));
- /* AltiVec addressing mode is [reg+reg]. */
- addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
- mem = gen_frame_mem (V4SImode, addr);
-
- reg = gen_rtx_REG (V4SImode, i);
- /* Rather than emitting a generic move, force use of the
- lvx instruction, which we always want. In particular
- we don't want lxvd2x/xxpermdi for little endian. */
- (void) emit_insn (gen_altivec_lvx_v4si_internal (reg, mem));
+ /* AltiVec addressing mode is [reg+reg]. */
+ addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
+ mem = gen_frame_mem (V4SImode, addr);
+
+ /* Rather than emitting a generic move, force use of the
+ lvx instruction, which we always want. In particular we
+ don't want lxvd2x/xxpermdi for little endian. */
+ insn = gen_altivec_lvx_v4si_internal (reg, mem);
+ }
+
+ (void) emit_insn (insn);
}
}
static bool
rs6000_lra_p (void)
{
- return rs6000_lra_flag;
+ return TARGET_LRA;
}
/* Given FROM and TO register numbers, say whether this elimination is allowed.
{ "power8-fusion", OPTION_MASK_P8_FUSION, false, true },
{ "power8-fusion-sign", OPTION_MASK_P8_FUSION_SIGN, false, true },
{ "power8-vector", OPTION_MASK_P8_VECTOR, false, true },
- { "power9-dform", OPTION_MASK_P9_DFORM, false, true },
+ { "power9-dform-scalar", OPTION_MASK_P9_DFORM_SCALAR, false, true },
+ { "power9-dform-vector", OPTION_MASK_P9_DFORM_VECTOR, false, true },
{ "power9-fusion", OPTION_MASK_P9_FUSION, false, true },
{ "power9-minmax", OPTION_MASK_P9_MINMAX, false, true },
{ "power9-vector", OPTION_MASK_P9_VECTOR, false, true },
size_t i;
size_t start_column = 0;
size_t cur_column;
- size_t max_column = 76;
+ size_t max_column = 120;
+ size_t prefix_len = strlen (prefix);
+ size_t comma_len = 0;
const char *comma = "";
if (indent)
cur_column = start_column;
for (i = 0; i < num_elements; i++)
{
- if ((flags & opts[i].mask) != 0)
+ bool invert = opts[i].invert;
+ const char *name = opts[i].name;
+ const char *no_str = "";
+ HOST_WIDE_INT mask = opts[i].mask;
+ size_t len = comma_len + prefix_len + strlen (name);
+
+ if (!invert)
{
- const char *no_str = rs6000_opt_masks[i].invert ? "no-" : "";
- size_t len = (strlen (comma)
- + strlen (prefix)
- + strlen (no_str)
- + strlen (rs6000_opt_masks[i].name));
+ if ((flags & mask) == 0)
+ {
+ no_str = "no-";
+ len += sizeof ("no-") - 1;
+ }
- cur_column += len;
- if (cur_column > max_column)
+ flags &= ~mask;
+ }
+
+ else
+ {
+ if ((flags & mask) != 0)
{
- fprintf (stderr, ", \\\n%*s", (int)start_column, "");
- cur_column = start_column + len;
- comma = "";
+ no_str = "no-";
+ len += sizeof ("no-") - 1;
}
- fprintf (file, "%s%s%s%s", comma, prefix, no_str,
- rs6000_opt_masks[i].name);
- flags &= ~ opts[i].mask;
- comma = ", ";
+ flags |= mask;
}
+
+ cur_column += len;
+ if (cur_column > max_column)
+ {
+ fprintf (stderr, ", \\\n%*s", (int)start_column, "");
+ cur_column = start_column + len;
+ comma = "";
+ }
+
+ fprintf (file, "%s%s%s%s", comma, prefix, no_str, name);
+ comma = ", ";
+ comma_len = sizeof (", ") - 1;
}
fputs ("\n", file);
UNSPEC_VSX_XVCVDPUXDS
])
-;; VSX (P9) moves
-
-(define_insn "*p9_vecload_<mode>"
- [(set (match_operand:VSX_M2 0 "vsx_register_operand" "=<VSa>")
- (match_operand:VSX_M2 1 "memory_operand" "Z"))]
- "TARGET_P9_VECTOR"
- "lxvx %x0,%y1"
- [(set_attr "type" "vecload")
- (set_attr "length" "4")])
-
-(define_insn "*p9_vecstore_<mode>"
- [(set (match_operand:VSX_M2 0 "memory_operand" "=Z")
- (match_operand:VSX_M2 1 "vsx_register_operand" "<VSa>"))]
- "TARGET_P9_VECTOR"
- "stxvx %x1,%y0"
- [(set_attr "type" "vecstore")
- (set_attr "length" "4")])
-
;; VSX moves
;; The patterns for LE permuted loads and stores come before the general
"")
(define_insn "*vsx_mov<mode>"
- [(set (match_operand:VSX_M 0 "nonimmediate_operand" "=Z,<VSr>,<VSr>,?Z,?<VSa>,?<VSa>,r,we,wQ,?&r,??Y,??r,??r,<VSr>,?<VSa>,*r,v,wZ,v")
- (match_operand:VSX_M 1 "input_operand" "<VSr>,Z,<VSr>,<VSa>,Z,<VSa>,we,b,r,wQ,r,Y,r,j,j,j,W,v,wZ"))]
+ [(set (match_operand:VSX_M 0 "nonimmediate_operand" "=ZwO,<VSr>,<VSr>,?ZwO,?<VSa>,?<VSa>,r,we,wQ,?&r,??Y,??r,??r,<VSr>,?<VSa>,*r,v,wZ,v")
+ (match_operand:VSX_M 1 "input_operand" "<VSr>,ZwO,<VSr>,<VSa>,ZwO,<VSa>,we,b,r,wQ,r,Y,r,j,j,j,W,v,wZ"))]
"VECTOR_MEM_VSX_P (<MODE>mode)
&& (register_operand (operands[0], <MODE>mode)
|| register_operand (operands[1], <MODE>mode))"
;; use of TImode is for unions. However for plain data movement, slightly
;; favor the vector loads
(define_insn "*vsx_movti_64bit"
- [(set (match_operand:TI 0 "nonimmediate_operand" "=Z,wa,wa,wa,r,we,v,v,wZ,wQ,&r,Y,r,r,?r")
- (match_operand:TI 1 "input_operand" "wa,Z,wa,O,we,b,W,wZ,v,r,wQ,r,Y,r,n"))]
+ [(set (match_operand:TI 0 "nonimmediate_operand" "=ZwO,wa,wa,wa,r,we,v,v,wZ,wQ,&r,Y,r,r,?r")
+ (match_operand:TI 1 "input_operand" "wa,ZwO,wa,O,we,b,W,wZ,v,r,wQ,r,Y,r,n"))]
"TARGET_POWERPC64 && VECTOR_MEM_VSX_P (TImode)
&& (register_operand (operands[0], TImode)
|| register_operand (operands[1], TImode))"
(set_attr "length" "4,4,4,4,8,4,16,4,4,8,8,8,8,8,8")])
(define_insn "*vsx_movti_32bit"
- [(set (match_operand:TI 0 "nonimmediate_operand" "=Z,wa,wa,wa,v, v,wZ,Q,Y,????r,????r,????r,r")
- (match_operand:TI 1 "input_operand" "wa, Z,wa, O,W,wZ, v,r,r, Q, Y, r,n"))]
+ [(set (match_operand:TI 0 "nonimmediate_operand" "=ZwO,wa,wa,wa,v,v,wZ,Q,Y,????r,????r,????r,r")
+ (match_operand:TI 1 "input_operand" "wa,ZwO,wa,O,W,wZ,v,r,r,Q,Y,r,n"))]
"! TARGET_POWERPC64 && VECTOR_MEM_VSX_P (TImode)
&& (register_operand (operands[0], TImode)
|| register_operand (operands[1], TImode))"