[gcc(refs/users/meissner/heads/work165-dmf)] RFC2686-Add paddis support.
Michael Meissner
meissner@gcc.gnu.org
Sat May 4 01:07:12 GMT 2024
https://gcc.gnu.org/g:c2f3d78cf66caa49c8379cca1f2604bf1de4b2fc
commit c2f3d78cf66caa49c8379cca1f2604bf1de4b2fc
Author: Michael Meissner <meissner@linux.ibm.com>
Date: Fri May 3 20:57:14 2024 -0400
RFC2686-Add paddis support.
2024-05-03 Michael Meissner <meissner@linux.ibm.com>
gcc/
* config/rs6000/constraints.md (eU): New constraint.
(eV): Likewise.
* config/rs6000/predicates.md (paddis_operand): New predicate.
(paddis_paddi_operand): Likewise.
(add_operand): Add paddis support.
* config/rs6000/rs6000.cc (num_insns_constant_gpr): Add paddis support.
(num_insns_constant_multi): Likewise.
(print_operand): Add %B<n> for paddis support.
* config/rs6000/rs6000.h (TARGET_PADDIS): New macro.
(SIGNED_INTEGER_32BIT_P): Likewise.
* config/rs6000/rs6000.md (isa attribute): Add paddis support.
(enabled attribute); Likewise.
(add<mode>3): Likewise.
(adddi3 splitter): New splitter for paddis.
(movdi_internal64): Add paddis support.
(movdi splitter): New splitter for paddis.
gcc/testsuite/
* gcc.target/powerpc/prefixed-addis.c: New test.
Diff:
---
gcc/config/rs6000/constraints.md | 10 +++
gcc/config/rs6000/predicates.md | 52 +++++++++++-
gcc/config/rs6000/rs6000.cc | 25 ++++++
gcc/config/rs6000/rs6000.h | 4 +
gcc/config/rs6000/rs6000.md | 96 ++++++++++++++++++++---
gcc/testsuite/gcc.target/powerpc/prefixed-addis.c | 24 ++++++
6 files changed, 197 insertions(+), 14 deletions(-)
diff --git a/gcc/config/rs6000/constraints.md b/gcc/config/rs6000/constraints.md
index 277a30a8245..4d8d21fd6bb 100644
--- a/gcc/config/rs6000/constraints.md
+++ b/gcc/config/rs6000/constraints.md
@@ -222,6 +222,16 @@
"An IEEE 128-bit constant that can be loaded into VSX registers."
(match_operand 0 "easy_vector_constant_ieee128"))
+(define_constraint "eU"
+ "@internal integer constant that can be loaded with paddis"
+ (and (match_code "const_int")
+ (match_operand 0 "paddis_operand")))
+
+(define_constraint "eV"
+ "@internal integer constant that can be loaded with paddis + paddi"
+ (and (match_code "const_int")
+ (match_operand 0 "paddis_paddi_operand")))
+
;; Floating-point constraints. These two are defined so that insn
;; length attributes can be calculated exactly.
diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index b325000690b..0b7c0bf4b0f 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -369,6 +369,53 @@
return SIGNED_INTEGER_34BIT_P (INTVAL (op));
})
+;; Return 1 if op is a 64-bit constant that uses the paddis instruction
+(define_predicate "paddis_operand"
+ (match_code "const_int")
+{
+ if (!TARGET_PADDIS && TARGET_POWERPC64)
+ return 0;
+
+ /* If addi, addis, or paddi can handle the number, don't return true. */
+ HOST_WIDE_INT value = INTVAL (op);
+ if (SIGNED_INTEGER_34BIT_P (value))
+ return false;
+
+ /* If the number is too large for padds, return false. */
+ if (!SIGNED_INTEGER_32BIT_P (value >> 32))
+ return false;
+
+ /* If the bottom 32-bits are non-zero, paddis can't handle it. */
+ if ((value & HOST_WIDE_INT_C(0xffffffff)) != 0)
+ return false;
+
+ return true;
+})
+
+;; Return 1 if op is a 64-bit constant that needs the paddis instruction and an
+;; addi/addis/paddi instruction combination.
+(define_predicate "paddis_paddi_operand"
+ (match_code "const_int")
+{
+ if (!TARGET_PADDIS && TARGET_POWERPC64)
+ return 0;
+
+ /* If addi, addis, or paddi can handle the number, don't return true. */
+ HOST_WIDE_INT value = INTVAL (op);
+ if (SIGNED_INTEGER_34BIT_P (value))
+ return false;
+
+ /* If the number is too large for padds, return false. */
+ if (!SIGNED_INTEGER_32BIT_P (value >> 32))
+ return false;
+
+ /* If the bottom 32-bits are zero, we can use paddis alone to handle it. */
+ if ((value & HOST_WIDE_INT_C(0xffffffff)) == 0)
+ return false;
+
+ return true;
+})
+
;; Return 1 if op is a register that is not special.
;; Disallow (SUBREG:SF (REG:SI)) and (SUBREG:SI (REG:SF)) on VSX systems where
;; you need to be careful in moving a SFmode to SImode and vice versa due to
@@ -1050,7 +1097,10 @@
(if_then_else (match_code "const_int")
(match_test "satisfies_constraint_I (op)
|| satisfies_constraint_L (op)
- || satisfies_constraint_eI (op)")
+ || satisfies_constraint_eI (op)
+ || satisfies_constraint_eU (op)
+ || satisfies_constraint_eV (op)")
+
(match_operand 0 "gpc_reg_operand")))
;; Return 1 if the operand is either a non-special register, or 0, or -1.
diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc
index 4dabf13aee9..160db4bba7a 100644
--- a/gcc/config/rs6000/rs6000.cc
+++ b/gcc/config/rs6000/rs6000.cc
@@ -4298,6 +4298,7 @@ rs6000_option_override_internal (bool global_init_p)
rs6000_isa_flags &= ~OPTION_MASK_PCREL;
}
+
/* Print the options after updating the defaults. */
if (TARGET_DEBUG_REG || TARGET_DEBUG_TARGET)
rs6000_print_isa_options (stderr, 0, "after defaults", rs6000_isa_flags);
@@ -6108,6 +6109,14 @@ num_insns_constant_gpr (HOST_WIDE_INT value)
else if (TARGET_PREFIXED && SIGNED_INTEGER_34BIT_P (value))
return 1;
+ /* PADDIS support. */
+ else if (TARGET_PADDIS && TARGET_POWERPC64
+ && !IN_RANGE (value >> 32, -1, 0)
+ && (SIGNED_INTEGER_32BIT_P (value >> 32)))
+ return ((value & HOST_WIDE_INT_C (0xffffffff)) == 0
+ ? 1
+ : 2);
+
else if (TARGET_POWERPC64)
{
int num_insns = 0;
@@ -6128,6 +6137,14 @@ num_insns_constant_multi (HOST_WIDE_INT value, machine_mode mode)
{
int nregs = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
int total = 0;
+ if (nregs == 1
+ && TARGET_PADDIS && TARGET_POWERPC64
+ && !IN_RANGE (value >> 32, -1, 0)
+ && SIGNED_INTEGER_32BIT_P (value >> 32))
+ return ((value & HOST_WIDE_INT_C (0xffffffff)) == 0
+ ? 1
+ : 2);
+
while (nregs-- > 0)
{
HOST_WIDE_INT low = sext_hwi (value, BITS_PER_WORD);
@@ -14202,6 +14219,14 @@ print_operand (FILE *file, rtx x, int code)
fprintf (file, "%d", (REGNO (x) - FIRST_FPR_REGNO) / 4);
return;
+ case 'B':
+ /* Upper 32-bits of a constant. */
+ if (!CONST_INT_P (x))
+ output_operand_lossage ("Not a constant.");
+
+ fprintf (file, "%" HOST_LONG_FORMAT "d", INTVAL (x) >> 32);
+ return;
+
case 'D':
/* Like 'J' but get to the GT bit only. */
if (!REG_P (x) || !CR_REGNO_P (REGNO (x)))
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index 16fc8a9e879..1c44726f074 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -575,6 +575,9 @@ extern int rs6000_vector_align[];
below. */
#define RS6000_FN_TARGET_INFO_HTM 1
+/* Whether we have PADDIS support. */
+#define TARGET_PADDIS TARGET_FUTURE
+
/* Whether the various reciprocal divide/square root estimate instructions
exist, and whether we should automatically generate code for the instruction
by default. */
@@ -2497,6 +2500,7 @@ typedef struct GTY(()) machine_function
(HOST_WIDE_INT_1 << ((N)-1)) - 1)
#define SIGNED_INTEGER_16BIT_P(VALUE) SIGNED_INTEGER_NBIT_P (VALUE, 16)
+#define SIGNED_INTEGER_32BIT_P(VALUE) SIGNED_INTEGER_NBIT_P (VALUE, 32)
#define SIGNED_INTEGER_34BIT_P(VALUE) SIGNED_INTEGER_NBIT_P (VALUE, 34)
/* Like SIGNED_INTEGER_16BIT_P and SIGNED_INTEGER_34BIT_P, but with an extra
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index d097d9cfd0b..ef7758c5188 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -357,7 +357,7 @@
(const (symbol_ref "(enum attr_cpu) rs6000_tune")))
;; The ISA we implement.
-(define_attr "isa" "any,p5,p6,p7,p7v,p8,p8v,p9,p9v,p9kf,p9tf,p10"
+(define_attr "isa" "any,p5,p6,p7,p7v,p8,p8v,p9,p9v,p9kf,p9tf,p10,paddis"
(const_string "any"))
;; Is this alternative enabled for the current CPU/ISA/etc.?
@@ -409,6 +409,11 @@
(and (eq_attr "isa" "p10")
(match_test "TARGET_POWER10"))
(const_int 1)
+
+ (and (eq_attr "isa" "paddis")
+ (match_test "TARGET_PADDIS"))
+ (const_int 1)
+
] (const_int 0)))
;; If this instruction is microcoded on the CELL processor
@@ -1814,17 +1819,42 @@
})
(define_insn "*add<mode>3"
- [(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r,r,r")
- (plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,b,b,b")
- (match_operand:GPR 2 "add_operand" "r,I,L,eI")))]
+ [(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r,r,r,r,b")
+ (plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,b,b,b,b,b")
+ (match_operand:GPR 2 "add_operand" "r,I,L,eI,eU,eV")))]
""
"@
add %0,%1,%2
addi %0,%1,%2
addis %0,%1,%v2
- addi %0,%1,%2"
+ addi %0,%1,%2
+ paddis %0,%1,%B2
+ #"
[(set_attr "type" "add")
- (set_attr "isa" "*,*,*,p10")])
+ (set_attr "isa" "*,*,*,p10,paddis,paddis")
+ (set_attr "length" "*,*,*,*,12,24")
+ (set_attr "prefixed" "*,*,*,*,yes,yes")
+ (set_attr "maybe_prefixed" "*,*,*,*,no,no")])
+
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand")
+ (plus:DI (match_operand:DI 1 "gpc_reg_operand")
+ (match_operand:DI 2 "paddis_paddi_operand")))]
+ "TARGET_PADDIS && TARGET_POWERPC64"
+ [(set (match_dup 3)
+ (plus:DI (match_dup 1)
+ (match_dup 4)))
+ (set (match_dup 0)
+ (plus:DI (match_dup 3)
+ (match_dup 5)))]
+{
+ HOST_WIDE_INT value = INTVAL (operands[2]);
+ operands[3] = (can_create_pseudo_p ()
+ ? gen_reg_rtx (DImode)
+ : operands[0]);
+ operands[4] = GEN_INT (value & ~HOST_WIDE_INT_C (0xffffffff));
+ operands[5] = GEN_INT (value & HOST_WIDE_INT_C (0xffffffff));
+})
(define_insn "*addsi3_high"
[(set (match_operand:SI 0 "gpc_reg_operand" "=b")
@@ -9839,7 +9869,7 @@
DONE;
})
-;; GPR store GPR load GPR move
+;; GPR store GPR load GPR move GPR paddis GPR paddis+paddi
;; GPR li GPR lis GPR pli GPR #
;; FPR store FPR load FPR move
;; AVX store AVX store AVX load AVX load VSX move
@@ -9849,7 +9879,7 @@
;; VSX->GPR GPR->VSX
(define_insn "*movdi_internal64"
[(set (match_operand:DI 0 "nonimmediate_operand"
- "=YZ, r, r,
+ "=YZ, r, r, r, b,
r, r, r, r,
m, ^d, ^d,
wY, Z, $v, $v, ^wa,
@@ -9858,7 +9888,7 @@
r, *h, *h,
?r, ?wa")
(match_operand:DI 1 "input_operand"
- "r, YZ, r,
+ "r, YZ, r, eU, eV,
I, L, eI, nF,
^d, m, ^d,
^v, $v, wY, Z, ^wa,
@@ -9873,6 +9903,8 @@
std%U0%X0 %1,%0
ld%U1%X1 %0,%1
mr %0,%1
+ paddis %0,0,%B1
+ #
li %0,%1
lis %0,%v1
li %0,%1
@@ -9898,7 +9930,7 @@
mfvsrd %0,%x1
mtvsrd %x0,%1"
[(set_attr "type"
- "store, load, *,
+ "store, load, *, *, *,
*, *, *, *,
fpstore, fpload, fpsimple,
fpstore, fpstore, fpload, fpload, veclogical,
@@ -9908,7 +9940,7 @@
mfvsr, mtvsr")
(set_attr "size" "64")
(set_attr "length"
- "*, *, *,
+ "*, *, *, 12, 24,
*, *, *, 20,
*, *, *,
*, *, *, *, *,
@@ -9917,14 +9949,32 @@
*, *, *,
*, *")
(set_attr "isa"
- "*, *, *,
+ "*, *, *, paddis, paddis,
*, *, p10, *,
*, *, *,
p9v, p7v, p9v, p7v, *,
p9v, p9v, p7v, *, *,
p7v, p7v,
*, *, *,
- p8v, p8v")])
+ p8v, p8v")
+ (set_attr "prefixed"
+ "*, *, *, yes, yes,
+ *, *, *, *,
+ *, *, *,
+ *, *, *, *, *,
+ *, *, *, *, *,
+ *, *,
+ *, *, *,
+ *, *")
+ (set_attr "maybe_prefixed"
+ "*, *, *, no, no,
+ *, *, *, *,
+ *, *, *,
+ *, *, *, *, *,
+ *, *, *, *, *,
+ *, *,
+ *, *, *,
+ *, *")])
; Some DImode loads are best done as a load of -1 followed by a mask
; instruction.
@@ -9942,6 +9992,26 @@
(match_dup 1)))]
"")
+;; Split a constant that can be generated by a paddis and paddi into 2
+;; instructions.
+(define_split
+ [(set (match_operand:DI 0 "int_reg_operand")
+ (match_operand:DI 1 "paddis_paddi_operand"))]
+ "TARGET_PADDIS && TARGET_POWERPC64"
+ [(set (match_dup 2)
+ (match_dup 3))
+ (set (match_dup 0)
+ (plus:DI (match_dup 2)
+ (match_dup 4)))]
+{
+ HOST_WIDE_INT value = INTVAL (operands[1]);
+ operands[2] = (can_create_pseudo_p ()
+ ? gen_reg_rtx (DImode)
+ : operands[0]);
+ operands[3] = GEN_INT (value & ~HOST_WIDE_INT_C (0xffffffff));
+ operands[4] = GEN_INT (value & HOST_WIDE_INT_C (0xffffffff));
+})
+
;; Split a load of a large constant into the appropriate five-instruction
;; sequence. Handle anything in a constant number of insns.
;; When non-easy constants can go in the TOC, this should use
diff --git a/gcc/testsuite/gcc.target/powerpc/prefixed-addis.c b/gcc/testsuite/gcc.target/powerpc/prefixed-addis.c
new file mode 100644
index 00000000000..d08e3675f94
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/prefixed-addis.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_future_ok } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-options "-mdejagnu-cpu=future -O2" } */
+
+/* Test whether the xvrl (vector word rotate left using VSX registers insead of
+ Altivec registers is generated. */
+
+#include <stddef.h>
+
+size_t
+prefix_addis_addi (size_t x)
+{
+ return x + 0x123456789ABCDEUL; /* paddis + paddi. */
+}
+
+size_t
+prefix_addis (size_t x)
+{
+ return x + 0x12345600000000UL; /* paddis. */
+}
+
+/* { dg-final { scan-assembler-times {\mpaddis\M} 2 } } */
+/* { dg-final { scan-assembler-times {\mpaddi\M} 1 } } */
More information about the Gcc-cvs
mailing list