[llvm] ef501bf - [MC] Omit DWARF unwind info if compact unwind is present where eligible

Jez Ng via llvm-commits llvm-commits at lists.llvm.org
Sun Jun 12 07:04:05 PDT 2022


Author: Jez Ng
Date: 2022-06-12T10:03:56-04:00
New Revision: ef501bf85d8c869248e51371f0e74bcec0e7b229

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

LOG: [MC] Omit DWARF unwind info if compact unwind is present where eligible

Previously, omitting unnecessary DWARF unwinds was only done in two
cases:
* For Darwin + aarch64, if no DWARF unwind info is needed for all the
  functions in a TU, then the `__eh_frame` section would be omitted
  entirely. If any one function needed DWARF unwind, then MC would emit
  DWARF unwind entries for all the functions in the TU.
* For watchOS, MC would omit DWARF unwind on a per-function basis, as
  long as compact unwind was available for that function.

This diff makes it so that we omit DWARF unwind on a per-function basis
for Darwin + aarch64 as well. In addition, we introduce the flag
`--emit-dwarf-unwind=` which can toggle between `always`,
`no-compact-unwind` (only emit DWARF when CU cannot be emitted for a
given function), and the target platform `default`.  `no-compact-unwind`
is particularly useful for newer x86_64 platforms: we don't want to omit
DWARF unwind for x86_64 in general due to possible backwards compat
issues, but we should make it possible for people to opt into this
behavior if they are only targeting newer platforms.

**Motivation:** I'm working on adding support for `__eh_frame` to LLD,
but I'm concerned that we would suffer a perf hit. Processing compact
unwind is already expensive, and that's a simpler format than EH frames.
Given that MC currently produces one EH frame entry for every compact
unwind entry, I don't think processing them will be cheap. I tried to do
something clever on LLD's end to drop the unnecessary EH frames at parse
time, but this made the code significantly more complex. So I'm looking
at fixing this at the MC level instead.

**Addendum:** It turns out that there was a latent bug in the X86
backend when `OmitDwarfIfHaveCompactUnwind` is naively enabled, which is
not too surprising given that this combination has not been heretofore
used.

For functions that have unwind info that cannot be encoded with CU, MC
would end up dropping both the compact unwind entry (OK; existing
behavior) as well as the DWARF entries (not OK).  This diff fixes things
so that we emit the DWARF entry, as well as a CU entry with encoding
`UNWIND_X86_MODE_DWARF` -- this basically tells the unwinder to look for
the DWARF entry. I'm not 100% sure the `UNWIND_X86_MODE_DWARF` CU entry
is necessary, this was the simplest fix. ld64 seems to be able to handle
both the absence and presence of this CU entry. Ultimately ld64 (and
LLD) will synthesize `UNWIND_X86_MODE_DWARF` if it is absent, so there
is no impact to the final binary size.

Reviewed By: davide, lhames

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

Added: 
    clang/test/Driver/femit-dwarf-unwind.c
    clang/test/Driver/femit-dwarf-unwind.s
    llvm/test/MC/MachO/emit-dwarf-unwind.s
    llvm/test/MC/X86/compact-unwind-mode-dwarf.s

Modified: 
    clang/include/clang/Basic/CodeGenOptions.def
    clang/include/clang/Driver/Options.td
    clang/lib/CodeGen/BackendUtil.cpp
    clang/lib/Driver/ToolChains/Clang.cpp
    clang/tools/driver/cc1as_main.cpp
    llvm/include/llvm/MC/MCContext.h
    llvm/include/llvm/MC/MCTargetOptions.h
    llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h
    llvm/lib/CodeGen/LLVMTargetMachine.cpp
    llvm/lib/CodeGen/MachineModuleInfo.cpp
    llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp
    llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp
    llvm/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp
    llvm/lib/MC/MCContext.cpp
    llvm/lib/MC/MCDwarf.cpp
    llvm/lib/MC/MCObjectFileInfo.cpp
    llvm/lib/MC/MCTargetOptions.cpp
    llvm/lib/MC/MCTargetOptionsCommandFlags.cpp
    llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index d8f667dc387bb..8e89106993c26 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -114,6 +114,10 @@ CODEGENOPT(StackSizeSection  , 1, 0) ///< Set when -fstack-size-section is enabl
 CODEGENOPT(ForceDwarfFrameSection , 1, 0) ///< Set when -fforce-dwarf-frame is
                                           ///< enabled.
 
