Exception filter IR model


I have a question about the IR model for SEH filters (as I want to use the same model for CLR filters). In particular, when an outer filter is invoked before entering an inner finally, which piece of IR reflects the filter’s side-effects? To take a concrete example, consider this C code:

void foo() {

int x;

__try {

x = 0;

__try {

x = 2;



__finally {

if (x == 1) {



else {





__except (x = 1) {



The IR for the path from “x = 2” to the load of x in the __finally (via the exception edge) looks like so:

store i32 2, i32* %x, align 4

invoke void bitcast (void (…)* @may_throw to void ()*)() #4

to label %invoke.cont unwind label %lpad

lpad: ; preds = %entry

%1 = landingpad { i8*, i32 } personality i8* bitcast (i32 (…)* @__C_specific_handler to i8*)


catch i8* bitcast (i32 (i8*, i8*)* @“\01?filt$0@0@foo@@” to i8*)

%2 = extractvalue { i8*, i32 } %1, 0

store i8* %2, i8** %exn.slot

%3 = extractvalue { i8*, i32 } %1, 1

store i32 %3, i32* %ehselector.slot

store i8 1, i8* %abnormal.termination.slot

br label %__finally

__finally: ; preds = %lpad, %invoke.cont

%0 = load i32, i32* %x, align 4

What I’m wondering is where exactly this models the call to @“\01?filt$0@0@foo@@” and its store to x. Is it implicitly part of the execution of the landingpad instruction itself? Or of the invoke?



The current model is that any variable used by an SEH filter is escaped in the entry block, and any external function that can throw should also be able to write to escaped memory. You can see the call to @llvm.frameescape in the entry block and to @llvm.framerecover in the filter function that implement this.

This isn’t a very accurate model, and it doesn’t lend itself to optimization or program analysis, but it was motivated by the idea that SEH filters are rare and changing LLVM’s EH model is expensive. Our assessment of rarity comes from experience in Chromium, however, which may not be representative of other programs. :slight_smile: SEH is also already an enormous barrier to optimization, so we figured it would be OK if we just don’t do a good job optimizing functions with SEH filters.

We’ve been discussing other designs that might avoid the early outlining that prevents precise analysis and optimization, but it’s not clear if we’ve found a winner yet. Part of the problem is that, as you’ve indicated, filters run in EH phase 1, before running cleanups and finally blocks. The current stack-driven EH emission strategy in Clang doesn’t really handle that, and even if it could, the CFG would be a complete mess.

Got it, thanks.

FWIW, I expect filters to be rare for us, too, and totally agree that outlining them is a sensible way forward.