From 3a905cbce66be7bc10ccd3bba47635541e06baea Mon Sep 17 00:00:00 2001 From: Robert Lytton Date: Mon, 6 Jan 2014 14:21:07 +0000 Subject: [PATCH] XCore target: Lower EH_RETURN git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@198615 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/XCore/XCoreFrameLowering.cpp | 9 ++++ lib/Target/XCore/XCoreISelLowering.cpp | 42 +++++++++++++++++ lib/Target/XCore/XCoreISelLowering.h | 5 ++ lib/Target/XCore/XCoreInstrInfo.td | 10 ++++ test/CodeGen/XCore/llvm-intrinsics.ll | 62 ++++++++++++++++++++++++- 5 files changed, 127 insertions(+), 1 deletion(-) diff --git a/lib/Target/XCore/XCoreFrameLowering.cpp b/lib/Target/XCore/XCoreFrameLowering.cpp index 3d1fb9cafc1..109b74d445c 100644 --- a/lib/Target/XCore/XCoreFrameLowering.cpp +++ b/lib/Target/XCore/XCoreFrameLowering.cpp @@ -252,6 +252,15 @@ void XCoreFrameLowering::emitEpilogue(MachineFunction &MF, DebugLoc dl = MBBI->getDebugLoc(); unsigned RetOpcode = MBBI->getOpcode(); + if (RetOpcode == XCore::EH_RETURN) { + unsigned EhStackReg = MBBI->getOperand(0).getReg(); + unsigned EhHandlerReg = MBBI->getOperand(1).getReg(); + BuildMI(MBB, MBBI, dl, TII.get(XCore::SETSP_1r)).addReg(EhStackReg); + BuildMI(MBB, MBBI, dl, TII.get(XCore::BAU_1r)).addReg(EhHandlerReg); + MBB.erase(MBBI); // Erase the previous return instruction. + return; + } + // Work out frame sizes. // We will adjust the SP in stages towards the final FrameSize. int RemainingAdj = MFI->getStackSize(); diff --git a/lib/Target/XCore/XCoreISelLowering.cpp b/lib/Target/XCore/XCoreISelLowering.cpp index c0edee55e43..dd268c4cddc 100644 --- a/lib/Target/XCore/XCoreISelLowering.cpp +++ b/lib/Target/XCore/XCoreISelLowering.cpp @@ -61,6 +61,7 @@ getTargetNodeName(unsigned Opcode) const case XCoreISD::BR_JT : return "XCoreISD::BR_JT"; case XCoreISD::BR_JT32 : return "XCoreISD::BR_JT32"; case XCoreISD::FRAME_TO_ARGS_OFFSET : return "XCoreISD::FRAME_TO_ARGS_OFFSET"; + case XCoreISD::EH_RETURN : return "XCoreISD::EH_RETURN"; case XCoreISD::MEMBARRIER : return "XCoreISD::MEMBARRIER"; default : return NULL; } @@ -152,6 +153,7 @@ XCoreTargetLowering::XCoreTargetLowering(XCoreTargetMachine &XTM) setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand); // Exception handling + setOperationAction(ISD::EH_RETURN, MVT::Other, Custom); setExceptionPointerRegister(XCore::R0); setExceptionSelectorRegister(XCore::R1); setOperationAction(ISD::FRAME_TO_ARGS_OFFSET, MVT::i32, Custom); @@ -199,6 +201,7 @@ SDValue XCoreTargetLowering:: LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { + case ISD::EH_RETURN: return LowerEH_RETURN(Op, DAG); case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); case ISD::BlockAddress: return LowerBlockAddress(Op, DAG); case ISD::ConstantPool: return LowerConstantPool(Op, DAG); @@ -838,6 +841,45 @@ LowerFRAME_TO_ARGS_OFFSET(SDValue Op, SelectionDAG &DAG) const { return DAG.getNode(XCoreISD::FRAME_TO_ARGS_OFFSET, SDLoc(Op), MVT::i32); } +SDValue XCoreTargetLowering:: +LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const { + // OUTCHAIN = EH_RETURN(INCHAIN, OFFSET, HANDLER) + // This node represents 'eh_return' gcc dwarf builtin, which is used to + // return from exception. The general meaning is: adjust stack by OFFSET and + // pass execution to HANDLER. + MachineFunction &MF = DAG.getMachineFunction(); + SDValue Chain = Op.getOperand(0); + SDValue Offset = Op.getOperand(1); + SDValue Handler = Op.getOperand(2); + SDLoc dl(Op); + + // Absolute SP = (FP + FrameToArgs) + Offset + const TargetRegisterInfo *RegInfo = getTargetMachine().getRegisterInfo(); + SDValue Stack = DAG.getCopyFromReg(DAG.getEntryNode(), dl, + RegInfo->getFrameRegister(MF), MVT::i32); + SDValue FrameToArgs = DAG.getNode(XCoreISD::FRAME_TO_ARGS_OFFSET, dl, + MVT::i32); + Stack = DAG.getNode(ISD::ADD, dl, MVT::i32, Stack, FrameToArgs); + Stack = DAG.getNode(ISD::ADD, dl, MVT::i32, Stack, Offset); + + // R0=ExceptionPointerRegister R1=ExceptionSelectorRegister + // which leaves 2 caller saved registers, R2 & R3 for us to use. + unsigned StackReg = XCore::R2; + unsigned HandlerReg = XCore::R3; + + SDValue OutChains[] = { + DAG.getCopyToReg(Chain, dl, StackReg, Stack), + DAG.getCopyToReg(Chain, dl, HandlerReg, Handler) + }; + + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains, 2); + + return DAG.getNode(XCoreISD::EH_RETURN, dl, MVT::Other, Chain, + DAG.getRegister(StackReg, MVT::i32), + DAG.getRegister(HandlerReg, MVT::i32)); + +} + SDValue XCoreTargetLowering:: LowerADJUST_TRAMPOLINE(SDValue Op, SelectionDAG &DAG) const { return Op.getOperand(0); diff --git a/lib/Target/XCore/XCoreISelLowering.h b/lib/Target/XCore/XCoreISelLowering.h index c4de86e22dc..05e2a86a9b5 100644 --- a/lib/Target/XCore/XCoreISelLowering.h +++ b/lib/Target/XCore/XCoreISelLowering.h @@ -75,6 +75,10 @@ namespace llvm { // Offset from frame pointer to the first (possible) on-stack argument FRAME_TO_ARGS_OFFSET, + // Exception handler return. The stack is restored to the first + // followed by a jump to the second argument. + EH_RETURN, + // Memory barrier. MEMBARRIER }; @@ -150,6 +154,7 @@ namespace llvm { // Lower Operand specifics SDValue LowerLOAD(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSTORE(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const; SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; SDValue LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const; SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; diff --git a/lib/Target/XCore/XCoreInstrInfo.td b/lib/Target/XCore/XCoreInstrInfo.td index 144d4fec246..0aecca064f2 100644 --- a/lib/Target/XCore/XCoreInstrInfo.td +++ b/lib/Target/XCore/XCoreInstrInfo.td @@ -35,6 +35,11 @@ def XCoreBranchLink : SDNode<"XCoreISD::BL",SDT_XCoreBranchLink, def XCoreRetsp : SDNode<"XCoreISD::RETSP", SDTBrind, [SDNPHasChain, SDNPOptInGlue, SDNPMayLoad, SDNPVariadic]>; +def SDT_XCoreEhRet : SDTypeProfile<0, 2, + [SDTCisSameAs<0, 1>, SDTCisPtrTy<0>]>; +def XCoreEhRet : SDNode<"XCoreISD::EH_RETURN", SDT_XCoreEhRet, + [SDNPHasChain, SDNPOptInGlue]>; + def SDT_XCoreBR_JT : SDTypeProfile<0, 2, [SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; @@ -334,6 +339,11 @@ def FRAME_TO_ARGS_OFFSET : PseudoInstXCore<(outs GRRegs:$dst), (ins), "# FRAME_TO_ARGS_OFFSET $dst", [(set GRRegs:$dst, (frametoargsoffset))]>; +let isReturn = 1, isTerminator = 1, isBarrier = 1 in +def EH_RETURN : PseudoInstXCore<(outs), (ins GRRegs:$s, GRRegs:$handler), + "# EH_RETURN $s, $handler", + [(XCoreEhRet GRRegs:$s, GRRegs:$handler)]>; + def LDWFI : PseudoInstXCore<(outs GRRegs:$dst), (ins MEMii:$addr), "# LDWFI $dst, $addr", [(set GRRegs:$dst, (load ADDRspii:$addr))]>; diff --git a/test/CodeGen/XCore/llvm-intrinsics.ll b/test/CodeGen/XCore/llvm-intrinsics.ll index 55b77ac9e6b..ac6453c8c7f 100644 --- a/test/CodeGen/XCore/llvm-intrinsics.ll +++ b/test/CodeGen/XCore/llvm-intrinsics.ll @@ -21,7 +21,6 @@ entry: ret i8* %1 } - declare i8* @llvm.returnaddress(i32) nounwind readnone define i8* @RA0() nounwind { entry: @@ -70,3 +69,64 @@ entry: %1 = call i8* @llvm.eh.dwarf.cfa(i32 0) ret i8* %1 } + +declare void @llvm.eh.return.i32(i32, i8*) +define i8* @EH0(i32 %offset, i8* %handler) { +entry: +; CHECK-LABEL: EH0 +; CHECK: ldc r2, 0 +; CHECK-NEXT: ldaw r3, sp[0] +; CHECK-NEXT: add r2, r3, r2 +; CHECK-NEXT: add r2, r2, r0 +; CHECK-NEXT: mov r3, r1 +; CHECK-NEXT: set sp, r2 +; CHECK-NEXT: bau r3 + call void @llvm.eh.return.i32(i32 %offset, i8* %handler) + unreachable +} + +declare void @foo(...) +define i8* @EH1(i32 %offset, i8* %handler) { +entry: +; CHECK-LABEL: EH1 +; CHECK: entsp 3 +; CHECK: stw r4, sp[2] +; CHECK: stw r5, sp[1] +; CHECK: mov r4, r1 +; CHECK-NEXT: mov r5, r0 +; CHECK-NEXT: bl foo +; CHECK-NEXT: ldc r0, 12 +; CHECK-NEXT: ldaw r1, sp[0] +; CHECK-NEXT: add r0, r1, r0 +; CHECK-NEXT: add r2, r0, r5 +; CHECK-NEXT: mov r3, r4 +; CHECK-NEXT: ldw r5, sp[1] +; CHECK-NEXT: ldw r4, sp[2] +; CHECK-NEXT: set sp, r2 +; CHECK-NEXT: bau r3 + call void (...)* @foo() + call void @llvm.eh.return.i32(i32 %offset, i8* %handler) + unreachable +} + +@offset = external constant i32 +@handler = external constant i8 +define i8* @EH2(i32 %r0, i32 %r1, i32 %r2, i32 %r3) { +entry: +; CHECK-LABEL: EH2 +; CHECK: entsp 1 +; CHECK: bl foo +; CHECK-NEXT: ldw r0, cp[offset] +; CHECK-NEXT: ldc r1, 4 +; CHECK-NEXT: ldaw r2, sp[0] +; CHECK-NEXT: add r1, r2, r1 +; CHECK-NEXT: add r2, r1, r0 +; CHECK-NEXT: ldaw r11, cp[handler] +; CHECK-NEXT: mov r3, r11 +; CHECK-NEXT: set sp, r2 +; CHECK-NEXT: bau r3 + call void (...)* @foo() + %0 = load i32* @offset + call void @llvm.eh.return.i32(i32 %0, i8* @handler) + unreachable +} -- 2.34.1