[LLVMdev] invoke/unwind

Mike Stump mrs at apple.com
Wed Jan 13 11:11:10 PST 2010


On Jan 13, 2010, at 9:27 AM, Dustin Laurence wrote:
> So how is clang doing C++ exceptions?

Roughly, like so:

$ cat t.cc
int main() {
  try { throw 1; } catch (int i) { }
}
$ clang -S t.cc -emit-llvm
$ cat t.s
; ModuleID = 't.cc'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-apple-darwin10.0"

@_ZTIi = external constant i8*                    ; <i8**> [#uses=1]

define i32 @main() ssp {
entry:
  %retval = alloca i32                            ; <i32*> [#uses=2]
  %exception.ptr = alloca i8*                     ; <i8**> [#uses=1]
  %_rethrow = alloca i8*                          ; <i8**> [#uses=4]
  %i = alloca i32, align 4                        ; <i32*> [#uses=1]
  %cleanup.dst = alloca i32                       ; <i32*> [#uses=3]
  %cleanup.dst6 = alloca i32                      ; <i32*> [#uses=5]
  store i32 0, i32* %retval
  %exception = call i8* @__cxa_allocate_exception(i64 4) ; <i8*> [#uses=3]
  store i8* %exception, i8** %exception.ptr
  %0 = bitcast i8* %exception to i32*             ; <i32*> [#uses=1]
  store i32 1, i32* %0
  invoke void @__cxa_throw(i8* %exception, i8* bitcast (i8** @_ZTIi to i8*), i8* null) noreturn
          to label %invoke.cont unwind label %try.handler

invoke.cont:                                      ; preds = %entry
  unreachable

terminate.handler:                                ; preds = %match.end
  %exc = call i8* @llvm.eh.exception()            ; <i8*> [#uses=1]
  %1 = call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* %exc, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i32 1) ; <i32> [#uses=0]
  call void @_ZSt9terminatev() noreturn nounwind
  unreachable

try.handler:                                      ; preds = %entry
  %exc1 = call i8* @llvm.eh.exception()           ; <i8*> [#uses=3]
  %selector = call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* %exc1, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*), i8* null) ; <i32> [#uses=1]
  %2 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) ; <i32> [#uses=1]
  %3 = icmp eq i32 %selector, %2                  ; <i1> [#uses=1]
  br i1 %3, label %match, label %catch.next

match:                                            ; preds = %try.handler
  %4 = call i8* @__cxa_begin_catch(i8* %exc1)     ; <i8*> [#uses=1]
  %5 = bitcast i8* %4 to i32*                     ; <i32*> [#uses=1]
  %6 = load i32* %5                               ; <i32> [#uses=1]
  store i32 %6, i32* %i
  store i32 1, i32* %cleanup.dst
  br label %match.end

match.handler:                                    ; No predecessors!
  %exc2 = call i8* @llvm.eh.exception()           ; <i8*> [#uses=2]
  %7 = call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* %exc2, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i32 0) ; <i32> [#uses=0]
  store i8* %exc2, i8** %_rethrow
  store i32 2, i32* %cleanup.dst
  br label %match.end

cleanup.pad:                                      ; preds = %cleanup.switch
  store i32 1, i32* %cleanup.dst6
  br label %finally

cleanup.pad3:                                     ; preds = %cleanup.switch
  store i32 2, i32* %cleanup.dst6
  br label %finally

match.end:                                        ; preds = %match.handler, %match
  invoke void @__cxa_end_catch()
          to label %invoke.cont4 unwind label %terminate.handler

invoke.cont4:                                     ; preds = %match.end
  br label %cleanup.switch

cleanup.switch:                                   ; preds = %invoke.cont4
  %tmp = load i32* %cleanup.dst                   ; <i32> [#uses=1]
  switch i32 %tmp, label %cleanup.end [
    i32 1, label %cleanup.pad
    i32 2, label %cleanup.pad3
  ]

cleanup.end:                                      ; preds = %cleanup.switch
  %exc5 = call i8* @llvm.eh.exception()           ; <i8*> [#uses=1]
  store i8* %exc5, i8** %_rethrow
  store i32 2, i32* %cleanup.dst6
  br label %finally

catch.next:                                       ; preds = %try.handler
  store i8* %exc1, i8** %_rethrow
  store i32 2, i32* %cleanup.dst6
  br label %finally

finally:                                          ; preds = %catch.next, %cleanup.end, %cleanup.pad3, %cleanup.pad
  br label %cleanup.switch8

cleanup.switch8:                                  ; preds = %finally
  %tmp7 = load i32* %cleanup.dst6                 ; <i32> [#uses=1]
  switch i32 %tmp7, label %cleanup.end9 [
    i32 1, label %finally.end
    i32 2, label %finally.throw
  ]

cleanup.end9:                                     ; preds = %cleanup.switch8
  br label %finally.end

finally.throw:                                    ; preds = %cleanup.switch8
  %8 = load i8** %_rethrow                        ; <i8*> [#uses=1]
  call void @_Unwind_Resume_or_Rethrow(i8* %8)
  unreachable

finally.end:                                      ; preds = %cleanup.end9, %cleanup.switch8
  %9 = load i32* %retval                          ; <i32> [#uses=1]
  ret i32 %9
}

declare i32 @__gxx_personality_v0(...)

declare i8* @llvm.eh.exception() nounwind readonly

declare i32 @llvm.eh.selector(i8*, i8*, ...) nounwind

declare i8* @__cxa_allocate_exception(i64)

declare void @__cxa_throw(i8*, i8*, i8*)

declare void @_ZSt9terminatev()

declare i32 @llvm.eh.typeid.for(i8*) nounwind

declare i8* @__cxa_begin_catch(i8*)

declare void @__cxa_end_catch()

declare void @_Unwind_Resume_or_Rethrow(i8*)




More information about the llvm-dev mailing list