Rewrite convulated code to avoid adding r0.

2020-02-03  Michael Meissner  <meissner@linux.ibm.com>

	* config/rs6000/rs6000.c (reg_to_non_prefixed): Add forward
	reference.
	(hard_reg_and_mode_to_addr_mask): Delete.
	(rs6000_adjust_vec_address): If the original vector address
	was REG+REG or REG+OFFSET and the element is not zero, do the add
	of the elements in the original address before adding the offset
	for the vector element.  Use address_to_insn_form to validate the
	address using the register being loaded, rather than guessing
	whether the address is a DS-FORM or DQ-FORM address.
This commit is contained in:
Michael Meissner 2020-02-03 18:22:18 -05:00
parent e7f3e07528
commit fb47dc28d2
2 changed files with 41 additions and 95 deletions

View File

@ -1,3 +1,15 @@
2020-02-03 Michael Meissner <meissner@linux.ibm.com>
* config/rs6000/rs6000.c (reg_to_non_prefixed): Add forward
reference.
(hard_reg_and_mode_to_addr_mask): Delete.
(rs6000_adjust_vec_address): If the original vector address
was REG+REG or REG+OFFSET and the element is not zero, do the add
of the elements in the original address before adding the offset
for the vector element. Use address_to_insn_form to validate the
address using the register being loaded, rather than guessing
whether the address is a DS-FORM or DQ-FORM address.
2020-02-03 Michael Meissner <meissner@linux.ibm.com>
* config/rs6000/rs6000.c (get_vector_offset): New helper function

View File

