diff mbox series

V10 patch #7, Improve vector_extract code of a PC-relative address with a constant offset for -mcpu=future

Message ID 20191212005835.GG27911@ibm-toto.the-meissners.org
State New
Headers show
Series V10 patch #7, Improve vector_extract code of a PC-relative address with a constant offset for -mcpu=future | expand

Commit Message

Michael Meissner Dec. 12, 2019, 12:58 a.m. UTC
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  <meissner@linux.ibm.com>

	* 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.
diff mbox series

Patch

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;