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> 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 * config/rs6000/rs6000.c (get_vector_offset): New helper function
to calculate the offset in memory from the start of a vector of a to calculate the offset in memory from the start of a vector of a
particular element. Add code to keep the element number in particular element. Add code to keep the element number in
......
...@@ -1169,6 +1169,7 @@ static bool rs6000_secondary_reload_move (enum rs6000_reg_type, ...@@ -1169,6 +1169,7 @@ static bool rs6000_secondary_reload_move (enum rs6000_reg_type,
machine_mode, machine_mode,
secondary_reload_info *, secondary_reload_info *,
bool); bool);
static enum non_prefixed_form reg_to_non_prefixed (rtx reg, machine_mode mode);
rtl_opt_pass *make_pass_analyze_swaps (gcc::context*); rtl_opt_pass *make_pass_analyze_swaps (gcc::context*);
/* Hash table stuff for keeping track of TOC entries. */ /* Hash table stuff for keeping track of TOC entries. */
...@@ -6726,30 +6727,6 @@ rs6000_expand_vector_extract (rtx target, rtx vec, rtx elt) ...@@ -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 /* 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 element within the vector (ELEMENT) with an element size (SCALAR_SIZE). If
the element is constant, we return a constant integer. the element is constant, we return a constant integer.
...@@ -6809,7 +6786,6 @@ rs6000_adjust_vec_address (rtx scalar_reg, ...@@ -6809,7 +6786,6 @@ rs6000_adjust_vec_address (rtx scalar_reg,
unsigned scalar_size = GET_MODE_SIZE (scalar_mode); unsigned scalar_size = GET_MODE_SIZE (scalar_mode);
rtx addr = XEXP (mem, 0); rtx addr = XEXP (mem, 0);
rtx new_addr; rtx new_addr;
bool valid_addr_p;
gcc_assert (!reg_mentioned_p (base_tmp, addr)); gcc_assert (!reg_mentioned_p (base_tmp, addr));
gcc_assert (!reg_mentioned_p (base_tmp, element)); gcc_assert (!reg_mentioned_p (base_tmp, element));
...@@ -6837,68 +6813,34 @@ rs6000_adjust_vec_address (rtx scalar_reg, ...@@ -6837,68 +6813,34 @@ rs6000_adjust_vec_address (rtx scalar_reg,
{ {
rtx op0 = XEXP (addr, 0); rtx op0 = XEXP (addr, 0);
rtx op1 = XEXP (addr, 1); rtx op1 = XEXP (addr, 1);
rtx insn;
gcc_assert (REG_P (op0) || SUBREG_P (op0)); gcc_assert (REG_P (op0) || SUBREG_P (op0));
if (CONST_INT_P (op1) && CONST_INT_P (element_offset)) 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); HOST_WIDE_INT offset = INTVAL (op1) + INTVAL (element_offset);
rtx offset_rtx = GEN_INT (offset); rtx offset_rtx = GEN_INT (offset);
new_addr = gen_rtx_PLUS (Pmode, op0, offset_rtx);
/* 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);
}
} }
else else
{ {
bool op1_reg_p = (REG_P (op1) || SUBREG_P (op1)); /* If we don't have a D-FORM address with a constant element number,
bool ele_reg_p = (REG_P (element_offset) || SUBREG_P (element_offset)); 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 Previously, we tried to add the offset to OP1 and change the
extracted is variable, and we've put the offset into base_tmp address to an X-FORM format adding OP0 and BASE_TMP, but it became
previously. */ complicated because we had to verify that op1 was not GPR0 and we
else if (reg_mentioned_p (base_tmp, element_offset)) had a constant element offset (due to the way ADDI is defined).
emit_insn (gen_add2_insn (base_tmp, op1)); 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
else allowed, the offset is part of the memory access to the vector
{ element. */
emit_move_insn (base_tmp, op1); emit_insn (gen_rtx_SET (base_tmp, gen_rtx_PLUS (Pmode, op0, op1)));
emit_insn (gen_add2_insn (base_tmp, element_offset)); new_addr = gen_rtx_PLUS (Pmode, base_tmp, element_offset);
}
new_addr = gen_rtx_PLUS (Pmode, op0, base_tmp);
} }
} }
...@@ -6908,27 +6850,19 @@ rs6000_adjust_vec_address (rtx scalar_reg, ...@@ -6908,27 +6850,19 @@ rs6000_adjust_vec_address (rtx scalar_reg,
new_addr = gen_rtx_PLUS (Pmode, base_tmp, element_offset); new_addr = gen_rtx_PLUS (Pmode, base_tmp, element_offset);
} }
/* If we have a PLUS, we need to see whether the particular register class /* If the address isn't valid, move the address into the temporary base
allows for D-FORM or X-FORM addressing. */ register. Some reasons it could not be valid include:
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 (REG_P (op1) || SUBREG_P (op1)) The address offset overflowed the 16 or 34 bit offset size;
valid_addr_p = (addr_mask & RELOAD_REG_INDEXED) != 0; We need to use a DS-FORM load, and the bottom 2 bits are non-zero;
else We need to use a DQ-FORM load, and the bottom 4 bits are non-zero;
valid_addr_p = (addr_mask & RELOAD_REG_OFFSET) != 0; Only X_FORM loads can be done, and the address is D_FORM. */
}
else if (REG_P (new_addr) || SUBREG_P (new_addr)) enum insn_form iform
valid_addr_p = true; = 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); emit_move_insn (base_tmp, new_addr);
new_addr = base_tmp; 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