Skip to content

Commit 1d59f99

Browse files
committed
Initial support for Win64 SEH IR emission
The lowering looks a lot like normal EH lowering, with the exception that the exceptions are caught by executing filter expression code instead of matching typeinfo globals. The filter expressions are outlined into functions which are used in landingpad clauses where typeinfo would normally go. Major aspects that still need work: - Non-call exceptions in __try bodies won't work yet. The plan is to outline the __try block in the frontend to keep things simple. - Filter expressions cannot use local variables until capturing is implemented. - __finally blocks will not run after exceptions. Fixing this requires work in the LLVM SEH preparation pass. The IR lowering looks like this: // C code: bool safe_div(int n, int d, int *r) { __try { *r = normal_div(n, d); } __except(_exception_code() == EXCEPTION_INT_DIVIDE_BY_ZERO) { return false; } return true; } ; LLVM IR: define i32 @filter(i8* %e, i8* %fp) { %ehptrs = bitcast i8* %e to i32** %ehrec = load i32** %ehptrs %code = load i32* %ehrec %matches = icmp eq i32 %code, i32 u0xC0000094 %matches.i32 = zext i1 %matches to i32 ret i32 %matches.i32 } define i1 zeroext @safe_div(i32 %n, i32 %d, i32* %r) { %rr = invoke i32 @normal_div(i32 %n, i32 %d) to label %normal unwind to label %lpad normal: store i32 %rr, i32* %r ret i1 1 lpad: %ehvals = landingpad {i8*, i32} personality i32 (...)* @__C_specific_handler catch i8* bitcast (i32 (i8*, i8*)* @filter to i8*) %ehptr = extractvalue {i8*, i32} %ehvals, i32 0 %sel = extractvalue {i8*, i32} %ehvals, i32 1 %filter_sel = call i32 @llvm.eh.seh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @filter to i8*)) %matches = icmp eq i32 %sel, %filter_sel br i1 %matches, label %eh.except, label %eh.resume eh.except: ret i1 false eh.resume: resume } Reviewers: rjmccall, rsmith, majnemer Differential Revision: http://reviews.llvm.org/D5607 llvm-svn: 226760
1 parent e855c2a commit 1d59f99

21 files changed

+667
-49
lines changed

clang/include/clang/AST/Mangle.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ class MangleContext {
132132
virtual void mangleDynamicAtExitDestructor(const VarDecl *D,
133133
raw_ostream &) = 0;
134134

135+
virtual void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
136+
raw_ostream &Out) = 0;
137+
135138
/// Generates a unique string for an externally visible type for use with TBAA
136139
/// or type uniquing.
137140
/// TODO: Extend this to internal types by generating names that are unique

clang/include/clang/Basic/Builtins.def

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -692,11 +692,15 @@ BUILTIN(__builtin_index, "c*cC*i", "Fn")
692692
BUILTIN(__builtin_rindex, "c*cC*i", "Fn")
693693

694694
// Microsoft builtins. These are only active with -fms-extensions.
695-
LANGBUILTIN(_alloca, "v*z", "n", ALL_MS_LANGUAGES)
696-
LANGBUILTIN(__assume, "vb", "n", ALL_MS_LANGUAGES)
697-
LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES)
698-
LANGBUILTIN(__debugbreak, "v", "n", ALL_MS_LANGUAGES)
699-
LANGBUILTIN(__va_start, "vc**.", "nt", ALL_MS_LANGUAGES)
695+
LANGBUILTIN(_alloca, "v*z", "n", ALL_MS_LANGUAGES)
696+
LANGBUILTIN(__assume, "vb", "n", ALL_MS_LANGUAGES)
697+
LANGBUILTIN(_exception_code, "ULi", "n", ALL_MS_LANGUAGES)
698+
LANGBUILTIN(__exception_code, "ULi", "n", ALL_MS_LANGUAGES)
699+
LANGBUILTIN(_exception_info, "v*", "n", ALL_MS_LANGUAGES)
700+
LANGBUILTIN(__exception_info, "v*", "n", ALL_MS_LANGUAGES)
701+
LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES)
702+
LANGBUILTIN(__debugbreak, "v", "n", ALL_MS_LANGUAGES)
703+
LANGBUILTIN(__va_start, "vc**.", "nt", ALL_MS_LANGUAGES)
700704
LANGBUILTIN(_InterlockedCompareExchange, "LiLiD*LiLi", "n", ALL_MS_LANGUAGES)
701705
LANGBUILTIN(_InterlockedCompareExchangePointer, "v*v*D*v*v*", "n", ALL_MS_LANGUAGES)
702706
LANGBUILTIN(_InterlockedIncrement, "LiLiD*", "n", ALL_MS_LANGUAGES)

clang/include/clang/Basic/DiagnosticCommonKinds.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,16 @@ def ext_integer_literal_too_large_for_signed : ExtWarn<
112112
"interpreting as unsigned">,
113113
InGroup<DiagGroup<"implicitly-unsigned-literal">>;
114114

115+
// SEH
116+
def err_seh_expected_handler : Error<
117+
"expected '__except' or '__finally' block">;
118+
def err_seh___except_block : Error<
119+
"%0 only allowed in __except block or filter expression">;
120+
def err_seh___except_filter : Error<
121+
"%0 only allowed in __except filter expression">;
122+
def err_seh___finally_block : Error<
123+
"%0 only allowed in __finally block">;
124+
115125
// Sema && AST
116126
def note_invalid_subexpr_in_const_expr : Note<
117127
"subexpression not valid in a constant expression">;

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -949,18 +949,6 @@ def warn_pragma_expected_enable_disable : Warning<
949949
def warn_pragma_unknown_extension : Warning<
950950
"unknown OpenCL extension %0 - ignoring">, InGroup<IgnoredPragmas>;
951951

