Skip to content

[win][x64] Updated llvm-objdump and llvm-readobj to be able to dump Windows x64 Unwind v3 information.#199120

Open
dpaoliello wants to merge 1 commit into
llvm:mainfrom
dpaoliello:dumpunwindv3
Open

[win][x64] Updated llvm-objdump and llvm-readobj to be able to dump Windows x64 Unwind v3 information.#199120
dpaoliello wants to merge 1 commit into
llvm:mainfrom
dpaoliello:dumpunwindv3

Conversation

@dpaoliello
Copy link
Copy Markdown
Contributor

Public docs: https://learn.microsoft.com/en-us/cpp/build/x64-unwind-information-v3?view=msvc-170

The change adds Windows x64 unwind v3 info decoding and printing support in LLVM, including new data structures, enums, and decoding functions to handle the different WOD opcodes and epilog descriptors. It also updates the dumping utilities (llvm-readobj and llvm-objdump) to correctly interpret v3 unwind info.

NOTE: This does not yet support large unwind or epilog info variants.

…mp Windows x64 Unwind v3 information.

Public docs: <https://learn.microsoft.com/en-us/cpp/build/x64-unwind-information-v3?view=msvc-170>

The change adds complete WIndows x64 V3 unwind info decoding and printing support in LLVM, including new data structures, enums, and decoding functions to handle the different WOD opcodes and epilog descriptors.
It also updates the dumping utilities (llvm-readobj and llvm-objdump) to correctly interpret V3 unwind info.
@llvmorg-github-actions
Copy link
Copy Markdown

llvmorg-github-actions Bot commented May 21, 2026

@llvm/pr-subscribers-platform-windows
@llvm/pr-subscribers-backend-x86
@llvm/pr-subscribers-llvm-binary-utilities

@llvm/pr-subscribers-llvm-support

Author: Daniel Paoliello (dpaoliello)

Changes

Public docs: <https://learn.microsoft.com/en-us/cpp/build/x64-unwind-information-v3?view=msvc-170>

The change adds Windows x64 unwind v3 info decoding and printing support in LLVM, including new data structures, enums, and decoding functions to handle the different WOD opcodes and epilog descriptors. It also updates the dumping utilities (llvm-readobj and llvm-objdump) to correctly interpret v3 unwind info.

NOTE: This does not yet support large unwind or epilog info variants.


Patch is 167.75 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/199120.diff

34 Files Affected:

  • (modified) llvm/include/llvm/Support/Win64EH.h (+76)
  • (modified) llvm/lib/Support/CMakeLists.txt (+1)
  • (added) llvm/lib/Support/Win64EH.cpp (+276)
  • (added) llvm/test/tools/llvm-objdump/COFF/win64-unwindv3-all-wods.yaml (+140)
  • (added) llvm/test/tools/llvm-objdump/COFF/win64-unwindv3-apx.yaml (+123)
  • (added) llvm/test/tools/llvm-objdump/COFF/win64-unwindv3-bad-inherit.yaml (+128)
  • (added) llvm/test/tools/llvm-objdump/COFF/win64-unwindv3-bad-opcode.yaml (+124)
  • (added) llvm/test/tools/llvm-objdump/COFF/win64-unwindv3-basic.yaml (+133)
  • (added) llvm/test/tools/llvm-objdump/COFF/win64-unwindv3-chain.yaml (+123)
  • (added) llvm/test/tools/llvm-objdump/COFF/win64-unwindv3-distinct-epilog.yaml (+125)
  • (added) llvm/test/tools/llvm-objdump/COFF/win64-unwindv3-epilog-flags.yaml (+128)
  • (added) llvm/test/tools/llvm-objdump/COFF/win64-unwindv3-epilog.yaml (+148)
  • (added) llvm/test/tools/llvm-objdump/COFF/win64-unwindv3-handler.yaml (+123)
  • (added) llvm/test/tools/llvm-objdump/COFF/win64-unwindv3-multi-epilog.yaml (+156)
  • (added) llvm/test/tools/llvm-objdump/COFF/win64-unwindv3-neg-offset.yaml (+128)
  • (added) llvm/test/tools/llvm-objdump/COFF/win64-unwindv3-pool-overflow.yaml (+127)
  • (added) llvm/test/tools/llvm-objdump/COFF/win64-unwindv3-reloc.yaml (+102)
  • (added) llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-v3-all-wods.yaml (+173)
  • (added) llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-v3-apx.yaml (+140)
  • (added) llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-v3-bad-inherit.yaml (+154)
  • (added) llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-v3-bad-opcode.yaml (+143)
  • (added) llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-v3-basic.yaml (+140)
  • (added) llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-v3-chain.yaml (+150)
  • (added) llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-v3-distinct-epilog.yaml (+156)
  • (added) llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-v3-epilog-flags.yaml (+156)
  • (added) llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-v3-epilog.yaml (+162)
  • (added) llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-v3-handler.yaml (+144)
  • (added) llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-v3-multi-epilog.yaml (+179)
  • (added) llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-v3-neg-offset.yaml (+162)
  • (added) llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-v3-pool-overflow.yaml (+154)
  • (added) llvm/test/tools/llvm-readobj/COFF/unwind-x86_64-v3-reloc.yaml (+117)
  • (modified) llvm/tools/llvm-objdump/COFFDump.cpp (+177-5)
  • (modified) llvm/tools/llvm-readobj/Win64EHDumper.cpp (+181-2)
  • (modified) llvm/tools/llvm-readobj/Win64EHDumper.h (+3)
