This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Fix pr48032, powerpc64 -mcmodel=medium invalid ld offset
This patch
a) Moves the offsettable_ok_by_alignment call from rs6000_emit_move to
legitimate_constant_pool_address_p, and
b) teaches offsettable_ok_by_alignment how to handle -fsection-anchors
addresses, and
c) teaches offsettable_ok_by_alignment about other SYMBOL_REF_DECL
trees I see there, various constant trees and CONSTRUCTOR.
About (a), well, that's just the way I should have written the
cmodel=medium optimization in the first place. There is no alignment
reason to not create a cmodel=medium address (ie. addis,addi relative
to toc pointer), it's just that they do need to be sufficiently
aligned to use in a MEM. We want reg=cmodel_medium_losum; mem[reg]
whenever we can do so, rather than creating a toc entry, but must not
allow the sequence to be combined into mem[cmodel_medium_losum] if
cmodel_medium_losum is not offsettable to access all the bytes of mem.
Perhaps legitimate_constant_pool_address_p should be renamed. I
didn't do that because it already allows the non-constant-pool
cmodel=medium addresses, and the name is long enough now. I commented
the function instead.
(b) is necessary because -fsection-anchors unfortunately loses the
real SYMBOL_REF_DECL when substituting anchor+offset into MEMs. The
way I imlemented this is why legitimate_constant_pool_address_p needs
the MEM mode. I suppose it would be possible to keep the original
SYMBOL_REF_DECL around in the rtl by some means or find the decl in
the struct object_block info, but both of these options seem like
overkill to me. Note that I pass QImode to l_c_p_a_p from
rs6000_mode_dependent_address, print_operand_address, and the 'R'
constraint to indicate that any cmodel=medium address is permissable.
(c) was developed specifically to fix problems found on
ibm/gcc-4_5-branch. I'd still like to commit this on mainline even
though it seems that mainline creates VAR_DECLs for constants.
Bootstrapped and regression tested powerpc64-linux. OK to apply?
PR target/48032
* config/rs6000/rs6000.c (offsettable_ok_by_alignment): Do not
presume symbol_refs without a symbol_ref_decl are suitably
aligned, nor other trees we may see here. Handle anchor symbols.
(legitimate_constant_pool_address_p): Comment. Add mode param.
Check cmodel=medium addresses. Adjust all calls.
(rs6000_emit_move): Don't call offsettable_ok_by_alignment on
creating cmodel=medium optimized access to locals.
* config/rs6000/constraints.md (R): Pass QImode to
legitimate_constant_pool_address_p.
* config/rs6000/predicates.md (input_operand): Pass mode to
legitimate_constant_pool_address_p.
* config/rs6000/rs6000-protos.h (legitimate_constant_pool_address_p):
Update prototype.
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c (revision 170807)
+++ gcc/config/rs6000/rs6000.c (working copy)
@@ -5768,6 +5768,91 @@ virtual_stack_registers_memory_p (rtx op
&& regnum <= LAST_VIRTUAL_POINTER_REGISTER);
}
+/* Return true if memory accesses to OP are known to never straddle
+ a 32k boundary. */
+
+static bool
+offsettable_ok_by_alignment (rtx op, HOST_WIDE_INT offset,
+ enum machine_mode mode)
+{
+ tree decl, type;
+ unsigned HOST_WIDE_INT dsize, dalign;
+
+ if (GET_CODE (op) != SYMBOL_REF)
+ return false;
+
+ decl = SYMBOL_REF_DECL (op);
+ if (!decl)
+ {
+ /* -fsection-anchors loses the original SYMBOL_REF_DECL when
+ replacing memory addresses with an anchor plus offset. We
+ could find the decl by rummaging around in the block->objects
+ VEC for the given offset but that seems like too much work. */
+ dalign = 1;
+ if (SYMBOL_REF_HAS_BLOCK_INFO_P (op)
+ && SYMBOL_REF_ANCHOR_P (op)
+ && SYMBOL_REF_BLOCK (op) != NULL)
+ {
+ struct object_block *block = SYMBOL_REF_BLOCK (op);
+ HOST_WIDE_INT lsb, mask;
+
+ /* Given the alignment of the block.. */
+ dalign = block->alignment;
+ mask = dalign / BITS_PER_UNIT - 1;
+
+ /* ..and the combined offset of the anchor and any offset
+ to this block object.. */
+ offset += SYMBOL_REF_BLOCK_OFFSET (op);
+ lsb = offset & -offset;
+
+ /* ..find how many bits of the alignment we know for the
+ object. */
+ mask &= lsb - 1;
+ dalign = mask + 1;
+ }
+ return dalign >= GET_MODE_SIZE (mode);
+ }
+
+ if (DECL_P (decl))
+ {
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ return true;
+
+ if (!DECL_SIZE_UNIT (decl))
+ return false;
+
+ if (!host_integerp (DECL_SIZE_UNIT (decl), 1))
+ return false;
+
+ dsize = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+ if (dsize > 32768)
+ return false;
+
+ dalign = DECL_ALIGN_UNIT (decl);
+ return dalign >= dsize;
+ }
+
+ type = TREE_TYPE (decl);
+
+ if (TREE_CODE (decl) == STRING_CST)
+ dsize = TREE_STRING_LENGTH (decl);
+ else if (TYPE_SIZE_UNIT (type)
+ && host_integerp (TYPE_SIZE_UNIT (type), 1))
+ dsize = tree_low_cst (TYPE_SIZE_UNIT (type), 1);
+ else
+ return false;
+ if (dsize > 32768)
+ return false;
+
+ dalign = TYPE_ALIGN (type);
+ if (CONSTANT_CLASS_P (decl))
+ dalign = CONSTANT_ALIGNMENT (decl, dalign);
+ else
+ dalign = DATA_ALIGNMENT (decl, dalign);
+ dalign /= BITS_PER_UNIT;
+ return dalign >= dsize;
+}
+
static bool
constant_pool_expr_p (rtx op)
{
@@ -5792,8 +5877,12 @@ toc_relative_expr_p (rtx op)
&& XINT (tocrel_base, 1) == UNSPEC_TOCREL);
}
+/* Return true if X is a constant pool address, and also for cmodel=medium
+ if X is a toc-relative address known to be offsettable within MODE. */
+
bool
-legitimate_constant_pool_address_p (const_rtx x, bool strict)
+legitimate_constant_pool_address_p (const_rtx x, enum machine_mode mode,
+ bool strict)
{
return (TARGET_TOC
&& (GET_CODE (x) == PLUS || GET_CODE (x) == LO_SUM)
@@ -5802,7 +5891,12 @@ legitimate_constant_pool_address_p (cons
|| ((TARGET_MINIMAL_TOC
|| TARGET_CMODEL != CMODEL_SMALL)
&& INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict)))
- && toc_relative_expr_p (XEXP (x, 1)));
+ && toc_relative_expr_p (XEXP (x, 1))
+ && (TARGET_CMODEL != CMODEL_MEDIUM
+ || constant_pool_expr_p (XVECEXP (tocrel_base, 0, 0))
+ || mode == QImode
+ || offsettable_ok_by_alignment (XVECEXP (tocrel_base, 0, 0),
+ INTVAL (tocrel_offset), mode)));
}
static bool
@@ -5830,7 +5924,7 @@ rs6000_legitimate_offset_address_p (enum
return false;
if (!reg_offset_addressing_ok_p (mode))
return virtual_stack_registers_memory_p (x);
- if (legitimate_constant_pool_address_p (x, strict))
+ if (legitimate_constant_pool_address_p (x, mode, strict))
return true;
if (GET_CODE (XEXP (x, 1)) != CONST_INT)
return false;
@@ -6830,7 +6924,8 @@ rs6000_legitimate_address_p (enum machin
return 1;
if (reg_offset_p && legitimate_small_data_p (mode, x))
return 1;
- if (reg_offset_p && legitimate_constant_pool_address_p (x, reg_ok_strict))
+ if (reg_offset_p
+ && legitimate_constant_pool_address_p (x, mode, reg_ok_strict))
return 1;
/* If not REG_OK_STRICT (before reload) let pass any stack offset. */
if (! reg_ok_strict
@@ -6940,7 +7035,7 @@ rs6000_mode_dependent_address (const_rtx
case LO_SUM:
/* Anything in the constant pool is sufficiently aligned that
all bytes have the same high part address. */
- return !legitimate_constant_pool_address_p (addr, false);
+ return !legitimate_constant_pool_address_p (addr, QImode, false);
/* Auto-increment cases are now treated generically in recog.c. */
case PRE_MODIFY:
@@ -7304,53 +7399,21 @@ rs6000_eliminate_indexed_memrefs (rtx op
if (GET_CODE (operands[0]) == MEM
&& GET_CODE (XEXP (operands[0], 0)) != REG
- && ! legitimate_constant_pool_address_p (XEXP (operands[0], 0), false))
+ && ! legitimate_constant_pool_address_p (XEXP (operands[0], 0),
+ GET_MODE (operands[0]), false))
operands[0]
= replace_equiv_address (operands[0],
copy_addr_to_reg (XEXP (operands[0], 0)));
if (GET_CODE (operands[1]) == MEM
&& GET_CODE (XEXP (operands[1], 0)) != REG
- && ! legitimate_constant_pool_address_p (XEXP (operands[1], 0), false))
+ && ! legitimate_constant_pool_address_p (XEXP (operands[1], 0),
+ GET_MODE (operands[1]), false))
operands[1]
= replace_equiv_address (operands[1],
copy_addr_to_reg (XEXP (operands[1], 0)));
}
-/* Return true if memory accesses to DECL are known to never straddle
- a 32k boundary. */
-
-static bool
-offsettable_ok_by_alignment (tree decl)
-{
- unsigned HOST_WIDE_INT dsize, dalign;
-
- /* Presume any compiler generated symbol_ref is suitably aligned. */
- if (!decl)
- return true;
-
- if (TREE_CODE (decl) != VAR_DECL
- && TREE_CODE (decl) != PARM_DECL
- && TREE_CODE (decl) != RESULT_DECL
- && TREE_CODE (decl) != FIELD_DECL)
- return true;
-
- if (!DECL_SIZE_UNIT (decl))
- return false;
-
- if (!host_integerp (DECL_SIZE_UNIT (decl), 1))
- return false;
-
- dsize = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
- if (dsize <= 1)
- return true;
- if (dsize > 32768)
- return false;
-
- dalign = DECL_ALIGN_UNIT (decl);
- return dalign >= dsize;
-}
-
/* Emit a move from SOURCE to DEST in mode MODE. */
void
rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
@@ -7672,8 +7735,7 @@ rs6000_emit_move (rtx dest, rtx source,
|| (TARGET_CMODEL == CMODEL_MEDIUM
&& GET_CODE (operands[1]) == SYMBOL_REF
&& !CONSTANT_POOL_ADDRESS_P (operands[1])
- && SYMBOL_REF_LOCAL_P (operands[1])
- && offsettable_ok_by_alignment (SYMBOL_REF_DECL (operands[1]))))
+ && SYMBOL_REF_LOCAL_P (operands[1])))
{
rtx reg = NULL_RTX;
if (TARGET_CMODEL != CMODEL_SMALL)
@@ -7695,7 +7757,8 @@ rs6000_emit_move (rtx dest, rtx source,
|| (GET_CODE (operands[0]) == REG
&& FP_REGNO_P (REGNO (operands[0]))))
&& GET_CODE (operands[1]) != HIGH
- && ! legitimate_constant_pool_address_p (operands[1], false)
+ && ! legitimate_constant_pool_address_p (operands[1], mode,
+ false)
&& ! toc_relative_expr_p (operands[1])
&& (TARGET_CMODEL == CMODEL_SMALL
|| can_create_pseudo_p ()
@@ -16421,7 +16484,7 @@ print_operand_address (FILE *file, rtx x
fprintf (file, ")(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
}
#endif
- else if (legitimate_constant_pool_address_p (x, true))
+ else if (legitimate_constant_pool_address_p (x, QImode, true))
{
/* This hack along with a corresponding hack in
rs6000_output_addr_const_extra arranges to output addends
Index: gcc/config/rs6000/constraints.md
===================================================================
--- gcc/config/rs6000/constraints.md (revision 170807)
+++ gcc/config/rs6000/constraints.md (working copy)
@@ -166,7 +166,7 @@ (define_address_constraint "a"
(define_constraint "R"
"AIX TOC entry"
- (match_test "legitimate_constant_pool_address_p (op, false)"))
+ (match_test "legitimate_constant_pool_address_p (op, QImode, false)"))
;; General constraints
Index: gcc/config/rs6000/predicates.md
===================================================================
--- gcc/config/rs6000/predicates.md (revision 170807)
+++ gcc/config/rs6000/predicates.md (working copy)
@@ -848,7 +848,7 @@ (define_predicate "input_operand"
return 1;
/* A SYMBOL_REF referring to the TOC is valid. */
- if (legitimate_constant_pool_address_p (op, false))
+ if (legitimate_constant_pool_address_p (op, mode, false))
return 1;
/* A constant pool expression (relative to the TOC) is valid */
Index: gcc/config/rs6000/rs6000-protos.h
===================================================================
--- gcc/config/rs6000/rs6000-protos.h (revision 170807)
+++ gcc/config/rs6000/rs6000-protos.h (working copy)
@@ -41,7 +41,8 @@ extern int small_data_operand (rtx, enum
extern bool toc_relative_expr_p (rtx);
extern bool invalid_e500_subreg (rtx, enum machine_mode);
extern void validate_condition_mode (enum rtx_code, enum machine_mode);
-extern bool legitimate_constant_pool_address_p (const_rtx, bool);
+extern bool legitimate_constant_pool_address_p (const_rtx, enum machine_mode,
+ bool);
extern bool legitimate_indirect_address_p (rtx, int);
extern bool legitimate_indexed_address_p (rtx, int);
extern bool avoiding_indexed_address_p (enum machine_mode);
--
Alan Modra
Australia Development Lab, IBM