-
Notifications
You must be signed in to change notification settings - Fork 15.3k
Open
Labels
Description
Consider the following translation unit:
struct nya {
int a;
};
void g(void *);
void f() {
_Alignas(64)
struct nya x = {3};
g(&x);
}When compiled with clang as follows, the generated code doesn't make any effort to actually satisfy the alignment constaint:
clang --target=avr-none -mmcu=atmega2560 -c test.c -o test-clang.o
LLVM IR generated by clang
; ModuleID = 'test.c'
source_filename = "test.c"
target datalayout = "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8"
target triple = "avr-none"
%struct.nya = type { i16 }
@__const.f.x = private unnamed_addr constant %struct.nya { i16 3 }, align 64
; Function Attrs: noinline nounwind optnone
define dso_local void @f() addrspace(1) #0 {
%1 = alloca %struct.nya, align 64
call addrspace(1) void @llvm.memcpy.p0.p0.i16(ptr align 64 %1, ptr align 64 @__const.f.x, i16 2, i1 false)
call addrspace(1) void @g(ptr noundef %1)
ret void
}
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
declare void @llvm.memcpy.p0.p0.i16(ptr noalias writeonly captures(none), ptr noalias readonly captures(none), i16, i1 immarg) addrspace(1) #1
declare dso_local void @g(ptr noundef) addrspace(1) #2
attributes #0 = { noinline nounwind optnone "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="atmega2560" }
attributes #1 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
attributes #2 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="atmega2560" }
!llvm.module.flags = !{!0, !1}
!llvm.ident = !{!2}
!0 = !{i32 1, !"wchar_size", i32 2}
!1 = !{i32 7, !"frame-pointer", i32 2}
!2 = !{!"clang version 21.1.6"}
Assembly generated by LLVM
f: ; @f
; %bb.0:
push r28
push r29
in r28, 61
in r29, 62
sbiw r28, 60
in r0, 63
cli
out 62, r29
out 63, r0
out 61, r28
lds r24, __const.f.x
lds r25, __const.f.x+1
std Y+2, r25
std Y+1, r24
movw r24, r28
adiw r24, 1
call g
adiw r28, 60
in r0, 63
cli
out 62, r29
out 63, r0
out 61, r28
pop r29
pop r28
ret
By comparison, GCC properly aligns the stack allocation (by allocating alignment - 1 + size bytes and positioning the actual object at a variable stack frame offset):
avr-gcc -mmcu=atmega2560 -c test.c -o test-gcc.o
Assembly generated by GCC
f:
push r28
push r29
in r28,__SP_L__
in r29,__SP_H__
subi r28,65
sbc r29,__zero_reg__
in __tmp_reg__,__SREG__
cli
out __SP_H__,r29
out __SREG__,__tmp_reg__
out __SP_L__,r28
/* prologue: function */
/* frame size = 65 */
/* stack size = 67 */
.L__stack_usage = 67
movw r24,r28
adiw r24,1
adiw r24,63
clr __tmp_reg__
lsl r24
rol r25
rol __tmp_reg__
lsl r24
rol r25
rol __tmp_reg__
mov r24,r25
mov r25,__tmp_reg__
clr __tmp_reg__
lsr r25
ror r24
ror __tmp_reg__
lsr r25
ror r24
ror __tmp_reg__
mov r25,r24
mov r24,__tmp_reg__
ldi r18,lo8(3)
ldi r19,0
movw r30,r24
std Z+1,r19
st Z,r18
call g
nop
/* epilogue start */
subi r28,-65
sbci r29,-1
in __tmp_reg__,__SREG__
cli
out __SP_H__,r29
out __SREG__,__tmp_reg__
out __SP_L__,r28
pop r29
pop r28
ret
Now, you might ask: "hold on, there's nothing on the AVR that'd be affected by memory alignment, why do you care about this". Well, recently the Rust formatting machinery has started making use of pointer tagging, which breaks spectacularly when LLVM ignores the alignment that rustc requests for some stack-allocated structs: rust-lang/rust#149223