re PR target/48032 (PowerPC64 -mcmodel=medium invalid ld offset)

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.

From-SVN: r170976
This commit is contained in:
Alan Modra 2011-03-15 12:49:28 +10:30 committed by Alan Modra
parent e95992339f
commit 77b0791e3d
5 changed files with 132 additions and 48 deletions

View File

@ -1,3 +1,20 @@
2011-03-15 Alan Modra <amodra@gmail.com>
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.
2011-03-14 Michael Meissner <meissner@linux.vnet.ibm.com>
PR target/48053

View File

@ -166,7 +166,7 @@ usually better to use @samp{m} or @samp{es} in @code{asm} statements)"
(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

View File

@ -854,7 +854,7 @@
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 */

View File

@ -41,7 +41,8 @@ extern int small_data_operand (rtx, enum machine_mode);
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);

View File

@ -5791,6 +5791,94 @@ 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)
{
if (GET_MODE_SIZE (mode) == 0)
return false;
/* -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)
{
@ -5815,8 +5903,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)
@ -5825,7 +5917,12 @@ legitimate_constant_pool_address_p (const_rtx x, bool strict)
|| ((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
@ -5853,7 +5950,7 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
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;
@ -6853,7 +6950,8 @@ rs6000_legitimate_address_p (enum machine_mode mode, rtx x, bool reg_ok_strict)
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
@ -6963,7 +7061,7 @@ rs6000_mode_dependent_address (const_rtx addr)
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:
@ -7327,53 +7425,21 @@ rs6000_eliminate_indexed_memrefs (rtx operands[2])
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)
@ -7695,8 +7761,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
|| (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)
@ -7718,7 +7783,8 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
|| (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 ()
@ -16444,7 +16510,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