Skip to content

Commit 5d722bb

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

File tree

24 files changed

+923
-33
lines changed

24 files changed

+923
-33
lines changed

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,9 @@ CODEGENOPT(StaticClosure, 1, 0)
483483
/// Assume that UAVs/SRVs may alias
484484
CODEGENOPT(ResMayAlias, 1, 0)
485485

486+
/// Enables unwind v2 (epilog) information for x64 Windows.
487+
CODEGENOPT(WinX64EHUnwindV2, 1, 0)
488+
486489
/// FIXME: Make DebugOptions its own top-level .def file.
487490
#include "DebugOptions.def"
488491

clang/include/clang/Driver/Options.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2167,6 +2167,11 @@ defm assume_nothrow_exception_dtor: BoolFOption<"assume-nothrow-exception-dtor",
21672167
LangOpts<"AssumeNothrowExceptionDtor">, DefaultFalse,
21682168
PosFlag<SetTrue, [], [ClangOption, CC1Option], "Assume that exception objects' destructors are non-throwing">,
21692169
NegFlag<SetFalse>>;
2170+
defm winx64_eh_unwindv2 : BoolFOption<"winx64-eh-unwindv2",
2171+
CodeGenOpts<"WinX64EHUnwindV2">, DefaultFalse,
2172+
PosFlag<SetTrue, [], [ClangOption, CC1Option], "Enable">,
2173+
NegFlag<SetFalse, [], [ClangOption], "Disable">,
2174+
BothFlags<[], [ClangOption], " unwind v2 (epilog) information for x64 Windows">>;
21702175
def fexcess_precision_EQ : Joined<["-"], "fexcess-precision=">, Group<f_Group>,
21712176
Visibility<[ClangOption, CLOption]>,
21722177
HelpText<"Allows control over excess precision on targets where native "
@@ -8935,6 +8940,8 @@ def _SLASH_M_Group : OptionGroup<"</M group>">, Group<cl_compile_Group>;
89358940
def _SLASH_volatile_Group : OptionGroup<"</volatile group>">,
89368941
Group<cl_compile_Group>;
89378942

8943+
def _SLASH_d2epilogunwind : CLFlag<"d2epilogunwind">,
8944+
HelpText<"Enable unwind v2 (epilog) information for x64 Windows">;
89388945
def _SLASH_EH : CLJoined<"EH">, HelpText<"Set exception handling model">;
89398946
def _SLASH_EP : CLFlag<"EP">,
89408947
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
@@ -1307,6 +1307,10 @@ void CodeGenModule::Release() {
13071307
getModule().addModuleFlag(llvm::Module::Warning, "import-call-optimization",
13081308
1);
13091309

1310+
// Enable unwind v2 (epilog).
1311+
if (CodeGenOpts.WinX64EHUnwindV2)
1312+
getModule().addModuleFlag(llvm::Module::Warning, "winx64-eh-unwindv2", 1);
1313+
13101314
// Indicate whether this Module was compiled with -fopenmp
13111315
if (getLangOpts().OpenMP && !getLangOpts().OpenMPSimd)
13121316
getModule().addModuleFlag(llvm::Module::Max, "openmp", LangOpts.OpenMP);

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7503,6 +7503,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
75037503
}
75047504
}
75057505

7506+
// Unwind v2 (epilog) information for x64 Windows.
7507+
Args.addOptInFlag(CmdArgs, options::OPT_fwinx64_eh_unwindv2,
7508+
options::OPT_fno_winx64_eh_unwindv2);
7509+
75067510
// C++ "sane" operator new.
75077511
Args.addOptOutFlag(CmdArgs, options::OPT_fassume_sane_operator_new,
75087512
options::OPT_fno_assume_sane_operator_new);
@@ -8548,6 +8552,10 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
85488552
if (Args.hasArg(options::OPT__SLASH_kernel))
85498553
CmdArgs.push_back("-fms-kernel");
85508554

