diff options
| author | Derek Schuff <dschuff@google.com> | 2016-08-01 21:34:04 +0000 |
|---|---|---|
| committer | Derek Schuff <dschuff@google.com> | 2016-08-01 21:34:04 +0000 |
| commit | f41f67d3d91ca7aea611fd6eb4dc11d32ff677d5 (patch) | |
| tree | 415db41f5891d4c73bde4d6a2b89c2e031758676 /llvm/test | |
| parent | 4a7130a8fb77e45f3e597a132a539ac323ac6a34 (diff) | |
| download | bcm5719-llvm-f41f67d3d91ca7aea611fd6eb4dc11d32ff677d5.tar.gz bcm5719-llvm-f41f67d3d91ca7aea611fd6eb4dc11d32ff677d5.zip | |
[WebAssembly] Add asm.js-style exception handling support
Summary: This patch includes asm.js-style exception handling support for
WebAssembly. The WebAssembly MVP does not have any support for
unwinding or non-local control flow. In order to support C++ exceptions,
emscripten currently uses JavaScript exceptions along with some support
code (written in JavaScript) that is bundled by emscripten with the
generated code.
This scheme lowers exception-related instructions for wasm such that
wasm modules can be compatible with emscripten's existing scheme and
share the support code.
Patch by Heejin Ahn
Differential Revision: https://reviews.llvm.org/D22958
llvm-svn: 277391
Diffstat (limited to 'llvm/test')
| -rw-r--r-- | llvm/test/CodeGen/WebAssembly/lower-em-exceptions.ll | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-exceptions.ll b/llvm/test/CodeGen/WebAssembly/lower-em-exceptions.ll new file mode 100644 index 00000000000..247118b1599 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/lower-em-exceptions.ll @@ -0,0 +1,143 @@ +; RUN: opt < %s -wasm-lower-em-exceptions -S | FileCheck %s + +@_ZTIi = external constant i8* +@_ZTIc = external constant i8* +; CHECK: @[[__THREW__:__THREW__.*]] = global i1 false +; CHECK: @[[THREWVALUE:threwValue.*]] = global i32 0 +; CHECK: @[[TEMPRET0:tempRet0.*]] = global i32 0 + +; Test invoke instruction with clauses (try-catch block) +define void @clause() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +; CHECK-LABEL: @clause( +entry: + invoke void @foo(i32 3) + to label %invoke.cont unwind label %lpad +; CHECK: entry: +; CHECK-NEXT: store i1 false, i1* @[[__THREW__]] +; CHECK-NEXT: call void @__invoke_void_i32(void (i32)* @foo, i32 3) +; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i1, i1* @[[__THREW__]] +; CHECK-NEXT: store i1 false, i1* @[[__THREW__]] +; CHECK-NEXT: br i1 %[[__THREW__VAL]], label %lpad, label %invoke.cont + +invoke.cont: ; preds = %entry + br label %try.cont + +lpad: ; preds = %entry + %0 = landingpad { i8*, i32 } + catch i8* bitcast (i8** @_ZTIi to i8*) + catch i8* null + %1 = extractvalue { i8*, i32 } %0, 0 + %2 = extractvalue { i8*, i32 } %0, 1 + br label %catch.dispatch +; CHECK: lpad: +; CHECK-NEXT: %[[FMC:.*]] = call i8* @___cxa_find_matching_catch_4(i8* bitcast (i8** @_ZTIi to i8*), i8* null) +; CHECK-NEXT: %[[IVI1:.*]] = insertvalue { i8*, i32 } undef, i8* %[[FMC]], 0 +; CHECK-NEXT: %[[TEMPRET0_VAL:.*]] = load i32, i32* @[[TEMPRET0]] +; CHECK-NEXT: %[[IVI2:.*]] = insertvalue { i8*, i32 } %[[IVI1]], i32 %[[TEMPRET0_VAL]], 1 +; CHECK-NEXT: extractvalue { i8*, i32 } %[[IVI2]], 0 +; CHECK-NEXT: extractvalue { i8*, i32 } %[[IVI2]], 1 + +catch.dispatch: ; preds = %lpad + %3 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) + %matches = icmp eq i32 %2, %3 + br i1 %matches, label %catch1, label %catch + +catch1: ; preds = %catch.dispatch + %4 = call i8* @__cxa_begin_catch(i8* %1) + %5 = bitcast i8* %4 to i32* + %6 = load i32, i32* %5, align 4 + call void @__cxa_end_catch() + br label %try.cont + +try.cont: ; preds = %catch, %catch1, %invoke.cont + ret void + +catch: ; preds = %catch.dispatch + %7 = call i8* @__cxa_begin_catch(i8* %1) + call void @__cxa_end_catch() + br label %try.cont +} + +; Test invoke instruction with filters (functions with throw(...) declaration) +define void @filter() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +; CHECK-LABEL: @filter( +entry: + invoke void @foo(i32 3) + to label %invoke.cont unwind label %lpad +; CHECK: entry: +; CHECK-NEXT: store i1 false, i1* @[[__THREW__]] +; CHECK-NEXT: call void @__invoke_void_i32(void (i32)* @foo, i32 3) +; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i1, i1* @[[__THREW__]] +; CHECK-NEXT: store i1 false, i1* @[[__THREW__]] +; CHECK-NEXT: br i1 %[[__THREW__VAL]], label %lpad, label %invoke.cont + +invoke.cont: ; preds = %entry + ret void + +lpad: ; preds = %entry + %0 = landingpad { i8*, i32 } + filter [2 x i8*] [i8* bitcast (i8** @_ZTIi to i8*), i8* bitcast (i8** @_ZTIc to i8*)] + %1 = extractvalue { i8*, i32 } %0, 0 + %2 = extractvalue { i8*, i32 } %0, 1 + br label %filter.dispatch +; CHECK: lpad: +; CHECK-NEXT: %[[FMC:.*]] = call i8* @___cxa_find_matching_catch_4(i8* bitcast (i8** @_ZTIi to i8*), i8* bitcast (i8** @_ZTIc to i8*)) +; CHECK-NEXT: %[[IVI1:.*]] = insertvalue { i8*, i32 } undef, i8* %[[FMC]], 0 +; CHECK-NEXT: %[[TEMPRET0_VAL:.*]] = load i32, i32* @[[TEMPRET0]] +; CHECK-NEXT: %[[IVI2:.*]] = insertvalue { i8*, i32 } %[[IVI1]], i32 %[[TEMPRET0_VAL]], 1 +; CHECK-NEXT: extractvalue { i8*, i32 } %[[IVI2]], 0 +; CHECK-NEXT: extractvalue { i8*, i32 } %[[IVI2]], 1 + +filter.dispatch: ; preds = %lpad + %ehspec.fails = icmp slt i32 %2, 0 + br i1 %ehspec.fails, label %ehspec.unexpected, label %eh.resume + +ehspec.unexpected: ; preds = %filter.dispatch + call void @__cxa_call_unexpected(i8* %1) #4 + unreachable + +eh.resume: ; preds = %filter.dispatch + %lpad.val = insertvalue { i8*, i32 } undef, i8* %1, 0 + %lpad.val3 = insertvalue { i8*, i32 } %lpad.val, i32 %2, 1 + resume { i8*, i32 } %lpad.val3 +; CHECK: eh.resume: +; CHECK-NEXT: insertvalue +; CHECK-NEXT: %[[LPAD_VAL:.*]] = insertvalue +; CHECK-NEXT: %[[LOW:.*]] = extractvalue { i8*, i32 } %[[LPAD_VAL]], 0 +; CHECK-NEXT: call void @___resumeException(i8* %[[LOW]]) +; CHECK-NEXT: unreachable +} + +declare void @foo(i32) + +declare i32 @__gxx_personality_v0(...) +declare i32 @llvm.eh.typeid.for(i8*) +declare i8* @__cxa_begin_catch(i8*) +declare void @__cxa_end_catch() +declare void @__cxa_call_unexpected(i8*) + +; JS glue functions and invoke wrappers registration +; CHECK: declare void @___resumeException(i8*) +; CHECK: declare void @__invoke_void_i32(void (i32)*, i32) +; CHECK: declare i8* @___cxa_find_matching_catch_4(i8*, i8*) + +; setThrew function creation +; CHECK-LABEL: define void @setThrew(i1 %threw, i32 %value) { +; CHECK: entry: +; CHECK-NEXT: %__THREW__.val = load i1, i1* @__THREW__ +; CHECK-NEXT: %cmp = icmp eq i1 %__THREW__.val, false +; CHECK-NEXT: br i1 %cmp, label %if.then, label %if.end +; CHECK: if.then: +; CHECK-NEXT: store i1 %threw, i1* @__THREW__ +; CHECK-NEXT: store i32 %value, i32* @threwValue +; CHECK-NEXT: br label %if.end +; CHECK: if.end: +; CHECK-NEXT: ret void +; CHECK: } + +; setTempRet0 function creation +; CHECK-LABEL: define void @setTempRet0(i32 %value) { +; CHECK: entry: +; CHECK-NEXT: store i32 %value, i32* @tempRet0 +; CHECK-NEXT: ret void +; CHECK: } |

