This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH, V3, #3 of 10], Add prefixed RTL insn attribute


This patch adds the basic RTL insn attribute for doing prefixed and
pc-relative addressing.

It is fairly similar to the version 1 patch #2.

This patch is an infrastructure patch that will be used by the next
patch (#4) to use prefixed loads and stores where it is appropriate.
In this patch, only the load pc-relative address operations will
actually be flagged as a prefixed instruction.

In this patch, I kept the changes in rs6000.c and I did not create a
new file rs6000-prefixed.c.  I used the 'trad_insn' type introduced in
v3 patch #1, instead of the insn_form that was used previously.

I changed the 3 functions used to return whether that the current insn
is prefixed (which are called from the prefixed RTL attribute) to use
the operands directly.  It checks whether the "indexed" and "update"
attributes are both "no" for load/store operands, and that there are at
least 2 operands.

In reworking this patch from the previous patch, I have changed the
method for forcing LWA to be a DS format instruction instead of D
format.

Since I reworked things and patch #1 now has the insns to load up both
local and external prefixed addresses, this patch modifies those two
insns to use the "prefixed" RTL attribute instead of manually printing
out the leading "p".

I made a minor change to patch #1 to deal with _Complex IBM long double
that I hadn't thought of when I was doing patch #1.

Aaron Sawdey had discovered that vector extracts with a variable
element number where the vector is a local pc-relative symbol (i.e. in
static), would fail because it only had one temporary register.  In
this patch, I just put an abort if the user tried to do this operation.
In a later patch (#6), I will have a patch that does not allow the
optimization of vector extract from memory to be combined with a
variable element number, and instead, it will load up the address into
a register, and do the extract with that address.

I have built the GCC compiler with this patch and the previous two
patches on a little endian power8 system.  It bootstrapped fine and
there no regressions in running make check.  Can I check this patch
into the trunk, once the previous two patches are checked in?

2019-08-26  Michael Meissner  <meissner@linux.ibm.com>

	* config/rs6000/rs6000-protos.h (prefixed_load_p): New
	declaration.
	(prefixed_store_p): New declaration.
	(prefixed_paddi_p): New declaration.
	(rs6000_asm_output_opcode): New declaration.
	(rs6000_final_prescan_insn): New declaration.
	* config/rs6000/rs6000.c (addr_mask_to_trad_insn): Rework to deal
	with things like _Complex __ibm128.
	(reg_to_trad_insn): New helper function.
	(prefixed_load_p): New function for prefixed memory.
	(prefixed_store_p): New function for prefixed memory.
	(prefixed_paddi_p): New function for prefixed memory.
	(next_insn_prefixed_p): New state static flag.
	(rs6000_final_prescan_insn): New function for prefixed memory.
	(rs6000_asm_output_opcode): New function for prifixed memory.
	* config/rs6000/rs6000.h (FINAL_PRESCAN_INSN): New target hook.
	(ASM_OUTPUT_OPCODE): New target hook.
	* config/rs6000/rs6000.md (prefixed RTL attribute): New attribute
	for prefixed memory support.
	(prefixed_length RTL attribute): New attribute for prefixed memory
	support.
	(non_prefixed_length RTL attribute): New attribute for prefixed
	memory support.
	(length RTL attribute): Use prefixed, prefixed_length, and
	non_prefixed_lengths to set the default instruction length.
	(pcrel_local_addr): Change to use the prefixed attribute.
	(pcrel_ext_addr): Change to use the prefixed attribute.

Index: gcc/config/rs6000/rs6000-protos.h
===================================================================
--- gcc/config/rs6000/rs6000-protos.h	(revision 274870)
+++ gcc/config/rs6000/rs6000-protos.h	(working copy)
@@ -170,6 +170,11 @@ typedef enum {
 } trad_insn_type;
 
 extern bool prefixed_local_addr_p (rtx, machine_mode, trad_insn_type);
+extern bool prefixed_load_p (rtx_insn *);
+extern bool prefixed_store_p (rtx_insn *);
+extern bool prefixed_paddi_p (rtx_insn *);
+extern void rs6000_asm_output_opcode (FILE *);
+void rs6000_final_prescan_insn (rtx_insn *, rtx [], int);
 #endif /* RTX_CODE */
 
 #ifdef TREE_CODE
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 274871)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -13827,23 +13827,23 @@ addr_mask_to_trad_insn (machine_mode mod
      early RTL stages before register allocation has been done.  */
   if ((addr_mask & flags) == RELOAD_REG_MULTIPLE)
     {
-      machine_mode inner = word_mode;
+      machine_mode mode2 = mode;
 
-      if (COMPLEX_MODE_P (mode))
+      if (COMPLEX_MODE_P (mode2))
 	{
-	  inner = GET_MODE_INNER (mode);
-	  if ((reg_addr[inner].default_addr_mask & RELOAD_REG_OFFSET) == 0)
-	    inner = word_mode;
+	  machine_mode inner = GET_MODE_INNER (mode);
+	  if ((reg_addr[inner].default_addr_mask & RELOAD_REG_OFFSET) != 0)
+	    mode2 = inner;
 	}
 
-      if (FLOAT128_2REG_P (mode))
+      if (FLOAT128_2REG_P (mode2))
 	{
-	  inner = DFmode;
-	  if ((reg_addr[inner].default_addr_mask & RELOAD_REG_OFFSET) == 0)
-	    inner = word_mode;
+	  if ((reg_addr[E_DFmode].default_addr_mask & RELOAD_REG_OFFSET) != 0)
+	    mode = DFmode;
 	}
 
-      addr_mask = reg_addr[inner].default_addr_mask;
+      if (mode != mode2)
+	addr_mask = reg_addr[mode2].default_addr_mask;
     }
 
   if ((addr_mask & RELOAD_REG_OFFSET) == 0)
@@ -13858,6 +13858,49 @@ addr_mask_to_trad_insn (machine_mode mod
   return TRAD_INSN_D;
 }
 
+/* Helper function to take a REG and a MODE and turn it into the traditional
+   instruction format (D/DS/DQ) used for offset memory.  */
+
+static trad_insn_type
+reg_to_trad_insn (rtx reg, machine_mode mode)
+{
+  addr_mask_type addr_mask;
+
+  /* If it isn't a register, use the defaults.  */
+  if (!REG_P (reg) && !SUBREG_P (reg))
+    addr_mask = reg_addr[mode].default_addr_mask;
+
+  else
+    {
+      unsigned int r = reg_or_subregno (reg);
+
+      /* If we have a pseudo, use the default instruction format.  */
+      if (r >= FIRST_PSEUDO_REGISTER)
+	addr_mask = reg_addr[mode].default_addr_mask;
+
+      /* If we have a hard register, use the addr_mask of that hard
+	 register's reload register class.  */
+      else
+	{
+	  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];
+
+	  /* Assume things like SPRs, CR, etc. will be loaded through the GPR
+	     registers.  */
+	  else
+	    addr_mask = reg_addr[mode].addr_mask[RELOAD_REG_GPR];
+	}
+    }
+
+  return addr_mask_to_trad_insn (mode, addr_mask);
+}
+
 /* Function to return true if ADDR is a valid prefixed memory address that uses
    mode MODE, and the traditional instruction uses the TRAD_INSN format.  */
 
@@ -13908,6 +13951,139 @@ prefixed_local_addr_p (rtx addr,
   return false;
 }
 
+/* Whether a load instruction is a prefixed instruction.  This is called from
+   the prefixed attribute processing.  */
+
+bool
+prefixed_load_p (rtx_insn *insn)
+{
+  /* Validate the insn to make sure it is a normal load insn.  */
+  extract_insn_cached (insn);
+  if (recog_data.n_operands < 2)
+    return false;
+
+  rtx reg = recog_data.operand[0];
+  rtx mem = recog_data.operand[1];
+
+  if (!REG_P (reg) && !SUBREG_P (reg))
+    return false;
+
+  if (!MEM_P (mem))
+    return false;
+
+  /* LWA uses the DS format instead of the D format that LWZ uses.  */
+  trad_insn_type trad_insn;
+  machine_mode reg_mode = GET_MODE (reg);
+  machine_mode mem_mode = GET_MODE (mem);
+
+  if (mem_mode == SImode && reg_mode == DImode
+      && get_attr_sign_extend (insn) == SIGN_EXTEND_YES)
+    trad_insn = TRAD_INSN_DS;
+
+  else
+    trad_insn = reg_to_trad_insn (reg, mem_mode);
+
+  return prefixed_local_addr_p (XEXP (mem, 0), mem_mode, trad_insn);
+}
+
+/* Whether a store instruction is a prefixed instruction.  This is called from
+   the prefixed attribute processing.  */
+
+bool
+prefixed_store_p (rtx_insn *insn)
+{
+  /* Validate the insn to make sure it is a normal store insn.  */
+  extract_insn_cached (insn);
+  if (recog_data.n_operands < 2)
+    return false;
+
+  rtx mem = recog_data.operand[0];
+  rtx reg = recog_data.operand[1];
+
+  if (!REG_P (reg) && !SUBREG_P (reg))
+    return false;
+
+  if (!MEM_P (mem))
+    return false;
+
+  machine_mode mem_mode = GET_MODE (mem);
+  trad_insn_type trad_insn = reg_to_trad_insn (reg, mem_mode);
+  return prefixed_local_addr_p (XEXP (mem, 0), mem_mode, trad_insn);
+}
+
+/* Whether a load immediate or add instruction is a prefixed instruction.  This
+   is called from the prefixed attribute processing.  */
+
+bool
+prefixed_paddi_p (rtx_insn *insn)
+{
+  rtx set = single_set (insn);
+  if (!set)
+    return false;
+
+  rtx dest = SET_DEST (set);
+  rtx src = SET_SRC (set);
+
+  if (!REG_P (dest) && !SUBREG_P (dest))
+    return false;
+
+  /* Is this a load immediate that can't be done with a simple ADDI or
+     ADDIS?  */
+  if (CONST_INT_P (src))
+    return (satisfies_constraint_eI (src)
+	    && !satisfies_constraint_I (src)
+	    && !satisfies_constraint_L (src));
+
+  /* Is this a PADDI instruction that can't be done with a simple ADDI or
+     ADDIS?  */
+  if (GET_CODE (src) == PLUS)
+    {
+      rtx op1 = XEXP (src, 1);
+
+      return (CONST_INT_P (op1)
+	      && satisfies_constraint_eI (op1)
+	      && !satisfies_constraint_I (op1)
+	      && !satisfies_constraint_L (op1));
+    }
+
+  /* If not, is it a load of a pc-relative address?  */
+  if (!TARGET_PCREL || GET_MODE (dest) != Pmode)
+    return false;
+
+  if (!SYMBOL_REF_P (src) && !LABEL_REF_P (src) && GET_CODE (src) != CONST)
+    return false;
+
+  return (pcrel_local_address (src, Pmode) || pcrel_ext_address (src, Pmode));
+}
+
+
+/* Whether the next instruction needs a 'p' prefix issued before the
+   instruction is printed out.  */
+static bool next_insn_prefixed_p;
+
+/* Define FINAL_PRESCAN_INSN if some processing needs to be done before
+   outputting the assembler code.  On the PowerPC, we remember if the current
+   insn is a prefixed insn where we need to emit a 'p' before the insn.  */
+void
+rs6000_final_prescan_insn (rtx_insn *insn, rtx [], int)
+{
+  next_insn_prefixed_p = (get_attr_prefixed (insn) != PREFIXED_NO);
+  return;
+}
+
+/* Define ASM_OUTPUT_OPCODE to do anything special before emitting an opcode.
+   We use it to emit a 'p' for prefixed insns that is set in
+   FINAL_PRESCAN_INSN.  */
+void
+rs6000_asm_output_opcode (FILE *stream)
+{
+  if (next_insn_prefixed_p)
+    fputc ('p', stream);
+
+  return;
+}
+
+
 #if defined (HAVE_GAS_HIDDEN) && !TARGET_MACHO
 /* Emit an assembler directive to set symbol visibility for DECL to
    VISIBILITY_TYPE.  */
Index: gcc/config/rs6000/rs6000.h
===================================================================
--- gcc/config/rs6000/rs6000.h	(revision 274864)
+++ gcc/config/rs6000/rs6000.h	(working copy)
@@ -2572,3 +2572,24 @@ typedef struct GTY(()) machine_function
   IN_RANGE ((VALUE),							\
 	    -(HOST_WIDE_INT_1 << 33),					\
 	    (HOST_WIDE_INT_1 << 33) - 1 - (EXTRA))
+
+/* Define this if some processing needs to be done before outputting the
+   assembler code.  On the PowerPC, we remember if the current insn is a normal
+   prefixed insn where we need to emit a 'p' before the insn.  */
+#define FINAL_PRESCAN_INSN(INSN, OPERANDS, NOPERANDS)			\
+do									\
+  {									\
+    if (TARGET_PREFIXED_ADDR)						\
+      rs6000_final_prescan_insn (INSN, OPERANDS, NOPERANDS);		\
+  }									\
+while (0)
+
+/* Do anything special before emitting an opcode.  We use it to emit a 'p' for
+   prefixed insns that is set in FINAL_PRESCAN_INSN.  */
+#define ASM_OUTPUT_OPCODE(STREAM, OPCODE)				\
+  do									\
+    {									\
+     if (TARGET_PREFIXED_ADDR)						\
+       rs6000_asm_output_opcode (STREAM);				\
+    }									\
+  while (0)
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md	(revision 274870)
+++ gcc/config/rs6000/rs6000.md	(working copy)
@@ -258,8 +258,51 @@ (define_attr "var_shift" "no,yes"
 ;; Is copying of this instruction disallowed?
 (define_attr "cannot_copy" "no,yes" (const_string "no"))
 
-;; Length of the instruction (in bytes).
-(define_attr "length" "" (const_int 4))
+;; Whether an insn is a prefixed insn, and an initial 'p' should be printed
+;; before the instruction.  A prefixed instruction has a prefix instruction
+;; word that extends the immediate value of the instructions from 12-16 bits to
+;; 34 bits.  The macro ASM_OUTPUT_OPCODE emits a leading 'p' for prefixed
+;; insns.  The default "length" attribute will also be adjusted by default to
+;; be 12 bytes.
+(define_attr "prefixed" "no,yes"
+  (cond [(ior (match_test "!TARGET_PREFIXED_ADDR")
+	      (match_test "!NONJUMP_INSN_P (insn)"))
+	 (const_string "no")
+
+	 (eq_attr "type" "load,fpload,vecload")
+	 (if_then_else (and (eq_attr "indexed" "no")
+			    (eq_attr "update" "no")
+			    (match_test "prefixed_load_p (insn)"))
+		       (const_string "yes")
+		       (const_string "no"))
+
+	 (eq_attr "type" "store,fpstore,vecstore")
+	 (if_then_else (and (eq_attr "indexed" "no")
+			    (eq_attr "update" "no")
+			    (match_test "prefixed_store_p (insn)"))
+		       (const_string "yes")
+		       (const_string "no"))
+
+	 (eq_attr "type" "integer,add")
+	 (if_then_else (match_test "prefixed_paddi_p (insn)")
+		       (const_string "yes")
+		       (const_string "no"))]
+	(const_string "no")))
+
+;; Length in bytes of instructions that use prefixed addressing and length in
+;; bytes of instructions that does not use prefixed addressing.  This allows
+;; both lengths to be defined as constants, and the length attribute can pick
+;; the size as appropriate.
+(define_attr "prefixed_length" "" (const_int 12))
+(define_attr "non_prefixed_length" "" (const_int 4))
+
+;; Length of the instruction (in bytes).  Prefixed insns are 8 bytes, but the
+;; assembler might issue need to issue a NOP so that the prefixed instruction
+;; does not cross a cache boundary, which makes them possibly 12 bytes.
+(define_attr "length" ""
+  (if_then_else (eq_attr "prefixed" "yes")
+		(attr "prefixed_length")
+		(attr "non_prefixed_length")))
 
 ;; Processor type -- this attribute must exactly match the processor_type
 ;; enumeration in rs6000-opts.h.
@@ -9883,8 +9926,8 @@ (define_insn "pcrel_local_addr"
   [(set (match_operand:DI 0 "gpc_reg_operand" "=b*r")
 	(match_operand:DI 1 "pcrel_local_address"))]
   "TARGET_PCREL"
-  "pla %0,%a1"
-  [(set_attr "length" "12")])
+  "la %0,%a1"
+  [(set_attr "prefixed" "yes")])
 
 ;; Load up a pc-relative address to an external symbol.  If the symbol and the
 ;; program are both defined in the main program, the linker will optimize this
@@ -9895,8 +9938,8 @@ (define_insn "pcrel_ext_addr"
   [(set (match_operand:DI 0 "gpc_reg_operand" "=b*r")
 	(match_operand:DI 1 "pcrel_ext_address"))]
   "TARGET_PCREL"
-  "pld %0,%a1"
-  [(set_attr "length" "12")
+  "ld %0,%a1"
+  [(set_attr "prefixed" "yes")
    (set_attr "type" "load")])
 
 ;; TOC register handling.

-- 
Michael Meissner, IBM
IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA
email: meissner@linux.ibm.com, phone: +1 (978) 899-4797


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]