+///< Set when -femit-dwarf-unwind is passed.
+ENUM_CODEGENOPT(EmitDwarfUnwind, llvm::EmitDwarfUnwindType, 2,
+                llvm::EmitDwarfUnwindType::Default)
+
 ///< Set when -fxray-always-emit-customevents is enabled.
 CODEGENOPT(XRayAlwaysEmitCustomEvents , 1, 0)
 

diff  --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 95840760f7746..002cd6cc8cb17 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3044,6 +3044,13 @@ def fmacro_prefix_map_EQ
 defm force_dwarf_frame : BoolFOption<"force-dwarf-frame",
   CodeGenOpts<"ForceDwarfFrameSection">, DefaultFalse,
   PosFlag<SetTrue, [CC1Option], "Always emit a debug frame section">, NegFlag<SetFalse>>;
+def femit_dwarf_unwind_EQ : Joined<["-"], "femit-dwarf-unwind=">,
+  Group<f_Group>, Flags<[CC1Option, CC1AsOption]>,
+  HelpText<"When to emit DWARF unwind (EH frame) info">,
+  Values<"always,no-compact-unwind,default">,
+  NormalizedValues<["Always", "NoCompactUnwind", "Default"]>,
+  NormalizedValuesScope<"llvm::EmitDwarfUnwindType">,
+  MarshallingInfoEnum<CodeGenOpts<"EmitDwarfUnwind">, "Default">;
 def g_Flag : Flag<["-"], "g">, Group<g_Group>,
   HelpText<"Generate source-level debug information">;
 def gline_tables_only : Flag<["-"], "gline-tables-only">, Group<gN_Group>,

diff  --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 0de15b1e48078..4b294c254e476 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -453,6 +453,7 @@ static bool initTargetOptions(DiagnosticsEngine &Diags,
   }
 
   Options.MCOptions.SplitDwarfFile = CodeGenOpts.SplitDwarfFile;
+  Options.MCOptions.EmitDwarfUnwind = CodeGenOpts.getEmitDwarfUnwind();
   Options.MCOptions.MCRelaxAll = CodeGenOpts.RelaxAll;
   Options.MCOptions.MCSaveTempLabels = CodeGenOpts.SaveTempLabels;
   Options.MCOptions.MCUseDwarfDirectory =

diff  --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index ceac142653ebe..62e891ce38c49 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -2518,6 +2518,8 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
                    DefaultIncrementalLinkerCompatible))
     CmdArgs.push_back("-mincremental-linker-compatible");
 
+  Args.AddLastArg(CmdArgs, options::OPT_femit_dwarf_unwind_EQ);
+
   // If you add more args here, also add them to the block below that
   // starts with "// If CollectArgsForIntegratedAssembler() isn't called below".
 
@@ -4622,6 +4624,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
     }
     Args.ClaimAllArgs(options::OPT_Wa_COMMA);
     Args.ClaimAllArgs(options::OPT_Xassembler);
