This fixes 29 FAILs. The ld, lwa etc. insns do not encode the low two bits of the offset in the opcode; those have to be zero. For -m64 this seemed to never matter, datums are always aligned; but for -m32 -mpowerpc64 you can get symbols that are not sufficiently aligned. So check for that.
[ Hrm, I think this triggers for lwz as well? I'll investigate. ] 2015-01-16 Segher Boessenkool <seg...@kernel.crashing.org> gcc/ * config/rs6000/rs6000.c (lo_sum_symbol_misaligned_p): New function. (legitimate_lo_sum_address_p): Use it for TARGET_POWERPC64. --- gcc/config/rs6000/rs6000.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 551181b..53bee13 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -6735,6 +6735,39 @@ macho_lo_sum_memory_operand (rtx x, machine_mode mode) return CONSTANT_P (x); } +/* Return true if X (which is the second operand of a LO_SUM) is a symbol + that is not sufficiently aligned for a DS-form instruction. */ +static bool +lo_sum_symbol_misaligned_p (rtx x) +{ + if (GET_CODE (x) == CONST) + x = XEXP (x, 0); + + if (GET_CODE (x) == PLUS) + x = XEXP (x, 0); + + if (GET_CODE (x) != SYMBOL_REF) + return false; + + tree decl = SYMBOL_REF_DECL (x); + if (decl) + return DECL_ALIGN_UNIT (decl) < 4; + + if (SYMBOL_REF_HAS_BLOCK_INFO_P (x) + && SYMBOL_REF_ANCHOR_P (x)) + { + struct object_block *block = SYMBOL_REF_BLOCK (x); + if (block) + return block->alignment < 32; + } + + if (CONSTANT_POOL_ADDRESS_P (x)) + return GET_MODE_ALIGNMENT (get_pool_mode (x)) < 32; + + /* Assume it's okay otherwise. */ + return false; +} + static bool legitimate_lo_sum_address_p (machine_mode mode, rtx x, int strict) { @@ -6774,6 +6807,10 @@ legitimate_lo_sum_address_p (machine_mode mode, rtx x, int strict) TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && (mode == DFmode || mode == DDmode))) return false; + if (TARGET_POWERPC64 + && GET_MODE_SIZE (mode) >= 4 + && lo_sum_symbol_misaligned_p (x)) + return false; return CONSTANT_P (x) || large_toc_ok; } -- 1.8.1.4