Index: lib/Target/NDS32/NDS32ISelLowering.h
===================================================================
--- lib/Target/NDS32/NDS32ISelLowering.h
+++ lib/Target/NDS32/NDS32ISelLowering.h
@@ -75,6 +75,10 @@
 
     SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const;
 
+    SDValue getReturnAddressFrameIndex(SelectionDAG &DAG) const;
+    SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
+    SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
+
     /// getTargetNodeName - This method returns the name of a target specific
     /// DAG node.
     const char *getTargetNodeName(unsigned Opcode) const override;
Index: lib/Target/NDS32/NDS32ISelLowering.cpp
===================================================================
--- lib/Target/NDS32/NDS32ISelLowering.cpp
+++ lib/Target/NDS32/NDS32ISelLowering.cpp
@@ -151,6 +151,8 @@
   case ISD::UDIVREM:          return LowerDIVREM(Op, DAG);
   case ISD::SDIVREM:          return LowerDIVREM(Op, DAG);
   case ISD::VASTART:          return LowerVASTART(Op, DAG);
+  case ISD::RETURNADDR:       return LowerRETURNADDR(Op, DAG);
+  case ISD::FRAMEADDR:        return LowerFRAMEADDR(Op, DAG);
   default:
     llvm_unreachable("unimplemented operand");
   }
@@ -227,6 +229,66 @@
                       MachinePointerInfo(SV));
 }
 
+SDValue
+NDS32TargetLowering::getReturnAddressFrameIndex(SelectionDAG &DAG) const {
+  MachineFunction &MF = DAG.getMachineFunction();
+  NDS32MachineFunctionInfo *FuncInfo = MF.getInfo<NDS32MachineFunctionInfo>();
+  int ReturnAddrIndex = FuncInfo->getRAIndex();
+  auto PtrVT = getPointerTy(MF.getDataLayout());
+
+  if (ReturnAddrIndex == 0) {
+    // Set up a frame object for the return address.
+    uint64_t SlotSize = MF.getDataLayout().getPointerSize();
+    ReturnAddrIndex = MF.getFrameInfo().CreateFixedObject(SlotSize, -SlotSize,
+                                                          true);
+    FuncInfo->setRAIndex(ReturnAddrIndex);
+  }
+
+  return DAG.getFrameIndex(ReturnAddrIndex, PtrVT);
+}
+
+SDValue NDS32TargetLowering::LowerFRAMEADDR(SDValue Op,
+                                            SelectionDAG &DAG) const {
+  MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+  MFI.setFrameAddressIsTaken(true);
+
+  EVT VT = Op.getValueType();
+  SDLoc dl(Op);
+  unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
+  SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl,
+                                         NDS32::FP, VT);
+  while (Depth--)
+    FrameAddr = DAG.getLoad(VT, dl, DAG.getEntryNode(), FrameAddr,
+                            MachinePointerInfo());
+  return FrameAddr;
+}
+
+SDValue NDS32TargetLowering::LowerRETURNADDR(SDValue Op,
+                                             SelectionDAG &DAG) const {
+  MachineFunction &MF = DAG.getMachineFunction();
+  MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+  MFI.setReturnAddressIsTaken(true);
+
+  if (verifyReturnAddressArgumentIsConstant(Op, DAG))
+    return SDValue();
+
+  unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
+  SDLoc dl(Op);
+  auto PtrVT = getPointerTy(DAG.getDataLayout());
+
+  if (Depth > 0) {
+    SDValue FrameAddr = LowerFRAMEADDR(Op, DAG);
+    SDValue Offset =
+        DAG.getConstant(DAG.getDataLayout().getPointerSize(), dl, MVT::i32);
+    return DAG.getLoad(PtrVT, dl, DAG.getEntryNode(),
+                       DAG.getNode(ISD::ADD, dl, PtrVT, FrameAddr, Offset),
+                       MachinePointerInfo());
+  }
+
+  unsigned Reg = MF.addLiveIn(NDS32::LP, getRegClassFor(MVT::i32));
+  return DAG.getCopyFromReg(DAG.getEntryNode(), dl, Reg, PtrVT);
+}
+
 
 //===----------------------------------------------------------------------===//
 //                       NDS32 Addressing Mode Support
Index: test/CodeGen/NDS32/return-addr.ll
===================================================================
--- /dev/null
+++ test/CodeGen/NDS32/return-addr.ll
@@ -0,0 +1,14 @@
+; RUN: llc < %s | FileCheck %s
+target datalayout = "e-m:e-p:32:32-i64:64-a:0:32-n32-S64"
+target triple = "nds32le---elf"
+
+; Function Attrs: noinline nounwind readnone
+define i8* @test1() local_unnamed_addr #0 {
+entry:
+  %0 = tail call i8* @llvm.returnaddress(i32 0)
+; CHECK: mov55   $r0, $lp
+  ret i8* %0
+}
+
+; Function Attrs: nounwind readnone
+declare i8* @llvm.returnaddress(i32) #1