+    Args.ClaimAllArgs(options::OPT_femit_dwarf_unwind_EQ);
   }
 
   if (isa<AnalyzeJobAction>(JA)) {

diff  --git a/clang/test/Driver/femit-dwarf-unwind.c b/clang/test/Driver/femit-dwarf-unwind.c
new file mode 100644
index 0000000000000..3101e1db7b9d4
--- /dev/null
+++ b/clang/test/Driver/femit-dwarf-unwind.c
@@ -0,0 +1,12 @@
+// RUN: rm -rf %t; mkdir %t
+// RUN: %clang -target x86_64-apple-macos11.0 -c %s -o %t/x86_64.o
+// RUN: %clang -target x86_64-apple-macos11.0 -femit-dwarf-unwind=no-compact-unwind -c %s -o %t/x86_64-no-dwarf.o
+// RUN: llvm-objdump --macho --dwarf=frames %t/x86_64.o | FileCheck %s --check-prefix=WITH-FDE
+// RUN: llvm-objdump --macho --dwarf=frames %t/x86_64-no-dwarf.o | FileCheck %s --check-prefix=NO-FDE
+
+// WITH-FDE: FDE
+// NO-FDE-NOT: FDE
+
+int foo() {
+  return 1;
+}

diff  --git a/clang/test/Driver/femit-dwarf-unwind.s b/clang/test/Driver/femit-dwarf-unwind.s
new file mode 100644
index 0000000000000..881925c76abd4
--- /dev/null
+++ b/clang/test/Driver/femit-dwarf-unwind.s
@@ -0,0 +1,15 @@
+// RUN: rm -rf %t; mkdir %t
+// RUN: %clang -target x86_64-apple-macos11.0 -c %s -o %t/x86_64.o
+// RUN: %clang -target x86_64-apple-macos11.0 -femit-dwarf-unwind=no-compact-unwind -c %s -o %t/x86_64-no-dwarf.o
+// RUN: llvm-objdump --macho --dwarf=frames %t/x86_64.o | FileCheck %s --check-prefix=WITH-FDE
+// RUN: llvm-objdump --macho --dwarf=frames %t/x86_64-no-dwarf.o | FileCheck %s --check-prefix=NO-FDE
+
+// WITH-FDE: FDE
+// NO-FDE-NOT: FDE
+
+.text
+_foo:
+  .cfi_startproc
+  .cfi_def_cfa_offset 8
+  ret
+  .cfi_endproc

diff  --git a/clang/tools/driver/cc1as_main.cpp b/clang/tools/driver/cc1as_main.cpp
index 6a11c25553ba3..264f747d6d740 100644
--- a/clang/tools/driver/cc1as_main.cpp
+++ b/clang/tools/driver/cc1as_main.cpp
@@ -137,6 +137,9 @@ struct AssemblerInvocation {
   unsigned IncrementalLinkerCompatible : 1;
   unsigned EmbedBitcode : 1;
 
+  /// Whether to emit DWARF unwind info.
+  EmitDwarfUnwindType EmitDwarfUnwind;
+
   /// The name of the relocation model to use.
   std::string RelocationModel;
 
@@ -317,6 +320,14 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
                             .Default(0);
   }
 
+  if (auto *A = Args.getLastArg(OPT_femit_dwarf_unwind_EQ)) {
+    Opts.EmitDwarfUnwind =
+        llvm::StringSwitch<EmitDwarfUnwindType>(A->getValue())
+            .Case("always", EmitDwarfUnwindType::Always)
+            .Case("no-compact-unwind", EmitDwarfUnwindType::NoCompactUnwind)
+            .Case("default", EmitDwarfUnwindType::Default);
+  }
+
   return Success;
 }
 
@@ -367,6 +378,8 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
   assert(MRI && "Unable to create target register info!");
 
   MCTargetOptions MCOptions;
+  MCOptions.EmitDwarfUnwind = Opts.EmitDwarfUnwind;
+
   std::unique_ptr<MCAsmInfo> MAI(
       TheTarget->createMCAsmInfo(*MRI, Opts.Triple, MCOptions));
   assert(MAI && "Unable to create target asm info!");

diff  --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h
index 5b81ba31b83c5..c3a4e57fdd753 100644
--- a/llvm/include/llvm/MC/MCContext.h
+++ b/llvm/include/llvm/MC/MCContext.h
@@ -67,6 +67,7 @@ template <typename T> class SmallVectorImpl;
 class SMDiagnostic;
 class SMLoc;
 class SourceMgr;