diff --git a/llvm/include/llvm/Support/Win64EH.h b/llvm/include/llvm/Support/Win64EH.h
index ec3413b31ee4a..cfe30c2fd06d2 100644
--- a/llvm/include/llvm/Support/Win64EH.h
+++ b/llvm/include/llvm/Support/Win64EH.h
@@ -15,8 +15,12 @@
 #ifndef LLVM_SUPPORT_WIN64EH_H
 #define LLVM_SUPPORT_WIN64EH_H
 
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
 #include "llvm/Support/DataTypes.h"
 #include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
 
 namespace llvm {
 namespace Win64EH {
@@ -221,6 +225,78 @@ struct UnwindInfo {
   }
 };
 
+//===----------------------------------------------------------------------===//
+// V3 Unwind Information
+//===----------------------------------------------------------------------===//
+
+/// V3 Winding Operation Descriptor opcodes.
+enum WODOpcode : uint8_t {
+  WOD_SET_FPREG = 0,            // 8-bit opcode, 2 bytes
+  WOD_ALLOC_HUGE = 1,           // 8-bit opcode, 5 bytes
+  WOD_ALLOC_LARGE = 2,          // 8-bit opcode, 3 bytes
+  WOD_PUSH_CANONICAL_FRAME = 3, // 8-bit opcode, 2 bytes
+  WOD_PUSH = 4,                 // 3-bit opcode, 1 byte
+  WOD_SAVE_NONVOL_FAR = 5,      // 3-bit opcode, 5 bytes
+  WOD_SAVE_NONVOL = 6,          // 3-bit opcode, 3 bytes
+  WOD_PUSH_CONSECUTIVE_2 = 7,   // 3-bit opcode, 1 byte
+  WOD_ALLOC_SMALL = 8,          // 4-bit opcode, 1 byte
+  WOD_SAVE_XMM128_FAR = 9,      // 4-bit opcode, 5 bytes
+  WOD_SAVE_XMM128 = 10,         // 4-bit opcode, 3 bytes
+  WOD_PUSH2 = 32,               // 6-bit opcode, 2 bytes
+};
+
+/// V3 EPILOG_INFO flags.
+enum EpilogInfoFlagsV3 : uint8_t {
+  EPILOG_PARENT_FRAGMENT_TRANSFER = 0x01,
+};
+
+/// Decoded V3 Winding Operation Descriptor.
+struct DecodedWOD {
+  WODOpcode Opcode;
+  uint8_t Register;      // For applicable ops (5-bit for int, 4-bit for XMM)
+  uint8_t Register2;     // For WOD_PUSH2
+  uint8_t Type;          // For WOD_PUSH_CANONICAL_FRAME
+  uint8_t ByteSize;      // How many bytes this WOD consumed (max 5)
+  uint32_t Size;         // For alloc ops: final computed size
+  uint32_t Displacement; // For save ops: final computed displacement
+};
+
+/// Decoded V3 epilog descriptor.
+struct DecodedEpilogV3 {
+  uint8_t Flags;
+  uint8_t NumberOfOps;
+  int16_t EpilogOffset;
+  uint16_t FirstOp;
+  uint8_t IpOffsetOfLastInstruction;
+  SmallVector<uint8_t, 8> IpOffsets;
+};
+
+/// Decoded V3 UNWIND_INFO.
+struct DecodedUnwindInfoV3 {
+  uint8_t Version;
+  uint8_t Flags;
+  uint8_t SizeOfProlog;
+  uint8_t CountOfCodes;
+  uint8_t NumberOfOps;
+  uint8_t NumberOfEpilogs;
+  /// Total bytes consumed by the payload (used to locate handler/chain).
+  uint16_t PayloadSize;
+  SmallVector<uint8_t, 8> PrologIpOffsets;
+  SmallVector<DecodedEpilogV3, 4> Epilogs;
+  ArrayRef<uint8_t> WODPool;
+};
+
+/// Return the register name for a 5-bit AMD64 integer register number.
+/// Covers 0-15 (RAX-R15) and 16-31 (R16-R31 for APX).
+StringRef getRegisterNameV3(unsigned Reg);
+
+/// Decode one WOD from the pool at the given byte offset.
+/// Returns an error on malformed data.
+Expected<DecodedWOD> decodeWOD(ArrayRef<uint8_t> Pool, unsigned Offset);
+
+/// Parse a V3 UNWIND_INFO from raw bytes.
+/// Returns an error on malformed data.
+Expected<DecodedUnwindInfoV3> decodeUnwindInfoV3(ArrayRef<uint8_t> Data);
 
 } // End of namespace Win64EH
 } // End of namespace llvm
diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt
index 100cfb567c348..58bf514265ca1 100644
--- a/llvm/lib/Support/CMakeLists.txt
+++ b/llvm/lib/Support/CMakeLists.txt
@@ -282,6 +282,7 @@ add_llvm_component_library(LLVMSupport
   VirtualOutputConfig.cpp
   VirtualOutputError.cpp
   VirtualOutputFile.cpp
+  Win64EH.cpp
   WithColor.cpp
   YAMLParser.cpp
   YAMLTraits.cpp
diff --git a/llvm/lib/Support/Win64EH.cpp b/llvm/lib/Support/Win64EH.cpp
new file mode 100644
index 0000000000000..28b4df64acf2a
--- /dev/null
+++ b/llvm/lib/Support/Win64EH.cpp
@@ -0,0 +1,276 @@
+//===-- Win64EH.cpp - Win64 EH V3 Support -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements decoding helpers for V3 unwind information on Win64.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Win64EH.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+
+using namespace llvm;
+using namespace llvm::Win64EH;
+
+StringRef Win64EH::getRegisterNameV3(unsigned Reg) {
+  static const char *const Names[] = {
+      "RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI",
+      "R8",  "R9",  "R10", "R11", "R12", "R13", "R14", "R15",
+      "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23",
+      "R24", "R25", "R26", "R27", "R28", "R29", "R30", "R31",
+  };
+  if (Reg >= std::size(Names))
+    return "<invalid>";
+  return Names[Reg];
+}
+
+Expected<DecodedWOD> Win64EH::decodeWOD(ArrayRef<uint8_t> Pool,
+                                        unsigned Offset) {
+  if (Offset >= Pool.size())
+    return createStringError("WOD pool overflow at offset %u", Offset);
+
+  uint8_t FirstByte = Pool[Offset];
+  DecodedWOD W = {};
+
+  // Determine opcode from variable-width prefix encoding.
+  // The dispatch order matters: check shorter prefixes first since they
+  // occupy the lowest bits, then fall through to longer prefixes.
+  //   3-bit prefix (bits [2:0] >= 4): opcodes 4-7
+  //   4-bit prefix (bits [3:0] >= 8): opcodes 8-10
+  //   6-bit prefix (bits [5:0] == 0x20): opcode 32 (PUSH2)
+  //   8-bit prefix (full byte 0-3): opcodes 0-3
+  uint8_t Low3 = FirstByte & 0x07;
+
+  // 3-bit opcode: bits [2:0] in {4, 5, 6, 7}
+  if (Low3 >= 4) {
+    switch (Low3) {
+    case WOD_PUSH: {
+      W.Opcode = WOD_PUSH;
+      W.ByteSize = 1;
+      W.Register = (FirstByte >> 3) & 0x1F; // 5-bit register
+      return W;
+    }
+    case WOD_SAVE_NONVOL_FAR: {
+      W.Opcode = WOD_SAVE_NONVOL_FAR;
+      W.ByteSize = 5;
+      if (Offset + 5 > Pool.size())
+        return createStringError("WOD_SAVE_NONVOL_FAR truncated at offset %u",
+                                 Offset);
+      W.Register = (FirstByte >> 3) & 0x1F;
+      W.Displacement = support::endian::read32le(&Pool[Offset + 1]);
+      return W;
+    }
+    case WOD_SAVE_NONVOL: {
+      W.Opcode = WOD_SAVE_NONVOL;
+      W.ByteSize = 3;
+      if (Offset + 3 > Pool.size())
+        return createStringError("WOD_SAVE_NONVOL truncated at offset %u",
+                                 Offset);
+      W.Register = (FirstByte >> 3) & 0x1F;
+      W.Displacement =
+          (uint32_t)support::endian::read16le(&Pool[Offset + 1]) * 8;
+      return W;
+    }
+    case WOD_PUSH_CONSECUTIVE_2: {
+      W.Opcode = WOD_PUSH_CONSECUTIVE_2;
+      W.ByteSize = 1;
+      W.Register = (FirstByte >> 3) & 0x1F;
+      return W;
+    }
+    default:
+      return createStringError("unknown WOD opcode 0x%02X at pool offset %u",
+                               FirstByte, Offset);
+    }
+  }
+
+  // 4-bit opcode: bits [3:0] in {8, 9, 10, ...}
+  uint8_t Low4 = FirstByte & 0x0F;
+  if (Low4 >= 8) {
+    switch (Low4) {
+    case WOD_ALLOC_SMALL: {
+      W.Opcode = WOD_ALLOC_SMALL;
+      W.ByteSize = 1;
+      W.Size = (unsigned)(((FirstByte >> 4) & 0x0F) + 1) * 8;
+      return W;
+    }
+    case WOD_SAVE_XMM128_FAR: {
+      W.Opcode = WOD_SAVE_XMM128_FAR;
+      W.ByteSize = 5;
+      if (Offset + 5 > Pool.size())
+        return createStringError("WOD_SAVE_XMM128_FAR truncated at offset %u",
+                                 Offset);
+      W.Register = (FirstByte >> 4) & 0x0F;
+      W.Displacement = support::endian::read32le(&Pool[Offset + 1]);
+      return W;
+    }
+    case WOD_SAVE_XMM128: {
+      W.Opcode = WOD_SAVE_XMM128;
+      W.ByteSize = 3;
+      if (Offset + 3 > Pool.size())
+        return createStringError("WOD_SAVE_XMM128 truncated at offset %u",
+                                 Offset);
+      W.Register = (FirstByte >> 4) & 0x0F;
+      W.Displacement =
+          (uint32_t)support::endian::read16le(&Pool[Offset + 1]) * 16;
+      return W;
+    }
+    default:
+      return createStringError("unknown WOD opcode 0x%02X at pool offset %u",
+                               FirstByte, Offset);
+    }
+  }
+
+  // 6-bit opcode: bits [5:0] == 0x20 (WOD_PUSH2)
+  uint8_t Low6 = FirstByte & 0x3F;
+  if (Low6 == WOD_PUSH2) {
+    W.Opcode = WOD_PUSH2;
+    W.ByteSize = 2;
+    if (Offset + 2 > Pool.size())
+      return createStringError("WOD_PUSH2 truncated at offset %u", Offset);
+    uint8_t SecondByte = Pool[Offset + 1];
+    // First reg from bits [7:6] of first byte (2 bits) and bits [2:0] of second
+    // (3 bits)
+    W.Register = ((FirstByte >> 6) & 0x03) | ((SecondByte & 0x07) << 2);
+    W.Register2 = (SecondByte >> 3) & 0x1F;
+    return W;
+  }
+
+  // 8-bit opcode: full byte is opcode (values 0-3)
+  switch (FirstByte) {
+  case WOD_SET_FPREG: {
+    W.Opcode = WOD_SET_FPREG;
+    W.ByteSize = 2;
+    if (Offset + 2 > Pool.size())
+      return createStringError("WOD_SET_FPREG truncated at offset %u", Offset);
+    uint8_t SecondByte = Pool[Offset + 1];
+    W.Register = SecondByte & 0x0F; // 4-bit register
+    W.Displacement = (unsigned)((SecondByte >> 4) & 0x0F) * 16;
+    return W;
+  }
+  case WOD_ALLOC_HUGE: {
+    W.Opcode = WOD_ALLOC_HUGE;
+    W.ByteSize = 5;
+    if (Offset + 5 > Pool.size())
+      return createStringError("WOD_ALLOC_HUGE truncated at offset %u", Offset);
+    W.Size = support::endian::read32le(&Pool[Offset + 1]);
+    return W;
+  }
+  case WOD_ALLOC_LARGE: {
+    W.Opcode = WOD_ALLOC_LARGE;
+    W.ByteSize = 3;
+    if (Offset + 3 > Pool.size())
+      return createStringError("WOD_ALLOC_LARGE truncated at offset %u",
+                               Offset);
+    W.Size = (uint32_t)support::endian::read16le(&Pool[Offset + 1]) * 8;
+    return W;
+  }
+  case WOD_PUSH_CANONICAL_FRAME: {
+    W.Opcode = WOD_PUSH_CANONICAL_FRAME;
+    W.ByteSize = 2;
+    if (Offset + 2 > Pool.size())
+      return createStringError(
+          "WOD_PUSH_CANONICAL_FRAME truncated at offset %u", Offset);
+    W.Type = Pool[Offset + 1];
+    return W;
+  }
+  default:
+    return createStringError("unknown WOD opcode 0x%02X at pool offset %u",
+                             FirstByte, Offset);
+  }
+}
+
+Expected<DecodedUnwindInfoV3>
+Win64EH::decodeUnwindInfoV3(ArrayRef<uint8_t> Data) {
+  if (Data.size() < 4)
+    return createStringError("V3 unwind info too short: %zu bytes",
+                             Data.size());
+
+  DecodedUnwindInfoV3 Info;
+  Info.Version = Data[0] & 0x07;
+  Info.Flags = (Data[0] >> 3) & 0x1F;
+  Info.SizeOfProlog = Data[1];
+  Info.CountOfCodes = Data[2];
+  Info.NumberOfOps = Data[3] & 0x1F;
+  Info.NumberOfEpilogs = (Data[3] >> 5) & 0x07;
+
+  unsigned Offset = 4; // Start of payload
+
+  // Read prolog IP offsets (one byte each)
+  for (unsigned I = 0; I < Info.NumberOfOps; ++I) {
+    if (Offset >= Data.size())
+      return createStringError(
+          "V3 payload truncated reading prolog IP offset %u", I);
+    Info.PrologIpOffsets.push_back(Data[Offset++]);
+  }
+
+  // Read epilog descriptors
+  for (unsigned I = 0; I < Info.NumberOfEpilogs; ++I) {
+    DecodedEpilogV3 Epi;
+    if (Offset >= Data.size())
+      return createStringError(
+          "V3 payload truncated reading epilog %u FlagsAndNumOps", I);
+    uint8_t FlagsAndNumOps = Data[Offset++];
+    Epi.Flags = FlagsAndNumOps & 0x07;
+    Epi.NumberOfOps = (FlagsAndNumOps >> 3) & 0x1F;
+
+    if (Offset + 2 > Data.size())
+      return createStringError(
+          "V3 payload truncated reading epilog %u EpilogOffset", I);
+    Epi.EpilogOffset =
+        static_cast<int16_t>(support::endian::read16le(&Data[Offset]));
+    Offset += 2;
+
+    // Inherited descriptors (NumberOfOps == 0) are only 3 bytes:
+    // FlagsAndNumOps(1) + EpilogOffset(2). They have no FirstOp,
+    // IpOffsetOfLastInstruction, or IP offset fields.
+    if (Epi.NumberOfOps == 0) {
+      Epi.FirstOp = 0;
+      Epi.IpOffsetOfLastInstruction = 0;
+      Info.Epilogs.push_back(std::move(Epi));
+      continue;
+    }
+
+    if (Offset + 2 > Data.size())
+      return createStringError("V3 payload truncated reading epilog %u FirstOp",
+                               I);
+    Epi.FirstOp = support::endian::read16le(&Data[Offset]);
+    Offset += 2;
+
+    if (Offset >= Data.size())
+      return createStringError(
+          "V3 payload truncated reading epilog %u IpOffsetOfLastInstruction",
+          I);
+    Epi.IpOffsetOfLastInstruction = Data[Offset++];
+
+    // Read epilog IP offsets (one byte each)
+    for (unsigned J = 0; J < Epi.NumberOfOps; ++J) {
+      if (Offset >= Data.size())
+        return createStringError(
+            "V3 payload truncated reading epilog %u IP offset %u", I, J);
+      Epi.IpOffsets.push_back(Data[Offset++]);
+    }
+
+    Info.Epilogs.push_back(std::move(Epi));
+  }
+
+  // Identify WOD pool: everything from current offset until end of
+  // CountOfCodes * 2 bytes (payload area)
+  unsigned PayloadEnd = 4 + Info.CountOfCodes * 2;
+  if (PayloadEnd > Data.size())
+    PayloadEnd = Data.size();
+  unsigned WODPoolStart = Offset;
+  unsigned WODPoolEnd = PayloadEnd;
+  if (WODPoolStart < WODPoolEnd)
+    Info.WODPool = Data.slice(WODPoolStart, WODPoolEnd - WODPoolStart);
+  else
+    Info.WODPool = ArrayRef<uint8_t>();
+
+  Info.PayloadSize = PayloadEnd;
+
+  return Info;
+}
diff --git a/llvm/test/tools/llvm-objdump/COFF/win64-unwindv3-all-wods.yaml b/llvm/test/tools/llvm-objdump/COFF/win64-unwindv3-all-wods.yaml
new file mode 100644
index 0000000000000..9c2636de06d16
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/COFF/win64-unwindv3-all-wods.yaml
@@ -0,0 +1,140 @@
+# RUN: yaml2obj %s -o %t.exe
+# RUN: llvm-objdump --unwind-info %t.exe | FileCheck %s
+
+## T4: V3 with all WOD types — comprehensive WOD decode coverage.
+##
+## .xdata hex breakdown:
+## Byte 0: 0x03  (Version=3, Flags=0)
+## Byte 1: 0x30  (SizeOfProlog=48)
+## Byte 2: 0x17  (CountOfCodes=23 words -> 46 bytes payload)
+## Byte 3: 0x0C  (NumberOfOps=12, NumberOfEpilogs=0)
+## See readobj test for full hex breakdown of WOD pool.
+
+# CHECK-LABEL:  Unwind info:
+# CHECK-EMPTY:
+# CHECK-NEXT:   Function Table:
+# CHECK-NEXT:     Start Address: 0x1000
+# CHECK-NEXT:     End Address: 0x1050
+# CHECK-NEXT:     Unwind Info Address: 0x2000
+# CHECK-NEXT:       Version: 3
+# CHECK-NEXT:       Flags: 0
+# CHECK-NEXT:       Size of prolog: 0x30
+# CHECK-NEXT:       CountOfCodes: 23
+# CHECK-NEXT:       NumberOfOps: 12
+# CHECK-NEXT:       NumberOfEpilogs: 0
+# CHECK-NEXT:       Prolog [12 ops]:
+# CHECK-NEXT:         [0] IP +0x30: WOD_PUSH Reg=RDI
+# CHECK-NEXT:         [1] IP +0x2C: WOD_PUSH2 Reg1=RAX, Reg2=RCX
+# CHECK-NEXT:         [2] IP +0x2B: WOD_PUSH_CONSECUTIVE_2 Reg=RBX (+RSP)
+# CHECK-NEXT:         [3] IP +0x2A: WOD_ALLOC_SMALL Size=0x20
+# CHECK-NEXT:         [4] IP +0x28: WOD_ALLOC_LARGE Size=0x1000
+# CHECK-NEXT:         [5] IP +0x24: WOD_ALLOC_HUGE Size=0x12345
+# CHECK-NEXT:         [6] IP +0x20: WOD_SET_FPREG Reg=RBP, Offset=0x30
+# CHECK-NEXT:         [7] IP +0x1C: WOD_SAVE_NONVOL Reg=R12, Disp=0x40
+# CHECK-NEXT:         [8] IP +0x18: WOD_SAVE_NONVOL_FAR Reg=R13, Disp=0x100000
+# CHECK-NEXT:         [9] IP +0x14: WOD_SAVE_XMM128 Reg=XMM4, Disp=0x100
+# CHECK-NEXT:         [10] IP +0x10: WOD_SAVE_XMM128_FAR Reg=XMM7, Disp=0x20000
+# CHECK-NEXT:         [11] IP +0x00: WOD_PUSH_CANONICAL_FRAME Type=1
+
+--- !COFF
+OptionalHeader:
+  AddressOfEntryPoint: 4096
+  ImageBase:       0
+  SectionAlignment: 4096
+  FileAlignment:   512
+  MajorOperatingSystemVersion: 6
+  MinorOperatingSystemVersion: 0
+  MajorImageVersion: 0
+  MinorImageVersion: 0
+  MajorSubsystemVersion: 6
+  MinorSubsystemVersion: 0
+  Subsystem:       IMAGE_SUBSYSTEM_WINDOWS_CUI
+  DLLCharacteristics: [ IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT ]
+  SizeOfStackReserve: 1048576
+  SizeOfStackCommit: 4096
+  SizeOfHeapReserve: 1048576
+  SizeOfHeapCommit: 4096
+  ExportTable:
+    RelativeVirtualAddress: 0
+    Size:            0
+  ImportTable:
+    RelativeVirtualAddress: 0
+    Size:            0
+  ResourceTable:
+    RelativeVirtualAddress: 0
+    Size:            0
+  ExceptionTable:
+    RelativeVirtualAddress: 12288
+    Size:            12
+  CertificateTable:
+    RelativeVirtualAddress: 0
+    Size:            0
+  BaseRelocationTable:
+    RelativeVirtualAddress: 0
+    Size:            0
+  Debug:
+    RelativeVirtualAddress: 0
+    Size:            0
+  Architecture:
+    RelativeVirtualAddress: 0
+    Size:            0
+  GlobalPtr:
+    RelativeVirtualAddress: 0
+    Size:            0
+  TlsTable:
+    RelativeVirtualAddress: 0
+    Size:            0
+  LoadConfigTable:
+    RelativeVirtualAddress: 0
+    Size:            0
+  BoundImport:
+    RelativeVirtualAddress: 0
+    Size:            0
+  IAT:
+    RelativeVirtualAddress: 0
+    Size:            0
+  DelayImportDescriptor:
+    RelativeVirtualAddress: 0
+    Size:            0
+  ClrRuntimeHeader:
+    RelativeVirtualAddress: 0
+    Size:            0
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  4096
+    VirtualSize:     80
+    SectionData:     '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+  - Name:            .xdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  8192
+    VirtualSize:     50
+    SectionData:     '0330170C302C2B2A2824201C181410003C20081F38020002014523010000356608006D000010004A10007900000200030100'
+  - Name:            .pdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  12288
+    VirtualSize:     12
+    SectionData:     '001000005010000000200000'
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .xdata
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .pdata
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+...
diff --git a/llvm/test/tools/llvm-objdump/COFF/win64-unwindv3-apx.yaml b/llvm/test/tools/llvm-objdump/COFF/win64-unwindv3-apx.yaml
new file mode 100644
index 0000000000000..3b558fb75c920
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/COFF/win64-unwindv3-apx.yaml
@@ -0,0 +1,123 @@
+# RUN: yaml2obj %s -o %t.exe
+# RUN: llvm-objdump --unwind-info %t.exe | FileCheck %s
+
+## T7: V3 with APX registers (R16-R31).
+
+# CHECK-LABEL:  Unwind info:
+# CHECK-EMPTY:
+# CHECK-NEXT:   Function Table:
+# CHECK-NEXT:     Start Address: 0x1000
+# CHECK-NEXT:     End Address: 0x1010
+# CHECK-NEXT:     Unwind Info Address: 0x2000
+# CHECK-NEXT:       Version: 3
+# CHECK-NEXT:       Flags: 0
+# CHECK-NEXT:       Size of prolog: 0x4
+# CHECK-NEXT:       CountOfCodes: 2
+# CHECK-NEXT:       NumberOfOps: 2
+# CHECK-NEXT:       NumberOfEpilogs: 0
+# CHECK-NEXT:       Prolog [2 ops]:
+# CHECK-NEXT:         [0] IP +0x04: WOD_PUSH Reg=R16
+# CHECK-NEXT:         [1] IP +0x00: WOD_PUSH Reg=R31
+
+--- !COFF
+OptionalHeader:
+  AddressOfEntryPoint: 4096
+  ImageBase:       0
+  SectionAlignment: 4096
+  FileAlignment:   512
+  MajorOperatingSystemVersion: 6
+  MinorOperatingSystemVersion: 0
+  MajorImageVersion: 0
+  MinorImageVersion: 0
+  MajorSubsystemVersion: 6
+  MinorSubsystemVersion: 0
+  Subsystem:       IMAGE_SUBSYSTEM_WINDOWS_CUI
+  DLLCharacteristics: [ IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA, IMAGE_DLL_CHARACTE...
[truncated]

@github-actions
Copy link
Copy Markdown

🐧 Linux x64 Test Results

  • 8170 tests passed
  • 420 tests skipped

All executed tests passed, but another part of the build failed. Click on a failure below to see the details.

tools/llvm-objdump/CMakeFiles/llvm-objdump.dir/COFFDump.cpp.o
FAILED: tools/llvm-objdump/CMakeFiles/llvm-objdump.dir/COFFDump.cpp.o
sccache /opt/llvm/bin/clang++ -DLLVM_BUILD_STATIC -D_DEBUG -D_GLIBCXX_ASSERTIONS -D_GLIBCXX_USE_CXX11_ABI=1 -D_GNU_SOURCE -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/llvm-objdump -I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/tools/llvm-objdump -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/include -gmlt -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wno-pass-failed -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -O3 -DNDEBUG -std=c++17 -UNDEBUG -fno-exceptions -funwind-tables -fno-rtti -MD -MT tools/llvm-objdump/CMakeFiles/llvm-objdump.dir/COFFDump.cpp.o -MF tools/llvm-objdump/CMakeFiles/llvm-objdump.dir/COFFDump.cpp.o.d -o tools/llvm-objdump/CMakeFiles/llvm-objdump.dir/COFFDump.cpp.o -c /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/tools/llvm-objdump/COFFDump.cpp
/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/tools/llvm-objdump/COFFDump.cpp:734:3: error: default label in switch which covers all enumeration values [-Werror,-Wcovered-switch-default]
734 |   default:
|   ^
1 error generated.
tools/llvm-readobj/CMakeFiles/llvm-readobj.dir/Win64EHDumper.cpp.o
FAILED: tools/llvm-readobj/CMakeFiles/llvm-readobj.dir/Win64EHDumper.cpp.o
sccache /opt/llvm/bin/clang++ -DLLVM_BUILD_STATIC -D_DEBUG -D_GLIBCXX_ASSERTIONS -D_GLIBCXX_USE_CXX11_ABI=1 -D_GNU_SOURCE -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/llvm-readobj -I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/tools/llvm-readobj -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/include -gmlt -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wno-pass-failed -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -O3 -DNDEBUG -std=c++17 -UNDEBUG -fno-exceptions -funwind-tables -fno-rtti -MD -MT tools/llvm-readobj/CMakeFiles/llvm-readobj.dir/Win64EHDumper.cpp.o -MF tools/llvm-readobj/CMakeFiles/llvm-readobj.dir/Win64EHDumper.cpp.o.d -o tools/llvm-readobj/CMakeFiles/llvm-readobj.dir/Win64EHDumper.cpp.o -c /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/tools/llvm-readobj/Win64EHDumper.cpp
/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/tools/llvm-readobj/Win64EHDumper.cpp:474:3: error: default label in switch which covers all enumeration values [-Werror,-Wcovered-switch-default]
474 |   default:
|   ^
1 error generated.

If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the infrastructure label.

@github-actions
Copy link
Copy Markdown

🪟 Windows x64 Test Results

  • 135001 tests passed
  • 3308 tests skipped
  • 1 test failed

Failed Tests

(click on a test name to see its output)

LLVM

LLVM.CodeGen/PowerPC/fast-isel-cmp-imm.ll
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 1
c:\_work\llvm-project\llvm-project\build\bin\llc.exe < C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\PowerPC\fast-isel-cmp-imm.ll -O0 -verify-machineinstrs -fast-isel-abort=1 -mtriple=powerpc64-unknown-linux-gnu -mcpu=pwr7 -mattr=-vsx | c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\PowerPC\fast-isel-cmp-imm.ll --check-prefix=ELF64
# executed command: 'c:\_work\llvm-project\llvm-project\build\bin\llc.exe' -O0 -verify-machineinstrs -fast-isel-abort=1 -mtriple=powerpc64-unknown-linux-gnu -mcpu=pwr7 -mattr=-vsx
# note: command had no output on stdout or stderr
# executed command: 'c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe' 'C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\PowerPC\fast-isel-cmp-imm.ll' --check-prefix=ELF64
# note: command had no output on stdout or stderr
# RUN: at line 2
c:\_work\llvm-project\llvm-project\build\bin\llc.exe < C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\PowerPC\fast-isel-cmp-imm.ll -O0 -verify-machineinstrs -fast-isel-abort=1 -mtriple=powerpc64le-unknown-linux-gnu -mattr=+vsx | c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\PowerPC\fast-isel-cmp-imm.ll --check-prefix=VSX
# executed command: 'c:\_work\llvm-project\llvm-project\build\bin\llc.exe' -O0 -verify-machineinstrs -fast-isel-abort=1 -mtriple=powerpc64le-unknown-linux-gnu -mattr=+vsx
# note: command had no output on stdout or stderr
# executed command: 'c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe' 'C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\PowerPC\fast-isel-cmp-imm.ll' --check-prefix=VSX
# note: command had no output on stdout or stderr
# RUN: at line 3
c:\_work\llvm-project\llvm-project\build\bin\llc.exe < C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\PowerPC\fast-isel-cmp-imm.ll -O0 -verify-machineinstrs -fast-isel-abort=1 -mtriple=powerpc-unknown-linux-gnu -mcpu=e500 -mattr=spe | c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\PowerPC\fast-isel-cmp-imm.ll --check-prefix=SPE
# executed command: 'c:\_work\llvm-project\llvm-project\build\bin\llc.exe' -O0 -verify-machineinstrs -fast-isel-abort=1 -mtriple=powerpc-unknown-linux-gnu -mcpu=e500 -mattr=spe
# note: command had no output on stdout or stderr
# executed command: 'c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe' 'C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\PowerPC\fast-isel-cmp-imm.ll' --check-prefix=SPE
# .---command stderr------------
# | C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\PowerPC\fast-isel-cmp-imm.ll:19:8: error: SPE: expected string not found in input
# | ; SPE: efscmpeq
# |        ^
# | <stdin>:11:12: note: scanning from here
# | t1a: # @t1a
# |            ^
# | <stdin>:12:2: note: possible intended match here
# | .Lfunc_begin0:
# |  ^
# | C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\PowerPC\fast-isel-cmp-imm.ll:42:8: error: SPE: expected string not found in input
# | ; SPE: efscmpeq
# |        ^
# | <stdin>:43:12: note: scanning from here
# | t1b: # @t1b
# |            ^
# | <stdin>:44:2: note: possible intended match here
# | .Lfunc_begin1:
# |  ^
# | C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\PowerPC\fast-isel-cmp-imm.ll:65:8: error: SPE: expected string not found in input
# | ; SPE: efscmpeq
# |        ^
# | <stdin>:75:12: note: scanning from here
# | t1c: # @t1c
# |            ^
# | <stdin>:76:2: note: possible intended match here
# | .Lfunc_begin2:
# |  ^
# | C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\PowerPC\fast-isel-cmp-imm.ll:88:8: error: SPE: expected string not found in input
# | ; SPE: efdcmpeq
# |        ^
# | <stdin>:108:12: note: scanning from here
# | t2a: # @t2a
# |            ^
# | <stdin>:109:2: note: possible intended match here
# | .Lfunc_begin3:
# |  ^
# | C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\PowerPC\fast-isel-cmp-imm.ll:111:8: error: SPE: expected string not found in input
# | ; SPE: efdcmpeq
# |        ^
# | <stdin>:149:12: note: scanning from here
# | t2b: # @t2b
# |            ^
# | <stdin>:150:2: note: possible intended match here
# | .Lfunc_begin4:
# |  ^
# | C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\PowerPC\fast-isel-cmp-imm.ll:134:8: error: SPE: expected string not found in input
# | ; SPE: efdcmpeq
# |        ^
# | <stdin>:190:12: note: scanning from here
# | t2c: # @t2c
# |            ^
# | <stdin>:191:2: note: possible intended match here
# | .Lfunc_begin5:
# |  ^
# | 
# | Input file: <stdin>
# | Check file: C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\PowerPC\fast-isel-cmp-imm.ll
# | 
# | -dump-input=help explains the following input dump.
# | 
# | Input was:
# | <<<<<<
# |              .
# |              .
# |              .
# |              6:  .text 
# |              7:  .globl t1a 
# |              8:  .p2align 2 
# |              9:  .prefalign 4, .Lfunc_end0, nop 
# |             10:  .type t1a,@function 
# |             11: t1a: # @t1a 
# | check:19'0                 X error: no match found
# |             12: .Lfunc_begin0: 
# | check:19'0      ~~~~~~~~~~~~~~~
# | check:19'1       ?              possible intended match
# |             13: # %bb.0: # %entry 
# | check:19'0      ~~~~~~~~~~~~~~~~~~
# |             14:  mflr 0 
# | check:19'0      ~~~~~~~~
# |             15:  stwu 1, -16(1) 
# | check:19'0      ~~~~~~~~~~~~~~~~
# |             16:  stw 0, 20(1) 
# | check:19'0      ~~~~~~~~~~~~~~
# |             17:  lis 4, .LCPI0_0@ha 
# | check:19'0      ~~~~~~~~~~~~~~~~~~~~
# |              .
# |              .
# |              .
# |             38:  .text 
# | check:19'0      ~~~~~~~
# |             39:  .globl t1b 
# | check:19'0      ~~~~~~~~~~~~
# |             40:  .p2align 2 
# | check:19'0      ~~~~~~~~~~~~
# |             41:  .prefalign 4, .Lfunc_end1, nop 
# | check:19'0      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# |             42:  .type t1b,@function 
# | check:19'0      ~~~~~~~~~~~~~~~~~~~~~
# |             43: t1b: # @t1b 
# | check:19'0      ~~~~~~~~~~~
# | check:42'0                 X error: no match found
# |             44: .Lfunc_begin1: 
# | check:42'0      ~~~~~~~~~~~~~~~
# | check:42'1       ?              possible intended match
# |             45: # %bb.0: # %entry 
# | check:42'0      ~~~~~~~~~~~~~~~~~~
# |             46:  mflr 0 
# | check:42'0      ~~~~~~~~
# |             47:  stwu 1, -16(1) 
# | check:42'0      ~~~~~~~~~~~~~~~~
# |             48:  stw 0, 20(1) 
# | check:42'0      ~~~~~~~~~~~~~~
# |             49:  lis 4, .LCPI1_0@ha 
# | check:42'0      ~~~~~~~~~~~~~~~~~~~~
# |              .
# |              .
# |              .
# |             70:  .text 
# | check:42'0      ~~~~~~~
# |             71:  .globl t1c 
# | check:42'0      ~~~~~~~~~~~~
# |             72:  .p2align 2 
# | check:42'0      ~~~~~~~~~~~~
# |             73:  .prefalign 4, .Lfunc_end2, nop 
# | check:42'0      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# |             74:  .type t1c,@function 
# | check:42'0      ~~~~~~~~~~~~~~~~~~~~~
# |             75: t1c: # @t1c 
# | check:42'0      ~~~~~~~~~~~
# | check:65'0                 X error: no match found
# |             76: .Lfunc_begin2: 
# | check:65'0      ~~~~~~~~~~~~~~~
# | check:65'1       ?              possible intended match
# |             77: # %bb.0: # %entry 
# | check:65'0      ~~~~~~~~~~~~~~~~~~
# |             78:  mflr 0 
# | check:65'0      ~~~~~~~~
# |             79:  stwu 1, -16(1) 
# | check:65'0      ~~~~~~~~~~~~~~~~
# |             80:  stw 0, 20(1) 
# | check:65'0      ~~~~~~~~~~~~~~
# |             81:  lis 4, .LCPI2_0@ha 
# | check:65'0      ~~~~~~~~~~~~~~~~~~~~
# |              .
# |              .
# |              .
# |            103:  .text 
# | check:65'0      ~~~~~~~
# |            104:  .globl t2a 
# | check:65'0      ~~~~~~~~~~~~
# |            105:  .p2align 2 
# | check:65'0      ~~~~~~~~~~~~
# |            106:  .prefalign 4, .Lfunc_end3, nop 
# | check:65'0      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# |            107:  .type t2a,@function 
# | check:65'0      ~~~~~~~~~~~~~~~~~~~~~
# |            108: t2a: # @t2a 
# | check:65'0      ~~~~~~~~~~~
# | check:88'0                 X error: no match found
# |            109: .Lfunc_begin3: 
# | check:88'0      ~~~~~~~~~~~~~~~
# | check:88'1       ?              possible intended match
# |            110: # %bb.0: # %entry 
# | check:88'0      ~~~~~~~~~~~~~~~~~~
# |            111:  mflr 0 
# | check:88'0      ~~~~~~~~
# |            112:  stwu 1, -16(1) 
# | check:88'0      ~~~~~~~~~~~~~~~~
# |            113:  stw 0, 20(1) 
# | check:88'0      ~~~~~~~~~~~~~~
# |            114:  evmergelo 3, 3, 4 
# | check:88'0      ~~~~~~~~~~~~~~~~~~~
# |              .
# |              .
# |              .
# |            144:  .text 
# | check:88'0      ~~~~~~~
# |            145:  .globl t2b 
# | check:88'0      ~~~~~~~~~~~~
# |            146:  .p2align 2 
# | check:88'0      ~~~~~~~~~~~~
# |            147:  .prefalign 4, .Lfunc_end4, nop 
# | check:88'0      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# |            148:  .type t2b,@function 
# | check:88'0      ~~~~~~~~~~~~~~~~~~~~~
# |            149: t2b: # @t2b 
# | check:88'0      ~~~~~~~~~~~
# | check:111'0                X error: no match found
# |            150: .Lfunc_begin4: 
# | check:111'0     ~~~~~~~~~~~~~~~
# | check:111'1      ?              possible intended match
# |            151: # %bb.0: # %entry 
# | check:111'0     ~~~~~~~~~~~~~~~~~~
# |            152:  mflr 0 
# | check:111'0     ~~~~~~~~
# |            153:  stwu 1, -16(1) 
# | check:111'0     ~~~~~~~~~~~~~~~~
# |            154:  stw 0, 20(1) 
# | check:111'0     ~~~~~~~~~~~~~~
# |            155:  evmergelo 3, 3, 4 
# | check:111'0     ~~~~~~~~~~~~~~~~~~~
# |              .
# |              .
# |              .
# |            185:  .text 
# | check:111'0     ~~~~~~~
# |            186:  .globl t2c 
# | check:111'0     ~~~~~~~~~~~~
# |            187:  .p2align 2 
# | check:111'0     ~~~~~~~~~~~~
# |            188:  .prefalign 4, .Lfunc_end5, nop 
# | check:111'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# |            189:  .type t2c,@function 
# | check:111'0     ~~~~~~~~~~~~~~~~~~~~~
# |            190: t2c: # @t2c 
# | check:111'0     ~~~~~~~~~~~
# | check:134'0                X error: no match found
# |            191: .Lfunc_begin5: 
# | check:134'0     ~~~~~~~~~~~~~~~
# | check:134'1      ?              possible intended match
# |            192: # %bb.0: # %entry 
# | check:134'0     ~~~~~~~~~~~~~~~~~~
# |            193:  mflr 0 
# | check:134'0     ~~~~~~~~
# |            194:  stwu 1, -16(1) 
# | check:134'0     ~~~~~~~~~~~~~~~~
# |            195:  stw 0, 20(1) 
# | check:134'0     ~~~~~~~~~~~~~~
# |            196:  evmergelo 3, 3, 4 
# | check:134'0     ~~~~~~~~~~~~~~~~~~~
# |              .
# |              .
# |              .
# | >>>>>>
# `-----------------------------
# error: command failed with exit status: 1

--

If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the infrastructure label.

Copy link
Copy Markdown
Member

@mikolaj-pirog mikolaj-pirog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

| NOTE: This does not yet support large unwind or epilog info variants.

Could you put some todo please?

};

/// Decoded V3 Winding Operation Descriptor.
struct DecodedWOD {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: could we drop the Decoded from this and subsequent structures?

# CHECK-NEXT: [0] IP +0x07: WOD_ALLOC_SMALL Size=0x20
# CHECK-NEXT: [1] IP +0x02: WOD_PUSH Reg=RSI
# CHECK-NEXT: [2] IP +0x00: WOD_PUSH Reg=RDI
# CHECK-NEXT: Epilog [0] (Flags=0x01, Offset=+0x14, IpOfLast=+0x6) [3 ops, FirstOp=0x0]:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about instead of displaying WODs for each prolog and epilog separately, displaying a WOD pool and displaying offsets to it for prolog/epilogs? That way it would be easy to see how the WOD pool is being shared. On the other hand it would be harder to see which WODs are used by each epilog and prolog..

outs().flush();
}

/// Helper to format a decoded WOD for llvm-objdump plain-text output.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Helper to format a decoded WOD for llvm-objdump plain-text output.

}

/// Helper to format a decoded WOD for llvm-objdump plain-text output.
static void printDecodedWODObjdump(const DecodedWOD &W) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: can we drop the "Objdump" from the name?

}
}

/// Decode and print N WODs from the pool for llvm-objdump.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Decode and print N WODs from the pool for llvm-objdump.

}

/// Decode and print N WODs from the pool for llvm-objdump.
static void printWODSequenceObjdump(ArrayRef<uint8_t> WODPool,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: can we drop the "Objdump" from the name?

}
}

/// Helper to print decoded WOD fields for llvm-readobj.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Helper to print decoded WOD fields for llvm-readobj.

WODOpcode Opcode;
uint8_t Register; // For applicable ops (5-bit for int, 4-bit for XMM)
uint8_t Register2; // For WOD_PUSH2
uint8_t Type; // For WOD_PUSH_CANONICAL_FRAME
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spec lists which types are possible and refers to windows SDK for details. Could you add a todo to handle this types as well? (Having an enum, nice display, etc.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants