changeset 246:7a500f3ef647

AArch64 sjlj first try
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Sun, 13 Aug 2023 19:54:59 +0900
parents b3a488e1e1b4
children 6c632a06ee27
files llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp llvm/lib/Target/AArch64/AArch64ISelLowering.cpp llvm/lib/Target/AArch64/AArch64ISelLowering.h llvm/lib/Target/AArch64/AArch64InstrInfo.td
diffstat 4 files changed, 355 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- 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<AArch64Subtarget>();
+
+    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<AArch64Subtarget>();
+
+    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;
--- 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.
--- 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,
--- 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]>;