8555+
// Unwind v2 (epilog) information for x64 Windows.
8556+
if (Args.hasArg(options::OPT__SLASH_d2epilogunwind))
8557+
CmdArgs.push_back("-fwinx64-eh-unwindv2");
8558+
85518559
for (const Arg *A : Args.filtered(options::OPT__SLASH_guard)) {
85528560
StringRef GuardArgs = A->getValue();
85538561
// The only valid options are "cf", "cf,nochecks", "cf-", "ehcont" and

clang/test/CodeGen/epilog-unwind.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s -check-prefix=DISABLED
2+
// RUN: %clang_cc1 -fwinx64-eh-unwindv2 -emit-llvm %s -o - | FileCheck %s -check-prefix=ENABLED
3+
// RUN: %clang -fwinx64-eh-unwindv2 -S -emit-llvm %s -o - | FileCheck %s -check-prefix=ENABLED
4+
// RUN: %clang -fno-winx64-eh-unwindv2 -S -emit-llvm %s -o - | FileCheck %s -check-prefix=DISABLED
5+
6+
void f(void) {}
7+
8+
// ENABLED: !"winx64-eh-unwindv2", i32 1}
9+
// DISABLED-NOT: "winx64-eh-unwindv2"

clang/test/Driver/cl-options.c

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

823+
// RUN: %clang_cl /d2epilogunwind /c -### -- %s 2>&1 | FileCheck %s --check-prefix=EPILOGUNWIND
824+
// EPILOGUNWIND: -fwinx64-eh-unwindv2
825+
823826
void f(void) { }

llvm/include/llvm/MC/MCStreamer.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -255,11 +255,8 @@ class MCStreamer {
255255
bool AllowAutoPadding = false;
256256

257257
protected:
258-
// True if we are processing SEH directives in an epilogue.
259-
bool InEpilogCFI = false;
260-
261258
// Symbol of the current epilog for which we are processing SEH directives.
262-
MCSymbol *CurrentEpilog = nullptr;
259+
WinEH::FrameInfo::Epilog *CurrentWinEpilog = nullptr;
263260

264261
MCFragment *CurFrag = nullptr;
265262

@@ -342,9 +339,11 @@ class MCStreamer {
342339
return WinFrameInfos;
343340
}
344341

345-
MCSymbol *getCurrentEpilog() const { return CurrentEpilog; }
342+
WinEH::FrameInfo::Epilog *getCurrentWinEpilog() const {
343+
return CurrentWinEpilog;
344+
}
346345

347-
bool isInEpilogCFI() const { return InEpilogCFI; }
346+
bool isInEpilogCFI() const { return CurrentWinEpilog; }
348347

349348
void generateCompactUnwindEncodings(MCAsmBackend *MAB);
350349

@@ -1026,6 +1025,8 @@ class MCStreamer {
10261025
virtual void emitWinCFIEndProlog(SMLoc Loc = SMLoc());
10271026
virtual void emitWinCFIBeginEpilogue(SMLoc Loc = SMLoc());
10281027
virtual void emitWinCFIEndEpilogue(SMLoc Loc = SMLoc());
1028+
virtual void emitWinCFIUnwindV2Start(SMLoc Loc = SMLoc());
1029+
virtual void emitWinCFIUnwindVersion(uint8_t Version, SMLoc Loc = SMLoc());
10291030
virtual void emitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except,
10301031
SMLoc Loc = SMLoc());
10311032
virtual void emitWinEHHandlerData(SMLoc Loc = SMLoc());

llvm/include/llvm/MC/MCWinEH.h

Lines changed: 8 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,19 @@ 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 *Start = nullptr;
67+
const MCSymbol *End = nullptr;
68+
const MCSymbol *UnwindV2Start = nullptr;
69+
SMLoc Loc;
6370
};
6471
MapVector<MCSymbol *, Epilog> EpilogMap;
6572

llvm/lib/MC/MCAsmStreamer.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,8 @@ class MCAsmStreamer final : public MCStreamer {
391391
void emitWinCFIEndProlog(SMLoc Loc) override;
392392
void emitWinCFIBeginEpilogue(SMLoc Loc) override;
393393
void emitWinCFIEndEpilogue(SMLoc Loc) override;
394+
void emitWinCFIUnwindV2Start(SMLoc Loc) override;
395+
void emitWinCFIUnwindVersion(uint8_t Version, SMLoc Loc) override;
394396

395397
void emitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except,
396398
SMLoc Loc) override;
@@ -2305,6 +2307,20 @@ void MCAsmStreamer::emitWinCFIEndEpilogue(SMLoc Loc) {
23052307
EmitEOL();
23062308
}
23072309

2310+
void MCAsmStreamer::emitWinCFIUnwindV2Start(SMLoc Loc) {
2311+
MCStreamer::emitWinCFIUnwindV2Start(Loc);
2312+
2313+
OS << "\t.seh_unwindv2start";
2314+
EmitEOL();
2315+
}
2316+
2317+
void MCAsmStreamer::emitWinCFIUnwindVersion(uint8_t Version, SMLoc Loc) {
2318+
MCStreamer::emitWinCFIUnwindVersion(Version, Loc);
2319+
2320+
OS << "\t.seh_unwindversion " << (unsigned)Version;
2321+
EmitEOL();
2322+
}
2323+
23082324
void MCAsmStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From,
23092325
const MCSymbolRefExpr *To,
23102326
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);
@@ -774,6 +780,28 @@ bool COFFAsmParser::ParseSEHDirectiveEndEpilog(StringRef, SMLoc Loc) {
774780
return false;
775781
}
776782

