Many (most? all?) assemblers (and really the 32-bit ABIs) do not handle lwa and ld properly. Those instructions have a 14-bit offset field, and the low two bits of the instruction are the extended opcode. But the 32-bit toolchains use a 16-bit offset relocation, clobbering the low two bits. See PR27619 and binutils #14758.
This works out fine for the most common case (word-aligned ld), but not for most others. This patch disables all lwa insns in 32-bit mode. We can later re-enable it if the assembler used handles it properly, and for lwax and lwaux, and fix the various ld patterns as well, but this is at least a small step in the right direction. gcc: -# of expected passes 108499 -# of unexpected failures 303 +# of expected passes 108508 +# of unexpected failures 295 gfortran: -# of expected passes 40555 -# of unexpected failures 175 +# of expected passes 40582 +# of unexpected failures 148 The lwa pattern must be below the extsw pattern, because the lwa_operand predicate allows registers as well. Changing lwa_operand causes other problems I do not want to deal with right now. Bootstrapped and tested on powerpc64-linux -m64,-m32,-m32/-mpowerpc64. Okay to apply? Segher 2012-10-25 Segher Boessenkool <seg...@kernel.crashing.org> gcc/ * config/rs6000/rs6000.md (sign_extend:SI patterns): Split the memory case off. Merge the two register cases. Change the condition for the memory case to require 64-bit mode. --- gcc/config/rs6000/rs6000.md | 22 ++++++++++++---------- 1 files changed, 12 insertions(+), 10 deletions(-) diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 2625bd7..5ce7963 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -519,18 +519,9 @@ (define_expand "extendsidi2" "") (define_insn "" - [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r") - (sign_extend:DI (match_operand:SI 1 "lwa_operand" "m,r")))] - "TARGET_POWERPC64 && rs6000_gen_cell_microcode" - "@ - lwa%U1%X1 %0,%1 - extsw %0,%1" - [(set_attr "type" "load_ext,exts")]) - -(define_insn "" [(set (match_operand:DI 0 "gpc_reg_operand" "=r") (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "r")))] - "TARGET_POWERPC64 && !rs6000_gen_cell_microcode" + "TARGET_POWERPC64" "extsw %0,%1" [(set_attr "type" "exts")]) @@ -586,6 +577,17 @@ (define_split (const_int 0)))] "") +; The 32-bit ABI has no relocation for DS_LO; the assembler uses a LO instead +; for the @l an lwa instruction uses, overwriting the low two bits in the +; opcode. We could do tricky tricks like adding 2 to the offset, but let's +; not: only allow this instruction in 64-bit mode. +(define_insn "" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (sign_extend:DI (match_operand:SI 1 "lwa_operand" "m")))] + "TARGET_64BIT && rs6000_gen_cell_microcode" + "lwa%U1%X1 %0,%1" + [(set_attr "type" "load_ext")]) + (define_expand "zero_extendqisi2" [(set (match_operand:SI 0 "gpc_reg_operand" "") (zero_extend:SI (match_operand:QI 1 "gpc_reg_operand" "")))] -- 1.7.7.6