mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 20:32:21 +00:00
Add support for GCC compatible builtin setjmp and longjmp intrinsics. This is
a supporting preliminary patch for GCC-compatible SjLJ exception handling. Note that these intrinsics are not designed to be invoked directly by the user, but rather used by the front-end as target hooks for exception handling. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@71610 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
9d3094b38e
commit
0e0da734bb
@ -70,6 +70,10 @@ class MachineFunction : private Annotation {
|
|||||||
const Function *Fn;
|
const Function *Fn;
|
||||||
const TargetMachine &Target;
|
const TargetMachine &Target;
|
||||||
|
|
||||||
|
// HasBuiltinSetjmp - true if the function uses builtin_setjmp. Used to
|
||||||
|
// adjust callee-saved register tracking.
|
||||||
|
bool HasBuiltinSetjmp;
|
||||||
|
|
||||||
// RegInfo - Information about each register in use in the function.
|
// RegInfo - Information about each register in use in the function.
|
||||||
MachineRegisterInfo *RegInfo;
|
MachineRegisterInfo *RegInfo;
|
||||||
|
|
||||||
@ -123,6 +127,14 @@ public:
|
|||||||
///
|
///
|
||||||
const TargetMachine &getTarget() const { return Target; }
|
const TargetMachine &getTarget() const { return Target; }
|
||||||
|
|
||||||
|
/// doesHaveBuiltinSetjmp - Return whether this function uses builtin_setjmp
|
||||||
|
///
|
||||||
|
bool doesHaveBuiltinSetjmp() const { return HasBuiltinSetjmp; }
|
||||||
|
|
||||||
|
/// setHasBuiltinSetjmp - Mark whether this function uses builtin_setjmp
|
||||||
|
///
|
||||||
|
void setHasBuiltinSetjmp (bool flag) { HasBuiltinSetjmp = flag; }
|
||||||
|
|
||||||
/// getRegInfo - Return information about the registers currently in use.
|
/// getRegInfo - Return information about the registers currently in use.
|
||||||
///
|
///
|
||||||
MachineRegisterInfo &getRegInfo() { return *RegInfo; }
|
MachineRegisterInfo &getRegInfo() { return *RegInfo; }
|
||||||
|
@ -299,6 +299,11 @@ def int_eh_unwind_init: Intrinsic<[llvm_void_ty]>,
|
|||||||
|
|
||||||
def int_eh_dwarf_cfa : Intrinsic<[llvm_ptr_ty], [llvm_i32_ty]>;
|
def int_eh_dwarf_cfa : Intrinsic<[llvm_ptr_ty], [llvm_i32_ty]>;
|
||||||
|
|
||||||
|
let Properties = [IntrNoMem] in {
|
||||||
|
def int_builtinsetjmp : Intrinsic<[llvm_i32_ty], [llvm_ptr_ty]>;
|
||||||
|
def int_builtinlongjmp : Intrinsic<[llvm_void_ty], [llvm_ptr_ty, llvm_i32_ty]>;
|
||||||
|
}
|
||||||
|
|
||||||
//===---------------- Generic Variable Attribute Intrinsics----------------===//
|
//===---------------- Generic Variable Attribute Intrinsics----------------===//
|
||||||
//
|
//
|
||||||
def int_var_annotation : Intrinsic<[llvm_void_ty],
|
def int_var_annotation : Intrinsic<[llvm_void_ty],
|
||||||
|
@ -121,6 +121,7 @@ MachineFunction::MachineFunction(const Function *F,
|
|||||||
MachineRegisterInfo(*TM.getRegisterInfo());
|
MachineRegisterInfo(*TM.getRegisterInfo());
|
||||||
else
|
else
|
||||||
RegInfo = 0;
|
RegInfo = 0;
|
||||||
|
HasBuiltinSetjmp = false;
|
||||||
MFInfo = 0;
|
MFInfo = 0;
|
||||||
FrameInfo = new (Allocator.Allocate<MachineFrameInfo>())
|
FrameInfo = new (Allocator.Allocate<MachineFrameInfo>())
|
||||||
MachineFrameInfo(*TM.getFrameInfo());
|
MachineFrameInfo(*TM.getFrameInfo());
|
||||||
|
@ -180,7 +180,7 @@ void PEI::calculateCalleeSavedRegisters(MachineFunction &Fn) {
|
|||||||
std::vector<CalleeSavedInfo> CSI;
|
std::vector<CalleeSavedInfo> CSI;
|
||||||
for (unsigned i = 0; CSRegs[i]; ++i) {
|
for (unsigned i = 0; CSRegs[i]; ++i) {
|
||||||
unsigned Reg = CSRegs[i];
|
unsigned Reg = CSRegs[i];
|
||||||
if (Fn.getRegInfo().isPhysRegUsed(Reg)) {
|
if (Fn.getRegInfo().isPhysRegUsed(Reg) || Fn.doesHaveBuiltinSetjmp()) {
|
||||||
// If the reg is modified, save it!
|
// If the reg is modified, save it!
|
||||||
CSI.push_back(CalleeSavedInfo(Reg, CSRegClasses[i]));
|
CSI.push_back(CalleeSavedInfo(Reg, CSRegClasses[i]));
|
||||||
} else {
|
} else {
|
||||||
|
@ -3849,6 +3849,12 @@ SelectionDAGLowering::visitIntrinsicCall(CallInst &I, unsigned Intrinsic) {
|
|||||||
case Intrinsic::longjmp:
|
case Intrinsic::longjmp:
|
||||||
return "_longjmp"+!TLI.usesUnderscoreLongJmp();
|
return "_longjmp"+!TLI.usesUnderscoreLongJmp();
|
||||||
break;
|
break;
|
||||||
|
case Intrinsic::builtinsetjmp:
|
||||||
|
// Mark this function has using builtin_setjmp so context gets preserved
|
||||||
|
DAG.getMachineFunction().setHasBuiltinSetjmp(true);
|
||||||
|
// Turn it into a target intrinsic node for the codegen
|
||||||
|
visitTargetIntrinsic(I, Intrinsic);
|
||||||
|
return 0;
|
||||||
case Intrinsic::memcpy: {
|
case Intrinsic::memcpy: {
|
||||||
SDValue Op1 = getValue(I.getOperand(1));
|
SDValue Op1 = getValue(I.getOperand(1));
|
||||||
SDValue Op2 = getValue(I.getOperand(2));
|
SDValue Op2 = getValue(I.getOperand(2));
|
||||||
|
@ -1035,14 +1035,19 @@ SDValue ARMTargetLowering::LowerGLOBAL_OFFSET_TABLE(SDValue Op,
|
|||||||
return DAG.getNode(ARMISD::PIC_ADD, dl, PtrVT, Result, PICLabel);
|
return DAG.getNode(ARMISD::PIC_ADD, dl, PtrVT, Result, PICLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) {
|
SDValue
|
||||||
|
ARMTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) {
|
||||||
MVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy();
|
MVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy();
|
||||||
unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
|
unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
|
||||||
|
DebugLoc dl = Op.getDebugLoc();
|
||||||
switch (IntNo) {
|
switch (IntNo) {
|
||||||
default: return SDValue(); // Don't custom lower most intrinsics.
|
default: return SDValue(); // Don't custom lower most intrinsics.
|
||||||
case Intrinsic::arm_thread_pointer:
|
case Intrinsic::arm_thread_pointer:
|
||||||
return DAG.getNode(ARMISD::THREAD_POINTER, DebugLoc::getUnknownLoc(),
|
return DAG.getNode(ARMISD::THREAD_POINTER, dl, PtrVT);
|
||||||
PtrVT);
|
case Intrinsic::builtinsetjmp:
|
||||||
|
SDValue Res = DAG.getNode(ARMISD::BUILTIN_SETJMP, dl, MVT::i32,
|
||||||
|
Op.getOperand(1));
|
||||||
|
return Res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1431,6 +1436,20 @@ static SDValue LowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) {
|
|||||||
return DAG.getNode(ARMISD::CNEG, dl, VT, AbsVal, AbsVal, ARMCC, CCR, Cmp);
|
return DAG.getNode(ARMISD::CNEG, dl, VT, AbsVal, AbsVal, ARMCC, CCR, Cmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDValue ARMTargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) {
|
||||||
|
MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
|
||||||
|
MFI->setFrameAddressIsTaken(true);
|
||||||
|
MVT VT = Op.getValueType();
|
||||||
|
DebugLoc dl = Op.getDebugLoc(); // FIXME probably not meaningful
|
||||||
|
unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
|
||||||
|
unsigned FrameReg = (Subtarget->isThumb() || Subtarget->useThumbBacktraces())
|
||||||
|
? ARM::R7 : ARM::R11;
|
||||||
|
SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, FrameReg, VT);
|
||||||
|
while (Depth--)
|
||||||
|
FrameAddr = DAG.getLoad(VT, dl, DAG.getEntryNode(), FrameAddr, NULL, 0);
|
||||||
|
return FrameAddr;
|
||||||
|
}
|
||||||
|
|
||||||
SDValue
|
SDValue
|
||||||
ARMTargetLowering::EmitTargetCodeForMemcpy(SelectionDAG &DAG, DebugLoc dl,
|
ARMTargetLowering::EmitTargetCodeForMemcpy(SelectionDAG &DAG, DebugLoc dl,
|
||||||
SDValue Chain,
|
SDValue Chain,
|
||||||
@ -1612,7 +1631,7 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) {
|
|||||||
case ISD::FCOPYSIGN: return LowerFCOPYSIGN(Op, DAG);
|
case ISD::FCOPYSIGN: return LowerFCOPYSIGN(Op, DAG);
|
||||||
case ISD::FORMAL_ARGUMENTS: return LowerFORMAL_ARGUMENTS(Op, DAG);
|
case ISD::FORMAL_ARGUMENTS: return LowerFORMAL_ARGUMENTS(Op, DAG);
|
||||||
case ISD::RETURNADDR: break;
|
case ISD::RETURNADDR: break;
|
||||||
case ISD::FRAMEADDR: break;
|
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
|
||||||
case ISD::GLOBAL_OFFSET_TABLE: return LowerGLOBAL_OFFSET_TABLE(Op, DAG);
|
case ISD::GLOBAL_OFFSET_TABLE: return LowerGLOBAL_OFFSET_TABLE(Op, DAG);
|
||||||
case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG);
|
case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG);
|
||||||
case ISD::BIT_CONVERT: return ExpandBIT_CONVERT(Op.getNode(), DAG);
|
case ISD::BIT_CONVERT: return ExpandBIT_CONVERT(Op.getNode(), DAG);
|
||||||
|
@ -64,6 +64,9 @@ namespace llvm {
|
|||||||
FMRRD, // double to two gprs.
|
FMRRD, // double to two gprs.
|
||||||
FMDRR, // Two gprs to double.
|
FMDRR, // Two gprs to double.
|
||||||
|
|
||||||
|
BUILTIN_SETJMP, // exception handling setjmp
|
||||||
|
BUILTIN_LONGJMP, // exception handling longjmp
|
||||||
|
|
||||||
THREAD_POINTER
|
THREAD_POINTER
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -154,6 +157,7 @@ namespace llvm {
|
|||||||
SDNode *LowerCallResult(SDValue Chain, SDValue InFlag, CallSDNode *TheCall,
|
SDNode *LowerCallResult(SDValue Chain, SDValue InFlag, CallSDNode *TheCall,
|
||||||
unsigned CallingConv, SelectionDAG &DAG);
|
unsigned CallingConv, SelectionDAG &DAG);
|
||||||
SDValue LowerCALL(SDValue Op, SelectionDAG &DAG);
|
SDValue LowerCALL(SDValue Op, SelectionDAG &DAG);
|
||||||
|
SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG);
|
||||||
SDValue LowerRET(SDValue Op, SelectionDAG &DAG);
|
SDValue LowerRET(SDValue Op, SelectionDAG &DAG);
|
||||||
SDValue LowerGlobalAddressDarwin(SDValue Op, SelectionDAG &DAG);
|
SDValue LowerGlobalAddressDarwin(SDValue Op, SelectionDAG &DAG);
|
||||||
SDValue LowerGlobalAddressELF(SDValue Op, SelectionDAG &DAG);
|
SDValue LowerGlobalAddressELF(SDValue Op, SelectionDAG &DAG);
|
||||||
@ -165,6 +169,7 @@ namespace llvm {
|
|||||||
SDValue LowerGLOBAL_OFFSET_TABLE(SDValue Op, SelectionDAG &DAG);
|
SDValue LowerGLOBAL_OFFSET_TABLE(SDValue Op, SelectionDAG &DAG);
|
||||||
SDValue LowerFORMAL_ARGUMENTS(SDValue Op, SelectionDAG &DAG);
|
SDValue LowerFORMAL_ARGUMENTS(SDValue Op, SelectionDAG &DAG);
|
||||||
SDValue LowerBR_JT(SDValue Op, SelectionDAG &DAG);
|
SDValue LowerBR_JT(SDValue Op, SelectionDAG &DAG);
|
||||||
|
SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG);
|
||||||
|
|
||||||
SDValue EmitTargetCodeForMemcpy(SelectionDAG &DAG, DebugLoc dl,
|
SDValue EmitTargetCodeForMemcpy(SelectionDAG &DAG, DebugLoc dl,
|
||||||
SDValue Chain,
|
SDValue Chain,
|
||||||
|
@ -991,6 +991,7 @@ unsigned ARMInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const {
|
|||||||
// If this machine instr is a constant pool entry, its size is recorded as
|
// If this machine instr is a constant pool entry, its size is recorded as
|
||||||
// operand #2.
|
// operand #2.
|
||||||
return MI->getOperand(2).getImm();
|
return MI->getOperand(2).getImm();
|
||||||
|
case ARM::Int_builtin_setjmp: return 12;
|
||||||
case ARM::BR_JTr:
|
case ARM::BR_JTr:
|
||||||
case ARM::BR_JTm:
|
case ARM::BR_JTm:
|
||||||
case ARM::BR_JTadd:
|
case ARM::BR_JTadd:
|
||||||
|
@ -40,6 +40,7 @@ def SDT_ARMPICAdd : SDTypeProfile<1, 2, [SDTCisSameAs<0, 1>,
|
|||||||
SDTCisPtrTy<1>, SDTCisVT<2, i32>]>;
|
SDTCisPtrTy<1>, SDTCisVT<2, i32>]>;
|
||||||
|
|
||||||
def SDT_ARMThreadPointer : SDTypeProfile<1, 0, [SDTCisPtrTy<0>]>;
|
def SDT_ARMThreadPointer : SDTypeProfile<1, 0, [SDTCisPtrTy<0>]>;
|
||||||
|
def SDT_ARMBuiltinSetjmp : SDTypeProfile<1, 1, [SDTCisInt<0>, SDTCisPtrTy<1>]>;
|
||||||
|
|
||||||
// Node definitions.
|
// Node definitions.
|
||||||
def ARMWrapper : SDNode<"ARMISD::Wrapper", SDTIntUnaryOp>;
|
def ARMWrapper : SDNode<"ARMISD::Wrapper", SDTIntUnaryOp>;
|
||||||
@ -84,6 +85,7 @@ def ARMsra_flag : SDNode<"ARMISD::SRA_FLAG", SDTIntUnaryOp, [SDNPOutFlag]>;
|
|||||||
def ARMrrx : SDNode<"ARMISD::RRX" , SDTIntUnaryOp, [SDNPInFlag ]>;
|
def ARMrrx : SDNode<"ARMISD::RRX" , SDTIntUnaryOp, [SDNPInFlag ]>;
|
||||||
|
|
||||||
def ARMthread_pointer: SDNode<"ARMISD::THREAD_POINTER", SDT_ARMThreadPointer>;
|
def ARMthread_pointer: SDNode<"ARMISD::THREAD_POINTER", SDT_ARMThreadPointer>;
|
||||||
|
def ARMbuiltin_setjmp: SDNode<"ARMISD::BUILTIN_SETJMP", SDT_ARMBuiltinSetjmp>;
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// ARM Instruction Predicate Definitions.
|
// ARM Instruction Predicate Definitions.
|
||||||
@ -1265,6 +1267,27 @@ let isCall = 1,
|
|||||||
[(set R0, ARMthread_pointer)]>;
|
[(set R0, ARMthread_pointer)]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// SJLJ Exception handling intrinsics
|
||||||
|
// setjmp() is a three instruction sequence to store the return address
|
||||||
|
// and save #0 in R0 for the non-longjmp case.
|
||||||
|
// Since by its nature we may be coming from some other function to get
|
||||||
|
// here, and we're using the stack frame for the containing function to
|
||||||
|
// save/restore registers, we can't keep anything live in regs across
|
||||||
|
// the setjmp(), else it will almost certainly have been tromped upon
|
||||||
|
// when we get here from a longjmp(). We force everthing out of registers
|
||||||
|
// except for our own input by listing the relevant registers in Defs.
|
||||||
|
let Defs =
|
||||||
|
[ R0, R1, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR,
|
||||||
|
D0, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15 ] in {
|
||||||
|
def Int_builtin_setjmp : XI<(outs), (ins GPR:$src),
|
||||||
|
AddrModeNone, SizeSpecial, IndexModeNone, Pseudo,
|
||||||
|
"add r0, pc, #4\n\t"
|
||||||
|
"str r0, [$src, #+4]\n\t"
|
||||||
|
"mov r0, #0 @ setjmp", "",
|
||||||
|
[(set R0, (ARMbuiltin_setjmp GPR:$src))]>;
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Non-Instruction Patterns
|
// Non-Instruction Patterns
|
||||||
//
|
//
|
||||||
|
Loading…
Reference in New Issue
Block a user