Commit fb47dc28 by Michael Meissner

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.
parent e7f3e075
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
to calculate the offset in memory from the start of a vector of a
particular element. Add code to keep the element number in
......
......@@ -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));
/* 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);
}
/* 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.
/* 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;
else
valid_addr_p = false;
enum insn_form iform
= address_to_insn_form (new_addr, scalar_mode,
reg_to_non_prefixed (scalar_reg, scalar_mode));
if (!valid_addr_p)
if (iform == INSN_FORM_BAD)
{
emit_move_insn (base_tmp, new_addr);
new_addr = base_tmp;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment