https://gcc.gnu.org/g:f85d222359d056353677bc2fc4a8ca9d2f1a4f5e
commit f85d222359d056353677bc2fc4a8ca9d2f1a4f5e Author: Michael Meissner <[email protected]> Date: Thu Jun 18 23:20:14 2026 -0400 [PATCH] Add paddis support. This patch adds support for the paddis instruction that might be added to a future PowerPC processor. 2026-06-18 Michael Meissner <[email protected]> gcc/ * config/rs6000/constraints.md (eU): New constraint. (eV): Likewise. * config/rs6000/predicates.md (paddis_operand): New predicate. (paddis_paddi_operand): Likewise. (add_cint_operand): Add paddis support. (add_operand): Likewise. * config/rs6000/rs6000.cc (num_insns_constant_gpr): Likewise. (print_operand): Add %B<n> for paddis support. * config/rs6000/rs6000.h (TARGET_PADDIS): New macro. (SIGNED_INTEGER_64BIT_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. * doc/md.texi (PowerPC constraints): Add eU and eV documentation. gcc/testsuite/ * gcc.target/powerpc/prefixed-addis.c: New test. 2026-06-18 Michael Meissner <[email protected]> gcc/ * config/rs6000/predicates.md (paddis_paddi_operand): Only handle postive values. Simplify test for addis/rldicl. (add_cint_operand): Do not allow paddis+paddi operands here. (reg_or_add_cint_operand): Add paddis/paddi support here. * config/rs6000/rs6000.md (add<mode>3, define_expand): Use op0/op1/op2 instead of operands[0]/operands[1]/operands[2]. If the add could be done via paddis + paddi/addi, split it here. (*add<mode>3, define_insn): Remove paddis+paddi support. (add<mode>3 splitter for paddis+paddi): Delete. (spliter to load constant int with paddis+paddi): Simplify code. --- gcc/config/rs6000/predicates.md | 16 +++--- gcc/config/rs6000/rs6000.md | 99 ++++++++++++++++----------------- 2 files changed, 57 insertions(+), 58 deletions(-) diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index 4800cc7fe5a..841619570c1 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -433,13 +433,16 @@ (define_predicate "paddis_paddi_operand" if (!SIGNED_INTEGER_64BIT_P (value)) return false; + /* Don't worry about negative values at the moment. */ + if (value < 0) + return false; + /* If paddi alone can handle the number, don't return true. */ if (SIGNED_INTEGER_34BIT_P (value)) return false; /* If we can do the add or generate the constant via addis/rldicl, fail. */ - if (num_insns_constant (op, mode) == 2 - && rs6000_is_valid_and_mask (op, mode)) + if (rs6000_is_valid_and_mask (op, mode)) return false; /* Only return true if we need both paddi and paddis. */ @@ -647,14 +650,14 @@ (define_predicate "add_cint_operand" + (mode == SImode ? 0x80000000 : 0x80008000)) < (unsigned HOST_WIDE_INT) 0x100000000ll") (match_operand 0 "cint34_operand") - (match_operand 0 "paddis_operand") - (match_operand 0 "paddis_paddi_operand")))) + (match_operand 0 "paddis_operand")))) ;; Return 1 if op is a constant integer valid for addition ;; or non-special register. (define_predicate "reg_or_add_cint_operand" (if_then_else (match_code "const_int") - (match_operand 0 "add_cint_operand") + (ior (match_operand 0 "add_cint_operand") + (match_operand 0 "paddis_paddi_operand")) (match_operand 0 "gpc_reg_operand"))) ;; Return 1 if op is a constant integer valid for subtraction @@ -1207,8 +1210,7 @@ (define_predicate "add_operand" (match_test "satisfies_constraint_I (op) || satisfies_constraint_L (op) || satisfies_constraint_eI (op) - || satisfies_constraint_eU (op) - || satisfies_constraint_eV (op)") + || satisfies_constraint_eU (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.md b/gcc/config/rs6000/rs6000.md index edfeca2040d..f1688ce409b 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -1914,14 +1914,18 @@ (define_expand "add<mode>3" (match_operand:SDI 2 "reg_or_add_cint_operand")))] "" { + rtx op0 = operands[0]; + rtx op1 = operands[1]; + rtx op2 = operands[2]; + if (<MODE>mode == DImode && !TARGET_POWERPC64) { - rtx lo0 = gen_lowpart (SImode, operands[0]); - rtx lo1 = gen_lowpart (SImode, operands[1]); - rtx lo2 = gen_lowpart (SImode, operands[2]); - rtx hi0 = gen_highpart (SImode, operands[0]); - rtx hi1 = gen_highpart (SImode, operands[1]); - rtx hi2 = gen_highpart_mode (SImode, DImode, operands[2]); + rtx lo0 = gen_lowpart (SImode, op0); + rtx lo1 = gen_lowpart (SImode, op1); + rtx lo2 = gen_lowpart (SImode, op2); + rtx hi0 = gen_highpart (SImode, op0); + rtx hi1 = gen_highpart (SImode, op1); + rtx hi2 = gen_highpart_mode (SImode, DImode, op2); if (!reg_or_short_operand (lo2, SImode)) lo2 = force_reg (SImode, lo2); @@ -1933,24 +1937,40 @@ (define_expand "add<mode>3" DONE; } - if (CONST_INT_P (operands[2]) && !add_operand (operands[2], <MODE>mode)) + if (CONST_INT_P (op2) && !add_operand (op2, <MODE>mode)) { - rtx tmp = ((!can_create_pseudo_p () - || rtx_equal_p (operands[0], operands[1])) - ? operands[0] : gen_reg_rtx (<MODE>mode)); + rtx tmp = ((!can_create_pseudo_p () || rtx_equal_p (op0, op1)) + ? op0 + : gen_reg_rtx (<MODE>mode)); /* Adding a constant to r0 is not a valid insn, so use a different strategy in that case. */ - if (reg_or_subregno (operands[1]) == 0 || reg_or_subregno (tmp) == 0) + if (reg_or_subregno (op1) == 0 || reg_or_subregno (tmp) == 0) { - if (operands[0] == operands[1]) + if (op0 == op1) FAIL; - rs6000_emit_move (operands[0], operands[2], <MODE>mode); - emit_insn (gen_add<mode>3 (operands[0], operands[1], operands[0])); + rs6000_emit_move (op0, op2, <MODE>mode); + emit_insn (gen_add<mode>3 (op0, op1, op0)); + DONE; + } + + HOST_WIDE_INT val = INTVAL (op2); + + /* If we have paddis, split the add into paddis and either addi or + paddi. However, if we can generate addis and rldicl, do that + instead of doing paddis/paddi. Emit the paddis first, just + in case this is a memory operation and we could fold the offset + into the memory ooperation. */ + + if (TARGET_PADDIS && paddis_paddi_operand (op2, <MODE>mode)) + { + const HOST_WIDE_INT mask = HOST_WIDE_INT_C(0xffffffff); + + emit_insn (gen_add<mode>3 (tmp, op1, GEN_INT (val & ~mask))); + emit_insn (gen_add<mode>3 (op0, tmp, GEN_INT (val & mask))); DONE; } - HOST_WIDE_INT val = INTVAL (operands[2]); HOST_WIDE_INT low = sext_hwi (val, 16); HOST_WIDE_INT rest = trunc_int_for_mode (val - low, <MODE>mode); @@ -1960,52 +1980,28 @@ (define_expand "add<mode>3" /* The ordering here is important for the prolog expander. When space is allocated from the stack, adding 'low' first may produce a temporary deallocation (which would be bad). */ - emit_insn (gen_add<mode>3 (tmp, operands[1], GEN_INT (rest))); - emit_insn (gen_add<mode>3 (operands[0], tmp, GEN_INT (low))); + emit_insn (gen_add<mode>3 (tmp, op1, GEN_INT (rest))); + emit_insn (gen_add<mode>3 (op0, tmp, GEN_INT (low))); DONE; } }) (define_insn "*add<mode>3" - [(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")))] + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r,r, r, r") + (plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,b,b, b, b") + (match_operand:GPR 2 "add_operand" "r,I,L,eI,eU")))] "" "@ add %0,%1,%2 addi %0,%1,%2 addis %0,%1,%v2 addi %0,%1,%2 - paddis %0,%1,%B2 - #" + paddis %0,%1,%B2" [(set_attr "type" "add") - (set_attr "isa" "*,*,*,p10,paddis,paddis") - (set_attr "length" "*,*,*,*,12,24") - (set_attr "prefixed" "*,*,*,*,yes,yes") - (set_attr "maybe_prefixed" "*,*,*,*,no,no")]) - -;; We can't split r0 + large_number due to encoding issues, so use base -;; registers only. - -(define_split - [(set (match_operand:DI 0 "base_reg_operand") - (plus:DI (match_operand:DI 1 "base_reg_operand") - (match_operand:DI 2 "paddis_paddi_operand")))] - "TARGET_PADDIS" - [(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)); -}) + (set_attr "isa" "*,*,*,p10,paddis") + (set_attr "length" "*,*,*,*,12") + (set_attr "prefixed" "*,*,*,*,yes") + (set_attr "maybe_prefixed" "*,*,*,*,no")]) (define_insn "*addsi3_high" [(set (match_operand:SI 0 "gpc_reg_operand" "=b") @@ -10169,11 +10165,12 @@ (define_split (match_dup 4)))] { HOST_WIDE_INT value = INTVAL (operands[1]); + const HOST_WIDE_INT mask = HOST_WIDE_INT_C (0xffffffff); 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)); + operands[3] = GEN_INT (value & ~mask); + operands[4] = GEN_INT (value & mask); }) ;; Split a load of a large constant into the appropriate five-instruction -- 2.54.0 Diff: --- gcc/config/rs6000/predicates.md | 16 ++++--- gcc/config/rs6000/rs6000.cc | 12 ++--- gcc/config/rs6000/rs6000.md | 99 ++++++++++++++++++++--------------------- 3 files changed, 63 insertions(+), 64 deletions(-) diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index 4800cc7fe5ab..841619570c11 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -433,13 +433,16 @@ if (!SIGNED_INTEGER_64BIT_P (value)) return false; + /* Don't worry about negative values at the moment. */ + if (value < 0) + return false; + /* If paddi alone can handle the number, don't return true. */ if (SIGNED_INTEGER_34BIT_P (value)) return false; /* If we can do the add or generate the constant via addis/rldicl, fail. */ - if (num_insns_constant (op, mode) == 2 - && rs6000_is_valid_and_mask (op, mode)) + if (rs6000_is_valid_and_mask (op, mode)) return false; /* Only return true if we need both paddi and paddis. */ @@ -647,14 +650,14 @@ + (mode == SImode ? 0x80000000 : 0x80008000)) < (unsigned HOST_WIDE_INT) 0x100000000ll") (match_operand 0 "cint34_operand") - (match_operand 0 "paddis_operand") - (match_operand 0 "paddis_paddi_operand")))) + (match_operand 0 "paddis_operand")))) ;; Return 1 if op is a constant integer valid for addition ;; or non-special register. (define_predicate "reg_or_add_cint_operand" (if_then_else (match_code "const_int") - (match_operand 0 "add_cint_operand") + (ior (match_operand 0 "add_cint_operand") + (match_operand 0 "paddis_paddi_operand")) (match_operand 0 "gpc_reg_operand"))) ;; Return 1 if op is a constant integer valid for subtraction @@ -1207,8 +1210,7 @@ (match_test "satisfies_constraint_I (op) || satisfies_constraint_L (op) || satisfies_constraint_eI (op) - || satisfies_constraint_eU (op) - || satisfies_constraint_eV (op)") + || satisfies_constraint_eU (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 32cd1de3055b..0e7848315139 100644 --- a/gcc/config/rs6000/rs6000.cc +++ b/gcc/config/rs6000/rs6000.cc @@ -6245,17 +6245,17 @@ num_insns_constant_gpr (HOST_WIDE_INT value) return 1; /* PADDIS support. */ - else if (TARGET_PADDIS && SIGNED_INTEGER_64BIT_P (value)) + else if (TARGET_PADDIS) { - if ((value & HOST_WIDE_INT_C(0xffffffff)) == 0) + rtx num = GEN_INT (value); + if (paddis_operand (num, VOIDmode)) return 1; /* paddis alone. */ - /* Don't do paddi + paddis if we can do addis and rldicl. */ - if (!rs6000_is_valid_and_mask (GEN_INT (value), DImode)) - return 2; /* paddi + paddis. */ + if (paddis_paddi_operand (num, VOIDmode)) + return 2; /* paddis + paddi/addi. */ } - else if (TARGET_POWERPC64) + if (TARGET_POWERPC64) { int num_insns = 0; rs6000_emit_set_long_const (nullptr, value, &num_insns); diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index edfeca2040d7..f1688ce409be 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -1914,14 +1914,18 @@ (match_operand:SDI 2 "reg_or_add_cint_operand")))] "" { + rtx op0 = operands[0]; + rtx op1 = operands[1]; + rtx op2 = operands[2]; + if (<MODE>mode == DImode && !TARGET_POWERPC64) { - rtx lo0 = gen_lowpart (SImode, operands[0]); - rtx lo1 = gen_lowpart (SImode, operands[1]); - rtx lo2 = gen_lowpart (SImode, operands[2]); - rtx hi0 = gen_highpart (SImode, operands[0]); - rtx hi1 = gen_highpart (SImode, operands[1]); - rtx hi2 = gen_highpart_mode (SImode, DImode, operands[2]); + rtx lo0 = gen_lowpart (SImode, op0); + rtx lo1 = gen_lowpart (SImode, op1); + rtx lo2 = gen_lowpart (SImode, op2); + rtx hi0 = gen_highpart (SImode, op0); + rtx hi1 = gen_highpart (SImode, op1); + rtx hi2 = gen_highpart_mode (SImode, DImode, op2); if (!reg_or_short_operand (lo2, SImode)) lo2 = force_reg (SImode, lo2); @@ -1933,24 +1937,40 @@ DONE; } - if (CONST_INT_P (operands[2]) && !add_operand (operands[2], <MODE>mode)) + if (CONST_INT_P (op2) && !add_operand (op2, <MODE>mode)) { - rtx tmp = ((!can_create_pseudo_p () - || rtx_equal_p (operands[0], operands[1])) - ? operands[0] : gen_reg_rtx (<MODE>mode)); + rtx tmp = ((!can_create_pseudo_p () || rtx_equal_p (op0, op1)) + ? op0 + : gen_reg_rtx (<MODE>mode)); /* Adding a constant to r0 is not a valid insn, so use a different strategy in that case. */ - if (reg_or_subregno (operands[1]) == 0 || reg_or_subregno (tmp) == 0) + if (reg_or_subregno (op1) == 0 || reg_or_subregno (tmp) == 0) { - if (operands[0] == operands[1]) + if (op0 == op1) FAIL; - rs6000_emit_move (operands[0], operands[2], <MODE>mode); - emit_insn (gen_add<mode>3 (operands[0], operands[1], operands[0])); + rs6000_emit_move (op0, op2, <MODE>mode); + emit_insn (gen_add<mode>3 (op0, op1, op0)); + DONE; + } + + HOST_WIDE_INT val = INTVAL (op2); + + /* If we have paddis, split the add into paddis and either addi or + paddi. However, if we can generate addis and rldicl, do that + instead of doing paddis/paddi. Emit the paddis first, just + in case this is a memory operation and we could fold the offset + into the memory ooperation. */ + + if (TARGET_PADDIS && paddis_paddi_operand (op2, <MODE>mode)) + { + const HOST_WIDE_INT mask = HOST_WIDE_INT_C(0xffffffff); + + emit_insn (gen_add<mode>3 (tmp, op1, GEN_INT (val & ~mask))); + emit_insn (gen_add<mode>3 (op0, tmp, GEN_INT (val & mask))); DONE; } - HOST_WIDE_INT val = INTVAL (operands[2]); HOST_WIDE_INT low = sext_hwi (val, 16); HOST_WIDE_INT rest = trunc_int_for_mode (val - low, <MODE>mode); @@ -1960,52 +1980,28 @@ /* The ordering here is important for the prolog expander. When space is allocated from the stack, adding 'low' first may produce a temporary deallocation (which would be bad). */ - emit_insn (gen_add<mode>3 (tmp, operands[1], GEN_INT (rest))); - emit_insn (gen_add<mode>3 (operands[0], tmp, GEN_INT (low))); + emit_insn (gen_add<mode>3 (tmp, op1, GEN_INT (rest))); + emit_insn (gen_add<mode>3 (op0, tmp, GEN_INT (low))); DONE; } }) (define_insn "*add<mode>3" - [(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")))] + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r,r, r, r") + (plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,b,b, b, b") + (match_operand:GPR 2 "add_operand" "r,I,L,eI,eU")))] "" "@ add %0,%1,%2 addi %0,%1,%2 addis %0,%1,%v2 addi %0,%1,%2 - paddis %0,%1,%B2 - #" + paddis %0,%1,%B2" [(set_attr "type" "add") - (set_attr "isa" "*,*,*,p10,paddis,paddis") - (set_attr "length" "*,*,*,*,12,24") - (set_attr "prefixed" "*,*,*,*,yes,yes") - (set_attr "maybe_prefixed" "*,*,*,*,no,no")]) - -;; We can't split r0 + large_number due to encoding issues, so use base -;; registers only. - -(define_split - [(set (match_operand:DI 0 "base_reg_operand") - (plus:DI (match_operand:DI 1 "base_reg_operand") - (match_operand:DI 2 "paddis_paddi_operand")))] - "TARGET_PADDIS" - [(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)); -}) + (set_attr "isa" "*,*,*,p10,paddis") + (set_attr "length" "*,*,*,*,12") + (set_attr "prefixed" "*,*,*,*,yes") + (set_attr "maybe_prefixed" "*,*,*,*,no")]) (define_insn "*addsi3_high" [(set (match_operand:SI 0 "gpc_reg_operand" "=b") @@ -10169,11 +10165,12 @@ (match_dup 4)))] { HOST_WIDE_INT value = INTVAL (operands[1]); + const HOST_WIDE_INT mask = HOST_WIDE_INT_C (0xffffffff); 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)); + operands[3] = GEN_INT (value & ~mask); + operands[4] = GEN_INT (value & mask); }) ;; Split a load of a large constant into the appropriate five-instruction
