[llvm] 64a3c63 - [MC] [Win64EH] Check for matches between epilogs and the prolog on ARM64

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


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

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

LOG: [MC] [Win64EH] Check for matches between epilogs and the prolog on ARM64

This allows sharing opcodes between prolog and epilog even when there
is more than one epilog.

I didn't make any handcrafted special MC level testcases for this (yet
at least), but it does seem to have the expected effect on two existing
CodeGen level testcases.

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

Added: 
    

Modified: 
    llvm/lib/MC/MCWin64EH.cpp
    llvm/test/CodeGen/AArch64/wineh4.mir
    llvm/test/CodeGen/AArch64/wineh8.mir

Removed: 
    


################################################################################
diff  --git a/llvm/lib/MC/MCWin64EH.cpp b/llvm/lib/MC/MCWin64EH.cpp
index 73d3a53605c8..b0e8ecd8999e 100644
--- a/llvm/lib/MC/MCWin64EH.cpp
+++ b/llvm/lib/MC/MCWin64EH.cpp
@@ -605,6 +605,27 @@ static void simplifyOpcodes(std::vector<WinEH::Instruction> &Instructions,
   }
 }
 
+// Check if an epilog exists as a subset of the end of a prolog (backwards).
+static int getOffsetInProlog(const std::vector<WinEH::Instruction> &Prolog,
+                             const std::vector<WinEH::Instruction> &Epilog) {
+  // Can't find an epilog as a subset if it is longer than the prolog.
+  if (Epilog.size() > Prolog.size())
+    return -1;
+
+  // 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 (Prolog[I] != Epilog[Epilog.size() - 1 - I])
+      return -1;
+  }
+
+  // If the epilog was a subset of the prolog, find its offset.
+  if (Epilog.size() == Prolog.size())
+    return 0;
+  return ARM64CountOfUnwindCodes(ArrayRef<WinEH::Instruction>(
+      &Prolog[Epilog.size()], Prolog.size() - Epilog.size()));
+}
+
 static int checkPackedEpilog(MCStreamer &streamer, WinEH::FrameInfo *info,
                              int PrologCodeBytes) {
   // Can only pack if there's one single epilog
@@ -630,23 +651,10 @@ static int checkPackedEpilog(MCStreamer &streamer, WinEH::FrameInfo *info,
       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())
+  int Offset = getOffsetInProlog(info->Instructions, Epilog);
+  if (Offset < 0)
     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 RetVal;
-  }
-
-  int Offset = Epilog.size() == info->Instructions.size()
-                   ? 0
-                   : ARM64CountOfUnwindCodes(ArrayRef<WinEH::Instruction>(
-                         &info->Instructions[Epilog.size()],
-                         info->Instructions.size() - Epilog.size()));
-
   // Check that the offset and prolog size fits in the first word; it's
   // unclear whether the epilog count in the extension word can be taken
   // as packed epilog offset.
@@ -990,6 +998,7 @@ static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info,
 
     MCSymbol* MatchingEpilog =
       FindMatchingEpilog(EpilogInstrs, AddedEpilogs, info);
