Richard Henderson <[email protected]> writes:
> On 11/20/2012 11:24 AM, Richard Henderson wrote:
>> On 11/20/2012 09:29 AM, Richard Sandiford wrote:
>>> Gah. How about this patch, currently bootstrapping on x86_64-linux-gnu
>>> as a sanity check? The last instance seems glaringly obvious in
>>> hindsight :-(
>>>
>>> Richard
>>>
>>>
>>> gcc/
>>> * expmed.c (store_bit_field_1): Use adjust_bitfield_address_size
>>> rather than adjust_bitfield_address to change the mode of a reference.
>>> (extract_bit_field_1): Likewise.
>>
>> That patch does fix my ICE.
>>
>> It looks all good, too. As you say, glaringly obvious even. ;-)
>
> One further point -- get_best_mem_extraction_insn does not work for
> the traditional 'extv' patterns that only accept memories. In
> particular, the QImode memory in the extv pattern never matches up
> at the beginning of get_traditional_extraction_insn, so that first
> "if (mode != struct_mode) return false;" always triggers.
Sorry for all the mishaps.
> I audited the existing extv patterns and the affected targets are
> alpha, sh, and vax. All of the others implement extv on registers,
> which appears to work. Test case:
>
> struct S { long y __attribute__((packed)); };
> long g(struct S *s) { return s->y; }
>
> Before:
>
> ldq_u $0,0($16)
> ldq_u $1,7($16)
> extql $0,$16,$0
> extqh $1,$16,$16
> bis $0,$16,$0
>
> After:
>
> ldbu $5,1($16)
> ldbu $8,0($16)
> ldbu $7,2($16)
> ldbu $6,3($16)
> ldbu $4,4($16)
> ldbu $3,5($16)
> sll $5,8,$5
> ldbu $2,6($16)
> ldbu $1,7($16)
> sll $7,16,$7
> sll $6,24,$6
> bis $5,$8,$5
> sll $4,32,$4
> sll $3,40,$3
> bis $7,$5,$5
> sll $2,48,$2
> sll $1,56,$1
> bis $6,$5,$0
> bis $4,$0,$0
> bis $3,$0,$0
> bis $2,$0,$0
> bis $1,$0,$0
>
> I suppose the question is: with only 3 affected targets, is it more
> trouble fiddling the somewhat confused "traditional" path, or to
> just go ahead and update the backends?
I suppose updating them would be the ideal eventually, but I'd still
like to fix the bug.
I belatedly did a similar audit and it looks there are no patterns that
use a mixture of field and structure modes for register operations.
They're either equal or not present. So how about the patch below?
I checked that it fixes this testcase.
Richard
gcc/
* optabs.c (get_traditional_extraction_insn): Check the field mode
against the given mode. Only check the structure mode for register
insertions and extractions.
Index: gcc/optabs.c
===================================================================
--- gcc/optabs.c 2012-11-18 17:33:42.000000000 +0000
+++ gcc/optabs.c 2012-11-20 20:46:16.893286686 +0000
@@ -8258,11 +8258,12 @@ #define CODE_FOR_extzv CODE_FOR_nothing
enum extraction_type { ET_unaligned_mem, ET_reg };
/* Check whether insv, extv or extzv pattern ICODE can be used for an
- insertion or extraction of type TYPE on a structure of mode MODE.
- Return true if so and fill in *INSN accordingly. STRUCT_OP is the
- operand number of the structure (the first sign_extract or zero_extract
- operand) and FIELD_OP is the operand number of the field (the other
- side of the set from the sign_extract or zero_extract). */
+ insertion or extraction of type TYPE on a structure and field of
+ mode MODE. Return true if so and fill in *INSN accordingly.
+ STRUCT_OP is the operand number of the structure (the first
+ sign_extract or zero_extract operand) and FIELD_OP is the operand
+ number of the field (the other side of the set from the sign_extract
+ or zero_extract). */
static bool
get_traditional_extraction_insn (extraction_insn *insn,
@@ -8273,15 +8274,23 @@ get_traditional_extraction_insn (extract
{
const struct insn_data_d *data = &insn_data[icode];
- enum machine_mode struct_mode = data->operand[struct_op].mode;
- if (struct_mode == VOIDmode)
- struct_mode = word_mode;
- if (mode != struct_mode)
- return false;
-
enum machine_mode field_mode = data->operand[field_op].mode;
if (field_mode == VOIDmode)
field_mode = word_mode;
+ if (mode != field_mode)
+ return false;
+
+ enum machine_mode struct_mode;
+ if (type == ET_unaligned_mem)
+ struct_mode = byte_mode;
+ else
+ {
+ struct_mode = data->operand[struct_op].mode;
+ if (struct_mode == VOIDmode)
+ struct_mode = word_mode;
+ if (mode != struct_mode)
+ return false;
+ }
enum machine_mode pos_mode = data->operand[struct_op + 2].mode;
if (pos_mode == VOIDmode)
@@ -8289,7 +8298,7 @@ get_traditional_extraction_insn (extract
insn->icode = icode;
insn->field_mode = field_mode;
- insn->struct_mode = (type == ET_unaligned_mem ? byte_mode : struct_mode);
+ insn->struct_mode = struct_mode;
insn->pos_mode = pos_mode;
return true;
}