@ -1169,6 +1169,7 @@ static bool rs6000_secondary_reload_move (enum rs6000_reg_type,
machine_mode,
secondary_reload_info *,
bool);
static enum non_prefixed_form reg_to_non_prefixed (rtx reg, machine_mode mode);
rtl_opt_pass *make_pass_analyze_swaps (gcc::context*);
/* Hash table stuff for keeping track of TOC entries. */
@ -6726,30 +6727,6 @@ rs6000_expand_vector_extract (rtx target, rtx vec, rtx elt)
}
}
/* Helper function to return an address mask based on a physical register. */
static addr_mask_type
hard_reg_and_mode_to_addr_mask (rtx reg, machine_mode mode)
{
unsigned int r = reg_or_subregno (reg);
addr_mask_type addr_mask;
gcc_assert (HARD_REGISTER_NUM_P (r));
if (INT_REGNO_P (r))
addr_mask = reg_addr[mode].addr_mask[RELOAD_REG_GPR];
else if (FP_REGNO_P (r))
addr_mask = reg_addr[mode].addr_mask[RELOAD_REG_FPR];
else if (ALTIVEC_REGNO_P (r))
addr_mask = reg_addr[mode].addr_mask[RELOAD_REG_VMX];
else
gcc_unreachable ();
return addr_mask;
}
/* Return the offset within a memory object (MEM) of a vector type to a given
element within the vector (ELEMENT) with an element size (SCALAR_SIZE). If
the element is constant, we return a constant integer.
@ -6809,7 +6786,6 @@ rs6000_adjust_vec_address (rtx scalar_reg,
unsigned scalar_size = GET_MODE_SIZE (scalar_mode);
rtx addr = XEXP (mem, 0);
rtx new_addr;
bool valid_addr_p;
gcc_assert (!reg_mentioned_p (base_tmp, addr));
gcc_assert (!reg_mentioned_p (base_tmp, element));
@ -6837,68 +6813,34 @@ rs6000_adjust_vec_address (rtx scalar_reg,
{
rtx op0 = XEXP (addr, 0);
rtx op1 = XEXP (addr, 1);
rtx insn;
gcc_assert (REG_P (op0) || SUBREG_P (op0));
if (CONST_INT_P (op1) && CONST_INT_P (element_offset))
{
/* op0 should never be r0, because r0+offset is not valid. But it
doesn't hurt to make sure it is not r0. */
gcc_assert (reg_or_subregno (op0) != 0);
/* D-FORM address with constant element number. */
HOST_WIDE_INT offset = INTVAL (op1) + INTVAL (element_offset);
rtx offset_rtx = GEN_INT (offset);
/* 16-bit offset. */
if (SIGNED_INTEGER_16BIT_P (offset)
&& (scalar_size < 8 || (offset & 0x3) == 0))
new_addr = gen_rtx_PLUS (Pmode, op0, offset_rtx);
/* 34-bit offset if we have prefixed addresses. */
else if (TARGET_PREFIXED_ADDR && SIGNED_INTEGER_34BIT_P (offset))
new_addr = gen_rtx_PLUS (Pmode, op0, offset_rtx);
else
{
/* Offset overflowed, move offset to the temporary (which will
likely be split), and do X-FORM addressing. */
emit_move_insn (base_tmp, offset_rtx);
new_addr = gen_rtx_PLUS (Pmode, op0, base_tmp);
}
new_addr = gen_rtx_PLUS (Pmode, op0, offset_rtx);
}
else
{
bool op1_reg_p = (REG_P (op1) || SUBREG_P (op1));
bool ele_reg_p = (REG_P (element_offset) || SUBREG_P (element_offset));
/* If we don't have a D-FORM address with a constant element number,
add the two elements in the current address. Then add the offset.
/* Note, ADDI requires the register being added to be a base
register. If the register was R0, load it up into the temporary
and do the add. */
if (op1_reg_p
&& (ele_reg_p || reg_or_subregno (op1) != FIRST_GPR_REGNO))
{
insn = gen_add3_insn (base_tmp, op1, element_offset);
gcc_assert (insn != NULL_RTX);
emit_insn (insn);
}
else if (ele_reg_p
&& reg_or_subregno (element_offset) != FIRST_GPR_REGNO)
{
insn = gen_add3_insn (base_tmp, element_offset, op1);
gcc_assert (insn != NULL_RTX);
emit_insn (insn);
}
/* Make sure we don't overwrite the temporary if the element being
extracted is variable, and we've put the offset into base_tmp
previously. */
else if (reg_mentioned_p (base_tmp, element_offset))
emit_insn (gen_add2_insn (base_tmp, op1));
else
{
emit_move_insn (base_tmp, op1);
emit_insn (gen_add2_insn (base_tmp, element_offset));
}
new_addr = gen_rtx_PLUS (Pmode, op0, base_tmp);
Previously, we tried to add the offset to OP1 and change the
address to an X-FORM format adding OP0 and BASE_TMP, but it became
complicated because we had to verify that op1 was not GPR0 and we
had a constant element offset (due to the way ADDI is defined).
By doing the add of OP0 and OP1 first, and then adding in the
offset, it has the benefit that if D-FORM instructions are
allowed, the offset is part of the memory access to the vector
element. */
emit_insn (gen_rtx_SET (base_tmp, gen_rtx_PLUS (Pmode, op0, op1)));
new_addr = gen_rtx_PLUS (Pmode, base_tmp, element_offset);
}
}
@ -6908,27 +6850,19 @@ rs6000_adjust_vec_address (rtx scalar_reg,
new_addr = gen_rtx_PLUS (Pmode, base_tmp, element_offset);
}
/* If we have a PLUS, we need to see whether the particular register class
allows for D-FORM or X-FORM addressing. */
if (GET_CODE (new_addr) == PLUS)
{
rtx op1 = XEXP (new_addr, 1);
addr_mask_type addr_mask
= hard_reg_and_mode_to_addr_mask (scalar_reg, scalar_mode);
/* If the address isn't valid, move the address into the temporary base
register. Some reasons it could not be valid include:
if (REG_P (op1) || SUBREG_P (op1))
valid_addr_p = (addr_mask & RELOAD_REG_INDEXED) != 0;
else
valid_addr_p = (addr_mask & RELOAD_REG_OFFSET) != 0;
}
The address offset overflowed the 16 or 34 bit offset size;
We need to use a DS-FORM load, and the bottom 2 bits are non-zero;
We need to use a DQ-FORM load, and the bottom 4 bits are non-zero;
Only X_FORM loads can be done, and the address is D_FORM. */
else if (REG_P (new_addr) || SUBREG_P (new_addr))
valid_addr_p = true;
enum insn_form iform
= address_to_insn_form (new_addr, scalar_mode,
reg_to_non_prefixed (scalar_reg, scalar_mode));
else
valid_addr_p = false;
if (!valid_addr_p)
if (iform == INSN_FORM_BAD)
{
emit_move_insn (base_tmp, new_addr);
new_addr = base_tmp;