This patch improves the code of vector_extract when the vector is addressed
with a PC-relative address, and the element number is constant.
I.e.
#include <altivec.h>
static vector double vd[10];
vector double *p = &vd[0];
double get (void)
{
return vector_extract (vd[4], 1);
}
I have bootstrapped this code on a little endian power8 and ran make check and
there were no regressions. Can I check this into the trunk?
2019-12-10 Michael Meissner <[email protected]>
* config/rs6000/rs6000.c (rs6000_reg_to_addr_mask): New helper
function.
(rs6000_adjust_vec_address): Add support for folding a constant
offset of a vector extract of a vector accessed with PC-relative
addressing into the offset of the load.
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c (revision 279200)
+++ gcc/config/rs6000/rs6000.c (working copy)
@@ -6698,6 +6698,30 @@ rs6000_expand_vector_extract (rtx target
}
}
+/* Helper function to return an address mask based on a physical register. */
+
+static addr_mask_type
+rs6000_reg_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;
+}
+
/* Adjust a memory address (MEM) of a vector type to point to a scalar field
within the vector (ELEMENT) with a mode (SCALAR_MODE). Use a base register
temporary (BASE_TMP) to fixup the address. Return the new memory address
@@ -6823,8 +6847,57 @@ rs6000_adjust_vec_address (rtx scalar_re
}
}
+ /* For references to local static variables, try to fold a constant offset
+ into the address. */
+ else if (pcrel_local_address (addr, Pmode) && CONST_INT_P (element_offset))
+ {
+ if (GET_CODE (addr) == CONST)
+ addr = XEXP (addr, 0);
+
+ if (GET_CODE (addr) == PLUS)
+ {
+ rtx op0 = XEXP (addr, 0);
+ rtx op1 = XEXP (addr, 1);
+ if (CONST_INT_P (op1))
+ {
+ HOST_WIDE_INT offset
+ = INTVAL (XEXP (addr, 1)) + INTVAL (element_offset);
+
+ if (offset == 0)
+ new_addr = op0;
+
+ else if (SIGNED_34BIT_OFFSET_P (offset))
+ {
+ rtx plus = gen_rtx_PLUS (Pmode, op0, GEN_INT (offset));
+ new_addr = gen_rtx_CONST (Pmode, plus);
+ }
+
+ else
+ {
+ emit_move_insn (base_tmp, addr);
+ new_addr = gen_rtx_PLUS (Pmode, base_tmp, element_offset);
+ }
+ }
+ else
+ {
+ emit_move_insn (base_tmp, addr);
+ new_addr = gen_rtx_PLUS (Pmode, base_tmp, element_offset);
+ }
+ }
+
+ else
+ {
+ rtx plus = gen_rtx_PLUS (Pmode, addr, element_offset);
+ new_addr = gen_rtx_CONST (Pmode, plus);
+ }
+ }
+
else
{
+ /* Make sure we don't overwrite the temporary if the vector extract
+ offset was variable. */
+ gcc_assert (!rtx_equal_p (base_tmp, element_offset));
+
emit_move_insn (base_tmp, addr);
new_addr = gen_rtx_PLUS (Pmode, base_tmp, element_offset);
}
@@ -6834,21 +6907,8 @@ rs6000_adjust_vec_address (rtx scalar_re
if (GET_CODE (new_addr) == PLUS)
{
rtx op1 = XEXP (new_addr, 1);
- addr_mask_type addr_mask;
- unsigned int scalar_regno = reg_or_subregno (scalar_reg);
-
- gcc_assert (HARD_REGISTER_NUM_P (scalar_regno));
- if (INT_REGNO_P (scalar_regno))
- addr_mask = reg_addr[scalar_mode].addr_mask[RELOAD_REG_GPR];
-
- else if (FP_REGNO_P (scalar_regno))
- addr_mask = reg_addr[scalar_mode].addr_mask[RELOAD_REG_FPR];
-
- else if (ALTIVEC_REGNO_P (scalar_regno))
- addr_mask = reg_addr[scalar_mode].addr_mask[RELOAD_REG_VMX];
-
- else
- gcc_unreachable ();
+ addr_mask_type addr_mask
+ = rs6000_reg_to_addr_mask (scalar_reg, scalar_mode);
if (REG_P (op1) || SUBREG_P (op1))
valid_addr_p = (addr_mask & RELOAD_REG_INDEXED) != 0;
@@ -6856,9 +6916,21 @@ rs6000_adjust_vec_address (rtx scalar_re
valid_addr_p = (addr_mask & RELOAD_REG_OFFSET) != 0;
}
+ /* An address that is a single register is always valid for either indexed or
+ offsettable loads. */
else if (REG_P (new_addr) || SUBREG_P (new_addr))
valid_addr_p = true;
+ /* If we have a PC-relative address, check if offsetable loads are
+ allowed. */
+ else if (pcrel_local_address (new_addr, Pmode))
+ {
+ addr_mask_type addr_mask
+ = rs6000_reg_to_addr_mask (scalar_reg, scalar_mode);
+
+ valid_addr_p = (addr_mask & RELOAD_REG_OFFSET) != 0;
+ }
+
else
valid_addr_p = false;
--
Michael Meissner, IBM
IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA
email: [email protected], phone: +1 (978) 899-4797