XCore target: Lower EH_RETURN

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@198615 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Robert Lytton 2014-01-06 14:21:07 +00:00
parent af74cbf553
commit 3a905cbce6
5 changed files with 127 additions and 1 deletions

View File

@ -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();

View File

@ -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);

View File

@ -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;

View File

@ -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))]>;

View File

@ -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
}