const std::vector<WinEH::Instruction> &Epilog =
info->EpilogMap.begin()->second;
+ // Check that the epilog actually is at the very end of the function,
+ // otherwise it can't be packed.
+ uint32_t DistanceFromEnd = (uint32_t)GetAbsDifference(
+ streamer, info->FuncletOrFuncEnd, info->EpilogMap.begin()->first);
+ if (DistanceFromEnd / 4 != Epilog.size())
+ return -1;
+
+ int RetVal = -1;
+ // Even if we don't end up sharing opcodes with the prolog, we can still
+ // write the offset as a packed offset, if the single epilog is located at
+ // the end of the function and the offset (pointing after the prolog) fits
+ // as a packed offset.
+ if (PrologCodeBytes <= 31 &&
+ PrologCodeBytes + ARM64CountOfUnwindCodes(Epilog) <= 124)
+ RetVal = PrologCodeBytes;
+
// Can pack if the epilog is a subset of the prolog but not vice versa
if (Epilog.size() > info->Instructions.size())
- return -1;
+ return RetVal;
// Check that the epilog actually is a perfect match for the end (backwrds)
// of the prolog.
for (int I = Epilog.size() - 1; I >= 0; I--) {
if (info->Instructions[I] != Epilog[Epilog.size() - 1 - I])
- return -1;
+ return RetVal;
}
- // Check that the epilog actually is at the very end of the function,
- // otherwise it can't be packed.
- uint32_t DistanceFromEnd = (uint32_t)GetAbsDifference(
- streamer, info->FuncletOrFuncEnd, info->EpilogMap.begin()->first);
- if (DistanceFromEnd / 4 != Epilog.size())
- return -1;
-
int Offset = Epilog.size() == info->Instructions.size()
? 0
: ARM64CountOfUnwindCodes(ArrayRef<WinEH::Instruction>(
// unclear whether the epilog count in the extension word can be taken
// as packed epilog offset.
if (Offset > 31 || PrologCodeBytes > 124)
- return -1;
+ return RetVal;
+ // As we choose to express the epilog as part of the prolog, remove the
+ // epilog from the map, so we don't try to emit its opcodes.
info->EpilogMap.clear();
return Offset;
}
int PackedEpilogOffset = checkPackedEpilog(streamer, info, PrologCodeBytes);
- if (PackedEpilogOffset >= 0 && !info->HandlesExceptions &&
- FuncLength <= 0x7ff && TryPacked) {
+ if (PackedEpilogOffset >= 0 &&
+ uint32_t(PackedEpilogOffset) < PrologCodeBytes &&
+ !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.
streamer.emitInt32(row2);
}
- // Epilog Start Index, Epilog Start Offset
- for (auto &I : EpilogInfo) {
- MCSymbol *EpilogStart = I.first;
- uint32_t EpilogIndex = I.second;
- uint32_t EpilogOffset =
- (uint32_t)GetAbsDifference(streamer, EpilogStart, info->Begin);
- if (EpilogOffset)
- EpilogOffset /= 4;
- uint32_t row3 = EpilogOffset;
- row3 |= (EpilogIndex & 0x3FF) << 22;
- streamer.emitInt32(row3);
+ if (PackedEpilogOffset < 0) {
+ // Epilog Start Index, Epilog Start Offset
+ for (auto &I : EpilogInfo) {
+ MCSymbol *EpilogStart = I.first;
+ uint32_t EpilogIndex = I.second;
+ uint32_t EpilogOffset =
+ (uint32_t)GetAbsDifference(streamer, EpilogStart, info->Begin);
+ if (EpilogOffset)
+ EpilogOffset /= 4;
+ uint32_t row3 = EpilogOffset;
+ row3 |= (EpilogIndex & 0x3FF) << 22;
+ streamer.emitInt32(row3);
+ }
}
// Emit prolog unwind instructions (in reverse order).
# CHECK-NEXT: FunctionLength: 96
# CHECK-NEXT: Version: 0
# CHECK-NEXT: ExceptionData: No
-# CHECK-NEXT: EpiloguePacked: No
-# CHECK-NEXT: EpilogueScopes: 1
+# CHECK-NEXT: EpiloguePacked: Yes
+# CHECK-NEXT: EpilogueOffset: 13
# CHECK-NEXT: ByteCodeLength: 28
# CHECK-NEXT: Prologue [
# CHECK-NEXT: 0xc808 ; stp x19, x20, [sp, #64]
# CHECK-NEXT: 0xce09 ; stp x27, x28, [sp, #-80]!
# CHECK-NEXT: 0xe4 ; end
# CHECK-NEXT: ]
-# CHECK-NEXT: EpilogueScopes [
-# CHECK-NEXT: EpilogueScope {
-# CHECK-NEXT: StartOffset: 16
-# CHECK-NEXT: EpilogueStartIndex: 13
-# CHECK-NEXT: Opcodes [
-# CHECK-NEXT: 0xc808 ; ldp x19, x20, [sp, #64]
-# CHECK-NEXT: 0xd086 ; ldr x21, [sp, #48]
-# CHECK-NEXT: 0xe3 ; nop
-# CHECK-NEXT: 0xd0c7 ; ldr x22, [sp, #56]
-# CHECK-NEXT: 0xc904 ; ldp x23, x24, [sp, #32]
-# CHECK-NEXT: 0xc982 ; ldp x25, x26, [sp, #16]
-# CHECK-NEXT: 0xce09 ; ldp x27, x28, [sp], #80
-# CHECK-NEXT: 0xe4 ; end
-# CHECK-NEXT: ]
-# CHECK-NEXT: }
+# CHECK-NEXT: Epilogue [
+# CHECK-NEXT: 0xc808 ; ldp x19, x20, [sp, #64]
+# CHECK-NEXT: 0xd086 ; ldr x21, [sp, #48]
+# CHECK-NEXT: 0xe3 ; nop
+# CHECK-NEXT: 0xd0c7 ; ldr x22, [sp, #56]
+# CHECK-NEXT: 0xc904 ; ldp x23, x24, [sp, #32]
+# CHECK-NEXT: 0xc982 ; ldp x25, x26, [sp, #16]
+# CHECK-NEXT: 0xce09 ; ldp x27, x28, [sp], #80
+# CHECK-NEXT: 0xe4 ; end
# CHECK-NEXT: ]
# CHECK-NEXT: }
# CHECK-NEXT: FunctionLength: 144
# CHECK-NEXT: Version: 0
# CHECK-NEXT: ExceptionData: No
-# CHECK-NEXT: EpiloguePacked: No
-# CHECK-NEXT: EpilogueScopes: 1
+# CHECK-NEXT: EpiloguePacked: Yes
+# CHECK-NEXT: EpilogueOffset: 19
# CHECK-NEXT: ByteCodeLength: 40
# CHECK-NEXT: Prologue [
# CHECK-NEXT: 0xc80e ; stp x19, x20, [sp, #112]
# CHECK-NEXT: 0xde8f ; str d12, [sp, #-128]!
# CHECK-NEXT: 0xe4 ; end
# CHECK-NEXT: ]
-# CHECK-NEXT: EpilogueScopes [
-# CHECK-NEXT: EpilogueScope {
-# CHECK-NEXT: StartOffset: 26
-# CHECK-NEXT: EpilogueStartIndex: 19
-# CHECK-NEXT: Opcodes [
-# CHECK-NEXT: 0xc80e ; ldp x19, x20, [sp, #112]
-# CHECK-NEXT: 0xc88c ; ldp x21, x22, [sp, #96]
-# CHECK-NEXT: 0xc90a ; ldp x23, x24, [sp, #80]
-# CHECK-NEXT: 0xc988 ; ldp x25, x26, [sp, #64]
-# CHECK-NEXT: 0xca06 ; ldp x27, x28, [sp, #48]
-# CHECK-NEXT: 0xdc04 ; ldr d8, [sp, #32]
-# CHECK-NEXT: 0xdc45 ; ldr d9, [sp, #40]
-# CHECK-NEXT: 0xd882 ; ldp d10, d11, [sp, #16]
-# CHECK-NEXT: 0xde8f ; ldr d12, [sp], #128
-# CHECK-NEXT: 0xe4 ; end
-# CHECK-NEXT: ]
-# CHECK-NEXT: }
+# CHECK-NEXT: Epilogue [
+# CHECK-NEXT: 0xc80e ; ldp x19, x20, [sp, #112]
+# CHECK-NEXT: 0xc88c ; ldp x21, x22, [sp, #96]
+# CHECK-NEXT: 0xc90a ; ldp x23, x24, [sp, #80]
+# CHECK-NEXT: 0xc988 ; ldp x25, x26, [sp, #64]
+# CHECK-NEXT: 0xca06 ; ldp x27, x28, [sp, #48]
+# CHECK-NEXT: 0xdc04 ; ldr d8, [sp, #32]
+# CHECK-NEXT: 0xdc45 ; ldr d9, [sp, #40]
+# CHECK-NEXT: 0xd882 ; ldp d10, d11, [sp, #16]
+# CHECK-NEXT: 0xde8f ; ldr d12, [sp], #128
+# CHECK-NEXT: 0xe4 ; end
# CHECK-NEXT: ]
# CHECK-NEXT: }
...
# CHECK-NEXT: FunctionLength: 156
# CHECK-NEXT: Version: 0
# CHECK-NEXT: ExceptionData: No
-# CHECK-NEXT: EpiloguePacked: No
-# CHECK-NEXT: EpilogueScopes: 1
+# CHECK-NEXT: EpiloguePacked: Yes
+# CHECK-NEXT: EpilogueOffset: 10
# CHECK-NEXT: ByteCodeLength: 20
# CHECK-NEXT: Prologue [
# CHECK-NEXT: 0xe002dac9 ; sub sp, #2993296
# CHECK-NEXT: 0xd53f ; str x28, [sp, #-256]!
# CHECK-NEXT: 0xe4 ; end
# CHECK-NEXT: ]
-# CHECK-NEXT: EpilogueScopes [
-# CHECK-NEXT: EpilogueScope {
-# CHECK-NEXT: StartOffset: 34
-# CHECK-NEXT: EpilogueStartIndex: 10
-# CHECK-NEXT: Opcodes [
-# CHECK-NEXT: 0xe002da00 ; add sp, #2990080
-# CHECK-NEXT: 0xc0c9 ; add sp, #3216
-# CHECK-NEXT: 0x42 ; ldp x29, x30, [sp, #16]
-# CHECK-NEXT: 0xd53f ; ldr x28, [sp], #256
-# CHECK-NEXT: 0xe4 ; end
-# CHECK-NEXT: ]
-# CHECK-NEXT: }
+# CHECK-NEXT: Epilogue [
+# CHECK-NEXT: 0xe002da00 ; add sp, #2990080
+# CHECK-NEXT: 0xc0c9 ; add sp, #3216
+# CHECK-NEXT: 0x42 ; ldp x29, x30, [sp, #16]
+# CHECK-NEXT: 0xd53f ; ldr x28, [sp], #256
+# CHECK-NEXT: 0xe4 ; end
# CHECK-NEXT: ]
# CHECK-NEXT: }
// CHECK-NEXT: 0xe201 ; add fp, sp, #8
// CHECK-NEXT: 0xe4 ; end
// CHECK-NEXT: ]
-// CHECK-NEXT: EpilogueScopes [
-// CHECK-NEXT: EpilogueScope {
-// CHECK: Opcodes [
-// CHECK-NEXT: 0xc904 ; ldp x23, x24, [sp, #32]
-// CHECK-NEXT: 0xe6 ; restore next
-// CHECK-NEXT: 0xcc83 ; ldp x21, x22, [sp], #32
-// CHECK-NEXT: 0x24 ; ldp x19, x20, [sp], #32
-// CHECK-NEXT: 0xcc1f ; ldp x19, x20, [sp], #256
-// CHECK-NEXT: 0xe4 ; end
-// CHECK-NEXT: ]
-// CHECK-NEXT: }
+// CHECK-NEXT: Epilogue [
+// CHECK-NEXT: 0xc904 ; ldp x23, x24, [sp, #32]
+// CHECK-NEXT: 0xe6 ; restore next
+// CHECK-NEXT: 0xcc83 ; ldp x21, x22, [sp], #32
+// CHECK-NEXT: 0x24 ; ldp x19, x20, [sp], #32
+// CHECK-NEXT: 0xcc1f ; ldp x19, x20, [sp], #256
+// CHECK-NEXT: 0xe4 ; end
// CHECK-NEXT: ]
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: ExceptionData {
// CHECK: ExceptionData:
// CHECK-NEXT: EpiloguePacked: Yes
+// CHECK-NEXT: EpilogueOffset: 0
+// CHECK-NEXT: ByteCodeLength: 4
+// CHECK-NEXT: Prologue [
+// CHECK-NEXT: 0x83 ; stp x29, x30, [sp, #-32]!
+// CHECK-NEXT: 0x03 ; sub sp, #48
+// CHECK-NEXT: 0xe4 ; end
+// CHECK-NEXT: ]
// CHECK: RuntimeFunction {
// CHECK-NEXT: Function: nonpacked1
// CHECK-NEXT: ExceptionRecord:
// CHECK: ExceptionData:
// CHECK-NEXT: EpiloguePacked: No
// CHECK: RuntimeFunction {
-// CHECK-NEXT: Function: nonpacked2
+// CHECK-NEXT: Function: nonshared2
// CHECK-NEXT: ExceptionRecord:
// CHECK-NEXT: ExceptionData {
// CHECK: ExceptionData:
-// CHECK-NEXT: EpiloguePacked: No
+// CHECK-NEXT: EpiloguePacked: Yes
+// CHECK-NEXT: EpilogueOffset: 3
+// CHECK-NEXT: ByteCodeLength: 8
+// CHECK-NEXT: Prologue [
+// CHECK-NEXT: 0x02 ; sub sp, #32
+// CHECK-NEXT: 0x03 ; sub sp, #48
+// CHECK-NEXT: 0xe4 ; end
+// CHECK-NEXT: ]
+// CHECK-NEXT: Epilogue [
+// CHECK-NEXT: 0x01 ; add sp, #16
+// CHECK-NEXT: 0x03 ; add sp, #48
+// CHECK-NEXT: 0xe4 ; end
+// CHECK-NEXT: ]
// CHECK: RuntimeFunction {
-// CHECK-NEXT: Function: nonpacked3
+// CHECK-NEXT: Function: nonshared3
// CHECK-NEXT: ExceptionRecord:
// CHECK-NEXT: ExceptionData {
// CHECK: ExceptionData:
-// CHECK-NEXT: EpiloguePacked: No
+// CHECK-NEXT: EpiloguePacked: Yes
+// CHECK-NEXT: EpilogueOffset: 3
+// CHECK-NEXT: ByteCodeLength: 8
+// CHECK-NEXT: Prologue [
+// CHECK-NEXT: 0x02 ; sub sp, #32
+// CHECK-NEXT: 0x03 ; sub sp, #48
+// CHECK-NEXT: 0xe4 ; end
+// CHECK-NEXT: ]
+// CHECK-NEXT: Epilogue [
+// CHECK-NEXT: 0xe1 ; mov sp, fp
+// CHECK-NEXT: 0x02 ; add sp, #32
+// CHECK-NEXT: 0x03 ; add sp, #48
+// CHECK-NEXT: 0xe4 ; end
+// CHECK-NEXT: ]
.text
.globl func
.seh_endproc
- .seh_proc nonpacked2
-nonpacked2:
+ .seh_proc nonshared2
+nonshared2:
sub sp, sp, #48
.seh_stackalloc 48
sub sp, sp, #32
nop
.seh_startepilogue
- // Not packed; the epilogue mismatches at the second opcode.
+ // Not shared; the epilogue mismatches at the second opcode.
add sp, sp, #16
.seh_stackalloc 16
add sp, sp, #48
ret
.seh_endproc
- .seh_proc nonpacked3
-nonpacked3:
+ .seh_proc nonshared3
+nonshared3:
sub sp, sp, #48
.seh_stackalloc 48
sub sp, sp, #32
nop
.seh_startepilogue
- // Not packed; the epilogue is longer than the prologue.
+ // Not shared; the epilogue is longer than the prologue.
mov sp, x29
.seh_set_fp
add sp, sp, #32