summaryrefslogtreecommitdiffstats
path: root/llvm/test
diff options
context:
space:
mode:
authorDerek Schuff <dschuff@google.com>2016-08-01 21:34:04 +0000
committerDerek Schuff <dschuff@google.com>2016-08-01 21:34:04 +0000
commitf41f67d3d91ca7aea611fd6eb4dc11d32ff677d5 (patch)
tree415db41f5891d4c73bde4d6a2b89c2e031758676 /llvm/test
parent4a7130a8fb77e45f3e597a132a539ac323ac6a34 (diff)
downloadbcm5719-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.ll143
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: }
OpenPOWER on IntegriCloud