+enum class EmitDwarfUnwindType;
 
 /// Context object for machine code objects.  This class owns all of the
 /// sections that it creates.
@@ -772,6 +773,7 @@ class MCContext {
   bool getGenDwarfForAssembly() { return GenDwarfForAssembly; }
   void setGenDwarfForAssembly(bool Value) { GenDwarfForAssembly = Value; }
   unsigned getGenDwarfFileNumber() { return GenDwarfFileNumber; }
+  EmitDwarfUnwindType emitDwarfUnwindInfo() const;
 
   void setGenDwarfFileNumber(unsigned FileNumber) {
     GenDwarfFileNumber = FileNumber;

diff  --git a/llvm/include/llvm/MC/MCTargetOptions.h b/llvm/include/llvm/MC/MCTargetOptions.h
index 93712a6b7d44b..9c906cdc90d02 100644
--- a/llvm/include/llvm/MC/MCTargetOptions.h
+++ b/llvm/include/llvm/MC/MCTargetOptions.h
@@ -31,6 +31,12 @@ enum class DebugCompressionType {
   Z,    ///< zlib style complession
 };
 
+enum class EmitDwarfUnwindType {
+  Always,          // Always emit dwarf unwind
+  NoCompactUnwind, // Only emit if compact unwind isn't available
+  Default,         // Default behavior is based on the target
+};
+
 class StringRef;
 
 class MCTargetOptions {
@@ -56,6 +62,9 @@ class MCTargetOptions {
   bool PreserveAsmComments : 1;
 
   bool Dwarf64 : 1;
+
+  EmitDwarfUnwindType EmitDwarfUnwind;
+
   int DwarfVersion = 0;
 
   enum DwarfDirectory {

diff  --git a/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h b/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h
index 1894841989166..d51e740177f77 100644
--- a/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h
+++ b/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h
@@ -20,6 +20,7 @@
 namespace llvm {
 
 class MCTargetOptions;
+enum class EmitDwarfUnwindType;
 
 namespace mc {
 
@@ -32,6 +33,8 @@ int getDwarfVersion();
 
 bool getDwarf64();
 
+EmitDwarfUnwindType getEmitDwarfUnwind();
+
 bool getShowMCInst();
 
 bool getFatalWarnings();

diff  --git a/llvm/lib/CodeGen/LLVMTargetMachine.cpp b/llvm/lib/CodeGen/LLVMTargetMachine.cpp
index af05dbced04e1..3192dcadb5f5e 100644
--- a/llvm/lib/CodeGen/LLVMTargetMachine.cpp
+++ b/llvm/lib/CodeGen/LLVMTargetMachine.cpp
@@ -264,6 +264,9 @@ bool LLVMTargetMachine::addPassesToEmitMC(PassManagerBase &PM, MCContext *&Ctx,
          "Cannot emit MC with limited codegen pipeline");
 
   Ctx = &MMIWP->getMMI().getContext();
+  // libunwind is unable to load compact unwind dynamically, so we must generate
+  // DWARF unwind info for the JIT.
+  Options.MCOptions.EmitDwarfUnwind = EmitDwarfUnwindType::Always;
   if (Options.MCOptions.MCSaveTempLabels)
     Ctx->setAllowTemporaryLabels(false);
 

diff  --git a/llvm/lib/CodeGen/MachineModuleInfo.cpp b/llvm/lib/CodeGen/MachineModuleInfo.cpp
index 07ada255eb83d..23d55a5df9f57 100644
--- a/llvm/lib/CodeGen/MachineModuleInfo.cpp
+++ b/llvm/lib/CodeGen/MachineModuleInfo.cpp
@@ -60,7 +60,7 @@ MachineModuleInfo::MachineModuleInfo(MachineModuleInfo &&MMI)
     : TM(std::move(MMI.TM)),
       Context(MMI.TM.getTargetTriple(), MMI.TM.getMCAsmInfo(),
               MMI.TM.getMCRegisterInfo(), MMI.TM.getMCSubtargetInfo(), nullptr,
-              nullptr, false),
+              &MMI.TM.Options.MCOptions, false),
       MachineFunctions(std::move(MMI.MachineFunctions)) {
   Context.setObjectFileInfo(MMI.TM.getObjFileLowering());
   ObjFileMMI = MMI.ObjFileMMI;
@@ -72,7 +72,7 @@ MachineModuleInfo::MachineModuleInfo(MachineModuleInfo &&MMI)
 MachineModuleInfo::MachineModuleInfo(const LLVMTargetMachine *TM)
     : TM(*TM), Context(TM->getTargetTriple(), TM->getMCAsmInfo(),
                        TM->getMCRegisterInfo(), TM->getMCSubtargetInfo(),
-                       nullptr, nullptr, false) {
+                       nullptr, &TM->Options.MCOptions, false) {
   Context.setObjectFileInfo(TM->getObjFileLowering());
   initialize();
 }
@@ -81,7 +81,7 @@ MachineModuleInfo::MachineModuleInfo(const LLVMTargetMachine *TM,
                                      MCContext *ExtContext)
     : TM(*TM), Context(TM->getTargetTriple(), TM->getMCAsmInfo(),
                        TM->getMCRegisterInfo(), TM->getMCSubtargetInfo(),
-                       nullptr, nullptr, false),
+                       nullptr, &TM->Options.MCOptions, false),
       ExternalContext(ExtContext) {
   Context.setObjectFileInfo(TM->getObjFileLowering());
   initialize();

diff  --git a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp
index ed912280ac826..4ac901daa5c83 100644
--- a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp
+++ b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp
@@ -19,6 +19,7 @@
 #include "llvm/IR/LegacyPassManager.h"
 #include "llvm/IR/Mangler.h"
 #include "llvm/IR/Module.h"
+#include "llvm/MC/MCContext.h"
 #include "llvm/Object/Archive.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Support/DynamicLibrary.h"

diff  --git a/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp b/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp
index f342470052581..fad7428e1f906 100644
--- a/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp
@@ -12,6 +12,7 @@
 #include "llvm/ExecutionEngine/ObjectCache.h"
 #include "llvm/IR/LegacyPassManager.h"
 #include "llvm/IR/Module.h"
+#include "llvm/MC/MCContext.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/ErrorHandling.h"

diff  --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp
index 820d1dbad8f20..bc42eebf3fec9 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp
@@ -95,18 +95,16 @@ void RTDyldMemoryManager::registerEHFramesInProcess(uint8_t *Addr,
   // and projects/libunwind/src/UnwindLevel1-gcc-ext.c.
   const char *P = (const char *)Addr;
   const char *End = P + Size;
-  do  {
+  while (P != End)
     P = processFDE(P, false);
-  } while(P != End);
 }
 
 void RTDyldMemoryManager::deregisterEHFramesInProcess(uint8_t *Addr,
                                                       size_t Size) {
   const char *P = (const char *)Addr;
   const char *End = P + Size;
-  do  {
+  while (P != End)
     P = processFDE(P, true);
-  } while(P != End);
 }
 
 #else

diff  --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp
index 887969fcd8410..52bf48b6d242b 100644
--- a/llvm/lib/MC/MCContext.cpp
+++ b/llvm/lib/MC/MCContext.cpp
@@ -877,6 +877,12 @@ void MCContext::RemapDebugPaths() {
 // Dwarf Management
 //===----------------------------------------------------------------------===//
 
+EmitDwarfUnwindType MCContext::emitDwarfUnwindInfo() const {
+  if (!TargetOptions)
+    return EmitDwarfUnwindType::Default;
+  return TargetOptions->EmitDwarfUnwind;
+}
+
 void MCContext::setGenDwarfRootFile(StringRef InputFileName, StringRef Buffer) {
   // MCDwarf needs the root file as well as the compilation directory.
   // If we find a '.file 0' directive that will supersede these values.

diff  --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp
index 6152b3e5210e2..d151b8b3f89a6 100644
--- a/llvm/lib/MC/MCDwarf.cpp
+++ b/llvm/lib/MC/MCDwarf.cpp
@@ -1842,8 +1842,6 @@ template <> struct DenseMapInfo<CIEKey> {
 
 void MCDwarfFrameEmitter::Emit(MCObjectStreamer &Streamer, MCAsmBackend *MAB,
                                bool IsEH) {
-  Streamer.generateCompactUnwindEncodings(MAB);
-
   MCContext &Context = Streamer.getContext();
   const MCObjectFileInfo *MOFI = Context.getObjectFileInfo();
   const MCAsmInfo *AsmInfo = Context.getAsmInfo();
@@ -1853,6 +1851,7 @@ void MCDwarfFrameEmitter::Emit(MCObjectStreamer &Streamer, MCAsmBackend *MAB,
   // Emit the compact unwind info if available.
   bool NeedsEHFrameSection = !MOFI->getSupportsCompactUnwindWithoutEHFrame();
   if (IsEH && MOFI->getCompactUnwindSection()) {
+    Streamer.generateCompactUnwindEncodings(MAB);
     bool SectionEmitted = false;
     for (const MCDwarfFrameInfo &Frame : FrameArray) {
       if (Frame.CompactUnwindEncoding == 0) continue;

diff  --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp
index 0d08976d98942..bb39e5aaad7f4 100644
--- a/llvm/lib/MC/MCObjectFileInfo.cpp
+++ b/llvm/lib/MC/MCObjectFileInfo.cpp
@@ -64,8 +64,18 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(const Triple &T) {
       (T.getArch() == Triple::aarch64 || T.getArch() == Triple::aarch64_32))
     SupportsCompactUnwindWithoutEHFrame = true;
 
-  if (T.isWatchABI())
+  switch (Ctx->emitDwarfUnwindInfo()) {
+  case EmitDwarfUnwindType::Always:
+    OmitDwarfIfHaveCompactUnwind = false;
+    break;
+  case EmitDwarfUnwindType::NoCompactUnwind:
     OmitDwarfIfHaveCompactUnwind = true;
+    break;
+  case EmitDwarfUnwindType::Default:
+    OmitDwarfIfHaveCompactUnwind =
+        T.isWatchABI() || SupportsCompactUnwindWithoutEHFrame;
+    break;
+  }
 
   FDECFIEncoding = dwarf::DW_EH_PE_pcrel;
 

diff  --git a/llvm/lib/MC/MCTargetOptions.cpp b/llvm/lib/MC/MCTargetOptions.cpp
index bb48182c6622b..c2946da3ee66f 100644
--- a/llvm/lib/MC/MCTargetOptions.cpp
+++ b/llvm/lib/MC/MCTargetOptions.cpp
@@ -17,6 +17,7 @@ MCTargetOptions::MCTargetOptions()
       MCSaveTempLabels(false), MCIncrementalLinkerCompatible(false),
       ShowMCEncoding(false), ShowMCInst(false), AsmVerbose(false),
       PreserveAsmComments(true), Dwarf64(false),
+      EmitDwarfUnwind(EmitDwarfUnwindType::Default),
       MCUseDwarfDirectory(DefaultDwarfDirectory) {}
 
 StringRef MCTargetOptions::getABIName() const {

diff  --git a/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp b/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp
index 762c8d43063c7..a310dc894021f 100644
--- a/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp
+++ b/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp
@@ -1,5 +1,4 @@
-//===-- MCTargetOptionsCommandFlags.cpp --------------------------*- C++
-//-*-===//
+//===-- MCTargetOptionsCommandFlags.cpp -----------------------*- C++ //-*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -39,6 +38,7 @@ MCOPT_EXP(bool, RelaxAll)
 MCOPT(bool, IncrementalLinkerCompatible)
 MCOPT(int, DwarfVersion)
 MCOPT(bool, Dwarf64)
+MCOPT(EmitDwarfUnwindType, EmitDwarfUnwind)
 MCOPT(bool, ShowMCInst)
 MCOPT(bool, FatalWarnings)
 MCOPT(bool, NoWarn)
@@ -73,6 +73,19 @@ llvm::mc::RegisterMCTargetOptionsFlags::RegisterMCTargetOptionsFlags() {
       cl::desc("Generate debugging info in the 64-bit DWARF format"));
   MCBINDOPT(Dwarf64);
 
+  static cl::opt<EmitDwarfUnwindType> EmitDwarfUnwind(
+      "emit-dwarf-unwind", cl::desc("Whether to emit DWARF EH frame entries."),
+      cl::init(EmitDwarfUnwindType::Default),
+      cl::values(clEnumValN(EmitDwarfUnwindType::Always, "always",
+                            "Always emit EH frame entries"),
+                 clEnumValN(EmitDwarfUnwindType::NoCompactUnwind,
+                            "no-compact-unwind",
+                            "Only emit EH frame entries when compact unwind is "
+                            "not available"),
+                 clEnumValN(EmitDwarfUnwindType::Default, "default",
+                            "Use target platform default")));
+  MCBINDOPT(EmitDwarfUnwind);
+
   static cl::opt<bool> ShowMCInst(
       "asm-show-inst",
       cl::desc("Emit internal instruction representation to assembly file"));
@@ -116,5 +129,7 @@ MCTargetOptions llvm::mc::InitMCTargetOptionsFromFlags() {
   Options.MCNoWarn = getNoWarn();
   Options.MCNoDeprecatedWarn = getNoDeprecatedWarn();
   Options.MCNoTypeCheck = getNoTypeCheck();
+  Options.EmitDwarfUnwind = getEmitDwarfUnwind();
+
   return Options;
 }

diff  --git a/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
index f09c3b36ff3a8..2d92b8d5b574b 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
@@ -1377,7 +1377,7 @@ class DarwinX86AsmBackend : public X86AsmBackend {
       default:
         // Any other CFI directives indicate a frame that we aren't prepared
         // to represent via compact unwind, so just bail out.
-        return 0;
+        return CU::UNWIND_MODE_DWARF;
       case MCCFIInstruction::OpDefCfaRegister: {
         // Defines a frame pointer. E.g.
         //
@@ -1391,7 +1391,7 @@ class DarwinX86AsmBackend : public X86AsmBackend {
         // generate a compact unwinding representation, so bail out.
         if (*MRI.getLLVMRegNum(Inst.getRegister(), true) !=
             (Is64Bit ? X86::RBP : X86::EBP))
-          return 0;
+          return CU::UNWIND_MODE_DWARF;
 
         // Reset the counts.
         memset(SavedRegs, 0, sizeof(SavedRegs));

diff  --git a/llvm/test/MC/MachO/emit-dwarf-unwind.s b/llvm/test/MC/MachO/emit-dwarf-unwind.s
new file mode 100644
index 0000000000000..89dc56b8aa87f
--- /dev/null
+++ b/llvm/test/MC/MachO/emit-dwarf-unwind.s
@@ -0,0 +1,33 @@
+// RUN: rm -rf %t; mkdir %t
+// RUN: llvm-mc -triple x86_64-apple-macos11.0 %s -filetype=obj -o %t/x86_64.o
+// RUN: llvm-objdump --macho --dwarf=frames %t/x86_64.o | FileCheck %s --check-prefix TWO-FDES
+// RUN: llvm-mc -triple arm64-apple-macos11.0 %s -filetype=obj -o %t/arm64.o
+// RUN: llvm-objdump --macho --dwarf=frames %t/arm64.o | FileCheck %s --check-prefix ONE-FDE
+// RUN: llvm-mc -triple x86_64-apple-macos11.0 %s -filetype=obj --emit-dwarf-unwind no-compact-unwind -o %t/x86_64-no-dwarf.o
+// RUN: llvm-objdump --macho --dwarf=frames %t/x86_64-no-dwarf.o | FileCheck %s --check-prefix ONE-FDE
+// RUN: llvm-mc -triple arm64-apple-macos11.0 %s -filetype=obj --emit-dwarf-unwind always -o %t/arm64-dwarf.o
+// RUN: llvm-objdump --macho --dwarf=frames %t/arm64-dwarf.o | FileCheck %s --check-prefix TWO-FDES
+
+// TWO-FDES: FDE
+// TWO-FDES: FDE
+
+// ONE-FDE-NOT: FDE
+// ONE-FDE:     FDE
+// ONE-FDE-NOT: FDE
+
+_main:
+  .cfi_startproc
+  .cfi_def_cfa_offset 16
+  ret
+  .cfi_endproc
+
+_foo:
+  .cfi_startproc
+  .cfi_def_cfa_offset 16
+  /// This encodes DW_CFA_GNU_args_size which cannot be expressed using compact
+  /// unwind, so we must use DWARf unwind for this function.
+  .cfi_escape 0x2e, 0x10
+  ret
+  .cfi_endproc
+
+.subsections_via_symbols

diff  --git a/llvm/test/MC/X86/compact-unwind-mode-dwarf.s b/llvm/test/MC/X86/compact-unwind-mode-dwarf.s
new file mode 100644
index 0000000000000..ca051b07b59ef
--- /dev/null
+++ b/llvm/test/MC/X86/compact-unwind-mode-dwarf.s
@@ -0,0 +1,50 @@
+// RUN: llvm-mc -triple x86_64-apple-macos10.6 -filetype=obj %s -o %t.o
+// RUN: llvm-objdump --macho --unwind-info --dwarf=frames %t.o | FileCheck %s
+
+/// For functions whose unwind info cannot be encoded with compact unwind, make
+/// sure that we encode them using DWARF unwind, and make sure we emit a compact
+/// unwind entry that indicates that a DWARF encoding is being used.
+
+_f:
+  .cfi_startproc
+  ## This encodes DW_CFA_GNU_args_size which cannot be expressed using compact
+  ## unwind, so we must use DWARF unwind instead.
+  .cfi_escape 0x2e, 0x10
+  ret
+  .cfi_endproc
+
+_g:
+  .cfi_startproc
+  ## This encodes DW_CFA_GNU_args_size which cannot be expressed using compact
+  ## unwind, so we must use DWARF unwind instead.
+  .cfi_escape 0x2e, 0x10
+  ret
+  .cfi_endproc
+
+// CHECK: Contents of __compact_unwind section:
+// CHECK:   Entry at offset 0x0:
+// CHECK:     start:                0x[[#%x,F:]] _f
+// CHECK:     length:               0x1
+// CHECK:     compact encoding:     0x04000000
+// CHECK:   Entry at offset 0x20:
+// CHECK:     start:                0x[[#%x,G:]] _g
+// CHECK:     length:               0x1
+// CHECK:     compact encoding:     0x04000000
+
+// CHECK: .eh_frame contents:
+// CHECK: 00000000 00000014 00000000 CIE
+// CHECK:   Format:                DWARF32
+// CHECK:   Version:               1
+// CHECK:   Augmentation:          "zR"
+// CHECK:   Code alignment factor: 1
+// CHECK:   Data alignment factor: -8
+// CHECK:   Return address column: 16
+// CHECK:   Augmentation data:     10
+
+// CHECK: FDE cie=00000000 pc=[[#%.8x,F]]...
+// CHECK:   Format:       DWARF32
+// CHECK:   DW_CFA_GNU_args_size: +16
+
+// CHECK: FDE cie=00000000 pc=[[#%.8x,G]]...
+// CHECK:   Format:       DWARF32
+// CHECK:   DW_CFA_GNU_args_size: +16


        


More information about the llvm-commits mailing list