+    int PrologOffset;
     if (MatchingEpilog) {
       assert(EpilogInfo.find(MatchingEpilog) != EpilogInfo.end() &&
              "Duplicate epilog not found");
@@ -997,6 +1006,12 @@ static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info,
       // Clear the unwind codes in the EpilogMap, so that they don't get output
       // in the logic below.
       EpilogInstrs.clear();
+    } else if ((PrologOffset =
+                    getOffsetInProlog(info->Instructions, EpilogInstrs)) >= 0) {
+      EpilogInfo[EpilogStart] = PrologOffset;
+      // Clear the unwind codes in the EpilogMap, so that they don't get output
+      // in the logic below.
+      EpilogInstrs.clear();
     } else {
       EpilogInfo[EpilogStart] = TotalCodeBytes;
       TotalCodeBytes += CodeBytes;
@@ -1027,8 +1042,6 @@ static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info,
   // Extended Code Words, Extended Epilog Count
   if (ExtensionWord) {
     // FIXME: We should be able to split unwind info into multiple sections.
-    // FIXME: We should share epilog codes across epilogs, where possible,
-    // which would make this issue show up less frequently.
     if (CodeWords > 0xFF || EpilogCount > 0xFFFF)
       report_fatal_error("SEH unwind data splitting not yet implemented");
     uint32_t row2 = 0x0;

diff  --git a/llvm/test/CodeGen/AArch64/wineh4.mir b/llvm/test/CodeGen/AArch64/wineh4.mir
index a281bb246a3a..1fb71bb9316b 100644
--- a/llvm/test/CodeGen/AArch64/wineh4.mir
+++ b/llvm/test/CodeGen/AArch64/wineh4.mir
@@ -9,7 +9,7 @@
 # CHECK-NEXT:      ExceptionData: No
 # CHECK-NEXT:      EpiloguePacked: No
 # CHECK-NEXT:      EpilogueScopes: 2
-# CHECK-NEXT:      ByteCodeLength: 32
+# CHECK-NEXT:      ByteCodeLength: 16
 # CHECK-NEXT:      Prologue [
 # CHECK-NEXT:        0xc80c              ; stp x19, x20, [sp, #96]
 # CHECK-NEXT:        0xc88a              ; stp x21, x22, [sp, #80]
@@ -23,7 +23,7 @@
 # CHECK-NEXT:      EpilogueScopes [
 # CHECK-NEXT:        EpilogueScope {
 # CHECK-NEXT:          StartOffset: 16
-# CHECK-NEXT:          EpilogueStartIndex: 15
+# CHECK-NEXT:          EpilogueStartIndex: 0
 # CHECK-NEXT:          Opcodes [
 # CHECK-NEXT:            0xc80c              ; ldp x19, x20, [sp, #96]
 # CHECK-NEXT:            0xc88a              ; ldp x21, x22, [sp, #80]
@@ -37,7 +37,7 @@
 # CHECK-NEXT:        }
 # CHECK-NEXT:        EpilogueScope {
 # CHECK-NEXT:          StartOffset: 33
-# CHECK-NEXT:          EpilogueStartIndex: 15
+# CHECK-NEXT:          EpilogueStartIndex: 0
 # CHECK-NEXT:          Opcodes [
 # CHECK-NEXT:            0xc80c              ; ldp x19, x20, [sp, #96]
 # CHECK-NEXT:            0xc88a              ; ldp x21, x22, [sp, #80]

diff  --git a/llvm/test/CodeGen/AArch64/wineh8.mir b/llvm/test/CodeGen/AArch64/wineh8.mir
index 38853e7d8d8b..12233fa8e723 100644
--- a/llvm/test/CodeGen/AArch64/wineh8.mir
+++ b/llvm/test/CodeGen/AArch64/wineh8.mir
@@ -9,7 +9,7 @@
 # CHECK-NEXT:      ExceptionData: No
 # CHECK-NEXT:      EpiloguePacked: No
 # CHECK-NEXT:      EpilogueScopes: 2
-# CHECK-NEXT:      ByteCodeLength: 44
+# CHECK-NEXT:      ByteCodeLength: 28
 # CHECK-NEXT:      Prologue [
 # CHECK-NEXT:        0xc80c              ; stp x19, x20, [sp, #96]
 # CHECK-NEXT:        0xc88a              ; stp x21, x22, [sp, #80]
@@ -36,7 +36,7 @@
 # CHECK-NEXT:        }
 # CHECK-NEXT:        EpilogueScope {
 # CHECK-NEXT:          StartOffset: 32
-# CHECK-NEXT:          EpilogueStartIndex: 28
+# CHECK-NEXT:          EpilogueStartIndex: 0
 # CHECK-NEXT:          Opcodes [
 # CHECK-NEXT:            0xc80c              ; ldp x19, x20, [sp, #96]
 # CHECK-NEXT:            0xc88a              ; ldp x21, x22, [sp, #80]


        


More information about the llvm-commits mailing list