952-
def err_seh_expected_handler : Error<
953-
"expected '__except' or '__finally' block">;
954-
955-
def err_seh___except_block : Error<
956-
"%0 only allowed in __except block">;
957-
958-
def err_seh___except_filter : Error<
959-
"%0 only allowed in __except filter expression">;
960-
961-
def err_seh___finally_block : Error<
962-
"%0 only allowed in __finally block">;
963-
964952
// OpenMP support.
965953
def warn_pragma_omp_ignored : Warning<
966954
"unexpected '#pragma omp ...' in program">, InGroup<SourceUsesOpenMP>, DefaultIgnore;

clang/include/clang/Sema/Scope.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,14 @@ class Scope {
115115
/// This scope corresponds to an enum.
116116
EnumScope = 0x40000,
117117

118-
/// This scope corresponds to a SEH try.
118+
/// This scope corresponds to an SEH try.
119119
SEHTryScope = 0x80000,
120+
121+
/// This scope corresponds to an SEH except.
122+
SEHExceptScope = 0x100000,
123+
124+
/// We are currently in the filter expression of an SEH except block.
125+
SEHFilterScope = 0x200000,
120126
};
121127
private:
122128
/// The parent scope for this scope. This is null for the translation-unit
@@ -407,6 +413,9 @@ class Scope {
407413
/// \brief Determine whether this scope is a SEH '__try' block.
408414
bool isSEHTryScope() const { return getFlags() & Scope::SEHTryScope; }
409415

416+
/// \brief Determine whether this scope is a SEH '__except' block.
417+
bool isSEHExceptScope() const { return getFlags() & Scope::SEHExceptScope; }
418+
410419
/// containedInPrototypeScope - Return true if this or a parent scope
411420
/// is a FunctionPrototypeScope.
412421
bool containedInPrototypeScope() const;

clang/lib/AST/ItaniumMangle.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext {
156156
void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override;
157157
void mangleDynamicAtExitDestructor(const VarDecl *D,
158158
raw_ostream &Out) override;
159+
void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
160+
raw_ostream &Out) override;
159161
void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &) override;
160162
void mangleItaniumThreadLocalWrapper(const VarDecl *D,
161163
raw_ostream &) override;
@@ -3845,6 +3847,16 @@ void ItaniumMangleContextImpl::mangleDynamicAtExitDestructor(const VarDecl *D,
38453847
Mangler.getStream() << D->getName();
38463848
}
38473849

3850+
void ItaniumMangleContextImpl::mangleSEHFilterExpression(
3851+
const NamedDecl *EnclosingDecl, raw_ostream &Out) {
3852+
CXXNameMangler Mangler(*this, Out);
3853+
Mangler.getStream() << "__filt_";
3854+
if (shouldMangleDeclName(EnclosingDecl))
3855+
Mangler.mangle(EnclosingDecl);
3856+
else
3857+
Mangler.getStream() << EnclosingDecl->getName();
3858+
}
3859+
38483860
void ItaniumMangleContextImpl::mangleItaniumThreadLocalInit(const VarDecl *D,
38493861
raw_ostream &Out) {
38503862
// <special-name> ::= TH <object name>

clang/lib/AST/MicrosoftMangle.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
8989
llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator;
9090
llvm::DenseMap<const NamedDecl *, unsigned> Uniquifier;
9191
llvm::DenseMap<const CXXRecordDecl *, unsigned> LambdaIds;
92+
llvm::DenseMap<const NamedDecl *, unsigned> SEHFilterIds;
9293

9394
public:
9495
MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags)
@@ -134,6 +135,8 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
134135
void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override;
135136
void mangleDynamicAtExitDestructor(const VarDecl *D,
136137
raw_ostream &Out) override;
138+
void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
139+
raw_ostream &Out) override;
137140
void mangleStringLiteral(const StringLiteral *SL, raw_ostream &Out) override;
138141
bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
139142
// Lambda closure types are already numbered.
@@ -2318,6 +2321,17 @@ void MicrosoftMangleContextImpl::mangleCXXRTTICompleteObjectLocator(
23182321
Mangler.getStream() << '@';
23192322
}
23202323

2324+
void MicrosoftMangleContextImpl::mangleSEHFilterExpression(
2325+
const NamedDecl *EnclosingDecl, raw_ostream &Out) {
2326+
MicrosoftCXXNameMangler Mangler(*this, Out);
2327+
// The function body is in the same comdat as the function with the handler,
2328+
// so the numbering here doesn't have to be the same across TUs.
2329+
//
2330+
// <mangled-name> ::= ?filt$ <filter-number> @0
2331+
Mangler.getStream() << "\01?filt$" << SEHFilterIds[EnclosingDecl]++ << "@0@";
2332+
Mangler.mangleName(EnclosingDecl);
2333+
}
2334+
23212335
void MicrosoftMangleContextImpl::mangleTypeName(QualType T, raw_ostream &Out) {
23222336
// This is just a made up unique string for the purposes of tbaa. undname
23232337
// does *not* know how to demangle it.

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1650,6 +1650,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
16501650
Builder.CreateAlignedLoad(IntToPtr, /*Align=*/4, /*isVolatile=*/true);
16511651
return RValue::get(Load);
16521652
}
1653+
1654+
case Builtin::BI__exception_code:
1655+
case Builtin::BI_exception_code:
1656+
return RValue::get(EmitSEHExceptionCode());
1657+
case Builtin::BI__exception_info:
1658+
case Builtin::BI_exception_info:
1659+
return RValue::get(EmitSEHExceptionInfo());
16531660
}
16541661

16551662
// If this is an alias for a lib function (e.g. __builtin_sin), emit

0 commit comments

Comments
 (0)