783+
bool COFFAsmParser::ParseSEHDirectiveUnwindV2Start(StringRef, SMLoc Loc) {
784+
Lex();
785+
getStreamer().emitWinCFIUnwindV2Start(Loc);
786+
return false;
787+
}
788+
789+
bool COFFAsmParser::ParseSEHDirectiveUnwindVersion(StringRef, SMLoc Loc) {
790+
int64_t Version;
791+
if (getParser().parseIntToken(Version, "expected unwind version number"))
792+
return true;
793+
794+
if ((Version < 1) || (Version > UINT8_MAX))
795+
return Error(Loc, "invalid unwind version");
796+
797+
if (getLexer().isNot(AsmToken::EndOfStatement))
798+
return TokError("unexpected token in directive");
799+
800+
Lex();
801+
getStreamer().emitWinCFIUnwindVersion(Version, Loc);
802+
return false;
803+
}
804+
777805
bool COFFAsmParser::parseAtUnwindOrAtExcept(bool &unwind, bool &except) {
778806
StringRef identifier;
779807
if (getLexer().isNot(AsmToken::At) && getLexer().isNot(AsmToken::Percent))

llvm/lib/MC/MCStreamer.cpp

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,7 @@ void MCStreamer::emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) {
743743
std::make_unique<WinEH::FrameInfo>(Symbol, StartProc));
744744
CurrentWinFrameInfo = WinFrameInfos.back().get();
745745
CurrentWinFrameInfo->TextSection = getCurrentSectionOnly();
746+
CurrentWinFrameInfo->FunctionLoc = Loc;
746747
}
747748

748749
void MCStreamer::emitWinCFIEndProc(SMLoc Loc) {
@@ -1000,23 +1001,63 @@ void MCStreamer::emitWinCFIBeginEpilogue(SMLoc Loc) {
10001001
"(.seh_endprologue) in " +
10011002
CurFrame->Function->getName());
10021003

1003-
InEpilogCFI = true;
1004-
CurrentEpilog = emitCFILabel();
1004+
MCSymbol *Label = emitCFILabel();
1005+
CurrentWinEpilog =
1006+
&CurFrame->EpilogMap.insert_or_assign(Label, WinEH::FrameInfo::Epilog())
1007+
.first->second;
1008+
CurrentWinEpilog->Start = Label;
1009+
CurrentWinEpilog->Loc = Loc;
10051010
}
10061011

10071012
void MCStreamer::emitWinCFIEndEpilogue(SMLoc Loc) {
10081013
WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc);
10091014
if (!CurFrame)
10101015
return;
10111016

1012-
if (!InEpilogCFI)
1017+
if (!CurrentWinEpilog)
10131018
return getContext().reportError(Loc, "Stray .seh_endepilogue in " +
10141019
CurFrame->Function->getName());
10151020

1016-
InEpilogCFI = false;
1021+
if ((CurFrame->Version >= 2) && !CurrentWinEpilog->UnwindV2Start)
1022+
return getContext().reportError(Loc, "Missing .seh_unwindv2start in " +
1023+
CurFrame->Function->getName());
1024+
1025+
CurrentWinEpilog->End = emitCFILabel();
1026+
CurrentWinEpilog = nullptr;
1027+
}
1028+
1029+
void MCStreamer::emitWinCFIUnwindV2Start(SMLoc Loc) {
1030+
WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc);
1031+
if (!CurFrame)
1032+
return;
1033+
1034+
if (!CurrentWinEpilog)
1035+
return getContext().reportError(Loc, "Stray .seh_unwindv2start in " +
1036+
CurFrame->Function->getName());
1037+
1038+
if (CurrentWinEpilog->UnwindV2Start)
1039+
return getContext().reportError(Loc, "Duplicate .seh_unwindv2start in " +
1040+
CurFrame->Function->getName());
1041+
10171042
MCSymbol *Label = emitCFILabel();
1018-
CurFrame->EpilogMap[CurrentEpilog].End = Label;
1019-
CurrentEpilog = nullptr;
1043+
CurrentWinEpilog->UnwindV2Start = Label;
1044+
}
1045+
1046+
void MCStreamer::emitWinCFIUnwindVersion(uint8_t Version, SMLoc Loc) {
1047+
WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc);
1048+
if (!CurFrame)
1049+
return;
1050+
1051+
if (CurFrame->Version != WinEH::FrameInfo::DefaultVersion)
1052+
return getContext().reportError(Loc, "Duplicate .seh_unwindversion in " +
1053+
CurFrame->Function->getName());
1054+
1055+
if (Version != 2)
1056+
return getContext().reportError(
1057+
Loc, "Unsupported version specified in .seh_unwindversion in " +
1058+
CurFrame->Function->getName());
1059+
1060+
CurFrame->Version = Version;
10201061
}
10211062

10221063
void MCStreamer::emitCOFFSafeSEH(MCSymbol const *Symbol) {}

0 commit comments

Comments
 (0)