[llvm] f69e090 - [MC] [Win64EH] Try to generate packed unwind info where possible

Martin Storsjö via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 22 23:03:09 PDT 2020


Author: Martin Storsjö
Date: 2020-09-23T09:03:01+03:00
New Revision: f69e090d7dca6bf2786145a9e97b0a7ddb3b514a

URL: https://github.com/llvm/llvm-project/commit/f69e090d7dca6bf2786145a9e97b0a7ddb3b514a
DIFF: https://github.com/llvm/llvm-project/commit/f69e090d7dca6bf2786145a9e97b0a7ddb3b514a.diff

LOG: [MC] [Win64EH] Try to generate packed unwind info where possible

In practice, this only gives modest savings (for a 6.5 MB DLL with
230 KB xdata, the xdata sections shrinks by around 2.5 KB); to
gain more, the frame lowering would need to be tweaked to more often
generate frame layouts that match the canonical layouts that can
be written in packed form.

Differential Revision: https://reviews.llvm.org/D87371

Added: 
    llvm/test/MC/AArch64/seh-packed-unwind.s

Modified: 
    llvm/include/llvm/MC/MCWinEH.h
    llvm/lib/MC/MCWin64EH.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/MC/MCWinEH.h b/llvm/include/llvm/MC/MCWinEH.h
