diff --git a/llvm/include/llvm/MC/MCAsmBackend.h b/llvm/include/llvm/MC/MCAsmBackend.h --- a/llvm/include/llvm/MC/MCAsmBackend.h +++ b/llvm/include/llvm/MC/MCAsmBackend.h @@ -25,7 +25,8 @@ class MCSymbol; class MCAsmLayout; class MCAssembler; -class MCCFIInstruction; +class MCContext; +class MCDwarfFrameInfo; struct MCFixupKindInfo; class MCInst; class MCObjectStreamer; @@ -210,8 +211,8 @@ virtual void handleAssemblerFlag(MCAssemblerFlag Flag) {} /// Generate the compact unwind encoding for the CFI instructions. - virtual uint32_t - generateCompactUnwindEncoding(ArrayRef) const { + virtual uint32_t generateCompactUnwindEncoding(const MCDwarfFrameInfo *FI, + const MCContext *Ctxt) const { return 0; } @@ -219,6 +220,8 @@ virtual bool isMicroMips(const MCSymbol *Sym) const { return false; } + + bool isDarwinCanonicalPersonality(const MCSymbol *Sym) const; }; } // end namespace llvm diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h --- a/llvm/include/llvm/MC/MCContext.h +++ b/llvm/include/llvm/MC/MCContext.h @@ -788,6 +788,7 @@ void setGenDwarfForAssembly(bool Value) { GenDwarfForAssembly = Value; } unsigned getGenDwarfFileNumber() { return GenDwarfFileNumber; } EmitDwarfUnwindType emitDwarfUnwindInfo() const; + bool emitCompactUnwindNonCanonical() const; void setGenDwarfFileNumber(unsigned FileNumber) { GenDwarfFileNumber = FileNumber; diff --git a/llvm/include/llvm/MC/MCTargetOptions.h b/llvm/include/llvm/MC/MCTargetOptions.h --- a/llvm/include/llvm/MC/MCTargetOptions.h +++ b/llvm/include/llvm/MC/MCTargetOptions.h @@ -85,6 +85,10 @@ /// integrated assembler. std::vector IASSearchPaths; + // Whether to emit compact-unwind for non-canonical personality + // functions on Darwins. + bool EmitCompactUnwindNonCanonical : 1; + MCTargetOptions(); /// getABIName - If this returns a non-empty string this represents the diff --git a/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h b/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h --- a/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h +++ b/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h @@ -35,6 +35,8 @@ EmitDwarfUnwindType getEmitDwarfUnwind(); +bool getEmitCompactUnwindNonCanonical(); + bool getShowMCInst(); bool getFatalWarnings(); diff --git a/llvm/lib/MC/MCAsmBackend.cpp b/llvm/lib/MC/MCAsmBackend.cpp --- a/llvm/lib/MC/MCAsmBackend.cpp +++ b/llvm/lib/MC/MCAsmBackend.cpp @@ -115,3 +115,12 @@ return true; return fixupNeedsRelaxation(Fixup, Value, DF, Layout); } + +bool MCAsmBackend::isDarwinCanonicalPersonality(const MCSymbol *Sym) const { + if (Sym && Sym->isMachO() && Sym->isExternal()) { + StringRef name = Sym->getName(); + return name.compare("__gxx_personality_v0,") == 0 || + name.compare("__objc_personality_v0") == 0; + } + return false; +} diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp --- a/llvm/lib/MC/MCContext.cpp +++ b/llvm/lib/MC/MCContext.cpp @@ -928,6 +928,12 @@ return TargetOptions->EmitDwarfUnwind; } +bool MCContext::emitCompactUnwindNonCanonical() const { + if (TargetOptions) + return TargetOptions->EmitCompactUnwindNonCanonical; + return false; +} + 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/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp --- a/llvm/lib/MC/MCStreamer.cpp +++ b/llvm/lib/MC/MCStreamer.cpp @@ -126,7 +126,7 @@ void MCStreamer::generateCompactUnwindEncodings(MCAsmBackend *MAB) { for (auto &FI : DwarfFrameInfos) FI.CompactUnwindEncoding = - (MAB ? MAB->generateCompactUnwindEncoding(FI.Instructions) : 0); + (MAB ? MAB->generateCompactUnwindEncoding(&FI, &Context) : 0); } /// EmitIntValue - Special case of EmitValue that avoids the client having to diff --git a/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp b/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp --- a/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp +++ b/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp @@ -39,6 +39,7 @@ MCOPT(int, DwarfVersion) MCOPT(bool, Dwarf64) MCOPT(EmitDwarfUnwindType, EmitDwarfUnwind) +MCOPT(bool, EmitCompactUnwindNonCanonical) MCOPT(bool, ShowMCInst) MCOPT(bool, FatalWarnings) MCOPT(bool, NoWarn) @@ -87,6 +88,13 @@ "Use target platform default"))); MCBINDOPT(EmitDwarfUnwind); + static cl::opt EmitCompactUnwindNonCanonical( + "emit-compact-unwind-non-canonical", + cl::desc( + "Whether to try to emit Compact Unwind for non canonical entries."), + cl::init(false)); // no CU for non-canonical by default + MCBINDOPT(EmitCompactUnwindNonCanonical); + static cl::opt ShowMCInst( "asm-show-inst", cl::desc("Emit internal instruction representation to assembly file")); @@ -135,6 +143,7 @@ Options.MCNoDeprecatedWarn = getNoDeprecatedWarn(); Options.MCNoTypeCheck = getNoTypeCheck(); Options.EmitDwarfUnwind = getEmitDwarfUnwind(); + Options.EmitCompactUnwindNonCanonical = getEmitCompactUnwindNonCanonical(); Options.AsSecureLogFile = getAsSecureLogFile(); return Options; diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp @@ -564,10 +564,14 @@ } /// Generate the compact unwind encoding from the CFI directives. - uint32_t generateCompactUnwindEncoding( - ArrayRef Instrs) const override { + uint32_t generateCompactUnwindEncoding(const MCDwarfFrameInfo *FI, + const MCContext *Ctxt) const override { + ArrayRef Instrs = FI->Instructions; if (Instrs.empty()) return CU::UNWIND_ARM64_MODE_FRAMELESS; + if (!isDarwinCanonicalPersonality(FI->Personality) && + !Ctxt->emitCompactUnwindNonCanonical()) + return 0; bool HasFP = false; unsigned StackSize = 0; diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp @@ -1109,14 +1109,19 @@ /// encoded in compact unwind, the method returns UNWIND_ARM_MODE_DWARF which /// tells the runtime to fallback and unwind using dwarf. uint32_t ARMAsmBackendDarwin::generateCompactUnwindEncoding( - ArrayRef Instrs) const { + const MCDwarfFrameInfo *FI, const MCContext *Ctxt) const { DEBUG_WITH_TYPE("compact-unwind", llvm::dbgs() << "generateCU()\n"); // Only armv7k uses CFI based unwinding. if (Subtype != MachO::CPU_SUBTYPE_ARM_V7K) return 0; // No .cfi directives means no frame. + ArrayRef Instrs = FI->Instructions; if (Instrs.empty()) return 0; + if (!isDarwinCanonicalPersonality(FI->Personality) && + !Ctxt->emitCompactUnwindNonCanonical()) + return 0; + // Start off assuming CFA is at SP+0. unsigned CFARegister = ARM::SP; int CFARegisterOffset = 0; diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackendDarwin.h b/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackendDarwin.h --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackendDarwin.h +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackendDarwin.h @@ -11,6 +11,7 @@ #include "ARMAsmBackend.h" #include "llvm/BinaryFormat/MachO.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCObjectWriter.h" namespace llvm { @@ -32,8 +33,8 @@ /*Is64Bit=*/false, cantFail(MachO::getCPUType(TT)), Subtype); } - uint32_t generateCompactUnwindEncoding( - ArrayRef Instrs) const override; + uint32_t generateCompactUnwindEncoding(const MCDwarfFrameInfo *FI, + const MCContext *Ctxt) const override; }; } // end namespace llvm diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp --- a/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp +++ b/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp @@ -1352,9 +1352,13 @@ /// Implementation of algorithm to generate the compact unwind encoding /// for the CFI instructions. - uint32_t - generateCompactUnwindEncoding(ArrayRef Instrs) const override { + uint32_t generateCompactUnwindEncoding(const MCDwarfFrameInfo *FI, + const MCContext *Ctxt) const override { + ArrayRef Instrs = FI->Instructions; if (Instrs.empty()) return 0; + if (!isDarwinCanonicalPersonality(FI->Personality) && + !Ctxt->emitCompactUnwindNonCanonical()) + return 0; // Reset the saved registers. unsigned SavedRegIdx = 0;