# HG changeset patch # User Shinji KONO # Date 1691924099 -32400 # Node ID 7a500f3ef647d1b21c733f7434a06e0e42315ce3 # Parent b3a488e1e1b4a2ae1f3f802517c539d41da673ee AArch64 sjlj first try diff -r b3a488e1e1b4 -r 7a500f3ef647 llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp Sun Aug 13 12:24:34 2023 +0900 +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp Sun Aug 13 19:54:59 2023 +0900 @@ -1539,6 +1539,301 @@ case TargetOpcode::FAULTING_OP: return LowerFAULTING_OP(*MI); + case AArch64::t2Int_eh_sjlj_setjmp: + case AArch64::t2Int_eh_sjlj_setjmp_nofp: + case AArch64::tInt_eh_sjlj_setjmp: { + // Two incoming args: GPR:$src, GPR:$val + // mov $val, pc + // adds $val, #7 + // str $val, [$src, #4] + // movs r0, #0 + // b LSJLJEH + // movs r0, #1 + // LSJLJEH: + Register SrcReg = MI->getOperand(0).getReg(); + Register ValReg = MI->getOperand(1).getReg(); + MCSymbol *Label = OutContext.createTempSymbol("SJLJEH"); + OutStreamer->AddComment("eh_setjmp begin"); + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::tMOVr) + .addReg(ValReg) + .addReg(AArch64::PC) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0)); + + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::tADDi3) + .addReg(ValReg) + // 's' bit operand + .addReg(AArch64::CPSR) + .addReg(ValReg) + .addImm(7) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0)); + + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::tSTRi) + .addReg(ValReg) + .addReg(SrcReg) + // The offset immediate is #4. The operand value is scaled by 4 for the + // tSTR instruction. + .addImm(1) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0)); + + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::tMOVi8) + .addReg(AArch64::R0) + .addReg(AArch64::CPSR) + .addImm(0) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0)); + + const MCExpr *SymbolExpr = MCSymbolRefExpr::create(Label, OutContext); + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::tB) + .addExpr(SymbolExpr) + .addImm(AArch64CC::AL) + .addReg(0)); + + OutStreamer->AddComment("eh_setjmp end"); + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::tMOVi8) + .addReg(AArch64::R0) + .addReg(AArch64::CPSR) + .addImm(1) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0)); + + OutStreamer->emitLabel(Label); + return; + } + + case AArch64::Int_eh_sjlj_setjmp_nofp: + case AArch64::Int_eh_sjlj_setjmp: { + // Two incoming args: GPR:$src, GPR:$val + // add $val, pc, #8 + // str $val, [$src, #+4] + // mov r0, #0 + // add pc, pc, #0 + // mov r0, #1 + Register SrcReg = MI->getOperand(0).getReg(); + Register ValReg = MI->getOperand(1).getReg(); + + OutStreamer->AddComment("eh_setjmp begin"); + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ADDri) + .addReg(ValReg) + .addReg(AArch64::PC) + .addImm(8) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0) + // 's' bit operand (always reg0 for this). + .addReg(0)); + + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::STRi12) + .addReg(ValReg) + .addReg(SrcReg) + .addImm(4) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0)); + + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVi) + .addReg(AArch64::R0) + .addImm(0) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0) + // 's' bit operand (always reg0 for this). + .addReg(0)); + + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ADDri) + .addReg(AArch64::PC) + .addReg(AArch64::PC) + .addImm(0) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0) + // 's' bit operand (always reg0 for this). + .addReg(0)); + + OutStreamer->AddComment("eh_setjmp end"); + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVi) + .addReg(AArch64::R0) + .addImm(1) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0) + // 's' bit operand (always reg0 for this). + .addReg(0)); + return; + } + case AArch64::Int_eh_sjlj_longjmp: { + // ldr sp, [$src, #8] + // ldr $scratch, [$src, #4] + // ldr r7, [$src] + // bx $scratch + Register SrcReg = MI->getOperand(0).getReg(); + Register ScratchReg = MI->getOperand(1).getReg(); + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRi12) + .addReg(AArch64::SP) + .addReg(SrcReg) + .addImm(8) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0)); + + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRi12) + .addReg(ScratchReg) + .addReg(SrcReg) + .addImm(4) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0)); + + const MachineFunction &MF = *MI->getParent()->getParent(); + const AArch64Subtarget &STI = MF.getSubtarget(); + + if (STI.isTargetDarwin() || STI.isTargetWindows()) { + // These platforms always use the same frame register + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRi12) + .addReg(STI.getFramePointerReg()) + .addReg(SrcReg) + .addImm(0) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0)); + } else { + // If the calling code might use either R7 or R11 as + // frame pointer register, restore it into both. + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRi12) + .addReg(AArch64::R7) + .addReg(SrcReg) + .addImm(0) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0)); + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRi12) + .addReg(AArch64::R11) + .addReg(SrcReg) + .addImm(0) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0)); + } + + assert(Subtarget->hasV4TOps()); + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::BX) + .addReg(ScratchReg) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0)); + return; + } + case AArch64::tInt_eh_sjlj_longjmp: { + // ldr $scratch, [$src, #8] + // mov sp, $scratch + // ldr $scratch, [$src, #4] + // ldr r7, [$src] + // bx $scratch + Register SrcReg = MI->getOperand(0).getReg(); + Register ScratchReg = MI->getOperand(1).getReg(); + + const MachineFunction &MF = *MI->getParent()->getParent(); + const AArch64Subtarget &STI = MF.getSubtarget(); + + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::tLDRi) + .addReg(ScratchReg) + .addReg(SrcReg) + // The offset immediate is #8. The operand value is scaled by 4 for the + // tLDR instruction. + .addImm(2) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0)); + + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::tMOVr) + .addReg(AArch64::SP) + .addReg(ScratchReg) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0)); + + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::tLDRi) + .addReg(ScratchReg) + .addReg(SrcReg) + .addImm(1) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0)); + + if (STI.isTargetDarwin() || STI.isTargetWindows()) { + // These platforms always use the same frame register + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::tLDRi) + .addReg(STI.getFramePointerReg()) + .addReg(SrcReg) + .addImm(0) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0)); + } else { + // If the calling code might use either R7 or R11 as + // frame pointer register, restore it into both. + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::tLDRi) + .addReg(AArch64::R7) + .addReg(SrcReg) + .addImm(0) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0)); + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::tLDRi) + .addReg(AArch64::R11) + .addReg(SrcReg) + .addImm(0) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0)); + } + + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::tBX) + .addReg(ScratchReg) + // Predicate. + .addImm(AArch64CC::AL) + .addReg(0)); + return; + } + case AArch64::tInt_WIN_eh_sjlj_longjmp: { + // ldr.w r11, [$src, #0] + // ldr.w sp, [$src, #8] + // ldr.w pc, [$src, #4] + + Register SrcReg = MI->getOperand(0).getReg(); + + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::t2LDRi12) + .addReg(AArch64::R11) + .addReg(SrcReg) + .addImm(0) + // Predicate + .addImm(AArch64CC::AL) + .addReg(0)); + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::t2LDRi12) + .addReg(AArch64::SP) + .addReg(SrcReg) + .addImm(8) + // Predicate + .addImm(AArch64CC::AL) + .addReg(0)); + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::t2LDRi12) + .addReg(AArch64::PC) + .addReg(SrcReg) + .addImm(4) + // Predicate + .addImm(AArch64CC::AL) + .addReg(0)); + return; + } + + case TargetOpcode::PATCHABLE_FUNCTION_ENTER: LowerPATCHABLE_FUNCTION_ENTER(*MI); return; diff -r b3a488e1e1b4 -r 7a500f3ef647 llvm/lib/Target/AArch64/AArch64ISelLowering.cpp --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp Sun Aug 13 12:24:34 2023 +0900 +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp Sun Aug 13 19:54:59 2023 +0900 @@ -557,6 +557,14 @@ setOperationAction(ISD::UREM, MVT::i32, Expand); setOperationAction(ISD::UREM, MVT::i64, Expand); + // We want to custom lower some of our intrinsics. + setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); + setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom); + setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom); + setOperationAction(ISD::EH_SJLJ_SETUP_DISPATCH, MVT::Other, Custom); + if (Subtarget->useSjLjEH()) + setLibcallName(RTLIB::UNWIND_RESUME, "_Unwind_SjLj_Resume"); + // Custom lower Add/Sub/Mul with overflow. setOperationAction(ISD::SADDO, MVT::i32, Custom); setOperationAction(ISD::SADDO, MVT::i64, Custom); @@ -2120,6 +2128,9 @@ MAKE_CASE(AArch64ISD::CSINV) MAKE_CASE(AArch64ISD::CSNEG) MAKE_CASE(AArch64ISD::CSINC) + MAKE_CASE(ARMISD::EH_SJLJ_SETJMP) + MAKE_CASE(ARMISD::EH_SJLJ_LONGJMP) + MAKE_CASE(ARMISD::EH_SJLJ_SETUP_DISPATCH) MAKE_CASE(AArch64ISD::THREAD_POINTER) MAKE_CASE(AArch64ISD::TLSDESC_CALLSEQ) MAKE_CASE(AArch64ISD::ABDS_PRED) @@ -2713,6 +2724,14 @@ return EmitAddVectorToTile(AArch64::ADDHA_MPPZ_D, AArch64::ZAD0, MI, BB); case AArch64::ADDVA_MPPZ_PSEUDO_D: return EmitAddVectorToTile(AArch64::ADDVA_MPPZ_D, AArch64::ZAD0, MI, BB); + + case AArch64::Int_eh_sjlj_setjmp: + case AArch64::Int_eh_sjlj_setjmp_nofp: + return BB; + + case AArch64::Int_eh_sjlj_setup_dispatch: + EmitSjLjDispatchBlock(MI, BB); + return BB; } } @@ -5661,6 +5680,9 @@ return LowerFP_EXTEND(Op, DAG); case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG); + case ISD::EH_SJLJ_SETJMP: return LowerEH_SJLJ_SETJMP(Op, DAG); + case ISD::EH_SJLJ_LONGJMP: return LowerEH_SJLJ_LONGJMP(Op, DAG); + case ISD::EH_SJLJ_SETUP_DISPATCH: return LowerEH_SJLJ_SETUP_DISPATCH(Op, DAG); case ISD::SPONENTRY: return LowerSPONENTRY(Op, DAG); case ISD::RETURNADDR: @@ -8110,6 +8132,29 @@ llvm_unreachable("Unexpected platform trying to use TLS"); } +SDValue +AArch64TargetLowering::LowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const { + SDLoc dl(Op); + SDValue Val = DAG.getConstant(0, dl, MVT::i32); + return DAG.getNode(AArch64ISD::EH_SJLJ_SETJMP, dl, + DAG.getVTList(MVT::i32, MVT::Other), Op.getOperand(0), + Op.getOperand(1), Val); +} + +SDValue +AArch64TargetLowering::LowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG) const { + SDLoc dl(Op); + return DAG.getNode(AArch64ISD::EH_SJLJ_LONGJMP, dl, MVT::Other, Op.getOperand(0), + Op.getOperand(1), DAG.getConstant(0, dl, MVT::i32)); +} + +SDValue AArch64TargetLowering::LowerEH_SJLJ_SETUP_DISPATCH(SDValue Op, + SelectionDAG &DAG) const { + SDLoc dl(Op); + return DAG.getNode(AArch64ISD::EH_SJLJ_SETUP_DISPATCH, dl, MVT::Other, + Op.getOperand(0)); +} + // Looks through \param Val to determine the bit that can be used to // check the sign of the value. It returns the unextended value and // the sign bit position. diff -r b3a488e1e1b4 -r 7a500f3ef647 llvm/lib/Target/AArch64/AArch64ISelLowering.h --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h Sun Aug 13 12:24:34 2023 +0900 +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h Sun Aug 13 19:54:59 2023 +0900 @@ -84,6 +84,10 @@ CSNEG, // Conditional select negate. CSINC, // Conditional select increment. + EH_SJLJ_SETJMP, // SjLj exception handling setjmp. + EH_SJLJ_LONGJMP, // SjLj exception handling longjmp. + EH_SJLJ_SETUP_DISPATCH, // SjLj exception handling setup_dispatch. + // Pointer to the thread's local storage area. Materialised from TPIDR_EL0 on // ELF. THREAD_POINTER, diff -r b3a488e1e1b4 -r 7a500f3ef647 llvm/lib/Target/AArch64/AArch64InstrInfo.td --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td Sun Aug 13 12:24:34 2023 +0900 +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td Sun Aug 13 19:54:59 2023 +0900 @@ -582,6 +582,17 @@ def AArch64threadpointer : SDNode<"AArch64ISD::THREAD_POINTER", SDTPtrLeaf>; +def AArch64eh_sjlj_setjmp: SDNode<"AArch64ISD::EH_SJLJ_SETJMP", + SDT_AArch64EH_SJLJ_Setjmp, + [SDNPHasChain, SDNPSideEffect]>; +def AArch64eh_sjlj_longjmp: SDNode<"AArch64ISD::EH_SJLJ_LONGJMP", + SDT_AArch64EH_SJLJ_Longjmp, + [SDNPHasChain, SDNPSideEffect]>; +def AArch64eh_sjlj_setup_dispatch: SDNode<"AArch64ISD::EH_SJLJ_SETUP_DISPATCH", + SDT_AArch64EH_SJLJ_SetupDispatch, + [SDNPHasChain, SDNPSideEffect]>; + + def AArch64fcmp : SDNode<"AArch64ISD::FCMP", SDT_AArch64FCmp>; def AArch64strict_fcmp : SDNode<"AArch64ISD::STRICT_FCMP", SDT_AArch64FCmp, [SDNPHasChain]>;