Skip to content

Commit 39beb38

Browse files
committed
[win][x64] Unwind v2 3/n: Add support for emitting unwind v2 information (equivalent to MSVC /d2epilogunwind)
1 parent 71478ec commit 39beb38

File tree

22 files changed

+903
-16
lines changed

22 files changed

+903
-16
lines changed

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,9 @@ CODEGENOPT(ImportCallOptimization, 1, 0)
476476
/// (BlocksRuntime) on Windows.
477477
CODEGENOPT(StaticClosure, 1, 0)
478478

479+
/// Enables unwind v2 (epilog) information for x64 Windows.
480+
CODEGENOPT(WinX64EHUnwindV2, 1, 0)
481+
479482
/// FIXME: Make DebugOptions its own top-level .def file.
480483
#include "DebugOptions.def"
481484

clang/include/clang/Driver/Options.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7613,6 +7613,10 @@ def import_call_optimization : Flag<["-"], "import-call-optimization">,
76137613
"by the Windows kernel to enable import call optimization">,
76147614
MarshallingInfoFlag<CodeGenOpts<"ImportCallOptimization">>;
76157615

7616+
def epilog_unwind : Flag<["-"], "winx64-eh-unwindv2">,
7617+
HelpText<"Enable unwind v2 (epilog) information for x64 Windows">,
7618+
MarshallingInfoFlag<CodeGenOpts<"WinX64EHUnwindV2">>;
7619+
76167620
} // let Visibility = [CC1Option]
76177621

76187622
//===----------------------------------------------------------------------===//
@@ -8725,6 +8729,8 @@ def _SLASH_M_Group : OptionGroup<"</M group>">, Group<cl_compile_Group>;
87258729
def _SLASH_volatile_Group : OptionGroup<"</volatile group>">,
87268730
Group<cl_compile_Group>;
87278731

