rv64: Preserve FP only for dynamic frames

7c9a7f91c60daea6af9b563519c84fd42b9d1d9bc888b890b0248247fe48d81b
Static frames do not modify FP, and the register allocator does not
assign it. Limit FP preservation to dynamic frames while keeping
frame sizes and stack offsets unchanged.

Assisted-by: Codex:gpt-6-astra
Alexis Sellier committed ago 1 parent 2c74c0a9
lib/std/arch/rv64/emit.rad +8 -8
621 621
//////////////////////////
622 622
// Prologue / Epilogue  //
623 623
//////////////////////////
624 624
625 625
/// Emit function prologue.
626 -
/// Allocates stack frame, saves RA/FP, saves callee-saved registers.
626 +
/// Allocate the frame and save registers. Save FP only for dynamic frames.
627 627
export fn emitPrologue(e: *mut Emitter, frame: *Frame) {
628 628
    // Fast path: leaf function with no locals.
629 629
    if frame.totalSize == 0 {
630 630
        return;
631 631
    }
641 641
    }
642 642
    // Save return address.
643 643
    if not frame.isLeaf {
644 644
        emitSd(e, super::RA, super::SP, totalSize - super::DWORD_SIZE);
645 645
    }
646 -
    // Save frame pointer.
647 -
    emitSd(e, super::FP, super::SP, totalSize - super::DWORD_SIZE * 2);
648 -
649 -
    // Set up frame pointer, only needed when dynamic allocs may move SP.
646 +
    // Save and set FP only when dynamic allocations can move SP.
650 647
    if frame.isDynamic {
648 +
        emitSd(e, super::FP, super::SP, totalSize - super::DWORD_SIZE * 2);
651 649
        emitAddImm(e, super::FP, super::SP, totalSize);
652 650
    }
653 651
    // Save callee-saved registers.
654 652
    for i in 0..frame.savedRegsLen {
655 653
        let sr = frame.savedRegs[i];
666 664
    }
667 665
    recordBranch(e, frame.epilogueBlock, BranchKind::Jump);
668 666
}
669 667
670 668
/// Emit function epilogue.
671 -
/// Restores callee-saved registers, `RA/FP`, deallocates frame, returns.
669 +
/// Restore saved registers and release the frame. Restore FP only for dynamic frames.
672 670
export fn emitEpilogue(e: *mut Emitter, frame: *Frame) {
673 671
    // Record epilogue block address for return jumps.
674 672
    recordBlock(e, frame.epilogueBlock);
675 673
676 674
    // Fast path: leaf function with no locals.
688 686
    // Restore callee-saved registers.
689 687
    for i in 0..frame.savedRegsLen {
690 688
        let sr = frame.savedRegs[i];
691 689
        emitLd(e, sr.reg, super::SP, sr.offset);
692 690
    }
693 -
    // Restore frame pointer.
694 -
    emitLd(e, super::FP, super::SP, totalSize - super::DWORD_SIZE * 2);
691 +
    // Restore FP only if the prologue saved and changed it.
692 +
    if frame.isDynamic {
693 +
        emitLd(e, super::FP, super::SP, totalSize - super::DWORD_SIZE * 2);
694 +
    }
695 695
    // Restore return address.
696 696
    if not frame.isLeaf {
697 697
        emitLd(e, super::RA, super::SP, totalSize - super::DWORD_SIZE);
698 698
    }
699 699
    // Deallocate stack frame.