140_fp_callee_save_bottom_frame.toy (1375B)
1 // Regression: aarch64 -O1 bottom-record (fp_at_bottom) frame layout must save 2 // and restore FP callee-saves (v8-v15) correctly. FP saves are always 3 // single-register, so they take the scaled `str d, [fp, #off]` / `ldr` path — 4 // the unscaled stur (+-256) the top-record layout uses cannot reach the large 5 // positive offsets the bottom-record layout produces. 6 // 7 // `acc` (an f64) is live across the call to `bump`, forcing an FP callee-save. 8 // The 40-element local array bloats the frame past 256 bytes, so the FP 9 // callee-save (reserved first => largest offset = frame_size-8) lands well past 10 // 255 and exercises the scaled d-register store/load. The body sums everything 11 // so nothing is dead-code-eliminated; the result is checked against .expected. 12 13 fn bump(x: i64): i64 { return x + 100; } 14 15 fn big_fp(seed: i64): i64 { 16 var buf: [40]i64; 17 var i: isize = 0; 18 while i < 40 { 19 buf[i] = seed + i; 20 i = i + 1; 21 } 22 var acc: f64 = (seed as f64) + 0.5; // f64 live across the call below 23 let y: i64 = bump(seed); // call: acc must survive in d8..d15 24 var s: i64 = 0; 25 i = 0; 26 while i < 40 { 27 s = s + buf[i]; 28 i = i + 1; 29 } 30 // seed=2: acc=2.5 -> 2; y=102; sum(2..41)=2*40+780=860; total=2+102+860=964. 31 return (acc as i64) + y + s; 32 } 33 34 fn __user_main(): i64 { 35 return big_fp(2); 36 } 37 38 fn main(): i32 { return __user_main() as i32; }