Skip to content

Commit 2488f26

Browse files
authored
[win][x64] Unwind v2 3/n: Add support for requiring unwind v2 to be used (equivalent to MSVC's /d2epilogunwindrequirev2) (#143577)
#129142 added support for emitting Windows x64 unwind v2 information, but it was "best effort". If any function didn't follow the requirements for v2 it was silently downgraded to v1. There are some parts of Windows (specifically kernel-mode code running on Xbox) that require v2, hence we need the ability to fail the compilation if v2 can't be used. This change also adds a heuristic to check if there might be too many unwind codes, it's currently conservative (i.e., assumes that certain prolog instructions will use the maximum number of unwind codes). Future work: attempting to chain unwind info across multiple tables if there are too many unwind codes due to epilogs and adding a heuristic to detect if an epilog will be too far from the end of the function.
1 parent 4bcf973 commit 2488f26

File tree

12 files changed

+595
-43
lines changed

12 files changed

+595
-43
lines changed

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -483,8 +483,10 @@ 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)
486+
/// Controls how unwind v2 (epilog) information should be generated for x64
487+
/// Windows.
488+
ENUM_CODEGENOPT(WinX64EHUnwindV2, llvm::WinX64EHUnwindV2Mode,
489+
2, llvm::WinX64EHUnwindV2Mode::Disabled)
488490

489491
/// FIXME: Make DebugOptions its own top-level .def file.
490492
#include "DebugOptions.def"

clang/include/clang/Driver/Options.td

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2167,11 +2167,14 @@ 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">>;
2170+
def winx64_eh_unwindv2
2171+
: Joined<["-"], "fwinx64-eh-unwindv2=">, Group<f_Group>,
2172+
Visibility<[ClangOption, CC1Option]>,
2173+
HelpText<"Generate unwind v2 (epilog) information for x64 Windows">,
2174+
Values<"disabled,best-effort,required">,
2175+
NormalizedValues<["Disabled", "BestEffort", "Required"]>,
2176+
NormalizedValuesScope<"llvm::WinX64EHUnwindV2Mode">,
2177+
MarshallingInfoEnum<CodeGenOpts<"WinX64EHUnwindV2">, "Disabled">;
21752178
def fexcess_precision_EQ : Joined<["-"], "fexcess-precision=">, Group<f_Group>,
21762179
Visibility<[ClangOption, CLOption]>,
21772180
HelpText<"Allows control over excess precision on targets where native "
@@ -8972,7 +8975,9 @@ def _SLASH_volatile_Group : OptionGroup<"</volatile group>">,
89728975
Group<cl_compile_Group>;
89738976

89748977
def _SLASH_d2epilogunwind : CLFlag<"d2epilogunwind">,
8975-
HelpText<"Enable unwind v2 (epilog) information for x64 Windows">;
8978+
HelpText<"Best effort generate unwind v2 (epilog) information for x64 Windows">;
8979+
def _SLASH_d2epilogunwindrequirev2 : CLFlag<"d2epilogunwindrequirev2">,
8980+
HelpText<"Require generation of unwind v2 (epilog) information for x64 Windows">;
89768981
def _SLASH_EH : CLJoined<"EH">, HelpText<"Set exception handling model">;
89778982
def _SLASH_EP : CLFlag<"EP">,
89788983
HelpText<"Disable linemarker output and preprocess to stdout">;

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,8 +1319,10 @@ void CodeGenModule::Release() {
13191319
1);
13201320

13211321
// Enable unwind v2 (epilog).
1322-
if (CodeGenOpts.WinX64EHUnwindV2)
1323-
getModule().addModuleFlag(llvm::Module::Warning, "winx64-eh-unwindv2", 1);
1322+
if (CodeGenOpts.getWinX64EHUnwindV2() != llvm::WinX64EHUnwindV2Mode::Disabled)
1323+
getModule().addModuleFlag(
1324+
llvm::Module::Warning, "winx64-eh-unwindv2",
1325+
static_cast<unsigned>(CodeGenOpts.getWinX64EHUnwindV2()));
13241326

13251327
// Indicate whether this Module was compiled with -fopenmp
13261328
if (getLangOpts().OpenMP && !getLangOpts().OpenMPSimd)

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7360,8 +7360,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
73607360
}
73617361

73627362
// Unwind v2 (epilog) information for x64 Windows.
7363-
Args.addOptInFlag(CmdArgs, options::OPT_fwinx64_eh_unwindv2,
7364-
options::OPT_fno_winx64_eh_unwindv2);
7363+
Args.AddLastArg(CmdArgs, options::OPT_winx64_eh_unwindv2);
73657364

