[llvm] cabefea - [MC] [Win64EH] Try writing an ARM64 "packed epilog" even if the epilog doesn't share opcodes with the prolog

Martin Storsjö via llvm-commits llvm-commits at lists.llvm.org
Mon May 16 14:41:48 PDT 2022


Author: Martin Storsjö
Date: 2022-05-17T00:41:39+03:00
New Revision: cabefea2ec99f80ecdf9d3d5fe955831532ff4b0

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

LOG: [MC] [Win64EH] Try writing an ARM64 "packed epilog" even if the epilog doesn't share opcodes with the prolog

The "packed epilog" form only implies that the epilog is located
exactly at the end of the function (so the location of the epilog
is implicit from the epilog opcodes), but it doesn't have to share
opcodes with the prolog - as long as the total number of opcode
bytes and the offset to the epilog fit within the bitfields.

This avoids writing a 4 byte epilog scope in many cases. (I haven't
measured how much this shrinks actual xdata sections in practice
though.)

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

Added: 
    

Modified: 
    llvm/lib/MC/MCWin64EH.cpp
    llvm/test/CodeGen/AArch64/wineh1.mir
    llvm/test/CodeGen/AArch64/wineh2.mir
    llvm/test/CodeGen/AArch64/wineh5.mir
    llvm/test/MC/AArch64/seh-optimize.s
    llvm/test/MC/AArch64/seh-packed-epilog.s

Removed: 
    


################################################################################
diff  --git a/llvm/lib/MC/MCWin64EH.cpp b/llvm/lib/MC/MCWin64EH.cpp
index 0aa066eba5948..73d3a53605c89 100644
--- a/llvm/lib/MC/MCWin64EH.cpp
+++ b/llvm/lib/MC/MCWin64EH.cpp
@@ -614,24 +614,33 @@ static int checkPackedEpilog(MCStreamer &streamer, WinEH::FrameInfo *info,
   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>(
@@ -642,8 +651,10 @@ static int checkPackedEpilog(MCStreamer &streamer, WinEH::FrameInfo *info,
   // 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;
 }
@@ -952,8 +963,9 @@ static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info,
 
   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.
@@ -1025,17 +1037,19 @@ static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info,
     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).

diff  --git a/llvm/test/CodeGen/AArch64/wineh1.mir b/llvm/test/CodeGen/AArch64/wineh1.mir
index 5aec175181d3f..1ba551a0f04b1 100644
--- a/llvm/test/CodeGen/AArch64/wineh1.mir
+++ b/llvm/test/CodeGen/AArch64/wineh1.mir
@@ -16,8 +16,8 @@
 # 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]
@@ -28,21 +28,15 @@
 # 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:    }
 

diff  --git a/llvm/test/CodeGen/AArch64/wineh2.mir b/llvm/test/CodeGen/AArch64/wineh2.mir
index 81c73460dd9ef..9dae28236f455 100644
--- a/llvm/test/CodeGen/AArch64/wineh2.mir
+++ b/llvm/test/CodeGen/AArch64/wineh2.mir
@@ -6,8 +6,8 @@
 # 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]
@@ -21,23 +21,17 @@
 # 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:    }
 ...

diff  --git a/llvm/test/CodeGen/AArch64/wineh5.mir b/llvm/test/CodeGen/AArch64/wineh5.mir
index 46b127a05a935..06456329778ee 100644
--- a/llvm/test/CodeGen/AArch64/wineh5.mir
+++ b/llvm/test/CodeGen/AArch64/wineh5.mir
@@ -7,8 +7,8 @@
 # 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
@@ -18,18 +18,12 @@
 # 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:   }
 

diff  --git a/llvm/test/MC/AArch64/seh-optimize.s b/llvm/test/MC/AArch64/seh-optimize.s
index 0bf33af9cc75f..56008888fec97 100644
--- a/llvm/test/MC/AArch64/seh-optimize.s
+++ b/llvm/test/MC/AArch64/seh-optimize.s
@@ -27,17 +27,13 @@
 // 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:   }

diff  --git a/llvm/test/MC/AArch64/seh-packed-epilog.s b/llvm/test/MC/AArch64/seh-packed-epilog.s
index f9978ea7a1139..85ac8e80dbdda 100644
--- a/llvm/test/MC/AArch64/seh-packed-epilog.s
+++ b/llvm/test/MC/AArch64/seh-packed-epilog.s
@@ -43,6 +43,13 @@
 // 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:
@@ -50,17 +57,42 @@
 // 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
@@ -146,8 +178,8 @@ nonpacked1:
     .seh_endproc
 
 
-    .seh_proc nonpacked2
-nonpacked2:
+    .seh_proc nonshared2
+nonshared2:
     sub sp, sp, #48
     .seh_stackalloc 48
     sub sp, sp, #32
@@ -156,7 +188,7 @@ nonpacked2:
 
     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
@@ -165,8 +197,8 @@ nonpacked2:
     ret
     .seh_endproc
 
-    .seh_proc nonpacked3
-nonpacked3:
+    .seh_proc nonshared3
+nonshared3:
     sub sp, sp, #48
     .seh_stackalloc 48
     sub sp, sp, #32
@@ -175,7 +207,7 @@ nonpacked3:
 
     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


        


More information about the llvm-commits mailing list