diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp index 13315c038c417e..d80d292f0691e3 100644 --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp @@ -256,19 +256,23 @@ SDValue LoongArchTargetLowering::lowerFRAMEADDR(SDValue Op, return SDValue(); } - // Currently only support lowering frame address for current frame. - if (cast(Op.getOperand(0))->getZExtValue() != 0) { - DAG.getContext()->emitError( - "frame address can only be determined for the current frame"); - return SDValue(); - } - MachineFunction &MF = DAG.getMachineFunction(); MF.getFrameInfo().setFrameAddressIsTaken(true); - - return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), - Subtarget.getRegisterInfo()->getFrameRegister(MF), - Op.getValueType()); + Register FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF); + EVT VT = Op.getValueType(); + SDLoc DL(Op); + SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameReg, VT); + unsigned Depth = cast(Op.getOperand(0))->getZExtValue(); + int GRLenInBytes = Subtarget.getGRLen() / 8; + + while (Depth--) { + int Offset = -(GRLenInBytes * 2); + SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr, + DAG.getIntPtrConstant(Offset, DL)); + FrameAddr = + DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo()); + } + return FrameAddr; } SDValue LoongArchTargetLowering::lowerRETURNADDR(SDValue Op, diff --git a/llvm/test/CodeGen/LoongArch/frameaddr-returnaddr-error.ll b/llvm/test/CodeGen/LoongArch/frameaddr-returnaddr-error.ll index 2ac837c1b4e54e..10fcdf2004b4f0 100644 --- a/llvm/test/CodeGen/LoongArch/frameaddr-returnaddr-error.ll +++ b/llvm/test/CodeGen/LoongArch/frameaddr-returnaddr-error.ll @@ -16,13 +16,6 @@ define ptr @non_const_depth_returnaddress(i32 %x) nounwind { ret ptr %1 } -define ptr @non_zero_frameaddress() nounwind { -; CHECK: frame address can only be determined for the current frame - %1 = call ptr @llvm.frameaddress(i32 1) - ret ptr %1 -} - - define ptr @non_zero_returnaddress() nounwind { ; CHECK: return address can only be determined for the current frame %1 = call ptr @llvm.returnaddress(i32 1) diff --git a/llvm/test/CodeGen/LoongArch/frameaddr-returnaddr.ll b/llvm/test/CodeGen/LoongArch/frameaddr-returnaddr.ll index 7b0a4627685a50..01c9173c2e982a 100644 --- a/llvm/test/CodeGen/LoongArch/frameaddr-returnaddr.ll +++ b/llvm/test/CodeGen/LoongArch/frameaddr-returnaddr.ll @@ -33,6 +33,36 @@ define ptr @test_frameaddress_0() nounwind { ret ptr %1 } +define ptr @test_frameaddress_2() nounwind { +; LA32-LABEL: test_frameaddress_2: +; LA32: # %bb.0: +; LA32-NEXT: addi.w $sp, $sp, -16 +; LA32-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill +; LA32-NEXT: st.w $fp, $sp, 8 # 4-byte Folded Spill +; LA32-NEXT: addi.w $fp, $sp, 16 +; LA32-NEXT: ld.w $a0, $fp, -8 +; LA32-NEXT: ld.w $a0, $a0, -8 +; LA32-NEXT: ld.w $fp, $sp, 8 # 4-byte Folded Reload +; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload +; LA32-NEXT: addi.w $sp, $sp, 16 +; LA32-NEXT: ret +; +; LA64-LABEL: test_frameaddress_2: +; LA64: # %bb.0: +; LA64-NEXT: addi.d $sp, $sp, -16 +; LA64-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill +; LA64-NEXT: st.d $fp, $sp, 0 # 8-byte Folded Spill +; LA64-NEXT: addi.d $fp, $sp, 16 +; LA64-NEXT: ld.d $a0, $fp, -16 +; LA64-NEXT: ld.d $a0, $a0, -16 +; LA64-NEXT: ld.d $fp, $sp, 0 # 8-byte Folded Reload +; LA64-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload +; LA64-NEXT: addi.d $sp, $sp, 16 +; LA64-NEXT: ret + %1 = call ptr @llvm.frameaddress(i32 2) + ret ptr %1 +} + define ptr @test_returnaddress_0() nounwind { ; LA32-LABEL: test_returnaddress_0: ; LA32: # %bb.0: