[llvm] [AVR] Implement selection of 'ISD::RETURNADDR' and 'ISD::FRAMEADDR' (PR #222909)
Ben Shi via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 17 17:50:28 PDT 2026
================
@@ -961,11 +963,94 @@ SDValue AVRTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
return LowerDivRem(Op, DAG);
case ISD::INLINEASM:
return LowerINLINEASM(Op, DAG);
+ case ISD::FRAMEADDR:
+ return LowerFRAMEADDR(Op, DAG);
+ case ISD::RETURNADDR:
+ return LowerRETURNADDR(Op, DAG);
}
return SDValue();
}
+SDValue AVRTargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const {
+ // The frame pointer (Y = r29:r28) is set up to contain the stack pointer
+ // *after* the frame has been allocated, i.e. Y == SP_entry - StackSize,
+ // which means it points to the lowest address of the frame: it is really a
+ // frame *base* rather than the canonical frame address. The slot holding the
+ // caller's Y therefore sits at a function dependent offset (the frame size)
+ // above it. Walking the frame chain is only possible for the current frame.
+ //
+ // This is also what avr-gcc returns for __builtin_frame_address(0).
+ if (Op.getConstantOperandVal(0) > 0)
+ // Use the legalizer's default expansion, which is to return 0 (what this
+ // function is documented to do).
+ return SDValue();
+
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+ MFI.setFrameAddressIsTaken(true);
+
+ // Note that AVRRegisterInfo::getFrameRegister returns R28, which is only
+ // the low half of the frame pointer: use the full 16-bit register pair.
+ return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), AVR::R29R28,
+ Op.getValueType());
+}
+
+SDValue AVRTargetLowering::LowerRETURNADDR(SDValue Op,
+ SelectionDAG &DAG) const {
+ // AVR has no link register: the return address is pushed onto the stack by
+ // the call instruction. The stack pointer always points at the first free
+ // byte, so the pushed return address ends up right below the local area (the
+ // incoming stack arguments), which starts at SP_entry + 3.
+ //
+ // The return address is pushed most significant byte first, hence it is
+ // stored big-endian: [SP_entry + 1] is the high byte and [SP_entry + 2] the
+ // low byte. This is why avr-gcc has to swap the two bytes it reads for
+ // __builtin_return_address(0).
+ //
+ // Walking the frame chain is not possible, because the distance between the
+ // frame base and the slot holding the caller's return address depends on the
+ // caller's frame size, which is not known here. This is also what avr-gcc
+ // does for __builtin_return_address(1), which returns zero.
+ if (Op.getConstantOperandVal(0) > 0)
+ // Use the legalizer's default expansion, which is to return 0 (what this
+ // function is documented to do).
+ return SDValue();
+
+ MachineFunction &MF = DAG.getMachineFunction();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ MFI.setReturnAddressIsTaken(true);
----------------
benshi001 wrote:
Thanks, I have added your extra comments.
https://github.com/llvm/llvm-project/pull/222909
More information about the llvm-commits
mailing list