Skip to content

Commit

Permalink
Initial support for Win64 SEH IR emission
Browse files Browse the repository at this point in the history
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
  • Loading branch information
rnk committed Jan 22, 2015
1 parent e855c2a commit 1d59f99
Show file tree
Hide file tree
Showing 21 changed files with 667 additions and 49 deletions.
3 changes: 3 additions & 0 deletions clang/include/clang/AST/Mangle.h
Expand Up @@ -132,6 +132,9 @@ class MangleContext {
virtual void mangleDynamicAtExitDestructor(const VarDecl *D,
raw_ostream &) = 0;

virtual void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
raw_ostream &Out) = 0;

/// Generates a unique string for an externally visible type for use with TBAA
/// or type uniquing.
/// TODO: Extend this to internal types by generating names that are unique
Expand Down
14 changes: 9 additions & 5 deletions clang/include/clang/Basic/Builtins.def
Expand Up @@ -692,11 +692,15 @@ BUILTIN(__builtin_index, "c*cC*i", "Fn")
BUILTIN(__builtin_rindex, "c*cC*i", "Fn")

// Microsoft builtins. These are only active with -fms-extensions.
LANGBUILTIN(_alloca, "v*z", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__assume, "vb", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__debugbreak, "v", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__va_start, "vc**.", "nt", ALL_MS_LANGUAGES)
LANGBUILTIN(_alloca, "v*z", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__assume, "vb", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_exception_code, "ULi", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__exception_code, "ULi", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_exception_info, "v*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__exception_info, "v*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__debugbreak, "v", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__va_start, "vc**.", "nt", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedCompareExchange, "LiLiD*LiLi", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedCompareExchangePointer, "v*v*D*v*v*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedIncrement, "LiLiD*", "n", ALL_MS_LANGUAGES)
Expand Down
10 changes: 10 additions & 0 deletions clang/include/clang/Basic/DiagnosticCommonKinds.td
Expand Up @@ -112,6 +112,16 @@ def ext_integer_literal_too_large_for_signed : ExtWarn<
"interpreting as unsigned">,
InGroup<DiagGroup<"implicitly-unsigned-literal">>;

// SEH
def err_seh_expected_handler : Error<
"expected '__except' or '__finally' block">;
def err_seh___except_block : Error<
"%0 only allowed in __except block or filter expression">;
def err_seh___except_filter : Error<
"%0 only allowed in __except filter expression">;
def err_seh___finally_block : Error<
"%0 only allowed in __finally block">;

// Sema && AST
def note_invalid_subexpr_in_const_expr : Note<
"subexpression not valid in a constant expression">;
Expand Down
12 changes: 0 additions & 12 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Expand Up @@ -949,18 +949,6 @@ def warn_pragma_expected_enable_disable : Warning<
def warn_pragma_unknown_extension : Warning<
"unknown OpenCL extension %0 - ignoring">, InGroup<IgnoredPragmas>;

def err_seh_expected_handler : Error<
"expected '__except' or '__finally' block">;

def err_seh___except_block : Error<
"%0 only allowed in __except block">;

def err_seh___except_filter : Error<
"%0 only allowed in __except filter expression">;

def err_seh___finally_block : Error<
"%0 only allowed in __finally block">;

// OpenMP support.
def warn_pragma_omp_ignored : Warning<
"unexpected '#pragma omp ...' in program">, InGroup<SourceUsesOpenMP>, DefaultIgnore;
Expand Down
11 changes: 10 additions & 1 deletion clang/include/clang/Sema/Scope.h
Expand Up @@ -115,8 +115,14 @@ class Scope {
/// This scope corresponds to an enum.
EnumScope = 0x40000,

/// This scope corresponds to a SEH try.
/// This scope corresponds to an SEH try.
SEHTryScope = 0x80000,

/// This scope corresponds to an SEH except.
SEHExceptScope = 0x100000,

/// We are currently in the filter expression of an SEH except block.
SEHFilterScope = 0x200000,
};
private:
/// The parent scope for this scope. This is null for the translation-unit
Expand Down Expand Up @@ -407,6 +413,9 @@ class Scope {
/// \brief Determine whether this scope is a SEH '__try' block.
bool isSEHTryScope() const { return getFlags() & Scope::SEHTryScope; }

/// \brief Determine whether this scope is a SEH '__except' block.
bool isSEHExceptScope() const { return getFlags() & Scope::SEHExceptScope; }

/// containedInPrototypeScope - Return true if this or a parent scope
/// is a FunctionPrototypeScope.
bool containedInPrototypeScope() const;
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/AST/ItaniumMangle.cpp
Expand Up @@ -156,6 +156,8 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext {
void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override;
void mangleDynamicAtExitDestructor(const VarDecl *D,
raw_ostream &Out) override;
void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
raw_ostream &Out) override;
void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &) override;
void mangleItaniumThreadLocalWrapper(const VarDecl *D,
raw_ostream &) override;
Expand Down Expand Up @@ -3845,6 +3847,16 @@ void ItaniumMangleContextImpl::mangleDynamicAtExitDestructor(const VarDecl *D,
Mangler.getStream() << D->getName();
}

void ItaniumMangleContextImpl::mangleSEHFilterExpression(
const NamedDecl *EnclosingDecl, raw_ostream &Out) {
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "__filt_";
if (shouldMangleDeclName(EnclosingDecl))
Mangler.mangle(EnclosingDecl);
else
Mangler.getStream() << EnclosingDecl->getName();
}

void ItaniumMangleContextImpl::mangleItaniumThreadLocalInit(const VarDecl *D,
raw_ostream &Out) {
// <special-name> ::= TH <object name>
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/AST/MicrosoftMangle.cpp
Expand Up @@ -89,6 +89,7 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator;
llvm::DenseMap<const NamedDecl *, unsigned> Uniquifier;
llvm::DenseMap<const CXXRecordDecl *, unsigned> LambdaIds;
llvm::DenseMap<const NamedDecl *, unsigned> SEHFilterIds;

public:
MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags)
Expand Down Expand Up @@ -134,6 +135,8 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override;
void mangleDynamicAtExitDestructor(const VarDecl *D,
raw_ostream &Out) override;
void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
raw_ostream &Out) override;
void mangleStringLiteral(const StringLiteral *SL, raw_ostream &Out) override;
bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
// Lambda closure types are already numbered.
Expand Down Expand Up @@ -2318,6 +2321,17 @@ void MicrosoftMangleContextImpl::mangleCXXRTTICompleteObjectLocator(
Mangler.getStream() << '@';
}

void MicrosoftMangleContextImpl::mangleSEHFilterExpression(
const NamedDecl *EnclosingDecl, raw_ostream &Out) {
MicrosoftCXXNameMangler Mangler(*this, Out);
// The function body is in the same comdat as the function with the handler,
// so the numbering here doesn't have to be the same across TUs.
//
// <mangled-name> ::= ?filt$ <filter-number> @0
Mangler.getStream() << "\01?filt$" << SEHFilterIds[EnclosingDecl]++ << "@0@";
Mangler.mangleName(EnclosingDecl);
}

void MicrosoftMangleContextImpl::mangleTypeName(QualType T, raw_ostream &Out) {
// This is just a made up unique string for the purposes of tbaa. undname
// does *not* know how to demangle it.
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Expand Up @@ -1650,6 +1650,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Builder.CreateAlignedLoad(IntToPtr, /*Align=*/4, /*isVolatile=*/true);
return RValue::get(Load);
}

case Builtin::BI__exception_code:
case Builtin::BI_exception_code:
return RValue::get(EmitSEHExceptionCode());
case Builtin::BI__exception_info:
case Builtin::BI_exception_info:
return RValue::get(EmitSEHExceptionInfo());
}

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

0 comments on commit 1d59f99

Please sign in to comment.