8732+
def _SLASH_d2epilogunwind : CLFlag<"d2epilogunwind">,
8733+
HelpText<"Enable unwind v2 (epilog) information for x64 Windows">;
87288734
def _SLASH_EH : CLJoined<"EH">, HelpText<"Set exception handling model">;
87298735
def _SLASH_EP : CLFlag<"EP">,
87308736
HelpText<"Disable linemarker output and preprocess to stdout">;

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,6 +1302,10 @@ void CodeGenModule::Release() {
13021302
getModule().addModuleFlag(llvm::Module::Warning, "import-call-optimization",
13031303
1);
13041304

1305+
// Enable unwind v2 (epilog).
1306+
if (CodeGenOpts.WinX64EHUnwindV2)
1307+
getModule().addModuleFlag(llvm::Module::Warning, "winx64-eh-unwindv2", 1);
1308+
13051309
// Indicate whether this Module was compiled with -fopenmp
13061310
if (getLangOpts().OpenMP && !getLangOpts().OpenMPSimd)
13071311
getModule().addModuleFlag(llvm::Module::Max, "openmp", LangOpts.OpenMP);

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8532,6 +8532,9 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
85328532
if (Args.hasArg(options::OPT__SLASH_kernel))
85338533
CmdArgs.push_back("-fms-kernel");
85348534

8535+
if (Args.hasArg(options::OPT__SLASH_d2epilogunwind))
8536+
CmdArgs.push_back("-winx64-eh-unwindv2");
8537+
85358538
for (const Arg *A : Args.filtered(options::OPT__SLASH_guard)) {
85368539
StringRef GuardArgs = A->getValue();
85378540
// The only valid options are "cf", "cf,nochecks", "cf-", "ehcont" and

clang/test/CodeGen/epilog-unwind.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// RUN: %clang_cc1 -winx64-eh-unwindv2 -emit-llvm %s -o - | FileCheck %s
2+
3+
void f(void) {}
4+
5+
// CHECK: !"winx64-eh-unwindv2", i32 1}

clang/test/Driver/cl-options.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,4 +817,7 @@
817817
// RUN: %clang_cl -vctoolsdir "" /arm64EC /c -target x86_64-pc-windows-msvc -### -- %s 2>&1 | FileCheck --check-prefix=ARM64EC_OVERRIDE %s
818818
// ARM64EC_OVERRIDE: warning: /arm64EC has been overridden by specified target: x86_64-pc-windows-msvc; option ignored
819819

820+
// RUN: %clang_cl /d2epilogunwind /c -### -- %s 2>&1 | FileCheck %s --check-prefix=EPILOGUNWIND
821+
// EPILOGUNWIND: -winx64-eh-unwindv2
822+
820823
void f(void) { }

llvm/include/llvm/MC/MCStreamer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,8 @@ class MCStreamer {
10661066
virtual void emitWinCFIEndProlog(SMLoc Loc = SMLoc());
10671067
virtual void emitWinCFIBeginEpilogue(SMLoc Loc = SMLoc());
10681068
virtual void emitWinCFIEndEpilogue(SMLoc Loc = SMLoc());
1069+
virtual void emitWinCFIUnwindV2Start(SMLoc Loc = SMLoc());
1070+
virtual void emitWinCFIUnwindVersion(uint8_t Version, SMLoc Loc = SMLoc());
10691071
virtual void emitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except,
10701072
SMLoc Loc = SMLoc());
10711073
virtual void emitWinEHHandlerData(SMLoc Loc = SMLoc());

llvm/include/llvm/MC/MCWinEH.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define LLVM_MC_MCWINEH_H
1111

1212
#include "llvm/ADT/MapVector.h"
13+
#include "llvm/Support/SMLoc.h"
1314
#include <vector>
1415

1516
namespace llvm {
@@ -42,6 +43,7 @@ struct FrameInfo {
4243
const MCSymbol *FuncletOrFuncEnd = nullptr;
4344
const MCSymbol *ExceptionHandler = nullptr;
4445
const MCSymbol *Function = nullptr;
46+
SMLoc FunctionLoc;
4547
const MCSymbol *PrologEnd = nullptr;
4648
const MCSymbol *Symbol = nullptr;
4749
MCSection *TextSection = nullptr;
@@ -52,14 +54,18 @@ struct FrameInfo {
5254
bool HandlesExceptions = false;
5355
bool EmitAttempted = false;
5456
bool Fragment = false;
57+
constexpr static uint8_t DefaultVersion = 1;
58+
uint8_t Version = DefaultVersion;
5559

5660
int LastFrameInst = -1;
5761
const FrameInfo *ChainedParent = nullptr;
5862
std::vector<Instruction> Instructions;
5963
struct Epilog {
6064
std::vector<Instruction> Instructions;
6165
unsigned Condition;
62-
MCSymbol *End;
66+
const MCSymbol *End = nullptr;
67+
const MCSymbol *UnwindV2Start = nullptr;
68+
SMLoc Loc;
6369
};
6470
MapVector<MCSymbol *, Epilog> EpilogMap;
6571

llvm/lib/MC/MCAsmStreamer.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,8 @@ class MCAsmStreamer final : public MCStreamer {
399399
void emitWinCFIEndProlog(SMLoc Loc) override;
400400
void emitWinCFIBeginEpilogue(SMLoc Loc) override;
401401
void emitWinCFIEndEpilogue(SMLoc Loc) override;
402+
void emitWinCFIUnwindV2Start(SMLoc Loc) override;
403+
void emitWinCFIUnwindVersion(uint8_t Version, SMLoc Loc) override;
402404

403405
void emitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except,
404406
SMLoc Loc) override;
@@ -2351,6 +2353,20 @@ void MCAsmStreamer::emitWinCFIEndEpilogue(SMLoc Loc) {
23512353
EmitEOL();
23522354
}
23532355

2356+
void MCAsmStreamer::emitWinCFIUnwindV2Start(SMLoc Loc) {
2357+
MCStreamer::emitWinCFIUnwindV2Start(Loc);
2358+
2359+
OS << "\t.seh_unwindv2start";
2360+
EmitEOL();
2361+
}
2362+
2363+
void MCAsmStreamer::emitWinCFIUnwindVersion(uint8_t Version, SMLoc Loc) {
2364+
MCStreamer::emitWinCFIUnwindVersion(Version, Loc);
2365+
2366+
OS << "\t.seh_unwindversion " << (unsigned)Version;
2367+
EmitEOL();
2368+
}
2369+
23542370
void MCAsmStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From,
23552371
const MCSymbolRefExpr *To,
23562372
uint64_t Count) {

llvm/lib/MC/MCParser/COFFAsmParser.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ class COFFAsmParser : public MCAsmParserExtension {
9696
".seh_startepilogue");
9797
addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndEpilog>(
9898
".seh_endepilogue");
99+
addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveUnwindV2Start>(
100+
".seh_unwindv2start");
101+
addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveUnwindVersion>(
102+
".seh_unwindversion");
99103
}
100104

101105
bool parseSectionDirectiveText(StringRef, SMLoc) {
@@ -147,6 +151,8 @@ class COFFAsmParser : public MCAsmParserExtension {
147151
bool parseSEHDirectiveEndProlog(StringRef, SMLoc);
148152
bool ParseSEHDirectiveBeginEpilog(StringRef, SMLoc);
149153
bool ParseSEHDirectiveEndEpilog(StringRef, SMLoc);
154+
bool ParseSEHDirectiveUnwindV2Start(StringRef, SMLoc);
155+
bool ParseSEHDirectiveUnwindVersion(StringRef, SMLoc);
150156

151157
bool parseAtUnwindOrAtExcept(bool &unwind, bool &except);
152158
bool parseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
@@ -767,6 +773,28 @@ bool COFFAsmParser::ParseSEHDirectiveEndEpilog(StringRef, SMLoc Loc) {
767773
return false;
768774
}
769775

776+
bool COFFAsmParser::ParseSEHDirectiveUnwindV2Start(StringRef, SMLoc Loc) {
777+
Lex();
778+
getStreamer().emitWinCFIUnwindV2Start(Loc);
779+
return false;
780+
}
781+
782+
bool COFFAsmParser::ParseSEHDirectiveUnwindVersion(StringRef, SMLoc Loc) {
783+
int64_t Version;
784+
if (getParser().parseIntToken(Version, "expected unwind version number"))
785+
return true;
786+
787+
if ((Version < 1) || (Version > UINT8_MAX))
788+
return Error(Loc, "invalid unwind version");
789+
790+
if (getLexer().isNot(AsmToken::EndOfStatement))
791+
return TokError("unexpected token in directive");
792+
793+
Lex();
794+
getStreamer().emitWinCFIUnwindVersion(Version, Loc);
795+
return false;
796+
}
797+
770798
bool COFFAsmParser::parseAtUnwindOrAtExcept(bool &unwind, bool &except) {
771799
StringRef identifier;
772800
if (getLexer().isNot(AsmToken::At) && getLexer().isNot(AsmToken::Percent))

0 commit comments

Comments
 (0)