https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118684

            Bug ID: 118684
           Summary: wrong alignment for stack temporary created during RTL
                    expansion
           Product: gcc
           Version: 15.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: middle-end
          Assignee: unassigned at gcc dot gnu.org
          Reporter: rguenth at gcc dot gnu.org
  Target Milestone: ---

typedef int v4si __attribute__((vector_size(16)));
v4si x;
int main ()
{
  int b __attribute__((aligned(16)));
  b = 0;
  x = *(v4si *)&b;
}

segfaults because we expand 'b' to a register, but then spill it to the stack
without honoring it's original alignment, eventually creating a MEM with
too large MEM_ALIGN, resulting in a movdqa that faults:

main:
.LFB0:  
        .cfi_startproc
        movl    $0, -12(%rsp)
        movdqa  -12(%rsp), %xmm0
        xorl    %eax, %eax
        movaps  %xmm0, x(%rip)
        ret

We go through

    case MEM_REF:                 
      {
        const bool reverse = REF_REVERSE_STORAGE_ORDER (exp);
        addr_space_t as
          = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))));
        machine_mode address_mode;
...
        unsigned align;
        /* Handle expansion of non-aliased memory with non-BLKmode.  That
           might end up in a register.  */
        if (mem_ref_refers_to_non_mem_p (exp))
          {
...
            exp = build3 (BIT_FIELD_REF, type, base, TYPE_SIZE (type),
                          bitsize_int (offset * BITS_PER_UNIT));
            REF_REVERSE_STORAGE_ORDER (exp) = reverse;
            return expand_expr (exp, target, tmode, modifier);

where the BIT_FIELD_REF expansion does

        /* Otherwise, if this is a constant or the object is not in memory
           and need be, put it there.  */
        else if (CONSTANT_P (op0) || (!MEM_P (op0) && must_force_mem))
          {     
            memloc = assign_temp (TREE_TYPE (tem), 1, 1);
            emit_move_insn (memloc, op0);
            op0 = memloc;
            clear_mem_expr = true;

and then

        /* Don't set memory attributes if the base expression is
           SSA_NAME that got expanded as a MEM or a CONSTANT.  In that case,
           we should just honor its original memory attributes.  */
        if (!(TREE_CODE (tem) == SSA_NAME
              && (MEM_P (orig_op0) || CONSTANT_P (orig_op0))))
          set_mem_attributes (op0, exp, 0);

yielding

(insn 6 5 7 (set (mem/c:SI (plus:DI (reg/f:DI 93 virtual-stack-vars)
                (const_int -4 [0xfffffffffffffffc])) [1  S4 A32])
        (reg/v:SI 99 [ b ])) "t.c":7:7 -1
     (nil))

(insn 7 6 8 (set (reg:V4SI 101)
        (mem/j:V4SI (plus:DI (reg/f:DI 93 virtual-stack-vars)
                (const_int -4 [0xfffffffffffffffc])) [1 +0 S16 A128]))
"t.c":7:5 -1  
     (nil))


The issue is that while there's DECL_ALIGN on the decl for 'b', it's type
is 'int' with natural alignment.  But assign_temp only looks at the type
for the alignment, even if you pass it a decl.

Reply via email to