73667365
// C++ "sane" operator new.
73677366
Args.addOptOutFlag(CmdArgs, options::OPT_fassume_sane_operator_new,
@@ -8418,8 +8417,10 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
84188417
CmdArgs.push_back("-fms-kernel");
84198418

84208419
// Unwind v2 (epilog) information for x64 Windows.
8421-
if (Args.hasArg(options::OPT__SLASH_d2epilogunwind))
8422-
CmdArgs.push_back("-fwinx64-eh-unwindv2");
8420+
if (Args.hasArg(options::OPT__SLASH_d2epilogunwindrequirev2))
8421+
CmdArgs.push_back("-fwinx64-eh-unwindv2=required");
8422+
else if (Args.hasArg(options::OPT__SLASH_d2epilogunwind))
8423+
CmdArgs.push_back("-fwinx64-eh-unwindv2=best-effort");
84238424

84248425
for (const Arg *A : Args.filtered(options::OPT__SLASH_guard)) {
84258426
StringRef GuardArgs = A->getValue();

clang/test/CodeGen/epilog-unwind.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
// 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
2+
// RUN: %clang_cc1 -fwinx64-eh-unwindv2=disabled -emit-llvm %s -o - | FileCheck %s -check-prefix=DISABLED
3+
// RUN: %clang_cc1 -fwinx64-eh-unwindv2=best-effort -emit-llvm %s -o - | FileCheck %s -check-prefix=BESTEFFORT
4+
// RUN: %clang_cc1 -fwinx64-eh-unwindv2=required -emit-llvm %s -o - | FileCheck %s -check-prefix=REQUIRED
5+
// RUN: %clang -fwinx64-eh-unwindv2=best-effort -S -emit-llvm %s -o - | FileCheck %s -check-prefix=BESTEFFORT
56

67
void f(void) {}
78

8-
// ENABLED: !"winx64-eh-unwindv2", i32 1}
9+
// BESTEFFORT: !"winx64-eh-unwindv2", i32 1}
10+
// REQUIRED: !"winx64-eh-unwindv2", i32 2}
911
// DISABLED-NOT: "winx64-eh-unwindv2"

clang/test/Driver/cl-options.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -821,7 +821,11 @@
821821
// ARM64EC_OVERRIDE: warning: /arm64EC has been overridden by specified target: x86_64-pc-windows-msvc; option ignored
822822

823823
// RUN: %clang_cl /d2epilogunwind /c -### -- %s 2>&1 | FileCheck %s --check-prefix=EPILOGUNWIND
824-
// EPILOGUNWIND: -fwinx64-eh-unwindv2
824+
// EPILOGUNWIND: -fwinx64-eh-unwindv2=best-effort
825+
826+
// RUN: %clang_cl /d2epilogunwindrequirev2 /c -### -- %s 2>&1 | FileCheck %s --check-prefix=EPILOGUNWINDREQUIREV2
827+
// RUN: %clang_cl /d2epilogunwindrequirev2 /d2epilogunwind /c -### -- %s 2>&1 | FileCheck %s --check-prefix=EPILOGUNWINDREQUIREV2
828+
// EPILOGUNWINDREQUIREV2: -fwinx64-eh-unwindv2=require
825829

826830
// RUN: %clang_cl /funcoverride:override_me1 /funcoverride:override_me2 /c -### -- %s 2>&1 | FileCheck %s --check-prefix=FUNCOVERRIDE
827831
// FUNCOVERRIDE: -loader-replaceable-function=override_me1

llvm/include/llvm/IR/Module.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,6 +1041,10 @@ class LLVM_ABI Module {
10411041

10421042
/// Returns target-abi from MDString, null if target-abi is absent.
10431043
StringRef getTargetABIFromMD();
1044+
1045+
/// Get how unwind v2 (epilog) information should be generated for x64
1046+
/// Windows.
1047+
WinX64EHUnwindV2Mode getWinX64EHUnwindV2Mode() const;
10441048
};
10451049

10461050
/// Given "llvm.used" or "llvm.compiler.used" as a global name, collect the

llvm/include/llvm/Support/CodeGen.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,15 @@ namespace llvm {
130130
Invalid = 2, ///< Not used.
131131
};
132132

133+
enum class WinX64EHUnwindV2Mode {
134+
// Don't use unwind v2 (i.e., use v1).
135+
Disabled = 0,
136+
// Use unwind v2 here possible, otherwise fallback to v1.
137+
BestEffort = 1,
138+
// Use unwind v2 everywhere, otherwise raise an error.
139+
Required = 2,
140+
};
141+
133142
} // namespace llvm
134143

135144
#endif

llvm/lib/IR/Module.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,3 +917,10 @@ StringRef Module::getTargetABIFromMD() {
917917
TargetABI = TargetABIMD->getString();
918918
return TargetABI;
919919
}
920+
921+
WinX64EHUnwindV2Mode Module::getWinX64EHUnwindV2Mode() const {
922+
Metadata *MD = getModuleFlag("winx64-eh-unwindv2");
923+
if (auto *CI = mdconst::dyn_extract_or_null<ConstantInt>(MD))
924+
return static_cast<WinX64EHUnwindV2Mode>(CI->getZExtValue());
925+
return WinX64EHUnwindV2Mode::Disabled;
926+
}

0 commit comments

Comments
 (0)