index f05f5f1641cd..a46f56d708ce 100644
--- a/llvm/include/llvm/MC/MCWinEH.h
+++ b/llvm/include/llvm/MC/MCWinEH.h
@@ -45,6 +45,7 @@ struct FrameInfo {
   const MCSymbol *PrologEnd = nullptr;
   const MCSymbol *Symbol = nullptr;
   MCSection *TextSection = nullptr;
+  uint32_t PackedInfo = 0;
 
   bool HandlesUnwind = false;
   bool HandlesExceptions = false;

diff  --git a/llvm/lib/MC/MCWin64EH.cpp b/llvm/lib/MC/MCWin64EH.cpp
index 8e8dba760853..ffc2ed9a3fb6 100644
--- a/llvm/lib/MC/MCWin64EH.cpp
+++ b/llvm/lib/MC/MCWin64EH.cpp
@@ -648,9 +648,233 @@ static int checkPackedEpilog(MCStreamer &streamer, WinEH::FrameInfo *info,
   return Offset;
 }
 
+static bool tryPackedUnwind(WinEH::FrameInfo *info, uint32_t FuncLength,
+                            int PackedEpilogOffset) {
+  if (PackedEpilogOffset == 0) {
+    // Fully symmetric prolog and epilog, should be ok for packed format.
+    // For CR=3, the corresponding synthesized epilog actually lacks the
+    // SetFP opcode, but unwinding should work just fine despite that
+    // (if at the SetFP opcode, the unwinder considers it as part of the
+    // function body and just unwinds the full prolog instead).
+  } else if (PackedEpilogOffset == 1) {
+    // One single case of 
diff erences between prolog and epilog is allowed:
+    // The epilog can lack a single SetFP that is the last opcode in the
+    // prolog, for the CR=3 case.
+    if (info->Instructions.back().Operation != Win64EH::UOP_SetFP)
+      return false;
+  } else {
+    // Too much 
diff erence between prolog and epilog.
+    return false;
+  }
+  unsigned RegI = 0, RegF = 0;
+  int Predecrement = 0;
+  enum {
+    Start,
+    Start2,
+    IntRegs,
+    FloatRegs,
+    InputArgs,
+    StackAdjust,
+    FrameRecord,
+    End
+  } Location = Start;
+  bool StandaloneLR = false, FPLRPair = false;
+  int StackOffset = 0;
+  int Nops = 0;
+  // Iterate over the prolog and check that all opcodes exactly match
+  // the canonical order and form. A more lax check could verify that
+  // all saved registers are in the expected locations, but not enforce
+  // the order - that would work fine when unwinding from within
+  // functions, but not be exactly right if unwinding happens within
+  // prologs/epilogs.
+  for (const WinEH::Instruction &Inst : info->Instructions) {
+    switch (Inst.Operation) {
+    case Win64EH::UOP_End:
+      if (Location != Start)
+        return false;
+      Location = Start2;
+      break;
+    case Win64EH::UOP_SaveR19R20X:
+      if (Location != Start2)
+        return false;
+      Predecrement = Inst.Offset;
+      RegI = 2;
+      Location = IntRegs;
+      break;
+    case Win64EH::UOP_SaveRegX:
+      if (Location != Start2)
+        return false;
+      Predecrement = Inst.Offset;
+      if (Inst.Register == 19)
+        RegI += 1;
+      else if (Inst.Register == 30)
+        StandaloneLR = true;
+      else
+        return false;
+      // Odd register; can't be any further int registers.
+      Location = FloatRegs;
+      break;
+    case Win64EH::UOP_SaveRegPX:
+      // Can't have this in a canonical prologue. Either this has been
+      // canonicalized into SaveR19R20X or SaveFPLRX, or it's an unsupported
+      // register pair.
+      // It can't be canonicalized into SaveR19R20X if the offset is
+      // larger than 248 bytes, but even with the maximum case with
+      // RegI=10/RegF=8/CR=1/H=1, we end up with SavSZ = 216, which should
+      // fit into SaveR19R20X.
+      // The unwinding opcodes can't describe the otherwise seemingly valid
+      // case for RegI=1 CR=1, that would start with a
+      // "stp x19, lr, [sp, #-...]!" as that fits neither SaveRegPX nor
+      // SaveLRPair.
+      return false;
+    case Win64EH::UOP_SaveRegP:
+      if (Location != IntRegs || Inst.Offset != 8 * RegI ||
+          Inst.Register != 19 + RegI)
+        return false;
+      RegI += 2;
+      break;
+    case Win64EH::UOP_SaveReg:
+      if (Location != IntRegs || Inst.Offset != 8 * RegI)
+        return false;
+      if (Inst.Register == 19 + RegI)
+        RegI += 1;
+      else if (Inst.Register == 30)
+        StandaloneLR = true;
+      else
+        return false;
+      // Odd register; can't be any further int registers.
+      Location = FloatRegs;
+      break;
+    case Win64EH::UOP_SaveLRPair:
+      if (Location != IntRegs || Inst.Offset != 8 * RegI ||
+          Inst.Register != 19 + RegI)
+        return false;
+      RegI += 1;
+      StandaloneLR = true;
+      Location = FloatRegs;
+      break;
+    case Win64EH::UOP_SaveFRegX:
+      // Packed unwind can't handle prologs that only save one single
+      // float register.
+      return false;
+    case Win64EH::UOP_SaveFReg:
+      if (Location != FloatRegs || RegF == 0 || Inst.Register != 8 + RegF ||
+          Inst.Offset != 8 * (RegI + (StandaloneLR ? 1 : 0) + RegF))
+        return false;
+      RegF += 1;
+      Location = InputArgs;
+      break;
+    case Win64EH::UOP_SaveFRegPX:
+      if (Location != Start2 || Inst.Register != 8)
+        return false;
+      Predecrement = Inst.Offset;
+      RegF = 2;
+      Location = FloatRegs;
+      break;
+    case Win64EH::UOP_SaveFRegP:
+      if ((Location != IntRegs && Location != FloatRegs) ||
+          Inst.Register != 8 + RegF ||
+          Inst.Offset != 8 * (RegI + (StandaloneLR ? 1 : 0) + RegF))
+        return false;
+      RegF += 2;
+      Location = FloatRegs;
+      break;
+    case Win64EH::UOP_SaveNext:
+      if (Location == IntRegs)
+        RegI += 2;
+      else if (Location == FloatRegs)
+        RegF += 2;
+      else
+        return false;
+      break;
+    case Win64EH::UOP_Nop:
+      if (Location != IntRegs && Location != FloatRegs && Location != InputArgs)
+        return false;
+      Location = InputArgs;
+      Nops++;
+      break;
+    case Win64EH::UOP_AllocSmall:
+    case Win64EH::UOP_AllocMedium:
+      if (Location != Start2 && Location != IntRegs && Location != FloatRegs &&
+          Location != InputArgs && Location != StackAdjust)
+        return false;
+      // Can have either a single decrement, or a pair of decrements with
+      // 4080 and another decrement.
+      if (StackOffset == 0)
+        StackOffset = Inst.Offset;
+      else if (StackOffset != 4080)
+        return false;
+      else
+        StackOffset += Inst.Offset;
+      Location = StackAdjust;
+      break;
+    case Win64EH::UOP_SaveFPLRX:
+      // Not allowing FPLRX after StackAdjust; if a StackAdjust is used, it
+      // should be followed by a FPLR instead.
+      if (Location != Start2 && Location != IntRegs && Location != FloatRegs &&
+          Location != InputArgs)
+        return false;
+      StackOffset = Inst.Offset;
+      Location = FrameRecord;
+      FPLRPair = true;
+      break;
+    case Win64EH::UOP_SaveFPLR:
+      // This can only follow after a StackAdjust
+      if (Location != StackAdjust || Inst.Offset != 0)
+        return false;
+      Location = FrameRecord;
+      FPLRPair = true;
+      break;
+    case Win64EH::UOP_SetFP:
+      if (Location != FrameRecord)
+        return false;
+      Location = End;
+      break;
+    }
+  }
+  if (RegI > 10 || RegF > 8)
+    return false;
+  if (StandaloneLR && FPLRPair)
+    return false;
+  if (FPLRPair && Location != End)
+    return false;
+  if (Nops != 0 && Nops != 4)
+    return false;
+  int H = Nops == 4;
+  int IntSZ = 8 * RegI;
+  if (StandaloneLR)
+    IntSZ += 8;
+  int FpSZ = 8 * RegF; // RegF not yet decremented
+  int SavSZ = (IntSZ + FpSZ + 8 * 8 * H + 0xF) & ~0xF;
+  if (Predecrement != SavSZ)
+    return false;
+  if (FPLRPair && StackOffset < 16)
+    return false;
+  if (StackOffset % 16)
+    return false;
+  uint32_t FrameSize = (StackOffset + SavSZ) / 16;
+  if (FrameSize > 0x1FF)
+    return false;
+  assert(RegF != 1 && "One single float reg not allowed");
+  if (RegF > 0)
+    RegF--; // Convert from actual number of registers, to value stored
+  assert(FuncLength <= 0x7FF && "FuncLength should have been checked earlier");
+  int Flag = 0x01; // Function segments not supported yet
+  int CR = FPLRPair ? 3 : StandaloneLR ? 1 : 0;
+  info->PackedInfo |= Flag << 0;
+  info->PackedInfo |= (FuncLength & 0x7FF) << 2;
+  info->PackedInfo |= (RegF & 0x7) << 13;
+  info->PackedInfo |= (RegI & 0xF) << 16;
+  info->PackedInfo |= (H & 0x1) << 20;
+  info->PackedInfo |= (CR & 0x3) << 21;
+  info->PackedInfo |= (FrameSize & 0x1FF) << 23;
+  return true;
+}
+
 // Populate the .xdata section.  The format of .xdata on ARM64 is documented at
 // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
-static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) {
+static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info,
+                                bool TryPacked = true) {
   // If this UNWIND_INFO already has a symbol, it's already been emitted.
   if (info->Symbol)
     return;
@@ -728,6 +952,20 @@ static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) {
 
   int PackedEpilogOffset = checkPackedEpilog(streamer, info, PrologCodeBytes);
 
+  if (PackedEpilogOffset >= 0 && !info->HandlesExceptions &&
+      FuncLength <= 0x7ff && TryPacked) {
+    // Matching prolog/epilog and no exception handlers; check if the
+    // prolog matches the patterns that can be described by the packed
+    // format.
+
+    // info->Symbol was already set even if we didn't actually write any
+    // unwind info there. Keep using that as indicator that this unwind
+    // info has been generated already.
+
+    if (tryPackedUnwind(info, FuncLength, PackedEpilogOffset))
+      return;
+  }
+
   // Process epilogs.
   MapVector<MCSymbol *, uint32_t> EpilogInfo;
   // Epilogs processed so far.
@@ -835,10 +1073,13 @@ static void ARM64EmitRuntimeFunction(MCStreamer &streamer,
 
   streamer.emitValueToAlignment(4);
   EmitSymbolRefWithOfs(streamer, info->Function, info->Begin);
-  streamer.emitValue(MCSymbolRefExpr::create(info->Symbol,
-                                             MCSymbolRefExpr::VK_COFF_IMGREL32,
-                                             context),
-                     4);
+  if (info->PackedInfo)
+    streamer.emitInt32(info->PackedInfo);
+  else
+    streamer.emitValue(
+        MCSymbolRefExpr::create(info->Symbol, MCSymbolRefExpr::VK_COFF_IMGREL32,
+                                context),
+        4);
 }
 
 void llvm::Win64EH::ARM64UnwindEmitter::Emit(MCStreamer &Streamer) const {
@@ -882,5 +1123,5 @@ void llvm::Win64EH::ARM64UnwindEmitter::EmitUnwindInfo(
   // here and from Emit().
   MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
   Streamer.SwitchSection(XData);
-  ARM64EmitUnwindInfo(Streamer, info);
+  ARM64EmitUnwindInfo(Streamer, info, false);
 }

diff  --git a/llvm/test/MC/AArch64/seh-packed-unwind.s b/llvm/test/MC/AArch64/seh-packed-unwind.s
new file mode 100644
index 000000000000..a053d7a29b5c
--- /dev/null
+++ b/llvm/test/MC/AArch64/seh-packed-unwind.s
@@ -0,0 +1,947 @@
+// Check that we generate the packed unwind info format whe possible.
+
+// For tests that don't generate packed unwind info, we still check that
+// the epilog was packed (so that the testcase otherwise had all other
+// preconditions for possibly making packed unwind info).
+
+// REQUIRES: aarch64-registered-target
+// RUN: llvm-mc -filetype=obj -triple aarch64-windows %s -o %t.o
+// RUN: llvm-readobj --unwind %t.o | FileCheck %s
+
+// CHECK:      UnwindInformation [
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func1
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 88
+// CHECK-NEXT:     RegF: 7
+// CHECK-NEXT:     RegI: 10
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 0
+// CHECK-NEXT:     FrameSize: 160
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       sub sp, sp, #16
+// CHECK-NEXT:       stp d14, d15, [sp, #128]
+// CHECK-NEXT:       stp d12, d13, [sp, #112]
+// CHECK-NEXT:       stp d10, d11, [sp, #96]
+// CHECK-NEXT:       stp d8, d9, [sp, #80]
+// CHECK-NEXT:       stp x27, x28, [sp, #64]
+// CHECK-NEXT:       stp x25, x26, [sp, #48]
+// CHECK-NEXT:       stp x23, x24, [sp, #32]
+// CHECK-NEXT:       stp x21, x22, [sp, #16]
+// CHECK-NEXT:       stp x19, x20, [sp, #-144]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func2
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 48
+// CHECK-NEXT:     RegF: 2
+// CHECK-NEXT:     RegI: 3
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 0
+// CHECK-NEXT:     FrameSize: 48
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       str d10, [sp, #40]
+// CHECK-NEXT:       stp d8, d9, [sp, #24]
+// CHECK-NEXT:       str x21, [sp, #16]
+// CHECK-NEXT:       stp x19, x20, [sp, #-48]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func3
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 32
+// CHECK-NEXT:     RegF: 3
+// CHECK-NEXT:     RegI: 1
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 0
+// CHECK-NEXT:     FrameSize: 48
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       stp d10, d11, [sp, #24]
+// CHECK-NEXT:       stp d8, d9, [sp, #8]
+// CHECK-NEXT:       str x19, [sp, #-48]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func4
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 24
+// CHECK-NEXT:     RegF: 1
+// CHECK-NEXT:     RegI: 0
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 0
+// CHECK-NEXT:     FrameSize: 48
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       sub sp, sp, #32
+// CHECK-NEXT:       stp d8, d9, [sp, #-16]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func5
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 56
+// CHECK-NEXT:     RegF: 0
+// CHECK-NEXT:     RegI: 1
+// CHECK-NEXT:     HomedParameters: Yes
+// CHECK-NEXT:     CR: 0
+// CHECK-NEXT:     FrameSize: 112
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       sub sp, sp, #32
+// CHECK-NEXT:       stp x6, x7, [sp, #56]
+// CHECK-NEXT:       stp x4, x5, [sp, #40]
+// CHECK-NEXT:       stp x2, x3, [sp, #24]
+// CHECK-NEXT:       stp x0, x1, [sp, #8]
+// CHECK-NEXT:       str x19, [sp, #-80]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func6
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 24
+// CHECK-NEXT:     RegF: 0
+// CHECK-NEXT:     RegI: 0
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 1
+// CHECK-NEXT:     FrameSize: 32
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       sub sp, sp, #16
+// CHECK-NEXT:       str lr, [sp, #-16]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func7
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 24
+// CHECK-NEXT:     RegF: 0
+// CHECK-NEXT:     RegI: 2
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 1
+// CHECK-NEXT:     FrameSize: 32
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       str lr, [sp, #16]
+// CHECK-NEXT:       stp x19, x20, [sp, #-32]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func8
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 32
+// CHECK-NEXT:     RegF: 0
+// CHECK-NEXT:     RegI: 3
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 1
+// CHECK-NEXT:     FrameSize: 48
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       sub sp, sp, #16
+// CHECK-NEXT:       stp x21, lr, [sp, #16]
+// CHECK-NEXT:       stp x19, x20, [sp, #-32]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func9
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 32
+// CHECK-NEXT:     RegF: 0
+// CHECK-NEXT:     RegI: 2
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 3
+// CHECK-NEXT:     FrameSize: 48
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       mov x29, sp
+// CHECK-NEXT:       stp x29, lr, [sp, #-32]!
+// CHECK-NEXT:       stp x19, x20, [sp, #-16]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func10
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 24
+// CHECK-NEXT:     RegF: 0
+// CHECK-NEXT:     RegI: 0
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 3
+// CHECK-NEXT:     FrameSize: 32
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       mov x29, sp
+// CHECK-NEXT:       stp x29, lr, [sp, #-32]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func11
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 40
+// CHECK-NEXT:     RegF: 0
+// CHECK-NEXT:     RegI: 2
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 3
+// CHECK-NEXT:     FrameSize: 544
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       mov x29, sp
+// CHECK-NEXT:       stp x29, lr, [sp, #0]
+// CHECK-NEXT:       sub sp, sp, #528
+// CHECK-NEXT:       stp x19, x20, [sp, #-16]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func12
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 48
+// CHECK-NEXT:     RegF: 0
+// CHECK-NEXT:     RegI: 2
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 3
+// CHECK-NEXT:     FrameSize: 4112
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       mov x29, sp
+// CHECK-NEXT:       stp x29, lr, [sp, #0]
+// CHECK-NEXT:       sub sp, sp, #16
+// CHECK-NEXT:       sub sp, sp, #4080
+// CHECK-NEXT:       stp x19, x20, [sp, #-16]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func13
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 32
+// CHECK-NEXT:     RegF: 0
+// CHECK-NEXT:     RegI: 2
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 0
+// CHECK-NEXT:     FrameSize: 4112
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       sub sp, sp, #16
+// CHECK-NEXT:       sub sp, sp, #4080
+// CHECK-NEXT:       stp x19, x20, [sp, #-16]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func14
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 32
+// CHECK-NEXT:     RegF: 2
+// CHECK-NEXT:     RegI: 0
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 1
+// CHECK-NEXT:     FrameSize: 32
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       str d10, [sp, #24]
+// CHECK-NEXT:       stp d8, d9, [sp, #8]
+// CHECK-NEXT:       str lr, [sp, #-32]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func15
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 20
+// CHECK-NEXT:     RegF: 0
+// CHECK-NEXT:     RegI: 0
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 3
+// CHECK-NEXT:     FrameSize: 32
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       mov x29, sp
+// CHECK-NEXT:       stp x29, lr, [sp, #-32]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK:        RuntimeFunction {
+// CHECK-NEXT:     Function: nonpacked1
+// CHECK-NEXT:     ExceptionRecord:
+// CHECK-NEXT:     ExceptionData {
+// CHECK:            EpiloguePacked: Yes
+// CHECK:        RuntimeFunction {
+// CHECK-NEXT:     Function: nonpacked2
+// CHECK-NEXT:     ExceptionRecord:
+// CHECK-NEXT:     ExceptionData {
+// CHECK:            EpiloguePacked: Yes
+// CHECK:        RuntimeFunction {
+// CHECK-NEXT:     Function: nonpacked3
+// CHECK-NEXT:     ExceptionRecord:
+// CHECK-NEXT:     ExceptionData {
+// CHECK:            EpiloguePacked: Yes
+// CHECK:        RuntimeFunction {
+// CHECK-NEXT:     Function: nonpacked4
+// CHECK-NEXT:     ExceptionRecord:
+// CHECK-NEXT:     ExceptionData {
+// CHECK:            EpiloguePacked: Yes
+// CHECK:        RuntimeFunction {
+// CHECK-NEXT:     Function: nonpacked5
+// CHECK-NEXT:     ExceptionRecord:
+// CHECK-NEXT:     ExceptionData {
+// CHECK:            EpiloguePacked: Yes
+// CHECK:        RuntimeFunction {
+// CHECK-NEXT:     Function: nonpacked6
+// CHECK-NEXT:     ExceptionRecord:
+// CHECK-NEXT:     ExceptionData {
+// CHECK:            EpiloguePacked: Yes
+// CHECK:        RuntimeFunction {
+// CHECK-NEXT:     Function: nonpacked7
+// CHECK-NEXT:     ExceptionRecord:
+// CHECK-NEXT:     ExceptionData {
+// CHECK:            EpiloguePacked: Yes
+// CHECK:        RuntimeFunction {
+// CHECK-NEXT:     Function: nonpacked8
+// CHECK-NEXT:     ExceptionRecord:
+// CHECK-NEXT:     ExceptionData {
+// CHECK:            EpiloguePacked: Yes
+// CHECK:        RuntimeFunction {
+// CHECK-NEXT:     Function: nonpacked9
+// CHECK-NEXT:     ExceptionRecord:
+// CHECK-NEXT:     ExceptionData {
+// CHECK:            EpiloguePacked: Yes
+// CHECK:        RuntimeFunction {
+// CHECK-NEXT:     Function: nonpacked10
+// CHECK-NEXT:     ExceptionRecord:
+// CHECK-NEXT:     ExceptionData {
+// CHECK:            EpiloguePacked: Yes
+// CHECK:        RuntimeFunction {
+// CHECK-NEXT:     Function: nonpacked11
+// CHECK-NEXT:     ExceptionRecord:
+// CHECK-NEXT:     ExceptionData {
+// CHECK:            EpiloguePacked: Yes
+// CHECK:        RuntimeFunction {
+// CHECK-NEXT:     Function: nonpacked12
+// CHECK-NEXT:     ExceptionRecord:
+// CHECK-NEXT:     ExceptionData {
+// CHECK:            EpiloguePacked: Yes
+// CHECK:        RuntimeFunction {
+// CHECK-NEXT:     Function: nonpacked13
+// CHECK-NEXT:     ExceptionRecord:
+// CHECK-NEXT:     ExceptionData {
+// CHECK:            EpiloguePacked: Yes
+
+    .text
+func1:
+    .seh_proc func1
+    stp x19, x20, [sp, #-144]!
+    .seh_save_r19r20_x 144
+    stp x21, x22, [sp, #16]
+    .seh_save_regp x21, 16
+    stp x23, x24, [sp, #32]
+    .seh_save_next
+    stp x25, x26, [sp, #48]
+    .seh_save_next
+    stp x27, x28, [sp, #64]
+    .seh_save_next
+    stp d8,  d9,  [sp, #80]
+    .seh_save_fregp d8, 80
+    stp d10, d11, [sp, #96]
+    .seh_save_fregp d10, 96
+    stp d12, d13, [sp, #112]
+    .seh_save_fregp d12, 112
+    stp d14, d15, [sp, #128]
+    .seh_save_fregp d14, 128
+    sub sp,  sp,  #16
+    .seh_stackalloc 16
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    add sp,  sp,  #16
+    .seh_stackalloc 16
+    ldp d14, d15, [sp, #128]
+    .seh_save_fregp d14, 128
+    ldp d12, d13, [sp, #112]
+    .seh_save_fregp d12, 112
+    ldp d10, d11, [sp, #96]
+    .seh_save_fregp d10, 96
+    ldp d8,  d9,  [sp, #80]
+    .seh_save_fregp d8, 80
+    ldp x27, x28, [sp, #64]
+    .seh_save_next
+    ldp x25, x26, [sp, #48]
+    .seh_save_next
+    ldp x23, x24, [sp, #32]
+    .seh_save_next
+    ldp x21, x22, [sp, #16]
+    .seh_save_next
+    ldp x19, x20, [sp], #144
+    .seh_save_regp_x x19, 144
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+func2:
+    .seh_proc func2
+    stp x19, x20, [sp, #-48]!
+    .seh_save_r19r20_x 48
+    str x21,      [sp, #16]
+    .seh_save_reg x21, 16
+    stp d8,  d9,  [sp, #24]
+    .seh_save_fregp d8, 24
+    str d10,      [sp, #40]
+    .seh_save_freg d10, 40
+    sub sp,  sp,  #0
+    .seh_stackalloc 0
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    add sp,  sp,  #0
+    .seh_stackalloc 0
+    ldr d10,      [sp, #40]
+    .seh_save_freg d10, 40
+    ldp d8,  d9,  [sp, #24]
+    .seh_save_fregp d8, 24
+    ldr x21,      [sp, #16]
+    .seh_save_reg x21, 16
+    ldp x19, x20, [sp], #48
+    .seh_save_r19r20_x 48
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+func3:
+    .seh_proc func3
+    str x19,      [sp, #-48]!
+    .seh_save_reg_x x19, 48
+    stp d8,  d9,  [sp, #8]
+    .seh_save_fregp d8, 8
+    stp d10, d11, [sp, #24]
+    .seh_save_fregp d10, 24
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    ldp d10, d11, [sp, #24]
+    .seh_save_fregp d10, 24
+    ldp d8,  d9,  [sp, #8]
+    .seh_save_fregp d8, 8
+    ldr x19,      [sp], #48
+    .seh_save_reg_x x19, 48
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+func4:
+    .seh_proc func4
+    stp d8,  d9,  [sp, #-16]!
+    .seh_save_fregp_x d8, 16
+    sub sp,  sp,  #32
+    .seh_stackalloc 32
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    add sp,  sp,  #32
+    .seh_stackalloc 32
+    ldp d8,  d9,  [sp], #16
+    .seh_save_fregp_x d8, 16
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+func5:
+    .seh_proc func5
+    str x19, [sp, #-80]!
+    .seh_save_reg_x x19, 80
+    stp x0,  x1,  [sp, #8]
+    .seh_nop
+    stp x2,  x3,  [sp, #24]
+    .seh_nop
+    stp x4,  x5,  [sp, #40]
+    .seh_nop
+    stp x6,  x7,  [sp, #56]
+    .seh_nop
+    sub sp,  sp,  #32
+    .seh_stackalloc 32
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    add sp,  sp,  #32
+    .seh_stackalloc 32
+    nop
+    .seh_nop
+    nop
+    .seh_nop
+    nop
+    .seh_nop
+    nop
+    .seh_nop
+    ldr x19, [sp], #80
+    .seh_save_reg_x x19, 80
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+func6:
+    .seh_proc func6
+    str lr,       [sp, #-16]!
+    .seh_save_reg_x lr, 16
+    sub sp,  sp,  #16
+    .seh_stackalloc 16
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    add sp,  sp,  #16
+    .seh_stackalloc 16
+    ldr lr,       [sp], #16
+    .seh_save_reg_x lr, 16
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+func7:
+    .seh_proc func7
+    stp x19, x20, [sp, #-32]!
+    .seh_save_r19r20_x 32
+    str lr,       [sp, #16]
+    .seh_save_reg lr, 16
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    ldr lr,       [sp, #16]
+    .seh_save_reg lr, 16
+    ldp x19, x20, [sp], #32
+    .seh_save_r19r20_x 32
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+func8:
+    .seh_proc func8
+    stp x19, x20, [sp, #-32]!
+    .seh_save_r19r20_x 32
+    stp x21, lr,  [sp, #16]
+    .seh_save_lrpair x21, 16
+    sub sp,  sp,  #16
+    .seh_stackalloc 16
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    add sp,  sp,  #16
+    .seh_stackalloc 16
+    ldp x21, lr,  [sp, #16]
+    .seh_save_lrpair x21, 16
+    ldp x19, x20, [sp], #32
+    .seh_save_r19r20_x 32
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+func9:
+    .seh_proc func9
+    stp x19, x20, [sp, #-16]!
+    .seh_save_r19r20_x 16
+    stp x29, lr,  [sp, #-32]!
+    .seh_save_fplr_x 32
+    mov x29, sp
+    .seh_set_fp
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    mov sp,  x29
+    .seh_set_fp
+    ldp x29, lr,  [sp], #32
+    .seh_save_fplr_x 32
+    ldp x19, x20, [sp], #16
+    .seh_save_r19r20_x 16
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+func10:
+    .seh_proc func10
+    stp x29, lr,  [sp, #-32]!
+    .seh_save_fplr_x 32
+    mov x29, sp
+    .seh_set_fp
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    mov sp,  x29
+    .seh_set_fp
+    ldp x29, lr,  [sp], #32
+    .seh_save_fplr_x 32
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+func11:
+    .seh_proc func11
+    stp x19, x20, [sp, #-16]!
+    .seh_save_r19r20_x 16
+    sub sp,  sp,  #528
+    .seh_stackalloc 528
+    stp x29, lr,  [sp, #0]
+    .seh_save_fplr 0
+    mov x29, sp
+    .seh_set_fp
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    mov sp,  x29
+    .seh_set_fp
+    ldp x29, lr,  [sp, #0]
+    .seh_save_fplr 0
+    add sp,  sp,  #528
+    .seh_stackalloc 528
+    ldp x19, x20, [sp], #16
+    .seh_save_r19r20_x 16
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+func12:
+    .seh_proc func12
+    stp x19, x20, [sp, #-16]!
+    .seh_save_r19r20_x 16
+    sub sp,  sp,  #4080
+    .seh_stackalloc 4080
+    sub sp,  sp,  #16
+    .seh_stackalloc 16
+    stp x29, lr,  [sp, #0]
+    .seh_save_fplr 0
+    mov x29, sp
+    .seh_set_fp
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    mov sp,  x29
+    .seh_set_fp
+    ldp x29, lr,  [sp, #0]
+    .seh_save_fplr 0
+    add sp,  sp,  #16
+    .seh_stackalloc 16
+    add sp,  sp,  #4080
+    .seh_stackalloc 4080
+    ldp x19, x20, [sp], #16
+    .seh_save_r19r20_x 16
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+func13:
+    .seh_proc func13
+    stp x19, x20, [sp, #-16]!
+    .seh_save_r19r20_x 16
+    sub sp,  sp,  #4080
+    .seh_stackalloc 4080
+    sub sp,  sp,  #16
+    .seh_stackalloc 16
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    add sp,  sp,  #16
+    .seh_stackalloc 16
+    add sp,  sp,  #4080
+    .seh_stackalloc 4080
+    ldp x19, x20, [sp], #16
+    .seh_save_r19r20_x 16
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+func14:
+    .seh_proc func14
+    str lr,       [sp, #-32]!
+    .seh_save_reg_x lr, 32
+    stp d8,  d9,  [sp, #8]
+    .seh_save_fregp d8, 8
+    str d10,      [sp, #24]
+    .seh_save_freg d10, 24
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    ldr d10,      [sp, #24]
+    .seh_save_freg d10, 24
+    ldp d8,  d9,  [sp, #8]
+    .seh_save_fregp d8, 8
+    ldr lr,       [sp], #32
+    .seh_save_reg_x lr, 32
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+func15:
+    .seh_proc func15
+    stp x29, lr,  [sp, #-32]!
+    .seh_save_fplr_x 32
+    mov x29, sp
+    .seh_set_fp
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    // Epilogue missing the .seh_set_fp, but still generating packed info.
+    ldp x29, lr,  [sp], #32
+    .seh_save_fplr_x 32
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+nonpacked1:
+    .seh_proc nonpacked1
+    // Can't be packed; can't save integer registers after float registers.
+    stp d8,  d9,  [sp, #-32]!
+    .seh_save_fregp_x d8, 32
+    stp x19, x20, [sp, #16]!
+    .seh_save_regp x19, 16
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    ldp x19, x20, [sp, #16]
+    .seh_save_regp x19, 16
+    ldp d8,  d9,  [sp], #32
+    .seh_save_fregp_x d8, 32
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+nonpacked2:
+    .seh_proc nonpacked2
+    // Can't be packed; x21/x22 aren't saved in the expected spot
+    stp x19, x20, [sp, #-48]!
+    .seh_save_r19r20_x 48
+    stp x21, x22, [sp, #32]
+    .seh_save_regp x21, 32
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    ldp x21, x22, [sp, #32]
+    .seh_save_regp x21, 32
+    ldp x19, x20, [sp], #48
+    .seh_save_r19r20_x 48
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+nonpacked3:
+    .seh_proc nonpacked3
+    // Can't be packed; x29/x30 can't be treated as the other saved registers
+    stp x19, x20, [sp, #-96]!
+    .seh_save_r19r20_x 96
+    stp x21, x22, [sp, #16]
+    .seh_save_next
+    stp x23, x24, [sp, #32]
+    .seh_save_next
+    stp x25, x26, [sp, #48]
+    .seh_save_next
+    stp x27, x28, [sp, #64]
+    .seh_save_next
+    stp x29, x30, [sp, #80]
+    .seh_save_next
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    ldp x29, x30, [sp, #80]
+    .seh_save_next
+    ldp x27, x28, [sp, #64]
+    .seh_save_next
+    ldp x25, x26, [sp, #48]
+    .seh_save_next
+    ldp x23, x24, [sp, #32]
+    .seh_save_next
+    ldp x21, x22, [sp, #16]
+    .seh_save_next
+    ldp x19, x20, [sp], #96
+    .seh_save_r19r20_x 96
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+nonpacked4:
+    .seh_proc nonpacked4
+    // Can't be packed; more predecrement for x19/x20 than used for
+    // corresponding RegI/RegF/LR saves
+    stp x19, x20, [sp, #-32]!
+    .seh_save_r19r20_x 32
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    ldp x19, x20, [sp], #32
+    .seh_save_r19r20_x 32
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+nonpacked5:
+    .seh_proc nonpacked5
+    // Can't be packed; can't save LR twice
+    stp x19, x20, [sp, #-32]!
+    .seh_save_r19r20_x 32
+    str lr, [sp, #16]
+    .seh_save_reg lr, 16
+    str lr, [sp, #24]
+    .seh_save_reg lr, 24
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    ldr lr, [sp, #24]
+    .seh_save_reg lr, 24
+    ldr lr, [sp, #16]
+    .seh_save_reg lr, 16
+    ldp x19, x20, [sp], #32
+    .seh_save_r19r20_x 32
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+nonpacked6:
+    .seh_proc nonpacked6
+    // Can't be packed; can't save LR both standalone (CR 1) and as FPLR (CR 3)
+    stp x19, x20, [sp, #-32]!
+    .seh_save_r19r20_x 32
+    str lr, [sp, #16]
+    .seh_save_reg lr, 16
+    stp x29, lr,  [sp, #-16]!
+    .seh_save_fplr_x 16
+    mov x29, sp
+    .seh_set_fp
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    mov sp,  x29
+    .seh_set_fp
+    ldp x29, lr,  [sp], #32
+    .seh_save_fplr_x 16
+    ldr lr, [sp, #16]
+    .seh_save_reg lr, 16
+    ldp x19, x20, [sp], #32
+    .seh_save_r19r20_x 32
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+nonpacked7:
+    .seh_proc nonpacked7
+    // Can't be packed; too many saved FP regs
+    stp d8,  d9,  [sp, #-80]!
+    .seh_save_fregp_x d8, 80
+    stp d10, d11, [sp, #16]
+    .seh_save_fregp d10, 16
+    stp d12, d13, [sp, #32]
+    .seh_save_fregp d12, 32
+    stp d14, d15, [sp, #48]
+    .seh_save_fregp d14, 48
+    stp d16, d17, [sp, #64]
+    .seh_save_next
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    ldp d16, d17, [sp, #64]
+    .seh_save_next
+    ldp d14, d15, [sp, #48]
+    .seh_save_fregp d14, 48
+    ldp d12, d13, [sp, #32]
+    .seh_save_fregp d12, 32
+    ldp d10, d11, [sp, #16]
+    .seh_save_fregp d10, 16
+    ldp d8,  d9,  [sp], #80
+    .seh_save_fregp_x d8, 80
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+nonpacked8:
+    .seh_proc nonpacked8
+    // Can't be packed; Can't handle only a single FP reg
+    str d8,  [sp, #-16]!
+    .seh_save_freg_x d8, 16
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    ldr d8,  [sp], #16
+    .seh_save_freg_x d8, 16
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+nonpacked9:
+    .seh_proc nonpacked9
+    // Can't be packed; can't have a separate stack adjustment with save_fplr_x
+    sub sp, sp, #32
+    .seh_stackalloc 32
+    stp x29, lr,  [sp, #-16]!
+    .seh_save_fplr_x 16
+    mov x29, sp
+    .seh_set_fp
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    mov sp,  x29
+    .seh_set_fp
+    ldp x29, lr,  [sp], #32
+    .seh_save_fplr_x 16
+    add sp, sp, #32
+    .seh_stackalloc 32
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+nonpacked10:
+    .seh_proc nonpacked10
+    // Can't be packed; wrong predecrement
+    stp x19, x20, [sp, #-16]!
+    .seh_save_r19r20_x 16
+    stp x21, x22, [sp, #16]
+    .seh_save_next
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    ldp x21, x22, [sp, #16]
+    .seh_save_next
+    ldp x19, x20, [sp], #16
+    .seh_save_r19r20_x 16
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+nonpacked11:
+    .seh_proc nonpacked11
+    // Can't be packed; too big stack allocation
+    sub sp, sp, #4080
+    .seh_stackalloc 4080
+    sub sp, sp, #8192
+    .seh_stackalloc 8192
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    add sp, sp, #8192
+    .seh_stackalloc 8192
+    add sp, sp, #4080
+    .seh_stackalloc 4080
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+nonpacked12:
+    .seh_proc nonpacked12
+    // Can't be packed; missing .seh_set_fp
+    stp x29, lr,  [sp, #-32]!
+    .seh_save_fplr_x 32
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    ldp x29, lr,  [sp], #32
+    .seh_save_fplr_x 32
+    .seh_endepilogue
+    ret
+    .seh_endproc
+
+nonpacked13:
+    .seh_proc nonpacked13
+    // Can't be packed; not doing a packed info if .seh_handlerdata is used
+    sub sp, sp, #16
+    .seh_stackalloc 16
+    .seh_endprologue
+    nop
+    .seh_startepilogue
+    add sp, sp, #16
+    .seh_stackalloc 16
+    .seh_endepilogue
+    ret
+    .seh_endfunclet
+    .seh_handlerdata
+    .long 0
+    .text
+    .seh_endproc


        


More information about the llvm-commits mailing list