aggregate_copy_far_slot_misaligned.c (1894B)
1 /* Aggregate copy of a 4-aligned record living in a far (>256B) frame slot. 2 * 3 * A struct returned by value is homed into a local that the large `pad` frame 4 * pushes past the aarch64 stur/ldur +-256 range. The struct is 12 bytes with 5 * 4-byte alignment, so its slot can land at a frame offset that is 4 (mod 8). 6 * The store-into-local copy chunks the record as an 8-byte + a 4-byte access; 7 * the 8-byte chunk is then at a 4-mod-8 offset, which a scaled ldr/str cannot 8 * encode. The aarch64 far-slot fast path must detect the under-aligned access 9 * and fall back to the address-build form instead of emitting an unencodable 10 * scaled offset (which previously tripped a "far slot offset ... misaligned" 11 * codegen panic). The `perturb` array nudges the frame layout so `a` lands on 12 * the misaligned offset with the current allocator. 13 * 14 * x64/rv64 have no scaled-offset alignment constraint, so this just confirms 15 * the aggregate copy stays correct everywhere. */ 16 17 struct loc { 18 unsigned file, line, col; 19 }; /* 12 bytes, align 4 */ 20 21 __attribute__((noinline)) static struct loc make_loc(unsigned x) { 22 struct loc r; 23 r.file = x; 24 r.line = x + 1u; 25 r.col = x + 2u; 26 return r; 27 } 28 29 __attribute__((noinline)) static unsigned work(unsigned seed) { 30 volatile long pad[40]; /* large frame: 'a' lands far from fp */ 31 volatile unsigned perturb[3]; 32 unsigned pt = 0; 33 for (int i = 0; i < 40; i++) pad[i] = i; 34 for (int i = 0; i < 3; i++) perturb[i] = seed + (unsigned)i; 35 struct loc a = make_loc(seed); /* struct-return -> 8+4 stack copy */ 36 for (int i = 0; i < 3; i++) pt += perturb[i]; 37 /* Keep pad live without folding its (large) sum into the checksum. */ 38 for (int i = 0; i < 40; i++) 39 if (pad[i] < 0) pt += (unsigned)pad[i]; 40 return a.file + a.line + a.col + pt; 41 } 42 43 int test_main(void) { 44 /* a = {5,6,7} = 18 ; perturb = 5+6+7 = 18 ; total 36 */ 45 return (int)work(5u); 46 }