[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