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.