This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH], V4.1, patch #2: Add prefixed insn attribute (revised)
- From: Michael Meissner <meissner at linux dot ibm dot com>
- To: Michael Meissner <meissner at linux dot ibm dot com>, gcc-patches at gcc dot gnu dot org, segher at kernel dot crashing dot org, dje dot gcc at gmail dot com
- Date: Tue, 24 Sep 2019 02:10:10 -0400
- Subject: [PATCH], V4.1, patch #2: Add prefixed insn attribute (revised)
- References: <20190918234214.GA27521@ibm-toto.the-meissners.org>
This patch revises patch #2, fixing an issue that shows up in compiling large
code like the Spec 2017 benchmark suite. The issue was when a vector register
uses TImode, it needs to assume the non-prefixed instruction uses the DQ
encoding.
I also changed the spelling of PC-relative to be consitant.
The patch is also adjusted due to the changes made in the revised patch #1.
Assuming the revised patch #1 is checked in, can I check in this revised patch
into the trunk? I did a bootstrap and make check with the patch and there were
no regressions. I applied the remaining patches, and they also have no
regressions, and they can build the Spec 2017 test suite.
2019-09-23 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): Move declaration and update calling
signature.
(address_is_prefixed): New helper inline function.
* config/rs6000/rs6000.c (rs6000_emit_move): Support loading
PC-relative addresses.
(reg_to_non_prefixed): New function to identify what the
non-prefixed memory instruction format is for a register.
(prefixed_load_p): New function to identify prefixed loads.
(prefixed_store_p): New function to identify prefixed stores.
(prefixed_paddi_p): New function to identify prefixed load
immediates.
(next_insn_prefixed_p): New static state variable.
(rs6000_final_prescan_insn): New function to determine if an insn
uses a prefixed instruction.
(rs6000_asm_output_opcode): New function to emit 'p' in front of a
prefixed instruction.
* config/rs6000/rs6000.h (FINAL_PRESCAN_INSN): New target hook.
(ASM_OUTPUT_OPCODE): New target hook.
* config/rs6000/rs6000.md (prefixed): New insn attribute for
prefixed instructions.
(prefixed_length): New insn attribute for the size of prefixed
instructions.
(non_prefixed_length): New insn attribute for the size of
non-prefixed instructions.
(pcrel_local_addr): New insn to load up a local PC-relative
address.
(pcrel_extern_addr): New insn to load up an external PC-relative
address.
Index: gcc/config/rs6000/rs6000-protos.h
===================================================================
--- gcc/config/rs6000/rs6000-protos.h (revision 276069)
+++ gcc/config/rs6000/rs6000-protos.h (working copy)
@@ -189,6 +189,30 @@ enum non_prefixed {
extern enum insn_form address_to_insn_form (rtx, machine_mode,
enum non_prefixed);
+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 *);
+extern void rs6000_final_prescan_insn (rtx_insn *, rtx [], int);
+
+/* Return true if the address is a prefixed instruction that can be directly
+ used in a memory instruction (i.e. using numeric offset or a PC-relative
+ reference to a local symbol).
+
+ References to external PC-relative symbols aren't allowed, because GCC has
+ to load the address into a register and then issue a separate load or
+ store. */
+
+static inline bool
+address_is_prefixed (rtx addr,
+ machine_mode mode,
+ enum non_prefixed non_prefixed_insn)
+{
+ enum insn_form iform = address_to_insn_form (addr, mode,
+ non_prefixed_insn);
+ return (iform == INSN_FORM_PREFIXED_NUMERIC
+ || iform == INSN_FORM_PCREL_LOCAL);
+}
#endif /* RTX_CODE */
#ifdef TREE_CODE
@@ -268,8 +292,6 @@ extern void rs6000_d_target_versions (vo
const char * rs6000_xcoff_strip_dollar (const char *);
#endif
-void rs6000_final_prescan_insn (rtx_insn *, rtx *operand, int num_operands);
-
extern unsigned char rs6000_class_max_nregs[][LIM_REG_CLASSES];
extern unsigned char rs6000_hard_regno_nregs[][FIRST_PSEUDO_REGISTER];
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c (revision 276069)
+++ gcc/config/rs6000/rs6000.c (working copy)
@@ -9639,6 +9639,22 @@ rs6000_emit_move (rtx dest, rtx source,
return;
}
+ /* Use the default pattern for loading up PC-relative addresses. */
+ if (TARGET_PCREL && mode == Pmode
+ && (SYMBOL_REF_P (operands[1]) || LABEL_REF_P (operands[1])
+ || GET_CODE (operands[1]) == CONST))
+ {
+ enum insn_form iform = address_to_insn_form (operands[1], mode,
+ NON_PREFIXED_DEFAULT);
+
+ if (iform == INSN_FORM_PCREL_LOCAL
+ || iform == INSN_FORM_PCREL_EXTERNAL)
+ {
+ emit_insn (gen_rtx_SET (operands[0], operands[1]));
+ return;
+ }
+ }
+
if (DEFAULT_ABI == ABI_V4
&& mode == Pmode && mode == SImode
&& flag_pic == 1 && got_operand (operands[1], mode))
@@ -24714,6 +24730,211 @@ address_to_insn_form (rtx addr,
return INSN_FORM_BAD;
}
+/* Helper function to take a REG and a MODE and turn it into the non-prefixed
+ instruction format (D/DS/DQ) used for offset memory. */
+
+static enum non_prefixed
+reg_to_non_prefixed (rtx reg, machine_mode mode)
+{
+ /* If it isn't a register, use the defaults. */
+ if (!REG_P (reg) && !SUBREG_P (reg))
+ return NON_PREFIXED_DEFAULT;
+
+ unsigned int r = reg_or_subregno (reg);
+
+ /* If we have a pseudo, use the default instruction format. */
+ if (r >= FIRST_PSEUDO_REGISTER)
+ return NON_PREFIXED_DEFAULT;
+
+ unsigned size = GET_MODE_SIZE (mode);
+
+ /* FPR registers use D-mode for scalars, and DQ-mode for vectors, IEEE
+ 128-bit floating point, and 128-bit integers. */
+ if (FP_REGNO_P (r))
+ {
+ if (mode == SFmode || size == 8 || FLOAT128_2REG_P (mode))
+ return NON_PREFIXED_D;
+
+ else if (size < 8)
+ return NON_PREFIXED_X;
+
+ else if (TARGET_VSX && size >= 16
+ && (VECTOR_MODE_P (mode)
+ || FLOAT128_VECTOR_P (mode)
+ || mode == TImode || mode == CTImode))
+ return NON_PREFIXED_DQ;
+
+ else
+ return NON_PREFIXED_DEFAULT;
+ }
+
+ /* Altivec registers use DS-mode for scalars, and DQ-mode for vectors, IEEE
+ 128-bit floating point, and 128-bit integers. */
+ else if (ALTIVEC_REGNO_P (r))
+ {
+ if (mode == SFmode || size == 8 || FLOAT128_2REG_P (mode))
+ return NON_PREFIXED_DS;
+
+ else if (size < 8)
+ return NON_PREFIXED_X;
+
+ else if (TARGET_VSX && size >= 16
+ && (VECTOR_MODE_P (mode)
+ || FLOAT128_VECTOR_P (mode)
+ || mode == TImode || mode == CTImode))
+ return NON_PREFIXED_DQ;
+
+ else
+ return NON_PREFIXED_DEFAULT;
+ }
+
+ /* GPR registers use DS-mode for 64-bit items on 64-bit systems, and D-mode
+ otherwise. Assume that any other register, such as LR, CRs, etc. will go
+ through the GPR registers for memory operations. */
+ else if (TARGET_POWERPC64 && size >= 8)
+ return NON_PREFIXED_DS;
+
+ return NON_PREFIXED_D;
+}
+
+
+/* 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. */
+ enum non_prefixed non_prefixed_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)
+ non_prefixed_insn = NON_PREFIXED_DS;
+
+ else
+ non_prefixed_insn = reg_to_non_prefixed (reg, mem_mode);
+
+ return address_is_prefixed (XEXP (mem, 0), mem_mode, non_prefixed_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);
+ enum non_prefixed non_prefixed_insn = reg_to_non_prefixed (reg, mem_mode);
+ return address_is_prefixed (XEXP (mem, 0), mem_mode, non_prefixed_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;
+
+ enum insn_form iform = address_to_insn_form (src, Pmode,
+ NON_PREFIXED_DEFAULT);
+
+ return (iform == INSN_FORM_PCREL_EXTERNAL || iform == INSN_FORM_PCREL_LOCAL);
+}
+
+/* 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.
+
+ In addition, if the insn is part of a PC-relative reference to an external
+ label optimization, this is recorded also. */
+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)
+ fprintf (stream "p");
+
+ return;
+}
+
#ifdef HAVE_GAS_HIDDEN
# define USE_HIDDEN_LINKONCE 1
Index: gcc/config/rs6000/rs6000.h
===================================================================
--- gcc/config/rs6000/rs6000.h (revision 276061)
+++ gcc/config/rs6000/rs6000.h (working copy)
@@ -2547,3 +2547,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 276061)
+++ gcc/config/rs6000/rs6000.md (working copy)
@@ -256,8 +256,52 @@ (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.
@@ -9875,6 +9919,28 @@ (define_expand "restore_stack_nonlocal"
operands[6] = gen_rtx_PARALLEL (VOIDmode, p);
})
+;; Load up a PC-relative address. Print_operand_address will append a @pcrel
+;; to the symbol or label.
+(define_insn "*pcrel_local_addr"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (match_operand:DI 1 "pcrel_local_address"))]
+ "TARGET_PCREL"
+ "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
+;; to a PADDI. Otherwise, it will create a GOT address that is relocated by
+;; the dynamic linker and loaded up. Print_operand_address will append a
+;; @got@pcrel to the symbol.
+(define_insn "*pcrel_extern_addr"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (match_operand:DI 1 "pcrel_external_address"))]
+ "TARGET_PCREL"
+ "ld %0,%a1"
+ [(set_attr "prefixed" "yes")
+ (set_attr "type" "load")])
+
;; TOC register handling.
;; Code to initialize the TOC register...
--
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