summaryrefslogtreecommitdiff
path: root/test/CodeGen/WebAssembly
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-01-02 19:17:04 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-01-02 19:17:04 +0000
commitb915e9e0fc85ba6f398b3fab0db6a81a8913af94 (patch)
tree98b8f811c7aff2547cab8642daf372d6c59502fb /test/CodeGen/WebAssembly
parent6421cca32f69ac849537a3cff78c352195e99f1b (diff)
Notes
Diffstat (limited to 'test/CodeGen/WebAssembly')
-rw-r--r--test/CodeGen/WebAssembly/address-offsets.ll116
-rw-r--r--test/CodeGen/WebAssembly/byval.ll33
-rw-r--r--test/CodeGen/WebAssembly/call.ll18
-rw-r--r--test/CodeGen/WebAssembly/cfg-stackify.ll268
-rw-r--r--test/CodeGen/WebAssembly/cfi.ll53
-rw-r--r--test/CodeGen/WebAssembly/dbgvalue.ll72
-rw-r--r--test/CodeGen/WebAssembly/fast-isel-noreg.ll35
-rw-r--r--test/CodeGen/WebAssembly/fast-isel.ll30
-rw-r--r--test/CodeGen/WebAssembly/globl.ll4
-rw-r--r--test/CodeGen/WebAssembly/i32-load-store-alignment.ll20
-rw-r--r--test/CodeGen/WebAssembly/i64-load-store-alignment.ll30
-rw-r--r--test/CodeGen/WebAssembly/implicit-def.ll50
-rw-r--r--test/CodeGen/WebAssembly/inline-asm.ll4
-rw-r--r--test/CodeGen/WebAssembly/load-store-i1.ll28
-rw-r--r--test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll61
-rw-r--r--test/CodeGen/WebAssembly/lower-em-exceptions-whitelist.ll65
-rw-r--r--test/CodeGen/WebAssembly/lower-em-exceptions.ll194
-rw-r--r--test/CodeGen/WebAssembly/lower-em-sjlj.ll213
-rw-r--r--test/CodeGen/WebAssembly/mem-intrinsics.ll2
-rw-r--r--test/CodeGen/WebAssembly/memory-addr64.ll27
-rw-r--r--test/CodeGen/WebAssembly/negative-base-reg.ll43
-rw-r--r--test/CodeGen/WebAssembly/offset.ll53
-rw-r--r--test/CodeGen/WebAssembly/reg-stackify.ll37
-rw-r--r--test/CodeGen/WebAssembly/simd-arith.ll158
-rw-r--r--test/CodeGen/WebAssembly/stack-alignment.ll137
-rw-r--r--test/CodeGen/WebAssembly/store-results.ll72
-rw-r--r--test/CodeGen/WebAssembly/store-trunc.ll10
-rw-r--r--test/CodeGen/WebAssembly/store.ll8
-rw-r--r--test/CodeGen/WebAssembly/switch.ll28
-rw-r--r--test/CodeGen/WebAssembly/userstack.ll183
-rw-r--r--test/CodeGen/WebAssembly/varargs.ll10
31 files changed, 1610 insertions, 452 deletions
diff --git a/test/CodeGen/WebAssembly/address-offsets.ll b/test/CodeGen/WebAssembly/address-offsets.ll
index 6403b3762992..b9efec86f0da 100644
--- a/test/CodeGen/WebAssembly/address-offsets.ll
+++ b/test/CodeGen/WebAssembly/address-offsets.ll
@@ -28,13 +28,17 @@ define i32 @load_test0_noinbounds() {
ret i32 %t
}
+; TODO: load_test1 - load_test8 are disabled because folding GA+reg is disabled
+; (there are cases where the value in the reg can be negative).
+; Likewise for stores.
+
; CHECK-LABEL: load_test1:
; CHECK-NEXT: param i32{{$}}
; CHECK-NEXT: result i32{{$}}
; CHECK-NEXT: i32.const $push0=, 2{{$}}
-; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
-; CHECK-NEXT: i32.load $push2=, g+40($pop1){{$}}
-; CHECK-NEXT: return $pop2{{$}}
+; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}}
+; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}}
+; CHECK-NEX T: return $pop2{{$}}
define i32 @load_test1(i32 %n) {
%add = add nsw i32 %n, 10
%arrayidx = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add
@@ -46,9 +50,9 @@ define i32 @load_test1(i32 %n) {
; CHECK-NEXT: param i32{{$}}
; CHECK-NEXT: result i32{{$}}
; CHECK-NEXT: i32.const $push0=, 2{{$}}
-; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
-; CHECK-NEXT: i32.load $push2=, g+40($pop1){{$}}
-; CHECK-NEXT: return $pop2{{$}}
+; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}}
+; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}}
+; CHECK-NEX T: return $pop2{{$}}
define i32 @load_test2(i32 %n) {
%add = add nsw i32 10, %n
%arrayidx = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add
@@ -60,9 +64,9 @@ define i32 @load_test2(i32 %n) {
; CHECK-NEXT: param i32{{$}}
; CHECK-NEXT: result i32{{$}}
; CHECK-NEXT: i32.const $push0=, 2{{$}}
-; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
-; CHECK-NEXT: i32.load $push2=, g+40($pop1){{$}}
-; CHECK-NEXT: return $pop2{{$}}
+; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}}
+; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}}
+; CHECK-NEX T: return $pop2{{$}}
define i32 @load_test3(i32 %n) {
%add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %n
%add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10
@@ -74,9 +78,9 @@ define i32 @load_test3(i32 %n) {
; CHECK-NEXT: param i32{{$}}
; CHECK-NEXT: result i32{{$}}
; CHECK-NEXT: i32.const $push0=, 2{{$}}
-; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
-; CHECK-NEXT: i32.load $push2=, g+40($pop1){{$}}
-; CHECK-NEXT: return $pop2{{$}}
+; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}}
+; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}}
+; CHECK-NEX T: return $pop2{{$}}
define i32 @load_test4(i32 %n) {
%add.ptr = getelementptr inbounds i32, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 10), i32 %n
%t = load i32, i32* %add.ptr, align 4
@@ -87,9 +91,9 @@ define i32 @load_test4(i32 %n) {
; CHECK-NEXT: param i32{{$}}
; CHECK-NEXT: result i32{{$}}
; CHECK-NEXT: i32.const $push0=, 2{{$}}
-; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
-; CHECK-NEXT: i32.load $push2=, g+40($pop1){{$}}
-; CHECK-NEXT: return $pop2{{$}}
+; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}}
+; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}}
+; CHECK-NEX T: return $pop2{{$}}
define i32 @load_test5(i32 %n) {
%add.ptr = getelementptr inbounds i32, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 10), i32 %n
%t = load i32, i32* %add.ptr, align 4
@@ -100,9 +104,9 @@ define i32 @load_test5(i32 %n) {
; CHECK-NEXT: param i32{{$}}
; CHECK-NEXT: result i32{{$}}
; CHECK-NEXT: i32.const $push0=, 2{{$}}
-; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
-; CHECK-NEXT: i32.load $push2=, g+40($pop1){{$}}
-; CHECK-NEXT: return $pop2{{$}}
+; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}}
+; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}}
+; CHECK-NEX T: return $pop2{{$}}
define i32 @load_test6(i32 %n) {
%add = add nsw i32 %n, 10
%add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add
@@ -114,9 +118,9 @@ define i32 @load_test6(i32 %n) {
; CHECK-NEXT: param i32{{$}}
; CHECK-NEXT: result i32{{$}}
; CHECK-NEXT: i32.const $push0=, 2{{$}}
-; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
-; CHECK-NEXT: i32.load $push2=, g+40($pop1){{$}}
-; CHECK-NEXT: return $pop2{{$}}
+; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}}
+; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}}
+; CHECK-NEX T: return $pop2{{$}}
define i32 @load_test7(i32 %n) {
%add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %n
%add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10
@@ -128,9 +132,9 @@ define i32 @load_test7(i32 %n) {
; CHECK-NEXT: param i32{{$}}
; CHECK-NEXT: result i32{{$}}
; CHECK-NEXT: i32.const $push0=, 2{{$}}
-; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
-; CHECK-NEXT: i32.load $push2=, g+40($pop1){{$}}
-; CHECK-NEXT: return $pop2{{$}}
+; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}}
+; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}}
+; CHECK-NEX T: return $pop2{{$}}
define i32 @load_test8(i32 %n) {
%add = add nsw i32 10, %n
%add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add
@@ -353,7 +357,7 @@ define i32 @load_test21(i32* %p, i32 %n) {
; CHECK-LABEL: store_test0:
; CHECK-NEXT: param i32{{$}}
; CHECK-NEXT: i32.const $push0=, 0{{$}}
-; CHECK-NEXT: i32.store $drop=, g+40($pop0), $0{{$}}
+; CHECK-NEXT: i32.store g+40($pop0), $0{{$}}
; CHECK-NEXT: return{{$}}
define void @store_test0(i32 %i) {
store i32 %i, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 10), align 4
@@ -363,7 +367,7 @@ define void @store_test0(i32 %i) {
; CHECK-LABEL: store_test0_noinbounds:
; CHECK-NEXT: param i32{{$}}
; CHECK-NEXT: i32.const $push0=, 0{{$}}
-; CHECK-NEXT: i32.store $drop=, g+40($pop0), $0{{$}}
+; CHECK-NEXT: i32.store g+40($pop0), $0{{$}}
; CHECK-NEXT: return{{$}}
define void @store_test0_noinbounds(i32 %i) {
store i32 %i, i32* getelementptr ([0 x i32], [0 x i32]* @g, i32 0, i32 10), align 4
@@ -374,8 +378,8 @@ define void @store_test0_noinbounds(i32 %i) {
; CHECK-NEXT: param i32, i32{{$}}
; CHECK-NEXT: i32.const $push0=, 2{{$}}
; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
-; CHECK-NEXT: i32.store $drop=, g+40($pop1), $1{{$}}
-; CHECK-NEXT: return{{$}}
+; CHECK-NEX T: i32.store g+40($pop1), $1{{$}}
+; CHECK-NEX T: return{{$}}
define void @store_test1(i32 %n, i32 %i) {
%add = add nsw i32 %n, 10
%arrayidx = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add
@@ -387,8 +391,8 @@ define void @store_test1(i32 %n, i32 %i) {
; CHECK-NEXT: param i32, i32{{$}}
; CHECK-NEXT: i32.const $push0=, 2{{$}}
; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
-; CHECK-NEXT: i32.store $drop=, g+40($pop1), $1{{$}}
-; CHECK-NEXT: return{{$}}
+; CHECK-NEX T: i32.store g+40($pop1), $1{{$}}
+; CHECK-NEX T: return{{$}}
define void @store_test2(i32 %n, i32 %i) {
%add = add nsw i32 10, %n
%arrayidx = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add
@@ -400,8 +404,8 @@ define void @store_test2(i32 %n, i32 %i) {
; CHECK-NEXT: param i32, i32{{$}}
; CHECK-NEXT: i32.const $push0=, 2{{$}}
; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
-; CHECK-NEXT: i32.store $drop=, g+40($pop1), $1{{$}}
-; CHECK-NEXT: return{{$}}
+; CHECK-NEX T: i32.store g+40($pop1), $1{{$}}
+; CHECK-NEX T: return{{$}}
define void @store_test3(i32 %n, i32 %i) {
%add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %n
%add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10
@@ -413,8 +417,8 @@ define void @store_test3(i32 %n, i32 %i) {
; CHECK-NEXT: param i32, i32{{$}}
; CHECK-NEXT: i32.const $push0=, 2{{$}}
; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
-; CHECK-NEXT: i32.store $drop=, g+40($pop1), $1{{$}}
-; CHECK-NEXT: return{{$}}
+; CHECK-NEX T: i32.store g+40($pop1), $1{{$}}
+; CHECK-NEX T: return{{$}}
define void @store_test4(i32 %n, i32 %i) {
%add.ptr = getelementptr inbounds i32, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 10), i32 %n
store i32 %i, i32* %add.ptr, align 4
@@ -425,8 +429,8 @@ define void @store_test4(i32 %n, i32 %i) {
; CHECK-NEXT: param i32, i32{{$}}
; CHECK-NEXT: i32.const $push0=, 2{{$}}
; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
-; CHECK-NEXT: i32.store $drop=, g+40($pop1), $1{{$}}
-; CHECK-NEXT: return{{$}}
+; CHECK-NEX T: i32.store g+40($pop1), $1{{$}}
+; CHECK-NEX T: return{{$}}
define void @store_test5(i32 %n, i32 %i) {
%add.ptr = getelementptr inbounds i32, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 10), i32 %n
store i32 %i, i32* %add.ptr, align 4
@@ -437,8 +441,8 @@ define void @store_test5(i32 %n, i32 %i) {
; CHECK-NEXT: param i32, i32{{$}}
; CHECK-NEXT: i32.const $push0=, 2{{$}}
; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
-; CHECK-NEXT: i32.store $drop=, g+40($pop1), $1{{$}}
-; CHECK-NEXT: return{{$}}
+; CHECK-NEX T: i32.store g+40($pop1), $1{{$}}
+; CHECK-NEX T: return{{$}}
define void @store_test6(i32 %n, i32 %i) {
%add = add nsw i32 %n, 10
%add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add
@@ -450,8 +454,8 @@ define void @store_test6(i32 %n, i32 %i) {
; CHECK-NEXT: param i32, i32{{$}}
; CHECK-NEXT: i32.const $push0=, 2{{$}}
; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
-; CHECK-NEXT: i32.store $drop=, g+40($pop1), $1{{$}}
-; CHECK-NEXT: return{{$}}
+; CHECK-NEX T: i32.store g+40($pop1), $1{{$}}
+; CHECK-NEX T: return{{$}}
define void @store_test7(i32 %n, i32 %i) {
%add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %n
%add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10
@@ -463,8 +467,8 @@ define void @store_test7(i32 %n, i32 %i) {
; CHECK-NEXT: param i32, i32{{$}}
; CHECK-NEXT: i32.const $push0=, 2{{$}}
; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
-; CHECK-NEXT: i32.store $drop=, g+40($pop1), $1{{$}}
-; CHECK-NEXT: return{{$}}
+; CHECK-NEX T: i32.store g+40($pop1), $1{{$}}
+; CHECK-NEX T: return{{$}}
define void @store_test8(i32 %n, i32 %i) {
%add = add nsw i32 10, %n
%add.ptr = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add
@@ -475,7 +479,7 @@ define void @store_test8(i32 %n, i32 %i) {
; CHECK-LABEL: store_test9:
; CHECK-NEXT: param i32{{$}}
; CHECK-NEXT: i32.const $push0=, 0{{$}}
-; CHECK-NEXT: i32.store $drop=, g-40($pop0), $0{{$}}
+; CHECK-NEXT: i32.store g-40($pop0), $0{{$}}
; CHECK-NEXT: return{{$}}
define void @store_test9(i32 %i) {
store i32 %i, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 1073741814), align 4
@@ -488,7 +492,7 @@ define void @store_test9(i32 %i) {
; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
; CHECK-NEXT: i32.const $push2=, g-40{{$}}
; CHECK-NEXT: i32.add $push3=, $pop1, $pop2{{$}}
-; CHECK-NEXT: i32.store $drop=, 0($pop3), $1{{$}}
+; CHECK-NEXT: i32.store 0($pop3), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @store_test10(i32 %n, i32 %i) {
%add = add nsw i32 %n, -10
@@ -499,7 +503,7 @@ define void @store_test10(i32 %n, i32 %i) {
; CHECK-LABEL: store_test11:
; CHECK-NEXT: param i32, i32{{$}}
-; CHECK-NEXT: i32.store $drop=, 40($0), $1{{$}}
+; CHECK-NEXT: i32.store 40($0), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @store_test11(i32* %p, i32 %i) {
%arrayidx = getelementptr inbounds i32, i32* %p, i32 10
@@ -511,7 +515,7 @@ define void @store_test11(i32* %p, i32 %i) {
; CHECK-NEXT: param i32, i32{{$}}
; CHECK-NEXT: i32.const $push0=, 40{{$}}
; CHECK-NEXT: i32.add $push1=, $0, $pop0{{$}}
-; CHECK-NEXT: i32.store $drop=, 0($pop1), $1{{$}}
+; CHECK-NEXT: i32.store 0($pop1), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @store_test11_noinbounds(i32* %p, i32 %i) {
%arrayidx = getelementptr i32, i32* %p, i32 10
@@ -526,7 +530,7 @@ define void @store_test11_noinbounds(i32* %p, i32 %i) {
; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}}
; CHECK-NEXT: i32.const $push3=, 40{{$}}
; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
-; CHECK-NEXT: i32.store $drop=, 0($pop4), $2{{$}}
+; CHECK-NEXT: i32.store 0($pop4), $2{{$}}
; CHECK-NEXT: return{{$}}
define void @store_test12(i32* %p, i32 %n, i32 %i) {
%add = add nsw i32 %n, 10
@@ -542,7 +546,7 @@ define void @store_test12(i32* %p, i32 %n, i32 %i) {
; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}}
; CHECK-NEXT: i32.const $push3=, 40{{$}}
; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
-; CHECK-NEXT: i32.store $drop=, 0($pop4), $2{{$}}
+; CHECK-NEXT: i32.store 0($pop4), $2{{$}}
; CHECK-NEXT: return{{$}}
define void @store_test13(i32* %p, i32 %n, i32 %i) {
%add = add nsw i32 10, %n
@@ -556,7 +560,7 @@ define void @store_test13(i32* %p, i32 %n, i32 %i) {
; CHECK-NEXT: i32.const $push0=, 2{{$}}
; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}}
; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}}
-; CHECK-NEXT: i32.store $drop=, 40($pop2), $2{{$}}
+; CHECK-NEXT: i32.store 40($pop2), $2{{$}}
; CHECK-NEXT: return{{$}}
define void @store_test14(i32* %p, i32 %n, i32 %i) {
%add.ptr = getelementptr inbounds i32, i32* %p, i32 %n
@@ -572,7 +576,7 @@ define void @store_test14(i32* %p, i32 %n, i32 %i) {
; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}}
; CHECK-NEXT: i32.const $push3=, 40{{$}}
; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
-; CHECK-NEXT: i32.store $drop=, 0($pop4), $2{{$}}
+; CHECK-NEXT: i32.store 0($pop4), $2{{$}}
; CHECK-NEXT: return{{$}}
define void @store_test15(i32* %p, i32 %n, i32 %i) {
%add.ptr = getelementptr inbounds i32, i32* %p, i32 10
@@ -588,7 +592,7 @@ define void @store_test15(i32* %p, i32 %n, i32 %i) {
; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}}
; CHECK-NEXT: i32.const $push3=, 40{{$}}
; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
-; CHECK-NEXT: i32.store $drop=, 0($pop4), $2{{$}}
+; CHECK-NEXT: i32.store 0($pop4), $2{{$}}
; CHECK-NEXT: return{{$}}
define void @store_test16(i32* %p, i32 %n, i32 %i) {
%add.ptr = getelementptr inbounds i32, i32* %p, i32 10
@@ -604,7 +608,7 @@ define void @store_test16(i32* %p, i32 %n, i32 %i) {
; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}}
; CHECK-NEXT: i32.const $push3=, 40{{$}}
; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
-; CHECK-NEXT: i32.store $drop=, 0($pop4), $2{{$}}
+; CHECK-NEXT: i32.store 0($pop4), $2{{$}}
; CHECK-NEXT: return{{$}}
define void @store_test17(i32* %p, i32 %n, i32 %i) {
%add = add nsw i32 %n, 10
@@ -618,7 +622,7 @@ define void @store_test17(i32* %p, i32 %n, i32 %i) {
; CHECK-NEXT: i32.const $push0=, 2{{$}}
; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}}
; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}}
-; CHECK-NEXT: i32.store $drop=, 40($pop2), $2{{$}}
+; CHECK-NEXT: i32.store 40($pop2), $2{{$}}
; CHECK-NEXT: return{{$}}
define void @store_test18(i32* %p, i32 %n, i32 %i) {
%add.ptr = getelementptr inbounds i32, i32* %p, i32 %n
@@ -634,7 +638,7 @@ define void @store_test18(i32* %p, i32 %n, i32 %i) {
; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}}
; CHECK-NEXT: i32.const $push3=, 40{{$}}
; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
-; CHECK-NEXT: i32.store $drop=, 0($pop4), $2{{$}}
+; CHECK-NEXT: i32.store 0($pop4), $2{{$}}
; CHECK-NEXT: return{{$}}
define void @store_test19(i32* %p, i32 %n, i32 %i) {
%add = add nsw i32 10, %n
@@ -647,7 +651,7 @@ define void @store_test19(i32* %p, i32 %n, i32 %i) {
; CHECK-NEXT: param i32, i32{{$}}
; CHECK-NEXT: i32.const $push0=, -40{{$}}
; CHECK-NEXT: i32.add $push1=, $0, $pop0{{$}}
-; CHECK-NEXT: i32.store $drop=, 0($pop1), $1{{$}}
+; CHECK-NEXT: i32.store 0($pop1), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @store_test20(i32* %p, i32 %i) {
%arrayidx = getelementptr inbounds i32, i32* %p, i32 -10
@@ -662,7 +666,7 @@ define void @store_test20(i32* %p, i32 %i) {
; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}}
; CHECK-NEXT: i32.const $push3=, -40{{$}}
; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
-; CHECK-NEXT: i32.store $drop=, 0($pop4), $2{{$}}
+; CHECK-NEXT: i32.store 0($pop4), $2{{$}}
; CHECK-NEXT: return{{$}}
define void @store_test21(i32* %p, i32 %n, i32 %i) {
%add = add nsw i32 %n, -10
diff --git a/test/CodeGen/WebAssembly/byval.ll b/test/CodeGen/WebAssembly/byval.ll
index ebbf50313a58..7a995769a8e7 100644
--- a/test/CodeGen/WebAssembly/byval.ll
+++ b/test/CodeGen/WebAssembly/byval.ll
@@ -28,13 +28,13 @@ define void @byval_arg(%SmallStruct* %ptr) {
; CHECK: i32.const $push[[L1:.+]]=, 0
; CHECK-NEXT: i32.load $push[[L2:.+]]=, __stack_pointer($pop[[L1]])
; CHECK-NEXT: i32.const $push[[L3:.+]]=, 16
- ; CHECK-NEXT: i32.sub $push[[L10:.+]]=, $pop[[L2]], $pop[[L3]]
+ ; CHECK-NEXT: i32.sub $push[[L11:.+]]=, $pop[[L2]], $pop[[L3]]
; Ensure SP is stored back before the call
- ; CHECK-NEXT: i32.store $push[[L12:.+]]=, __stack_pointer($pop[[L4]]), $pop[[L10]]{{$}}
- ; CHECK-NEXT: tee_local $push[[L11:.+]]=, $[[SP:.+]]=, $pop[[L12]]{{$}}
+ ; CHECK-NEXT: tee_local $push[[L10:.+]]=, $[[SP:.+]]=, $pop[[L11]]{{$}}
+ ; CHECK-NEXT: i32.store __stack_pointer($pop[[L4]]), $pop[[L10]]{{$}}
; Copy the SmallStruct argument to the stack (SP+12, original SP-4)
; CHECK-NEXT: i32.load $push[[L0:.+]]=, 0($0)
- ; CHECK-NEXT: i32.store $drop=, 12($pop[[L11]]), $pop[[L0]]
+ ; CHECK-NEXT: i32.store 12($[[SP]]), $pop[[L0]]
; Pass a pointer to the stack slot to the function
; CHECK-NEXT: i32.const $push[[L5:.+]]=, 12{{$}}
; CHECK-NEXT: i32.add $push[[ARG:.+]]=, $[[SP]], $pop[[L5]]{{$}}
@@ -44,7 +44,7 @@ define void @byval_arg(%SmallStruct* %ptr) {
; CHECK-NEXT: i32.const $push[[L7:.+]]=, 0
; CHECK-NEXT: i32.const $push[[L6:.+]]=, 16
; CHECK-NEXT: i32.add $push[[L8:.+]]=, $[[SP]], $pop[[L6]]
- ; CHECK-NEXT: i32.store {{.*}}=, __stack_pointer($pop[[L7]]), $pop[[L8]]
+ ; CHECK-NEXT: i32.store __stack_pointer($pop[[L7]]), $pop[[L8]]
; CHECK-NEXT: return
ret void
}
@@ -54,12 +54,12 @@ define void @byval_arg_align8(%SmallStruct* %ptr) {
; CHECK: .param i32
; Don't check the entire SP sequence, just enough to get the alignment.
; CHECK: i32.const $push[[L1:.+]]=, 16
- ; CHECK-NEXT: i32.sub $push[[L10:.+]]=, {{.+}}, $pop[[L1]]
- ; CHECK-NEXT: i32.store $push[[L12:.+]]=, __stack_pointer($pop{{.+}}), $pop[[L10]]{{$}}
- ; CHECK-NEXT: tee_local $push[[L11:.+]]=, $[[SP:.+]]=, $pop[[L12]]{{$}}
+ ; CHECK-NEXT: i32.sub $push[[L11:.+]]=, {{.+}}, $pop[[L1]]
+ ; CHECK-NEXT: tee_local $push[[L10:.+]]=, $[[SP:.+]]=, $pop[[L11]]{{$}}
+ ; CHECK-NEXT: i32.store __stack_pointer($pop{{.+}}), $pop[[L10]]{{$}}
; Copy the SmallStruct argument to the stack (SP+8, original SP-8)
; CHECK-NEXT: i32.load $push[[L0:.+]]=, 0($0){{$}}
- ; CHECK-NEXT: i32.store $drop=, 8($pop[[L11]]), $pop[[L0]]{{$}}
+ ; CHECK-NEXT: i32.store 8($[[SP]]), $pop[[L0]]{{$}}
; Pass a pointer to the stack slot to the function
; CHECK-NEXT: i32.const $push[[L5:.+]]=, 8{{$}}
; CHECK-NEXT: i32.add $push[[ARG:.+]]=, $[[SP]], $pop[[L5]]{{$}}
@@ -73,13 +73,13 @@ define void @byval_arg_double(%AlignedStruct* %ptr) {
; CHECK: .param i32
; Subtract 16 from SP (SP is 16-byte aligned)
; CHECK: i32.const $push[[L1:.+]]=, 16
- ; CHECK-NEXT: i32.sub $push[[L12:.+]]=, {{.+}}, $pop[[L1]]
- ; CHECK-NEXT: i32.store $push[[L15:.+]]=, {{.+}}, $pop[[L12]]
- ; CHECK-NEXT: tee_local $push[[L14:.+]]=, $[[SP:.+]]=, $pop[[L15]]
+ ; CHECK-NEXT: i32.sub $push[[L14:.+]]=, {{.+}}, $pop[[L1]]
+ ; CHECK-NEXT: tee_local $push[[L13:.+]]=, $[[SP:.+]]=, $pop[[L14]]
+ ; CHECK-NEXT: i32.store {{.+}}, $pop[[L13]]
; Copy the AlignedStruct argument to the stack (SP+0, original SP-16)
; Just check the last load/store pair of the memcpy
; CHECK: i64.load $push[[L4:.+]]=, 0($0)
- ; CHECK-NEXT: i64.store $drop=, 0($[[SP]]), $pop[[L4]]
+ ; CHECK-NEXT: i64.store 0($[[SP]]), $pop[[L4]]
; Pass a pointer to the stack slot to the function
; CHECK-NEXT: call ext_byval_func_alignedstruct@FUNCTION, $[[SP]]
tail call void @ext_byval_func_alignedstruct(%AlignedStruct* byval %ptr)
@@ -117,10 +117,11 @@ define void @byval_empty_callee(%EmptyStruct* byval %ptr) {
; CHECK: i32.const $push[[L1:.+]]=, 0
; CHECK-NEXT: i32.load $push[[L2:.+]]=, __stack_pointer($pop[[L1]])
; CHECK-NEXT: i32.const $push[[L3:.+]]=, 131072
-; CHECK-NEXT: i32.sub $push[[L8:.+]]=, $pop[[L2]], $pop[[L3]]
-; CHECK-NEXT: i32.store $push[[L12:.+]]=, __stack_pointer($pop[[L4]]), $pop[[L8]]{{$}}
+; CHECK-NEXT: i32.sub $push[[L11:.+]]=, $pop[[L2]], $pop[[L3]]
+; CHECK-NEXT: tee_local $push[[L10:.+]]=, $[[SP:.+]]=, $pop[[L11]]{{$}}
+; CHECK-NEXT: i32.store __stack_pointer($pop[[L4]]), $pop[[L10]]{{$}}
; CHECK-NEXT: i32.const $push[[L0:.+]]=, 131072
-; CHECK-NEXT: i32.call $push[[L11:.+]]=, memcpy@FUNCTION, $pop{{.+}}, ${{.+}}, $pop{{.+}}
+; CHECK-NEXT: i32.call $push[[L11:.+]]=, memcpy@FUNCTION, $[[SP]], ${{.+}}, $pop{{.+}}
; CHECK-NEXT: tee_local $push[[L9:.+]]=, $[[SP:.+]]=, $pop[[L11]]{{$}}
; CHECK-NEXT: call big_byval_callee@FUNCTION,
%big = type [131072 x i8]
diff --git a/test/CodeGen/WebAssembly/call.ll b/test/CodeGen/WebAssembly/call.ll
index bd5f7b80edba..1a9d5b8fb8e6 100644
--- a/test/CodeGen/WebAssembly/call.ll
+++ b/test/CodeGen/WebAssembly/call.ll
@@ -97,6 +97,24 @@ define i32 @call_indirect_i32(i32 ()* %callee) {
ret i32 %t
}
+; CHECK-LABEL: call_indirect_arg:
+; CHECK-NEXT: .param i32, i32{{$}}
+; CHECK-NEXT: {{^}} call_indirect $1, $0{{$}}
+; CHECK-NEXT: return{{$}}
+define void @call_indirect_arg(void (i32)* %callee, i32 %arg) {
+ call void %callee(i32 %arg)
+ ret void
+}
+
+; CHECK-LABEL: call_indirect_arg_2:
+; CHECK-NEXT: .param i32, i32, i32{{$}}
+; CHECK-NEXT: {{^}} i32.call_indirect $drop=, $1, $2, $0{{$}}
+; CHECK-NEXT: return{{$}}
+define void @call_indirect_arg_2(i32 (i32, i32)* %callee, i32 %arg, i32 %arg2) {
+ call i32 %callee(i32 %arg, i32 %arg2)
+ ret void
+}
+
; CHECK-LABEL: tail_call_void_nullary:
; CHECK-NEXT: {{^}} call void_nullary@FUNCTION{{$}}
; CHECK-NEXT: return{{$}}
diff --git a/test/CodeGen/WebAssembly/cfg-stackify.ll b/test/CodeGen/WebAssembly/cfg-stackify.ll
index d46898b44703..3b42df190266 100644
--- a/test/CodeGen/WebAssembly/cfg-stackify.ll
+++ b/test/CodeGen/WebAssembly/cfg-stackify.ll
@@ -1,5 +1,5 @@
-; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-block-placement -verify-machineinstrs -fast-isel=false | FileCheck %s
-; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -verify-machineinstrs -fast-isel=false | FileCheck -check-prefix=OPT %s
+; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 | FileCheck %s
+; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -tail-dup-placement=0 -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 | FileCheck -check-prefix=OPT %s
; Test the CFG stackifier pass.
@@ -16,23 +16,23 @@ declare void @something()
; CHECK-LABEL: test0:
; CHECK: loop
; CHECK-NEXT: block
-; CHECK-NEXT: i32.const
-; CHECK-NEXT: i32.add
; CHECK: i32.lt_s
; CHECK-NEXT: br_if
; CHECK-NEXT: return
; CHECK-NEXT: .LBB0_3:
; CHECK-NEXT: end_block
+; CHECK-NEXT: i32.const
+; CHECK-NEXT: i32.add
; CHECK-NEXT: call
; CHECK-NEXT: br
; CHECK-NEXT: .LBB0_4:
; CHECK-NEXT: end_loop
; OPT-LABEL: test0:
; OPT: loop
-; OPT-NEXT: i32.const
-; OPT-NEXT: i32.add
; OPT: i32.ge_s
; OPT-NEXT: br_if
+; OPT-NEXT: i32.const
+; OPT-NEXT: i32.add
; OPT-NOT: br
; OPT: call
; OPT: br 0{{$}}
@@ -61,23 +61,23 @@ back:
; CHECK-LABEL: test1:
; CHECK: loop
; CHECK-NEXT: block
-; CHECK-NEXT: i32.const
-; CHECK-NEXT: i32.add
; CHECK: i32.lt_s
; CHECK-NEXT: br_if
; CHECK-NEXT: return
; CHECK-NEXT: .LBB1_3:
; CHECK-NEXT: end_block
+; CHECK-NEXT: i32.const
+; CHECK-NEXT: i32.add
; CHECK-NEXT: call
; CHECK-NEXT: br
; CHECK-NEXT: .LBB1_4:
; CHECK-NEXT: end_loop
; OPT-LABEL: test1:
; OPT: loop
-; OPT-NEXT: i32.const
-; OPT-NEXT: i32.add
; OPT: i32.ge_s
; OPT-NEXT: br_if
+; OPT-NEXT: i32.const
+; OPT-NEXT: i32.add
; OPT-NOT: br
; OPT: call
; OPT: br 0{{$}}
@@ -105,7 +105,7 @@ back:
; CHECK-LABEL: test2:
; CHECK-NOT: local
-; CHECK: block{{$}}
+; CHECK: block {{$}}
; CHECK: br_if 0, {{[^,]+}}{{$}}
; CHECK: .LBB2_{{[0-9]+}}:
; CHECK: loop
@@ -116,7 +116,7 @@ back:
; CHECK: return{{$}}
; OPT-LABEL: test2:
; OPT-NOT: local
-; OPT: block{{$}}
+; OPT: block {{$}}
; OPT: br_if 0, {{[^,]+}}{{$}}
; OPT: .LBB2_{{[0-9]+}}:
; OPT: loop
@@ -151,13 +151,13 @@ for.end:
}
; CHECK-LABEL: doublediamond:
-; CHECK: block{{$}}
-; CHECK-NEXT: block{{$}}
+; CHECK: block {{$}}
+; CHECK-NEXT: block {{$}}
; CHECK: br_if 0, ${{[^,]+}}{{$}}
; CHECK: br 1{{$}}
; CHECK: .LBB3_2:
; CHECK-NEXT: end_block{{$}}
-; CHECK: block{{$}}
+; CHECK: block {{$}}
; CHECK: br_if 0, ${{[^,]+}}{{$}}
; CHECK: br 1{{$}}
; CHECK: .LBB3_4:
@@ -167,9 +167,9 @@ for.end:
; CHECK: i32.const $push{{[0-9]+}}=, 0{{$}}
; CHECK-NEXT: return $pop{{[0-9]+}}{{$}}
; OPT-LABEL: doublediamond:
-; OPT: block{{$}}
-; OPT-NEXT: block{{$}}
-; OPT-NEXT: block{{$}}
+; OPT: block {{$}}
+; OPT-NEXT: block {{$}}
+; OPT-NEXT: block {{$}}
; OPT: br_if 0, ${{[^,]+}}{{$}}
; OPT: br_if 1, ${{[^,]+}}{{$}}
; OPT: br 2{{$}}
@@ -204,15 +204,15 @@ exit:
}
; CHECK-LABEL: triangle:
-; CHECK: block{{$}}
+; CHECK: block {{$}}
; CHECK: br_if 0, $1{{$}}
; CHECK: .LBB4_2:
-; CHECK: return ${{[0-9]+}}{{$}}
+; CHECK: return
; OPT-LABEL: triangle:
-; OPT: block{{$}}
+; OPT: block {{$}}
; OPT: br_if 0, $1{{$}}
; OPT: .LBB4_2:
-; OPT: return ${{[0-9]+}}{{$}}
+; OPT: return
define i32 @triangle(i32* %p, i32 %a) {
entry:
%c = icmp eq i32 %a, 0
@@ -227,8 +227,8 @@ exit:
}
; CHECK-LABEL: diamond:
-; CHECK: block{{$}}
-; CHECK: block{{$}}
+; CHECK: block {{$}}
+; CHECK: block {{$}}
; CHECK: br_if 0, $1{{$}}
; CHECK: br 1{{$}}
; CHECK: .LBB5_2:
@@ -236,8 +236,8 @@ exit:
; CHECK: i32.const $push{{[0-9]+}}=, 0{{$}}
; CHECK-NEXT: return $pop{{[0-9]+}}{{$}}
; OPT-LABEL: diamond:
-; OPT: block{{$}}
-; OPT: block{{$}}
+; OPT: block {{$}}
+; OPT: block {{$}}
; OPT: br_if 0, {{[^,]+}}{{$}}
; OPT: br 1{{$}}
; OPT: .LBB5_2:
@@ -275,13 +275,15 @@ entry:
; CHECK-LABEL: minimal_loop:
; CHECK-NOT: br
; CHECK: .LBB7_1:
-; CHECK: i32.store $drop=, 0($0), $pop{{[0-9]+}}{{$}}
+; CHECK: loop i32
+; CHECK: i32.store 0($0), $pop{{[0-9]+}}{{$}}
; CHECK: br 0{{$}}
; CHECK: .LBB7_2:
; OPT-LABEL: minimal_loop:
; OPT-NOT: br
; OPT: .LBB7_1:
-; OPT: i32.store $drop=, 0($0), $pop{{[0-9]+}}{{$}}
+; OPT: loop i32
+; OPT: i32.store 0($0), $pop{{[0-9]+}}{{$}}
; OPT: br 0{{$}}
; OPT: .LBB7_2:
define i32 @minimal_loop(i32* %p) {
@@ -296,7 +298,7 @@ loop:
; CHECK-LABEL: simple_loop:
; CHECK-NOT: br
; CHECK: .LBB8_1:
-; CHECK: loop{{$}}
+; CHECK: loop {{$}}
; CHECK: br_if 0, $pop{{[0-9]+}}{{$}}
; CHECK-NEXT: end_loop{{$}}
; CHECK: i32.const $push{{[0-9]+}}=, 0{{$}}
@@ -304,7 +306,7 @@ loop:
; OPT-LABEL: simple_loop:
; OPT-NOT: br
; OPT: .LBB8_1:
-; OPT: loop{{$}}
+; OPT: loop {{$}}
; OPT: br_if 0, {{[^,]+}}{{$}}
; OPT-NEXT: end_loop{{$}}
; OPT: i32.const $push{{[0-9]+}}=, 0{{$}}
@@ -323,21 +325,21 @@ exit:
}
; CHECK-LABEL: doubletriangle:
-; CHECK: block{{$}}
+; CHECK: block {{$}}
; CHECK: br_if 0, $0{{$}}
-; CHECK: block{{$}}
+; CHECK: block {{$}}
; CHECK: br_if 0, $1{{$}}
; CHECK: .LBB9_3:
; CHECK: .LBB9_4:
-; CHECK: return ${{[0-9]+}}{{$}}
+; CHECK: return
; OPT-LABEL: doubletriangle:
-; OPT: block{{$}}
+; OPT: block {{$}}
; OPT: br_if 0, $0{{$}}
-; OPT: block{{$}}
+; OPT: block {{$}}
; OPT: br_if 0, $1{{$}}
; OPT: .LBB9_3:
; OPT: .LBB9_4:
-; OPT: return ${{[0-9]+}}{{$}}
+; OPT: return
define i32 @doubletriangle(i32 %a, i32 %b, i32* %p) {
entry:
%c = icmp eq i32 %a, 0
@@ -359,8 +361,8 @@ exit:
}
; CHECK-LABEL: ifelse_earlyexits:
-; CHECK: block{{$}}
-; CHECK: block{{$}}
+; CHECK: block {{$}}
+; CHECK: block {{$}}
; CHECK: br_if 0, $0{{$}}
; CHECK: br 1{{$}}
; CHECK: .LBB10_2:
@@ -369,8 +371,8 @@ exit:
; CHECK: i32.const $push{{[0-9]+}}=, 0{{$}}
; CHECK-NEXT: return $pop{{[0-9]+}}{{$}}
; OPT-LABEL: ifelse_earlyexits:
-; OPT: block{{$}}
-; OPT: block{{$}}
+; OPT: block {{$}}
+; OPT: block {{$}}
; OPT: br_if 0, {{[^,]+}}{{$}}
; OPT: br_if 1, $1{{$}}
; OPT: br 1{{$}}
@@ -400,13 +402,13 @@ exit:
; CHECK-LABEL: doublediamond_in_a_loop:
; CHECK: .LBB11_1:
-; CHECK: loop{{$}}
-; CHECK: block{{$}}
+; CHECK: loop i32{{$}}
+; CHECK: block {{$}}
; CHECK: br_if 0, $0{{$}}
; CHECK: br 1{{$}}
; CHECK: .LBB11_3:
; CHECK: end_block{{$}}
-; CHECK: block{{$}}
+; CHECK: block {{$}}
; CHECK: br_if 0, $1{{$}}
; CHECK: br 1{{$}}
; CHECK: .LBB11_5:
@@ -415,10 +417,10 @@ exit:
; CHECK-NEXT: end_loop{{$}}
; OPT-LABEL: doublediamond_in_a_loop:
; OPT: .LBB11_1:
-; OPT: loop{{$}}
-; OPT: block{{$}}
+; OPT: loop i32{{$}}
+; OPT: block {{$}}
; OPT: br_if 0, {{[^,]+}}{{$}}
-; OPT: block{{$}}
+; OPT: block {{$}}
; OPT: br_if 0, {{[^,]+}}{{$}}
; OPT: br 2{{$}}
; OPT-NEXT: .LBB11_4:
@@ -513,14 +515,14 @@ if.end:
; CHECK-LABEL: test4:
; CHECK-NEXT: .param i32{{$}}
-; CHECK: block{{$}}
-; CHECK-NEXT: block{{$}}
+; CHECK: block {{$}}
+; CHECK-NEXT: block {{$}}
; CHECK: br_if 0, $pop{{[0-9]+}}{{$}}
; CHECK: br_if 1, $pop{{[0-9]+}}{{$}}
; CHECK: br 1{{$}}
; CHECK-NEXT: .LBB13_3:
; CHECK-NEXT: end_block{{$}}
-; CHECK-NEXT: block{{$}}
+; CHECK-NEXT: block {{$}}
; CHECK: br_if 0, $pop{{[0-9]+}}{{$}}
; CHECK: br_if 1, $pop{{[0-9]+}}{{$}}
; CHECK-NEXT: .LBB13_5:
@@ -531,14 +533,14 @@ if.end:
; CHECK-NEXT: return{{$}}
; OPT-LABEL: test4:
; OPT-NEXT: .param i32{{$}}
-; OPT: block{{$}}
-; OPT-NEXT: block{{$}}
+; OPT: block {{$}}
+; OPT-NEXT: block {{$}}
; OPT: br_if 0, $pop{{[0-9]+}}{{$}}
; OPT: br_if 1, $pop{{[0-9]+}}{{$}}
; OPT: br 1{{$}}
; OPT-NEXT: .LBB13_3:
; OPT-NEXT: end_block{{$}}
-; OPT-NEXT: block{{$}}
+; OPT-NEXT: block {{$}}
; OPT: br_if 0, $pop{{[0-9]+}}{{$}}
; OPT: br_if 1, $pop{{[0-9]+}}{{$}}
; OPT-NEXT: .LBB13_5:
@@ -574,9 +576,9 @@ default:
; CHECK-LABEL: test5:
; CHECK: .LBB14_1:
-; CHECK-NEXT: block{{$}}
-; CHECK-NEXT: loop{{$}}
-; CHECK: br_if 2, {{[^,]+}}{{$}}
+; CHECK-NEXT: block {{$}}
+; CHECK-NEXT: loop {{$}}
+; CHECK: br_if 1, {{[^,]+}}{{$}}
; CHECK: br_if 0, {{[^,]+}}{{$}}
; CHECK-NEXT: end_loop{{$}}
; CHECK: return{{$}}
@@ -584,9 +586,9 @@ default:
; CHECK: return{{$}}
; OPT-LABEL: test5:
; OPT: .LBB14_1:
-; OPT-NEXT: block{{$}}
-; OPT-NEXT: loop{{$}}
-; OPT: br_if 2, {{[^,]+}}{{$}}
+; OPT-NEXT: block {{$}}
+; OPT-NEXT: loop {{$}}
+; OPT: br_if 1, {{[^,]+}}{{$}}
; OPT: br_if 0, {{[^,]+}}{{$}}
; OPT-NEXT: end_loop{{$}}
; OPT: return{{$}}
@@ -619,14 +621,14 @@ return:
; CHECK-LABEL: test6:
; CHECK: .LBB15_1:
-; CHECK-NEXT: block{{$}}
-; CHECK-NEXT: block{{$}}
-; CHECK-NEXT: loop{{$}}
-; CHECK-NOT: block
-; CHECK: br_if 3, {{[^,]+}}{{$}}
+; CHECK-NEXT: block {{$}}
+; CHECK-NEXT: block {{$}}
+; CHECK-NEXT: loop {{$}}
; CHECK-NOT: block
; CHECK: br_if 2, {{[^,]+}}{{$}}
; CHECK-NOT: block
+; CHECK: br_if 1, {{[^,]+}}{{$}}
+; CHECK-NOT: block
; CHECK: br_if 0, {{[^,]+}}{{$}}
; CHECK-NEXT: end_loop{{$}}
; CHECK-NOT: block
@@ -640,14 +642,14 @@ return:
; CHECK: return{{$}}
; OPT-LABEL: test6:
; OPT: .LBB15_1:
-; OPT-NEXT: block{{$}}
-; OPT-NEXT: block{{$}}
-; OPT-NEXT: loop{{$}}
-; OPT-NOT: block
-; OPT: br_if 3, {{[^,]+}}{{$}}
+; OPT-NEXT: block {{$}}
+; OPT-NEXT: block {{$}}
+; OPT-NEXT: loop {{$}}
; OPT-NOT: block
; OPT: br_if 2, {{[^,]+}}{{$}}
; OPT-NOT: block
+; OPT: br_if 1, {{[^,]+}}{{$}}
+; OPT-NOT: block
; OPT: br_if 0, {{[^,]+}}{{$}}
; OPT-NEXT: end_loop{{$}}
; OPT-NOT: block
@@ -693,9 +695,9 @@ second:
; CHECK-LABEL: test7:
; CHECK: .LBB16_1:
-; CHECK-NEXT: loop{{$}}
+; CHECK-NEXT: loop {{$}}
; CHECK-NOT: block
-; CHECK: block{{$}}
+; CHECK: block {{$}}
; CHECK: br_if 0, {{[^,]+}}{{$}}
; CHECK-NOT: block
; CHECK: br_if 1, {{[^,]+}}{{$}}
@@ -711,14 +713,14 @@ second:
; OPT-LABEL: test7:
; OPT: .LBB16_1:
; OPT-NEXT: block
-; OPT-NEXT: loop{{$}}
+; OPT-NEXT: loop {{$}}
; OPT-NOT: block
-; OPT: block{{$}}
+; OPT: block {{$}}
; OPT-NOT: block
; OPT: br_if 0, {{[^,]+}}{{$}}
; OPT-NOT: block
; OPT: br_if 1, {{[^,]+}}{{$}}
-; OPT: br 3{{$}}
+; OPT: br 2{{$}}
; OPT-NEXT: .LBB16_3:
; OPT-NEXT: end_block
; OPT-NOT: block
@@ -760,7 +762,7 @@ u1:
; CHECK-LABEL: test8:
; CHECK: .LBB17_1:
-; CHECK-NEXT: loop{{$}}
+; CHECK-NEXT: loop i32{{$}}
; CHECK-NEXT: i32.const $push{{[^,]+}}, 0{{$}}
; CHECK-NEXT: br_if 0, {{[^,]+}}{{$}}
; CHECK-NEXT: br 0{{$}}
@@ -768,7 +770,7 @@ u1:
; CHECK-NEXT: end_loop{{$}}
; OPT-LABEL: test8:
; OPT: .LBB17_1:
-; OPT-NEXT: loop{{$}}
+; OPT-NEXT: loop i32{{$}}
; OPT-NEXT: i32.const $push{{[^,]+}}, 0{{$}}
; OPT-NEXT: br_if 0, {{[^,]+}}{{$}}
; OPT-NEXT: br 0{{$}}
@@ -796,47 +798,53 @@ bb3:
; CHECK-LABEL: test9:
; CHECK: .LBB18_1:
-; CHECK-NEXT: loop{{$}}
+; CHECK-NEXT: block {{$}}
+; CHECK-NEXT: loop {{$}}
; CHECK-NOT: block
; CHECK: br_if 1, {{[^,]+}}{{$}}
; CHECK-NEXT: .LBB18_2:
-; CHECK-NEXT: loop{{$}}
+; CHECK-NEXT: loop {{$}}
; CHECK-NOT: block
-; CHECK: block{{$}}
+; CHECK: block {{$}}
; CHECK-NOT: block
; CHECK: br_if 0, {{[^,]+}}{{$}}
; CHECK-NOT: block
-; CHECK: br_if 3, {{[^,]+}}{{$}}
+; CHECK: br_if 2, {{[^,]+}}{{$}}
; CHECK-NEXT: br 1{{$}}
; CHECK-NEXT: .LBB18_4:
; CHECK-NEXT: end_block{{$}}
; CHECK-NOT: block
-; CHECK: br_if 2, {{[^,]+}}{{$}}
+; CHECK: br_if 1, {{[^,]+}}{{$}}
; CHECK-NEXT: br 0{{$}}
; CHECK-NEXT: .LBB18_5:
; CHECK-NOT: block
+; CHECK: end_block
+; CHECK-NOT: block
; CHECK: return{{$}}
; OPT-LABEL: test9:
; OPT: .LBB18_1:
-; OPT-NEXT: loop{{$}}
+; OPT-NEXT: block {{$}}
+; OPT-NEXT: loop {{$}}
; OPT-NOT: block
; OPT: br_if 1, {{[^,]+}}{{$}}
; OPT-NEXT: .LBB18_2:
-; OPT-NEXT: loop{{$}}
+; OPT-NEXT: loop {{$}}
; OPT-NOT: block
-; OPT: block{{$}}
+; OPT: block {{$}}
; OPT-NOT: block
; OPT: br_if 0, {{[^,]+}}{{$}}
; OPT-NOT: block
; OPT: br_if 1, {{[^,]+}}{{$}}
-; OPT-NEXT: br 3{{$}}
+; OPT-NEXT: br 2{{$}}
; OPT-NEXT: .LBB18_4:
; OPT-NEXT: end_block{{$}}
; OPT-NOT: block
; OPT: br_if 0, {{[^,]+}}{{$}}
-; OPT-NEXT: br 2{{$}}
+; OPT-NEXT: br 1{{$}}
; OPT-NEXT: .LBB18_5:
; OPT-NOT: block
+; OPT: end_block
+; OPT-NOT: block
; OPT: return{{$}}
declare i1 @a()
define void @test9() {
@@ -874,20 +882,21 @@ end:
; CHECK-LABEL: test10:
; CHECK: .LBB19_1:
-; CHECK-NEXT: loop{{$}}
+; CHECK-NEXT: loop {{$}}
; CHECK-NOT: block
; CHECK: br_if 0, {{[^,]+}}{{$}}
; CHECK: .LBB19_3:
-; CHECK-NEXT: block{{$}}
-; CHECK-NEXT: loop{{$}}
+; CHECK-NEXT: block {{$}}
+; CHECK-NEXT: loop {{$}}
; CHECK-NOT: block
; CHECK: .LBB19_4:
-; CHECK-NEXT: loop{{$}}
+; CHECK-NEXT: loop {{$}}
; CHECK-NOT: block
-; CHECK: br_if 5, {{[^,]+}}{{$}}
-; CHECK-NOT: block
-; CHECK: br_table {{[^,]+}}, 0, 1, 5, 2, 4, 0{{$}}
+; CHECK: br_if 3, {{[^,]+}}{{$}}
+; CHECK: block {{$}}
+; CHECK: br_table {{[^,]+}}, 1, 0, 4, 2, 3, 1{{$}}
; CHECK-NEXT: .LBB19_6:
+; CHECK-NEXT: end_block{{$}}
; CHECK-NEXT: end_loop{{$}}
; CHECK-NEXT: end_loop{{$}}
; CHECK-NEXT: return{{$}}
@@ -898,20 +907,21 @@ end:
; CHECK-NEXT: .LBB19_8:
; OPT-LABEL: test10:
; OPT: .LBB19_1:
-; OPT-NEXT: loop{{$}}
+; OPT-NEXT: loop {{$}}
; OPT-NOT: block
; OPT: br_if 0, {{[^,]+}}{{$}}
; OPT: .LBB19_3:
-; OPT-NEXT: block{{$}}
-; OPT-NEXT: loop{{$}}
+; OPT-NEXT: block {{$}}
+; OPT-NEXT: loop {{$}}
; OPT-NOT: block
; OPT: .LBB19_4:
-; OPT-NEXT: loop{{$}}
+; OPT-NEXT: loop {{$}}
; OPT-NOT: block
-; OPT: br_if 5, {{[^,]+}}{{$}}
-; OPT-NOT: block
-; OPT: br_table {{[^,]+}}, 0, 1, 5, 2, 4, 0{{$}}
+; OPT: br_if 3, {{[^,]+}}{{$}}
+; OPT: block
+; OPT: br_table {{[^,]+}}, 1, 0, 4, 2, 3, 1{{$}}
; OPT-NEXT: .LBB19_6:
+; OPT-NEXT: end_block{{$}}
; OPT-NEXT: end_loop{{$}}
; OPT-NEXT: end_loop{{$}}
; OPT-NEXT: return{{$}}
@@ -958,13 +968,14 @@ bb6:
; Test a CFG DAG with interesting merging.
; CHECK-LABEL: test11:
-; CHECK: block{{$}}
-; CHECK-NEXT: block{{$}}
-; CHECK-NEXT: block{{$}}
-; CHECK-NEXT: block{{$}}
+; CHECK: block {{$}}
+; CHECK-NEXT: block {{$}}
+; CHECK-NEXT: block {{$}}
+; CHECK-NEXT: block {{$}}
; CHECK: br_if 0, {{[^,]+}}{{$}}
; CHECK-NOT: block
-; CHECK: block{{$}}
+; CHECK: block {{$}}
+; CHECK-NEXT: i32.const
; CHECK-NEXT: br_if 0, {{[^,]+}}{{$}}
; CHECK-NOT: block
; CHECK: br_if 2, {{[^,]+}}{{$}}
@@ -991,12 +1002,13 @@ bb6:
; CHECK-NOT: block
; CHECK: return{{$}}
; OPT-LABEL: test11:
-; OPT: block{{$}}
-; OPT-NEXT: block{{$}}
+; OPT: block {{$}}
+; OPT-NEXT: block {{$}}
; OPT: br_if 0, $pop{{[0-9]+}}{{$}}
; OPT-NOT: block
-; OPT: block{{$}}
-; OPT-NEXT: br_if 0, $0{{$}}
+; OPT: block {{$}}
+; OPT-NEXT: i32.const
+; OPT-NEXT: br_if 0, {{[^,]+}}{{$}}
; OPT-NOT: block
; OPT: br_if 2, {{[^,]+}}{{$}}
; OPT-NEXT: .LBB20_3:
@@ -1006,7 +1018,7 @@ bb6:
; OPT-NEXT: .LBB20_4:
; OPT-NEXT: end_block{{$}}
; OPT-NOT: block
-; OPT: block{{$}}
+; OPT: block {{$}}
; OPT-NOT: block
; OPT: br_if 0, $pop{{[0-9]+}}{{$}}
; OPT-NOT: block
@@ -1053,10 +1065,11 @@ bb8:
; CHECK-LABEL: test12:
; CHECK: .LBB21_1:
-; CHECK-NEXT: loop{{$}}
+; CHECK-NEXT: block {{$}}
+; CHECK-NEXT: loop {{$}}
; CHECK-NOT: block
-; CHECK: block{{$}}
-; CHECK-NEXT: block{{$}}
+; CHECK: block {{$}}
+; CHECK-NEXT: block {{$}}
; CHECK: br_if 0, {{[^,]+}}{{$}}
; CHECK-NOT: block
; CHECK: br_if 1, {{[^,]+}}{{$}}
@@ -1075,13 +1088,15 @@ bb8:
; CHECK: br 0{{$}}
; CHECK-NEXT: .LBB21_7:
; CHECK-NEXT: end_loop{{$}}
+; CHECK-NEXT: end_block{{$}}
; CHECK-NEXT: return{{$}}
; OPT-LABEL: test12:
; OPT: .LBB21_1:
-; OPT-NEXT: loop{{$}}
+; OPT-NEXT: block {{$}}
+; OPT-NEXT: loop {{$}}
; OPT-NOT: block
-; OPT: block{{$}}
-; OPT-NEXT: block{{$}}
+; OPT: block {{$}}
+; OPT-NEXT: block {{$}}
; OPT: br_if 0, {{[^,]+}}{{$}}
; OPT-NOT: block
; OPT: br_if 1, {{[^,]+}}{{$}}
@@ -1099,6 +1114,7 @@ bb8:
; OPT: br 0{{$}}
; OPT-NEXT: .LBB21_7:
; OPT-NEXT: end_loop{{$}}
+; OPT-NEXT: end_block{{$}}
; OPT-NEXT: return{{$}}
define void @test12(i8* %arg) {
bb:
@@ -1129,10 +1145,10 @@ bb7:
; CHECK-LABEL: test13:
; CHECK-NEXT: .local i32{{$}}
-; CHECK-NEXT: block{{$}}
-; CHECK-NEXT: block{{$}}
+; CHECK-NEXT: block {{$}}
+; CHECK-NEXT: block {{$}}
; CHECK: br_if 0, $pop0{{$}}
-; CHECK: block{{$}}
+; CHECK: block {{$}}
; CHECK: br_if 0, $pop3{{$}}
; CHECK: .LBB22_3:
; CHECK-NEXT: end_block{{$}}
@@ -1146,10 +1162,10 @@ bb7:
; CHECK-NEXT: unreachable{{$}}
; OPT-LABEL: test13:
; OPT-NEXT: .local i32{{$}}
-; OPT-NEXT: block{{$}}
-; OPT-NEXT: block{{$}}
+; OPT-NEXT: block {{$}}
+; OPT-NEXT: block {{$}}
; OPT: br_if 0, $pop0{{$}}
-; OPT: block{{$}}
+; OPT: block {{$}}
; OPT: br_if 0, $pop3{{$}}
; OPT: .LBB22_3:
; OPT-NEXT: end_block{{$}}
@@ -1183,12 +1199,12 @@ bb5:
; CHECK-LABEL: test14:
; CHECK-NEXT: .LBB23_1:{{$}}
-; CHECK-NEXT: loop{{$}}
+; CHECK-NEXT: loop {{$}}
; CHECK-NEXT: i32.const $push0=, 0{{$}}
; CHECK-NEXT: br_if 0, $pop0{{$}}
; CHECK-NEXT: end_loop{{$}}
; CHECK-NEXT: .LBB23_3:{{$}}
-; CHECK-NEXT: loop{{$}}
+; CHECK-NEXT: loop {{$}}
; CHECK-NEXT: i32.const $push1=, 0{{$}}
; CHECK-NEXT: br_if 0, $pop1{{$}}
; CHECK-NEXT: end_loop{{$}}
@@ -1247,8 +1263,9 @@ bb50:
; CHECK-NEXT: block
; CHECK: br_if 0, $pop{{.*}}{{$}}
; CHECK: .LBB24_2:
-; CHECK-NEXT: block{{$}}
-; CHECK-NEXT: loop{{$}}
+; CHECK-NEXT: block {{$}}
+; CHECK-NEXT: block {{$}}
+; CHECK-NEXT: loop {{$}}
; CHECK: br_if 1, $pop{{.*}}{{$}}
; CHECK: br_if 0, ${{.*}}{{$}}
; CHECK-NEXT: br 2{{$}}
@@ -1276,6 +1293,7 @@ bb50:
; OPT-NEXT: i32.const
; OPT-NEXT: .LBB24_3:
; OPT-NEXT: block
+; OPT-NEXT: block
; OPT-NEXT: loop
%0 = type { i8, i32 }
declare void @test15_callee0()
diff --git a/test/CodeGen/WebAssembly/cfi.ll b/test/CodeGen/WebAssembly/cfi.ll
new file mode 100644
index 000000000000..e5664ba73a0d
--- /dev/null
+++ b/test/CodeGen/WebAssembly/cfi.ll
@@ -0,0 +1,53 @@
+; RUN: opt -S -lowertypetests < %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
+
+; Tests that we correctly assign indexes for control flow integrity.
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+@0 = private unnamed_addr constant [2 x void (...)*] [void (...)* bitcast (void ()* @f to void (...)*), void (...)* bitcast (void ()* @g to void (...)*)], align 16
+
+; CHECK-LABEL: h:
+; CHECK-NOT: .indidx
+define void @h() !type !0 {
+ ret void
+}
+
+; CHECK-LABEL: f:
+; CHECK: .indidx 1
+define void @f() !type !0 {
+ ret void
+}
+
+; CHECK-LABEL: g:
+; CHECK: .indidx 2
+define void @g() !type !1 {
+ ret void
+}
+
+!0 = !{i32 0, !"typeid1"}
+!1 = !{i32 0, !"typeid2"}
+
+declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone
+declare void @llvm.trap() nounwind noreturn
+
+; CHECK-LABEL: foo:
+; CHECK: br_if
+; CHECK: br_if
+; CHECK: unreachable
+define i1 @foo(i8* %p) {
+ %x = call i1 @llvm.type.test(i8* %p, metadata !"typeid1")
+ br i1 %x, label %contx, label %trap
+
+trap:
+ tail call void @llvm.trap() #1
+ unreachable
+
+contx:
+ %y = call i1 @llvm.type.test(i8* %p, metadata !"typeid2")
+ br i1 %y, label %conty, label %trap
+
+conty:
+ %z = add i1 %x, %y
+ ret i1 %z
+}
diff --git a/test/CodeGen/WebAssembly/dbgvalue.ll b/test/CodeGen/WebAssembly/dbgvalue.ll
new file mode 100644
index 000000000000..c6a091bc78c8
--- /dev/null
+++ b/test/CodeGen/WebAssembly/dbgvalue.ll
@@ -0,0 +1,72 @@
+; RUN: llc < %s -O0 -verify-machineinstrs -mtriple=wasm32-unknown-unknown | FileCheck %s
+
+; CHECK: BB#0
+; CHECK: #DEBUG_VALUE: usage:self <- %vreg4
+; CHECK: BB#1
+; CHECK: DW_TAG_variable
+source_filename = "test/CodeGen/WebAssembly/dbgvalue.ll"
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+@key = external local_unnamed_addr global [15 x i8], align 1
+@.str = external unnamed_addr constant [33 x i8], align 1
+
+define internal i32 @0(i8*) local_unnamed_addr !dbg !15 !type !23 {
+ tail call void @llvm.dbg.value(metadata i8* %0, i64 0, metadata !22, metadata !24), !dbg !25
+ %2 = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([33 x i8], [33 x i8]* @.str, i32 0, i32 0), i8* %0), !dbg !26
+ br i1 true, label %a, label %b
+
+a: ; preds = %1
+ %3 = add i32 %2, %2
+ br label %c
+
+b: ; preds = %1
+ %4 = sub i32 %2, %2
+ br label %c
+
+c: ; preds = %b, %a
+ %5 = phi i32 [ %3, %a ], [ %4, %b ]
+ %6 = add i32 ptrtoint (i32 (i8*)* @0 to i32), %5
+ ret i32 %6, !dbg !27
+}
+
+declare i32 @printf(i8* nocapture readonly, ...) local_unnamed_addr
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #0
+
+attributes #0 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!12, !13}
+!llvm.ident = !{!14}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.9.0 (trunk 273884) (llvm/trunk 273897)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3)
+!1 = !DIFile(filename: "crash.c", directory: "wasm/tests")
+!2 = !{}
+!3 = !{!4}
+!4 = !DIGlobalVariableExpression(var: !5)
+!5 = !DIGlobalVariable(name: "key", scope: !0, file: !1, line: 7, type: !6, isLocal: false, isDefinition: true)
+!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 120, align: 8, elements: !10)
+!7 = !DIDerivedType(tag: DW_TAG_typedef, name: "uint8_t", file: !8, line: 185, baseType: !9)
+!8 = !DIFile(filename: "wasm/emscripten/system/include/libc/bits/alltypes.h", directory: "wasm/tests")
+!9 = !DIBasicType(name: "unsigned char", size: 8, align: 8, encoding: DW_ATE_unsigned_char)
+!10 = !{!11}
+!11 = !DISubrange(count: 15)
+!12 = !{i32 2, !"Dwarf Version", i32 4}
+!13 = !{i32 2, !"Debug Info Version", i32 3}
+!14 = !{!"clang version 3.9.0 (trunk 273884) (llvm/trunk 273897)"}
+!15 = distinct !DISubprogram(name: "usage", scope: !1, file: !1, line: 15, type: !16, isLocal: false, isDefinition: true, scopeLine: 15, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !21)
+!16 = !DISubroutineType(types: !17)
+!17 = !{!18, !19}
+!18 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 32, align: 32)
+!20 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char)
+!21 = !{!22}
+!22 = !DILocalVariable(name: "self", arg: 1, scope: !15, file: !1, line: 15, type: !19)
+!23 = !{i64 0, !"_ZTSFiPcE"}
+!24 = !DIExpression()
+!25 = !DILocation(line: 15, column: 17, scope: !15)
+!26 = !DILocation(line: 16, column: 3, scope: !15)
+!27 = !DILocation(line: 17, column: 3, scope: !15)
+
diff --git a/test/CodeGen/WebAssembly/fast-isel-noreg.ll b/test/CodeGen/WebAssembly/fast-isel-noreg.ll
new file mode 100644
index 000000000000..a2504822dd1c
--- /dev/null
+++ b/test/CodeGen/WebAssembly/fast-isel-noreg.ll
@@ -0,0 +1,35 @@
+; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -verify-machineinstrs | FileCheck %s
+; RUN: llc < %s -asm-verbose=false -fast-isel -verify-machineinstrs | FileCheck %s
+
+; Test that FastISel does not generate instructions with NoReg
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+; CHECK: i32.const $push0=, 0
+define hidden i32 @a() #0 {
+entry:
+ ret i32 zext (i1 icmp eq (void (...)* inttoptr (i32 10 to void (...)*), void (...)* null) to i32)
+}
+
+; CHECK: i32.const $push0=, 1
+; CHECK: br_if 0, $pop0
+define hidden i32 @b() #0 {
+entry:
+ br i1 icmp eq (void (...)* inttoptr (i32 10 to void (...)*), void (...)* null), label %a, label %b
+a:
+ unreachable
+b:
+ ret i32 0
+}
+
+; CHECK: i32.const $push1=, 0
+; CHECK: i32.const $push2=, 0
+; CHECK: i32.store 0($pop1), $pop2
+define hidden i32 @c() #0 {
+entry:
+ store i32 zext (i1 icmp eq (void (...)* inttoptr (i32 10 to void (...)*), void (...)* null) to i32), i32* inttoptr (i32 0 to i32 *)
+ ret i32 0
+}
+
+attributes #0 = { noinline optnone }
diff --git a/test/CodeGen/WebAssembly/fast-isel.ll b/test/CodeGen/WebAssembly/fast-isel.ll
index d3ee77632bca..953bd610b1bc 100644
--- a/test/CodeGen/WebAssembly/fast-isel.ll
+++ b/test/CodeGen/WebAssembly/fast-isel.ll
@@ -46,3 +46,33 @@ define double @bitcast_f64_i64(i64 %x) {
%y = bitcast i64 %x to double
ret double %y
}
+
+; Do fold offsets into geps.
+; CHECK-LABEL: do_fold_offset_into_gep:
+; CHECK: i64.load $push{{[0-9]+}}=, 8($0)
+define i64 @do_fold_offset_into_gep(i64* %p) {
+bb:
+ %tmp = getelementptr inbounds i64, i64* %p, i32 1
+ %tmp2 = load i64, i64* %tmp, align 8
+ ret i64 %tmp2
+}
+
+; Don't fold negative offsets into geps.
+; CHECK-LABEL: dont_fold_negative_offset:
+; CHECK: i64.load $push{{[0-9]+}}=, 0($pop{{[0-9]+}})
+define i64 @dont_fold_negative_offset(i64* %p) {
+bb:
+ %tmp = getelementptr inbounds i64, i64* %p, i32 -1
+ %tmp2 = load i64, i64* %tmp, align 8
+ ret i64 %tmp2
+}
+
+; Don't fold non-inbounds geps.
+; CHECK-LABEL: dont_fold_non_inbounds_gep:
+; CHECK: i64.load $push{{[0-9]+}}=, 0($pop{{[0-9]+}})
+define i64 @dont_fold_non_inbounds_gep(i64* %p) {
+bb:
+ %tmp = getelementptr i64, i64* %p, i32 1
+ %tmp2 = load i64, i64* %tmp, align 8
+ ret i64 %tmp2
+}
diff --git a/test/CodeGen/WebAssembly/globl.ll b/test/CodeGen/WebAssembly/globl.ll
index 91d3ade4666b..3ebd3d88fb4e 100644
--- a/test/CodeGen/WebAssembly/globl.ll
+++ b/test/CodeGen/WebAssembly/globl.ll
@@ -8,3 +8,7 @@ target triple = "wasm32-unknown-unknown"
define void @foo() {
ret void
}
+
+; Check import directives - must be at the end of the file
+; CHECK: .import_global bar{{$}}
+@bar = external global i32
diff --git a/test/CodeGen/WebAssembly/i32-load-store-alignment.ll b/test/CodeGen/WebAssembly/i32-load-store-alignment.ll
index b254413d380f..fb7deecff33a 100644
--- a/test/CodeGen/WebAssembly/i32-load-store-alignment.ll
+++ b/test/CodeGen/WebAssembly/i32-load-store-alignment.ll
@@ -117,7 +117,7 @@ define i16 @ldi16_a4(i16 *%p) {
; CHECK-LABEL: sti32_a1:
; CHECK-NEXT: .param i32, i32{{$}}
-; CHECK-NEXT: i32.store $drop=, 0($0):p2align=0, $1{{$}}
+; CHECK-NEXT: i32.store 0($0):p2align=0, $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti32_a1(i32 *%p, i32 %v) {
store i32 %v, i32* %p, align 1
@@ -126,7 +126,7 @@ define void @sti32_a1(i32 *%p, i32 %v) {
; CHECK-LABEL: sti32_a2:
; CHECK-NEXT: .param i32, i32{{$}}
-; CHECK-NEXT: i32.store $drop=, 0($0):p2align=1, $1{{$}}
+; CHECK-NEXT: i32.store 0($0):p2align=1, $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti32_a2(i32 *%p, i32 %v) {
store i32 %v, i32* %p, align 2
@@ -137,7 +137,7 @@ define void @sti32_a2(i32 *%p, i32 %v) {
; CHECK-LABEL: sti32_a4:
; CHECK-NEXT: .param i32, i32{{$}}
-; CHECK-NEXT: i32.store $drop=, 0($0), $1{{$}}
+; CHECK-NEXT: i32.store 0($0), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti32_a4(i32 *%p, i32 %v) {
store i32 %v, i32* %p, align 4
@@ -148,7 +148,7 @@ define void @sti32_a4(i32 *%p, i32 %v) {
; CHECK-LABEL: sti32:
; CHECK-NEXT: .param i32, i32{{$}}
-; CHECK-NEXT: i32.store $drop=, 0($0), $1{{$}}
+; CHECK-NEXT: i32.store 0($0), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti32(i32 *%p, i32 %v) {
store i32 %v, i32* %p
@@ -157,7 +157,7 @@ define void @sti32(i32 *%p, i32 %v) {
; CHECK-LABEL: sti32_a8:
; CHECK-NEXT: .param i32, i32{{$}}
-; CHECK-NEXT: i32.store $drop=, 0($0), $1{{$}}
+; CHECK-NEXT: i32.store 0($0), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti32_a8(i32 *%p, i32 %v) {
store i32 %v, i32* %p, align 8
@@ -168,7 +168,7 @@ define void @sti32_a8(i32 *%p, i32 %v) {
; CHECK-LABEL: sti8_a1:
; CHECK-NEXT: .param i32, i32{{$}}
-; CHECK-NEXT: i32.store8 $drop=, 0($0), $1{{$}}
+; CHECK-NEXT: i32.store8 0($0), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti8_a1(i8 *%p, i8 %v) {
store i8 %v, i8* %p, align 1
@@ -177,7 +177,7 @@ define void @sti8_a1(i8 *%p, i8 %v) {
; CHECK-LABEL: sti8_a2:
; CHECK-NEXT: .param i32, i32{{$}}
-; CHECK-NEXT: i32.store8 $drop=, 0($0), $1{{$}}
+; CHECK-NEXT: i32.store8 0($0), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti8_a2(i8 *%p, i8 %v) {
store i8 %v, i8* %p, align 2
@@ -186,7 +186,7 @@ define void @sti8_a2(i8 *%p, i8 %v) {
; CHECK-LABEL: sti16_a1:
; CHECK-NEXT: .param i32, i32{{$}}
-; CHECK-NEXT: i32.store16 $drop=, 0($0):p2align=0, $1{{$}}
+; CHECK-NEXT: i32.store16 0($0):p2align=0, $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti16_a1(i16 *%p, i16 %v) {
store i16 %v, i16* %p, align 1
@@ -195,7 +195,7 @@ define void @sti16_a1(i16 *%p, i16 %v) {
; CHECK-LABEL: sti16_a2:
; CHECK-NEXT: .param i32, i32{{$}}
-; CHECK-NEXT: i32.store16 $drop=, 0($0), $1{{$}}
+; CHECK-NEXT: i32.store16 0($0), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti16_a2(i16 *%p, i16 %v) {
store i16 %v, i16* %p, align 2
@@ -204,7 +204,7 @@ define void @sti16_a2(i16 *%p, i16 %v) {
; CHECK-LABEL: sti16_a4:
; CHECK-NEXT: .param i32, i32{{$}}
-; CHECK-NEXT: i32.store16 $drop=, 0($0), $1{{$}}
+; CHECK-NEXT: i32.store16 0($0), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti16_a4(i16 *%p, i16 %v) {
store i16 %v, i16* %p, align 4
diff --git a/test/CodeGen/WebAssembly/i64-load-store-alignment.ll b/test/CodeGen/WebAssembly/i64-load-store-alignment.ll
index b2fb96290391..a3901dfc079a 100644
--- a/test/CodeGen/WebAssembly/i64-load-store-alignment.ll
+++ b/test/CodeGen/WebAssembly/i64-load-store-alignment.ll
@@ -176,7 +176,7 @@ define i64 @ldi32_a8(i32 *%p) {
; CHECK-LABEL: sti64_a1:
; CHECK-NEXT: .param i32, i64{{$}}
-; CHECK-NEXT: i64.store $drop=, 0($0):p2align=0, $1{{$}}
+; CHECK-NEXT: i64.store 0($0):p2align=0, $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti64_a1(i64 *%p, i64 %v) {
store i64 %v, i64* %p, align 1
@@ -185,7 +185,7 @@ define void @sti64_a1(i64 *%p, i64 %v) {
; CHECK-LABEL: sti64_a2:
; CHECK-NEXT: .param i32, i64{{$}}
-; CHECK-NEXT: i64.store $drop=, 0($0):p2align=1, $1{{$}}
+; CHECK-NEXT: i64.store 0($0):p2align=1, $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti64_a2(i64 *%p, i64 %v) {
store i64 %v, i64* %p, align 2
@@ -194,7 +194,7 @@ define void @sti64_a2(i64 *%p, i64 %v) {
; CHECK-LABEL: sti64_a4:
; CHECK-NEXT: .param i32, i64{{$}}
-; CHECK-NEXT: i64.store $drop=, 0($0):p2align=2, $1{{$}}
+; CHECK-NEXT: i64.store 0($0):p2align=2, $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti64_a4(i64 *%p, i64 %v) {
store i64 %v, i64* %p, align 4
@@ -205,7 +205,7 @@ define void @sti64_a4(i64 *%p, i64 %v) {
; CHECK-LABEL: sti64_a8:
; CHECK-NEXT: .param i32, i64{{$}}
-; CHECK-NEXT: i64.store $drop=, 0($0), $1{{$}}
+; CHECK-NEXT: i64.store 0($0), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti64_a8(i64 *%p, i64 %v) {
store i64 %v, i64* %p, align 8
@@ -216,7 +216,7 @@ define void @sti64_a8(i64 *%p, i64 %v) {
; CHECK-LABEL: sti64:
; CHECK-NEXT: .param i32, i64{{$}}
-; CHECK-NEXT: i64.store $drop=, 0($0), $1{{$}}
+; CHECK-NEXT: i64.store 0($0), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti64(i64 *%p, i64 %v) {
store i64 %v, i64* %p
@@ -225,7 +225,7 @@ define void @sti64(i64 *%p, i64 %v) {
; CHECK-LABEL: sti64_a16:
; CHECK-NEXT: .param i32, i64{{$}}
-; CHECK-NEXT: i64.store $drop=, 0($0), $1{{$}}
+; CHECK-NEXT: i64.store 0($0), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti64_a16(i64 *%p, i64 %v) {
store i64 %v, i64* %p, align 16
@@ -236,7 +236,7 @@ define void @sti64_a16(i64 *%p, i64 %v) {
; CHECK-LABEL: sti8_a1:
; CHECK-NEXT: .param i32, i64{{$}}
-; CHECK-NEXT: i64.store8 $drop=, 0($0), $1{{$}}
+; CHECK-NEXT: i64.store8 0($0), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti8_a1(i8 *%p, i64 %w) {
%v = trunc i64 %w to i8
@@ -246,7 +246,7 @@ define void @sti8_a1(i8 *%p, i64 %w) {
; CHECK-LABEL: sti8_a2:
; CHECK-NEXT: .param i32, i64{{$}}
-; CHECK-NEXT: i64.store8 $drop=, 0($0), $1{{$}}
+; CHECK-NEXT: i64.store8 0($0), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti8_a2(i8 *%p, i64 %w) {
%v = trunc i64 %w to i8
@@ -256,7 +256,7 @@ define void @sti8_a2(i8 *%p, i64 %w) {
; CHECK-LABEL: sti16_a1:
; CHECK-NEXT: .param i32, i64{{$}}
-; CHECK-NEXT: i64.store16 $drop=, 0($0):p2align=0, $1{{$}}
+; CHECK-NEXT: i64.store16 0($0):p2align=0, $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti16_a1(i16 *%p, i64 %w) {
%v = trunc i64 %w to i16
@@ -266,7 +266,7 @@ define void @sti16_a1(i16 *%p, i64 %w) {
; CHECK-LABEL: sti16_a2:
; CHECK-NEXT: .param i32, i64{{$}}
-; CHECK-NEXT: i64.store16 $drop=, 0($0), $1{{$}}
+; CHECK-NEXT: i64.store16 0($0), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti16_a2(i16 *%p, i64 %w) {
%v = trunc i64 %w to i16
@@ -276,7 +276,7 @@ define void @sti16_a2(i16 *%p, i64 %w) {
; CHECK-LABEL: sti16_a4:
; CHECK-NEXT: .param i32, i64{{$}}
-; CHECK-NEXT: i64.store16 $drop=, 0($0), $1{{$}}
+; CHECK-NEXT: i64.store16 0($0), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti16_a4(i16 *%p, i64 %w) {
%v = trunc i64 %w to i16
@@ -286,7 +286,7 @@ define void @sti16_a4(i16 *%p, i64 %w) {
; CHECK-LABEL: sti32_a1:
; CHECK-NEXT: .param i32, i64{{$}}
-; CHECK-NEXT: i64.store32 $drop=, 0($0):p2align=0, $1{{$}}
+; CHECK-NEXT: i64.store32 0($0):p2align=0, $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti32_a1(i32 *%p, i64 %w) {
%v = trunc i64 %w to i32
@@ -296,7 +296,7 @@ define void @sti32_a1(i32 *%p, i64 %w) {
; CHECK-LABEL: sti32_a2:
; CHECK-NEXT: .param i32, i64{{$}}
-; CHECK-NEXT: i64.store32 $drop=, 0($0):p2align=1, $1{{$}}
+; CHECK-NEXT: i64.store32 0($0):p2align=1, $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti32_a2(i32 *%p, i64 %w) {
%v = trunc i64 %w to i32
@@ -306,7 +306,7 @@ define void @sti32_a2(i32 *%p, i64 %w) {
; CHECK-LABEL: sti32_a4:
; CHECK-NEXT: .param i32, i64{{$}}
-; CHECK-NEXT: i64.store32 $drop=, 0($0), $1{{$}}
+; CHECK-NEXT: i64.store32 0($0), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti32_a4(i32 *%p, i64 %w) {
%v = trunc i64 %w to i32
@@ -316,7 +316,7 @@ define void @sti32_a4(i32 *%p, i64 %w) {
; CHECK-LABEL: sti32_a8:
; CHECK-NEXT: .param i32, i64{{$}}
-; CHECK-NEXT: i64.store32 $drop=, 0($0), $1{{$}}
+; CHECK-NEXT: i64.store32 0($0), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti32_a8(i32 *%p, i64 %w) {
%v = trunc i64 %w to i32
diff --git a/test/CodeGen/WebAssembly/implicit-def.ll b/test/CodeGen/WebAssembly/implicit-def.ll
new file mode 100644
index 000000000000..01ee171b449b
--- /dev/null
+++ b/test/CodeGen/WebAssembly/implicit-def.ll
@@ -0,0 +1,50 @@
+; RUN: llc -o - %s | FileCheck %s
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+; Test that stackified IMPLICIT_DEF instructions are converted into
+; CONST_I32 to provide an explicit push.
+
+; CHECK: br_if 2,
+; CHECK: i32.const $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: return $pop[[L0]]{{$}}
+define i1 @f() {
+ %a = xor i1 0, 0
+ switch i1 %a, label %C [
+ i1 0, label %A
+ i1 1, label %B
+ ]
+
+A:
+ %b = xor i1 0, 0
+ br label %X
+
+B:
+ %c = xor i1 0, 0
+ br i1 %c, label %D, label %X
+
+C:
+ %d = icmp slt i32 0, 0
+ br i1 %d, label %G, label %F
+
+D:
+ %e = xor i1 0, 0
+ br i1 %e, label %E, label %X
+
+E:
+ %f = xor i1 0, 0
+ br label %X
+
+F:
+ %g = xor i1 0, 0
+ br label %G
+
+G:
+ %h = phi i1 [ undef, %C ], [ false, %F ]
+ br label %X
+
+X:
+ %i = phi i1 [ true, %A ], [ true, %B ], [ true, %D ], [ true, %E ], [ %h, %G ]
+ ret i1 %i
+}
+
diff --git a/test/CodeGen/WebAssembly/inline-asm.ll b/test/CodeGen/WebAssembly/inline-asm.ll
index d36c32b546d3..9b72eb65e0d5 100644
--- a/test/CodeGen/WebAssembly/inline-asm.ll
+++ b/test/CodeGen/WebAssembly/inline-asm.ll
@@ -59,7 +59,7 @@ entry:
; CHECK-LABEL: X_i16:
; CHECK: foo $1{{$}}
-; CHECK: i32.store16 $drop=, 0($0), $1{{$}}
+; CHECK: i32.store16 0($0), $1{{$}}
define void @X_i16(i16 * %t) {
call void asm sideeffect "foo $0", "=*X,~{dirflag},~{fpsr},~{flags},~{memory}"(i16* %t)
ret void
@@ -67,7 +67,7 @@ define void @X_i16(i16 * %t) {
; CHECK-LABEL: X_ptr:
; CHECK: foo $1{{$}}
-; CHECK: i32.store $drop=, 0($0), $1{{$}}
+; CHECK: i32.store 0($0), $1{{$}}
define void @X_ptr(i16 ** %t) {
call void asm sideeffect "foo $0", "=*X,~{dirflag},~{fpsr},~{flags},~{memory}"(i16** %t)
ret void
diff --git a/test/CodeGen/WebAssembly/load-store-i1.ll b/test/CodeGen/WebAssembly/load-store-i1.ll
index 2a2318fde10e..ea0ec717c7a0 100644
--- a/test/CodeGen/WebAssembly/load-store-i1.ll
+++ b/test/CodeGen/WebAssembly/load-store-i1.ll
@@ -15,12 +15,12 @@ define i32 @load_u_i1_i32(i1* %p) {
}
; CHECK-LABEL: load_s_i1_i32:
-; CHECK: i32.load8_u $push[[NUM0:[0-9]+]]=, 0($0){{$}}
-; CHECK-NEXT: i32.const $push[[NUM1:[0-9]+]]=, 31{{$}}
-; CHECK-NEXT: shl $push[[NUM2:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM1]]{{$}}
-; CHECK-NEXT: i32.const $push[[NUM4:[0-9]+]]=, 31{{$}}
-; CHECK-NEXT: shr_s $push[[NUM3:[0-9]+]]=, $pop[[NUM2]], $pop[[NUM4]]{{$}}
-; CHECK-NEXT: return $pop[[NUM3]]{{$}}
+; CHECK: i32.const $push[[NUM3:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: i32.load8_u $push[[NUM0:[0-9]+]]=, 0($0){{$}}
+; CHECK-NEXT: i32.const $push[[NUM1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i32.and $push[[NUM2:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM1]]{{$}}
+; CHECK-NEXT: i32.sub $push[[NUM4:[0-9]+]]=, $pop[[NUM3]], $pop[[NUM2]]{{$}}
+; CHECK-NEXT: return $pop[[NUM4]]{{$}}
define i32 @load_s_i1_i32(i1* %p) {
%v = load i1, i1* %p
%e = sext i1 %v to i32
@@ -37,12 +37,12 @@ define i64 @load_u_i1_i64(i1* %p) {
}
; CHECK-LABEL: load_s_i1_i64:
-; CHECK: i64.load8_u $push[[NUM0:[0-9]+]]=, 0($0){{$}}
-; CHECK-NEXT: i64.const $push[[NUM1:[0-9]+]]=, 63{{$}}
-; CHECK-NEXT: shl $push[[NUM2:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM1]]{{$}}
-; CHECK-NEXT: i64.const $push[[NUM4:[0-9]+]]=, 63{{$}}
-; CHECK-NEXT: shr_s $push[[NUM3:[0-9]+]]=, $pop[[NUM2]], $pop[[NUM4]]{{$}}
-; CHECK-NEXT: return $pop[[NUM3]]{{$}}
+; CHECK: i64.const $push[[NUM3:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: i64.load8_u $push[[NUM0:[0-9]+]]=, 0($0){{$}}
+; CHECK-NEXT: i64.const $push[[NUM1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i64.and $push[[NUM2:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM1]]{{$}}
+; CHECK-NEXT: i64.sub $push[[NUM4:[0-9]+]]=, $pop[[NUM3]], $pop[[NUM2]]{{$}}
+; CHECK-NEXT: return $pop[[NUM4]]{{$}}
define i64 @load_s_i1_i64(i1* %p) {
%v = load i1, i1* %p
%e = sext i1 %v to i64
@@ -52,7 +52,7 @@ define i64 @load_s_i1_i64(i1* %p) {
; CHECK-LABEL: store_i32_i1:
; CHECK: i32.const $push[[NUM0:[0-9]+]]=, 1{{$}}
; CHECK-NEXT: i32.and $push[[NUM1:[0-9]+]]=, $1, $pop[[NUM0]]{{$}}
-; CHECK-NEXT: i32.store8 $drop=, 0($0), $pop[[NUM1]]{{$}}
+; CHECK-NEXT: i32.store8 0($0), $pop[[NUM1]]{{$}}
define void @store_i32_i1(i1* %p, i32 %v) {
%t = trunc i32 %v to i1
store i1 %t, i1* %p
@@ -62,7 +62,7 @@ define void @store_i32_i1(i1* %p, i32 %v) {
; CHECK-LABEL: store_i64_i1:
; CHECK: i64.const $push[[NUM0:[0-9]+]]=, 1{{$}}
; CHECK-NEXT: i64.and $push[[NUM1:[0-9]+]]=, $1, $pop[[NUM0]]{{$}}
-; CHECK-NEXT: i64.store8 $drop=, 0($0), $pop[[NUM1]]{{$}}
+; CHECK-NEXT: i64.store8 0($0), $pop[[NUM1]]{{$}}
define void @store_i64_i1(i1* %p, i64 %v) {
%t = trunc i64 %v to i1
store i1 %t, i1* %p
diff --git a/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll b/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll
new file mode 100644
index 000000000000..8283b49cd584
--- /dev/null
+++ b/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll
@@ -0,0 +1,61 @@
+; RUN: llc < %s -enable-emscripten-cxx-exceptions | FileCheck %s --check-prefix=EH
+; RUN: llc < %s -enable-emscripten-sjlj | FileCheck %s --check-prefix=SJLJ
+; RUN: llc < %s | FileCheck %s --check-prefix=NONE
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+%struct.__jmp_buf_tag = type { [6 x i32], i32, [32 x i32] }
+
+define hidden void @exception() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+; EH-LABEL: type exception,@function
+; NONE-LABEL: type exception,@function
+entry:
+ invoke void @foo()
+ to label %try.cont unwind label %lpad
+; EH: call __invoke_void@FUNCTION
+; NONE: call foo@FUNCTION
+
+lpad: ; preds = %entry
+ %0 = landingpad { i8*, i32 }
+ catch i8* null
+ %1 = extractvalue { i8*, i32 } %0, 0
+ %2 = extractvalue { i8*, i32 } %0, 1
+ %3 = call i8* @__cxa_begin_catch(i8* %1) #2
+ call void @__cxa_end_catch()
+ br label %try.cont
+
+try.cont: ; preds = %entry, %lpad
+ ret void
+}
+
+define hidden void @setjmp_longjmp() {
+; SJLJ-LABEL: type setjmp_longjmp,@function
+; NONE-LABEL: type setjmp_longjmp,@function
+entry:
+ %buf = alloca [1 x %struct.__jmp_buf_tag], align 16
+ %arraydecay = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0
+ %call = call i32 @setjmp(%struct.__jmp_buf_tag* %arraydecay) #0
+ %arraydecay1 = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0
+ call void @longjmp(%struct.__jmp_buf_tag* %arraydecay1, i32 1) #1
+ unreachable
+; SJLJ: i32.call ${{[a-zA-Z0-9]+}}=, saveSetjmp@FUNCTION
+; SJLJ: i32.call ${{[a-zA-Z0-9]+}}=, testSetjmp@FUNCTION
+; NONE: i32.call ${{[a-zA-Z0-9]+}}=, setjmp@FUNCTION
+; NONE: call longjmp@FUNCTION
+}
+
+declare void @foo()
+declare i32 @__gxx_personality_v0(...)
+declare i8* @__cxa_begin_catch(i8*)
+declare void @__cxa_end_catch()
+; Function Attrs: returns_twice
+declare i32 @setjmp(%struct.__jmp_buf_tag*) #0
+; Function Attrs: noreturn
+declare void @longjmp(%struct.__jmp_buf_tag*, i32) #1
+declare i8* @malloc(i32)
+declare void @free(i8*)
+
+attributes #0 = { returns_twice }
+attributes #1 = { noreturn }
+attributes #2 = { nounwind }
diff --git a/test/CodeGen/WebAssembly/lower-em-exceptions-whitelist.ll b/test/CodeGen/WebAssembly/lower-em-exceptions-whitelist.ll
new file mode 100644
index 000000000000..5fcc39909b05
--- /dev/null
+++ b/test/CodeGen/WebAssembly/lower-em-exceptions-whitelist.ll
@@ -0,0 +1,65 @@
+; RUN: opt < %s -wasm-lower-em-ehsjlj -emscripten-cxx-exceptions-whitelist=do_catch -S | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+define void @dont_catch() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+; CHECK-LABEL: @dont_catch(
+entry:
+ invoke void @foo()
+ to label %invoke.cont unwind label %lpad
+; CHECK: entry:
+; CHECK-NEXT: call void @foo()
+; CHECK-NEXT: br label %invoke.cont
+
+invoke.cont: ; preds = %entry
+ br label %try.cont
+
+lpad: ; preds = %entry
+ %0 = landingpad { i8*, i32 }
+ catch i8* null
+ %1 = extractvalue { i8*, i32 } %0, 0
+ %2 = extractvalue { i8*, i32 } %0, 1
+ br label %catch
+
+catch: ; preds = %lpad
+ %3 = call i8* @__cxa_begin_catch(i8* %1)
+ call void @__cxa_end_catch()
+ br label %try.cont
+
+try.cont: ; preds = %catch, %invoke.cont
+ ret void
+}
+
+define void @do_catch() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+; CHECK-LABEL: @do_catch(
+entry:
+ invoke void @foo()
+ to label %invoke.cont unwind label %lpad
+; CHECK: entry:
+; CHECK-NEXT: store i32 0, i32*
+; CHECK-NEXT: call void @__invoke_void(void ()* @foo)
+
+invoke.cont: ; preds = %entry
+ br label %try.cont
+
+lpad: ; preds = %entry
+ %0 = landingpad { i8*, i32 }
+ catch i8* null
+ %1 = extractvalue { i8*, i32 } %0, 0
+ %2 = extractvalue { i8*, i32 } %0, 1
+ br label %catch
+
+catch: ; preds = %lpad
+ %3 = call i8* @__cxa_begin_catch(i8* %1)
+ call void @__cxa_end_catch()
+ br label %try.cont
+
+try.cont: ; preds = %catch, %invoke.cont
+ ret void
+}
+
+declare void @foo()
+declare i32 @__gxx_personality_v0(...)
+declare i8* @__cxa_begin_catch(i8*)
+declare void @__cxa_end_catch()
diff --git a/test/CodeGen/WebAssembly/lower-em-exceptions.ll b/test/CodeGen/WebAssembly/lower-em-exceptions.ll
new file mode 100644
index 000000000000..60953cdb6efe
--- /dev/null
+++ b/test/CodeGen/WebAssembly/lower-em-exceptions.ll
@@ -0,0 +1,194 @@
+; RUN: opt < %s -wasm-lower-em-ehsjlj -S | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+@_ZTIi = external constant i8*
+@_ZTIc = external constant i8*
+; CHECK-DAG: @[[__THREW__:__THREW__.*]] = global i32 0
+; CHECK-DAG: @[[THREWVALUE:__threwValue.*]] = global i32 0
+; CHECK-DAG: @[[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 i32 0, i32* @[[__THREW__]]
+; CHECK-NEXT: call void @__invoke_void_i32(void (i32)* @foo, i32 3)
+; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i32, i32* @[[__THREW__]]
+; CHECK-NEXT: store i32 0, i32* @[[__THREW__]]
+; CHECK-NEXT: %cmp = icmp eq i32 %[[__THREW__VAL]], 1
+; CHECK-NEXT: br i1 %cmp, 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: %[[CDR:.*]] = 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
+; CHECK: catch.dispatch:
+; CHECK-NEXT: %[[TYPEID:.*]] = call i32 @llvm_eh_typeid_for(i8* bitcast (i8** @_ZTIi to i8*))
+; CHECK-NEXT: %matches = icmp eq i32 %[[CDR]], %[[TYPEID]]
+
+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 i32 0, i32* @[[__THREW__]]
+; CHECK-NEXT: call void @__invoke_void_i32(void (i32)* @foo, i32 3)
+; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i32, i32* @[[__THREW__]]
+; CHECK-NEXT: store i32 0, i32* @[[__THREW__]]
+; CHECK-NEXT: %cmp = icmp eq i32 %[[__THREW__VAL]], 1
+; CHECK-NEXT: br i1 %cmp, 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
+}
+
+; Test if argument attributes indices in newly created call instructions are correct
+define void @arg_attributes() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+; CHECK-LABEL: @arg_attributes(
+entry:
+ %0 = invoke noalias i8* @bar(i8 signext 1, i8 zeroext 2)
+ to label %invoke.cont unwind label %lpad
+; CHECK: entry:
+; CHECK-NEXT: store i32 0, i32* @[[__THREW__]]
+; CHECK-NEXT: %0 = call noalias i8* @"__invoke_i8*_i8_i8"(i8* (i8, i8)* @bar, i8 signext 1, i8 zeroext 2)
+
+invoke.cont: ; preds = %entry
+ br label %try.cont
+
+lpad: ; preds = %entry
+ %1 = landingpad { i8*, i32 }
+ catch i8* bitcast (i8** @_ZTIi to i8*)
+ catch i8* null
+ %2 = extractvalue { i8*, i32 } %1, 0
+ %3 = extractvalue { i8*, i32 } %1, 1
+ br label %catch.dispatch
+
+catch.dispatch: ; preds = %lpad
+ %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
+ %matches = icmp eq i32 %3, %4
+ br i1 %matches, label %catch1, label %catch
+
+catch1: ; preds = %catch.dispatch
+ %5 = call i8* @__cxa_begin_catch(i8* %2)
+ %6 = bitcast i8* %5 to i32*
+ %7 = load i32, i32* %6, align 4
+ call void @__cxa_end_catch()
+ br label %try.cont
+
+try.cont: ; preds = %catch, %catch1, %invoke.cont
+ ret void
+
+catch: ; preds = %catch.dispatch
+ %8 = call i8* @__cxa_begin_catch(i8* %2)
+ call void @__cxa_end_catch()
+ br label %try.cont
+}
+
+declare void @foo(i32)
+declare i8* @bar(i8, i8)
+
+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 declaration
+; CHECK-DAG: declare void @__resumeException(i8*)
+; CHECK-DAG: declare void @__invoke_void_i32(void (i32)*, i32)
+; CHECK-DAG: declare i8* @__cxa_find_matching_catch_4(i8*, i8*)
+
+; setThrew function creation
+; CHECK-LABEL: define void @setThrew(i32 %threw, i32 %value) {
+; CHECK: entry:
+; CHECK-NEXT: %[[__THREW__]].val = load i32, i32* @[[__THREW__]]
+; CHECK-NEXT: %cmp = icmp eq i32 %[[__THREW__]].val, 0
+; CHECK-NEXT: br i1 %cmp, label %if.then, label %if.end
+; CHECK: if.then:
+; CHECK-NEXT: store i32 %threw, i32* @[[__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: }
diff --git a/test/CodeGen/WebAssembly/lower-em-sjlj.ll b/test/CodeGen/WebAssembly/lower-em-sjlj.ll
new file mode 100644
index 000000000000..40b9d62a0360
--- /dev/null
+++ b/test/CodeGen/WebAssembly/lower-em-sjlj.ll
@@ -0,0 +1,213 @@
+; RUN: opt < %s -wasm-lower-em-ehsjlj -S | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+%struct.__jmp_buf_tag = type { [6 x i32], i32, [32 x i32] }
+
+@global_var = hidden global i32 0, align 4
+; CHECK-DAG: @[[__THREW__:__THREW__.*]] = global i32 0
+; CHECK-DAG: @[[THREWVALUE:__threwValue.*]] = global i32 0
+; CHECK-DAG: @[[TEMPRET0:__tempRet0.*]] = global i32 0
+
+; Test a simple setjmp - longjmp sequence
+define hidden void @setjmp_longjmp() {
+; CHECK-LABEL: @setjmp_longjmp
+entry:
+ %buf = alloca [1 x %struct.__jmp_buf_tag], align 16
+ %arraydecay = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0
+ %call = call i32 @setjmp(%struct.__jmp_buf_tag* %arraydecay) #0
+ %arraydecay1 = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0
+ call void @longjmp(%struct.__jmp_buf_tag* %arraydecay1, i32 1) #1
+ unreachable
+; CHECK: entry:
+; CHECK-NEXT: %[[MALLOCCALL:.*]] = tail call i8* @malloc(i32 40)
+; CHECK-NEXT: %[[SETJMP_TABLE:.*]] = bitcast i8* %[[MALLOCCALL]] to i32*
+; CHECK-NEXT: store i32 0, i32* %[[SETJMP_TABLE]]
+; CHECK-NEXT: %[[SETJMP_TABLE_SIZE:.*]] = add i32 4, 0
+; CHECK-NEXT: %[[BUF:.*]] = alloca [1 x %struct.__jmp_buf_tag]
+; CHECK-NEXT: %[[ARRAYDECAY:.*]] = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %[[BUF]], i32 0, i32 0
+; CHECK-NEXT: %[[SETJMP_TABLE1:.*]] = call i32* @saveSetjmp(%struct.__jmp_buf_tag* %[[ARRAYDECAY]], i32 1, i32* %[[SETJMP_TABLE]], i32 %[[SETJMP_TABLE_SIZE]])
+; CHECK-NEXT: %[[SETJMP_TABLE_SIZE1:.*]] = load i32, i32* @[[TEMPRET0]]
+; CHECK-NEXT: br label %entry.split
+
+; CHECK: entry.split:
+; CHECK-NEXT: phi i32 [ 0, %entry ], [ %[[LONGJMP_RESULT:.*]], %if.end ]
+; CHECK-NEXT: %[[ARRAYDECAY1:.*]] = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %[[BUF]], i32 0, i32 0
+; CHECK-NEXT: store i32 0, i32* @[[__THREW__]]
+; CHECK-NEXT: call void @"__invoke_void_%struct.__jmp_buf_tag*_i32"(void (%struct.__jmp_buf_tag*, i32)* @emscripten_longjmp_jmpbuf, %struct.__jmp_buf_tag* %[[ARRAYDECAY1]], i32 1)
+; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i32, i32* @[[__THREW__]]
+; CHECK-NEXT: store i32 0, i32* @[[__THREW__]]
+; CHECK-NEXT: %[[CMP0:.*]] = icmp ne i32 %__THREW__.val, 0
+; CHECK-NEXT: %[[THREWVALUE_VAL:.*]] = load i32, i32* @[[THREWVALUE]]
+; CHECK-NEXT: %[[CMP1:.*]] = icmp ne i32 %[[THREWVALUE_VAL]], 0
+; CHECK-NEXT: %[[CMP:.*]] = and i1 %[[CMP0]], %[[CMP1]]
+; CHECK-NEXT: br i1 %[[CMP]], label %if.then1, label %if.else1
+
+; CHECK: entry.split.split:
+; CHECK-NEXT: unreachable
+
+; CHECK: if.then1:
+; CHECK-NEXT: %[[__THREW__VAL_I32P:.*]] = inttoptr i32 %[[__THREW__VAL]] to i32*
+; CHECK-NEXT: %[[__THREW__VAL_I32P_LOADED:.*]] = load i32, i32* %[[__THREW__VAL_I32P]]
+; CHECK-NEXT: %[[LABEL:.*]] = call i32 @testSetjmp(i32 %[[__THREW__VAL_I32P_LOADED]], i32* %[[SETJMP_TABLE1]], i32 %[[SETJMP_TABLE_SIZE1]])
+; CHECK-NEXT: %[[CMP:.*]] = icmp eq i32 %[[LABEL]], 0
+; CHECK-NEXT: br i1 %[[CMP]], label %if.then2, label %if.end2
+
+; CHECK: if.else1:
+; CHECK-NEXT: br label %if.end
+
+; CHECK: if.end:
+; CHECK-NEXT: %[[LABEL_PHI:.*]] = phi i32 [ %[[LABEL:.*]], %if.end2 ], [ -1, %if.else1 ]
+; CHECK-NEXT: %[[LONGJMP_RESULT]] = load i32, i32* @[[TEMPRET0]]
+; CHECK-NEXT: switch i32 %[[LABEL_PHI]], label %entry.split.split [
+; CHECK-NEXT: i32 1, label %entry.split
+; CHECK-NEXT: ]
+
+; CHECK: if.then2:
+; CHECK-NEXT: call void @emscripten_longjmp(i32 %[[__THREW__VAL]], i32 %[[THREWVALUE_VAL]])
+; CHECK-NEXT: unreachable
+
+; CHECK: if.end2:
+; CHECK-NEXT: store i32 %[[THREWVALUE_VAL]], i32* @[[TEMPRET0]]
+; CHECK-NEXT: br label %if.end
+}
+
+; Test a case of a function call (which is not longjmp) after a setjmp
+define hidden void @setjmp_other() {
+; CHECK-LABEL: @setjmp_other
+entry:
+ %buf = alloca [1 x %struct.__jmp_buf_tag], align 16
+ %arraydecay = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0
+ %call = call i32 @setjmp(%struct.__jmp_buf_tag* %arraydecay) #0
+ call void @foo()
+ ret void
+; CHECK: entry:
+; CHECK: %[[SETJMP_TABLE:.*]] = call i32* @saveSetjmp(
+
+; CHECK: entry.split:
+; CHECK: call void @__invoke_void(void ()* @foo)
+
+; CHECK: entry.split.split:
+; CHECK-NEXT: %[[BUF:.*]] = bitcast i32* %[[SETJMP_TABLE]] to i8*
+; CHECK-NEXT: tail call void @free(i8* %[[BUF]])
+; CHECK-NEXT: ret void
+}
+
+; Test a case when a function call is within try-catch, after a setjmp
+define hidden void @exception_and_longjmp() #3 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+; CHECK-LABEL: @exception_and_longjmp
+entry:
+ %buf = alloca [1 x %struct.__jmp_buf_tag], align 16
+ %arraydecay = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0
+ %call = call i32 @setjmp(%struct.__jmp_buf_tag* %arraydecay) #0
+ invoke void @foo()
+ to label %try.cont unwind label %lpad
+
+; CHECK: entry.split:
+; CHECK: store i32 0, i32* @[[__THREW__]]
+; CHECK-NEXT: call void @__invoke_void(void ()* @foo)
+; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i32, i32* @[[__THREW__]]
+; CHECK-NEXT: store i32 0, i32* @[[__THREW__]]
+; CHECK-NEXT: %[[CMP0:.*]] = icmp ne i32 %[[__THREW__VAL]], 0
+; CHECK-NEXT: %[[THREWVALUE_VAL:.*]] = load i32, i32* @[[THREWVALUE]]
+; CHECK-NEXT: %[[CMP1:.*]] = icmp ne i32 %[[THREWVALUE_VAL]], 0
+; CHECK-NEXT: %[[CMP:.*]] = and i1 %[[CMP0]], %[[CMP1]]
+; CHECK-NEXT: br i1 %[[CMP]], label %if.then1, label %if.else1
+
+; CHECK: entry.split.split:
+; CHECK-NEXT: %[[CMP:.*]] = icmp eq i32 %[[__THREW__VAL]], 1
+; CHECK-NEXT: br i1 %[[CMP]], label %lpad, label %try.cont
+
+lpad: ; preds = %entry
+ %0 = landingpad { i8*, i32 }
+ catch i8* null
+ %1 = extractvalue { i8*, i32 } %0, 0
+ %2 = extractvalue { i8*, i32 } %0, 1
+ %3 = call i8* @__cxa_begin_catch(i8* %1) #2
+ call void @__cxa_end_catch()
+ br label %try.cont
+
+try.cont: ; preds = %entry, %lpad
+ ret void
+}
+
+; Test SSA validity
+define hidden void @ssa(i32 %n) {
+; CHECK-LABEL: @ssa
+entry:
+ %buf = alloca [1 x %struct.__jmp_buf_tag], align 16
+ %cmp = icmp sgt i32 %n, 5
+ br i1 %cmp, label %if.then, label %if.end
+; CHECK: entry:
+; CHECK: %[[SETJMP_TABLE0:.*]] = bitcast i8*
+; CHECK: %[[SETJMP_TABLE_SIZE0:.*]] = add i32 4, 0
+
+if.then: ; preds = %entry
+ %0 = load i32, i32* @global_var, align 4
+ %arraydecay = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0
+ %call = call i32 @setjmp(%struct.__jmp_buf_tag* %arraydecay) #0
+ store i32 %0, i32* @global_var, align 4
+ br label %if.end
+; CHECK: if.then:
+; CHECK: %[[VAR0:.*]] = load i32, i32* @global_var, align 4
+; CHECK: %[[SETJMP_TABLE1:.*]] = call i32* @saveSetjmp(
+; CHECK-NEXT: %[[SETJMP_TABLE_SIZE1:.*]] = load i32, i32* @[[TEMPRET0]]
+
+; CHECK: if.then.split:
+; CHECK: %[[VAR1:.*]] = phi i32 [ %[[VAR0]], %if.then ], [ %[[VAR2:.*]], %if.end3 ]
+; CHECK: %[[SETJMP_TABLE_SIZE2:.*]] = phi i32 [ %[[SETJMP_TABLE_SIZE1]], %if.then ], [ %[[SETJMP_TABLE_SIZE3:.*]], %if.end3 ]
+; CHECK: %[[SETJMP_TABLE2:.*]] = phi i32* [ %[[SETJMP_TABLE1]], %if.then ], [ %[[SETJMP_TABLE3:.*]], %if.end3 ]
+; CHECK: store i32 %[[VAR1]], i32* @global_var, align 4
+
+if.end: ; preds = %if.then, %entry
+ %arraydecay1 = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0
+ call void @longjmp(%struct.__jmp_buf_tag* %arraydecay1, i32 5) #1
+ unreachable
+; CHECK: if.end:
+; CHECK: %[[VAR2]] = phi i32 [ %[[VAR1]], %if.then.split ], [ undef, %entry ]
+; CHECK: %[[SETJMP_TABLE_SIZE3]] = phi i32 [ %[[SETJMP_TABLE_SIZE2]], %if.then.split ], [ %[[SETJMP_TABLE_SIZE0]], %entry ]
+; CHECK: %[[SETJMP_TABLE3]] = phi i32* [ %[[SETJMP_TABLE2]], %if.then.split ], [ %[[SETJMP_TABLE0]], %entry ]
+}
+
+; Test a case when a function only calls other functions that are neither setjmp nor longjmp
+define hidden void @only_other_func() {
+entry:
+ call void @foo()
+ ret void
+; CHECK: call void @foo()
+}
+
+; Test a case when a function only calls longjmp and not setjmp
+define hidden void @only_longjmp() {
+entry:
+ %buf = alloca [1 x %struct.__jmp_buf_tag], align 16
+ %arraydecay = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0
+ call void @longjmp(%struct.__jmp_buf_tag* %arraydecay, i32 5) #1
+ unreachable
+; CHECK: %[[ARRAYDECAY:.*]] = getelementptr inbounds
+; CHECK-NEXT: call void @emscripten_longjmp_jmpbuf(%struct.__jmp_buf_tag* %[[ARRAYDECAY]], i32 5) #1
+}
+
+declare void @foo()
+; Function Attrs: returns_twice
+declare i32 @setjmp(%struct.__jmp_buf_tag*) #0
+; Function Attrs: noreturn
+declare void @longjmp(%struct.__jmp_buf_tag*, i32) #1
+declare i32 @__gxx_personality_v0(...)
+declare i8* @__cxa_begin_catch(i8*)
+declare void @__cxa_end_catch()
+declare i8* @malloc(i32)
+declare void @free(i8*)
+
+; JS glue functions and invoke wrappers declaration
+; CHECK-DAG: declare i32* @saveSetjmp(%struct.__jmp_buf_tag*, i32, i32*, i32)
+; CHECK-DAG: declare i32 @testSetjmp(i32, i32*, i32)
+; CHECK-DAG: declare void @emscripten_longjmp_jmpbuf(%struct.__jmp_buf_tag*, i32)
+; CHECK-DAG: declare void @emscripten_longjmp(i32, i32)
+; CHECK-DAG: declare void @__invoke_void(void ()*)
+; CHECK-DAG: declare void @"__invoke_void_%struct.__jmp_buf_tag*_i32"(void (%struct.__jmp_buf_tag*, i32)*, %struct.__jmp_buf_tag*, i32)
+
+attributes #0 = { returns_twice }
+attributes #1 = { noreturn }
+attributes #2 = { nounwind }
diff --git a/test/CodeGen/WebAssembly/mem-intrinsics.ll b/test/CodeGen/WebAssembly/mem-intrinsics.ll
index 71787feb77dc..0ac1e1e182cd 100644
--- a/test/CodeGen/WebAssembly/mem-intrinsics.ll
+++ b/test/CodeGen/WebAssembly/mem-intrinsics.ll
@@ -1,4 +1,4 @@
-; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
+; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -tail-dup-placement=0| FileCheck %s
; Test memcpy, memmove, and memset intrinsics.
diff --git a/test/CodeGen/WebAssembly/memory-addr64.ll b/test/CodeGen/WebAssembly/memory-addr64.ll
deleted file mode 100644
index dc6da6121718..000000000000
--- a/test/CodeGen/WebAssembly/memory-addr64.ll
+++ /dev/null
@@ -1,27 +0,0 @@
-; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
-
-; Test that basic memory operations assemble as expected with 64-bit addresses.
-
-target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128"
-target triple = "wasm64-unknown-unknown"
-
-declare i64 @llvm.wasm.current.memory.i64() nounwind readonly
-declare void @llvm.wasm.grow.memory.i64(i64) nounwind
-
-; CHECK-LABEL: current_memory:
-; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: current_memory $push0={{$}}
-; CHECK-NEXT: return $pop0{{$}}
-define i64 @current_memory() {
- %a = call i64 @llvm.wasm.current.memory.i64()
- ret i64 %a
-}
-
-; CHECK-LABEL: grow_memory:
-; CHECK-NEXT: .param i64{{$}}
-; CHECK: grow_memory $0{{$}}
-; CHECK-NEXT: return{{$}}
-define void @grow_memory(i64 %n) {
- call void @llvm.wasm.grow.memory.i64(i64 %n)
- ret void
-}
diff --git a/test/CodeGen/WebAssembly/negative-base-reg.ll b/test/CodeGen/WebAssembly/negative-base-reg.ll
new file mode 100644
index 000000000000..377966ffa8d9
--- /dev/null
+++ b/test/CodeGen/WebAssembly/negative-base-reg.ll
@@ -0,0 +1,43 @@
+; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-wasm-fallthrough-return-opt | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32"
+
+@args = hidden local_unnamed_addr global [32 x i32] zeroinitializer, align 16
+
+; Function Attrs: norecurse nounwind
+define hidden i32 @main() local_unnamed_addr #0 {
+
+; If LSR stops selecting a negative base reg value, then this test will no
+; longer be useful as written.
+; CHECK: i32.const $0=, -128
+entry:
+ br label %for.body
+
+for.body: ; preds = %for.body, %entry
+ %i.04 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
+; The offset should not be folded into the store.
+; CHECK: i32.const $push{{[0-9]+}}=, args+128
+; CHECK: i32.add
+; CHECK: i32.store 0(
+ %arrayidx = getelementptr inbounds [32 x i32], [32 x i32]* @args, i32 0, i32 %i.04
+ store i32 1, i32* %arrayidx, align 4, !tbaa !1
+ %inc = add nuw nsw i32 %i.04, 1
+ %exitcond = icmp eq i32 %inc, 32
+ br i1 %exitcond, label %for.end, label %for.body, !llvm.loop !5
+
+for.end: ; preds = %for.body
+ ret i32 0
+}
+
+attributes #0 = { norecurse nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 4.0.0 (trunk 279056) (llvm/trunk 279074)"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"int", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
+!5 = distinct !{!5, !6}
+!6 = !{!"llvm.loop.unroll.disable"}
diff --git a/test/CodeGen/WebAssembly/offset.ll b/test/CodeGen/WebAssembly/offset.ll
index fcd8b49758ed..37f08abc9fa8 100644
--- a/test/CodeGen/WebAssembly/offset.ll
+++ b/test/CodeGen/WebAssembly/offset.ll
@@ -139,7 +139,7 @@ define i32 @load_i32_with_folded_or_offset(i32 %x) {
; Same as above but with store.
; CHECK-LABEL: store_i32_with_folded_offset:
-; CHECK: i32.store $drop=, 24($0), $pop0{{$}}
+; CHECK: i32.store 24($0), $pop0{{$}}
define void @store_i32_with_folded_offset(i32* %p) {
%q = ptrtoint i32* %p to i32
%r = add nuw i32 %q, 24
@@ -151,7 +151,7 @@ define void @store_i32_with_folded_offset(i32* %p) {
; Same as above but with store.
; CHECK-LABEL: store_i32_with_folded_gep_offset:
-; CHECK: i32.store $drop=, 24($0), $pop0{{$}}
+; CHECK: i32.store 24($0), $pop0{{$}}
define void @store_i32_with_folded_gep_offset(i32* %p) {
%s = getelementptr inbounds i32, i32* %p, i32 6
store i32 0, i32* %s
@@ -163,7 +163,7 @@ define void @store_i32_with_folded_gep_offset(i32* %p) {
; CHECK-LABEL: store_i32_with_unfolded_gep_negative_offset:
; CHECK: i32.const $push0=, -24{{$}}
; CHECK: i32.add $push1=, $0, $pop0{{$}}
-; CHECK: i32.store $drop=, 0($pop1), $pop2{{$}}
+; CHECK: i32.store 0($pop1), $pop2{{$}}
define void @store_i32_with_unfolded_gep_negative_offset(i32* %p) {
%s = getelementptr inbounds i32, i32* %p, i32 -6
store i32 0, i32* %s
@@ -175,7 +175,7 @@ define void @store_i32_with_unfolded_gep_negative_offset(i32* %p) {
; CHECK-LABEL: store_i32_with_unfolded_offset:
; CHECK: i32.const $push0=, 24{{$}}
; CHECK: i32.add $push1=, $0, $pop0{{$}}
-; CHECK: i32.store $drop=, 0($pop1), $pop2{{$}}
+; CHECK: i32.store 0($pop1), $pop2{{$}}
define void @store_i32_with_unfolded_offset(i32* %p) {
%q = ptrtoint i32* %p to i32
%r = add nsw i32 %q, 24
@@ -189,7 +189,7 @@ define void @store_i32_with_unfolded_offset(i32* %p) {
; CHECK-LABEL: store_i32_with_unfolded_gep_offset:
; CHECK: i32.const $push0=, 24{{$}}
; CHECK: i32.add $push1=, $0, $pop0{{$}}
-; CHECK: i32.store $drop=, 0($pop1), $pop2{{$}}
+; CHECK: i32.store 0($pop1), $pop2{{$}}
define void @store_i32_with_unfolded_gep_offset(i32* %p) {
%s = getelementptr i32, i32* %p, i32 6
store i32 0, i32* %s
@@ -199,7 +199,7 @@ define void @store_i32_with_unfolded_gep_offset(i32* %p) {
; Same as above but with store with i64.
; CHECK-LABEL: store_i64_with_folded_offset:
-; CHECK: i64.store $drop=, 24($0), $pop0{{$}}
+; CHECK: i64.store 24($0), $pop0{{$}}
define void @store_i64_with_folded_offset(i64* %p) {
%q = ptrtoint i64* %p to i32
%r = add nuw i32 %q, 24
@@ -211,7 +211,7 @@ define void @store_i64_with_folded_offset(i64* %p) {
; Same as above but with store with i64.
; CHECK-LABEL: store_i64_with_folded_gep_offset:
-; CHECK: i64.store $drop=, 24($0), $pop0{{$}}
+; CHECK: i64.store 24($0), $pop0{{$}}
define void @store_i64_with_folded_gep_offset(i64* %p) {
%s = getelementptr inbounds i64, i64* %p, i32 3
store i64 0, i64* %s
@@ -223,7 +223,7 @@ define void @store_i64_with_folded_gep_offset(i64* %p) {
; CHECK-LABEL: store_i64_with_unfolded_gep_negative_offset:
; CHECK: i32.const $push0=, -24{{$}}
; CHECK: i32.add $push1=, $0, $pop0{{$}}
-; CHECK: i64.store $drop=, 0($pop1), $pop2{{$}}
+; CHECK: i64.store 0($pop1), $pop2{{$}}
define void @store_i64_with_unfolded_gep_negative_offset(i64* %p) {
%s = getelementptr inbounds i64, i64* %p, i32 -3
store i64 0, i64* %s
@@ -235,7 +235,7 @@ define void @store_i64_with_unfolded_gep_negative_offset(i64* %p) {
; CHECK-LABEL: store_i64_with_unfolded_offset:
; CHECK: i32.const $push0=, 24{{$}}
; CHECK: i32.add $push1=, $0, $pop0{{$}}
-; CHECK: i64.store $drop=, 0($pop1), $pop2{{$}}
+; CHECK: i64.store 0($pop1), $pop2{{$}}
define void @store_i64_with_unfolded_offset(i64* %p) {
%q = ptrtoint i64* %p to i32
%r = add nsw i32 %q, 24
@@ -249,7 +249,7 @@ define void @store_i64_with_unfolded_offset(i64* %p) {
; CHECK-LABEL: store_i64_with_unfolded_gep_offset:
; CHECK: i32.const $push0=, 24{{$}}
; CHECK: i32.add $push1=, $0, $pop0{{$}}
-; CHECK: i64.store $drop=, 0($pop1), $pop2{{$}}
+; CHECK: i64.store 0($pop1), $pop2{{$}}
define void @store_i64_with_unfolded_gep_offset(i64* %p) {
%s = getelementptr i64, i64* %p, i32 3
store i64 0, i64* %s
@@ -257,7 +257,7 @@ define void @store_i64_with_unfolded_gep_offset(i64* %p) {
}
; CHECK-LABEL: store_i32_with_folded_or_offset:
-; CHECK: i32.store8 $drop=, 2($pop{{[0-9]+}}), $pop{{[0-9]+}}{{$}}
+; CHECK: i32.store8 2($pop{{[0-9]+}}), $pop{{[0-9]+}}{{$}}
define void @store_i32_with_folded_or_offset(i32 %x) {
%and = and i32 %x, -4
%t0 = inttoptr i32 %and to i8*
@@ -289,7 +289,7 @@ define i32 @load_i32_from_global_address() {
; CHECK-LABEL: store_i32_to_numeric_address:
; CHECK-NEXT: i32.const $push0=, 0{{$}}
; CHECK-NEXT: i32.const $push1=, 0{{$}}
-; CHECK-NEXT: i32.store $drop=, 42($pop0), $pop1{{$}}
+; CHECK-NEXT: i32.store 42($pop0), $pop1{{$}}
define void @store_i32_to_numeric_address() {
%s = inttoptr i32 42 to i32*
store i32 0, i32* %s
@@ -299,7 +299,7 @@ define void @store_i32_to_numeric_address() {
; CHECK-LABEL: store_i32_to_global_address:
; CHECK: i32.const $push0=, 0{{$}}
; CHECK: i32.const $push1=, 0{{$}}
-; CHECK: i32.store $drop=, gv($pop0), $pop1{{$}}
+; CHECK: i32.store gv($pop0), $pop1{{$}}
define void @store_i32_to_global_address() {
store i32 0, i32* @gv
ret void
@@ -356,7 +356,7 @@ define i32 @load_i8_u_with_folded_gep_offset(i8* %p) {
; Fold an offset into a truncating store.
; CHECK-LABEL: store_i8_with_folded_offset:
-; CHECK: i32.store8 $drop=, 24($0), $pop0{{$}}
+; CHECK: i32.store8 24($0), $pop0{{$}}
define void @store_i8_with_folded_offset(i8* %p) {
%q = ptrtoint i8* %p to i32
%r = add nuw i32 %q, 24
@@ -368,7 +368,7 @@ define void @store_i8_with_folded_offset(i8* %p) {
; Fold a gep offset into a truncating store.
; CHECK-LABEL: store_i8_with_folded_gep_offset:
-; CHECK: i32.store8 $drop=, 24($0), $pop0{{$}}
+; CHECK: i32.store8 24($0), $pop0{{$}}
define void @store_i8_with_folded_gep_offset(i8* %p) {
%s = getelementptr inbounds i8, i8* %p, i32 24
store i8 0, i8* %s
@@ -382,10 +382,10 @@ define void @store_i8_with_folded_gep_offset(i8* %p) {
; CHECK: i32.load $3=, 4($0){{$}}
; CHECK: i32.load $4=, 8($0){{$}}
; CHECK: i32.load $push0=, 12($0){{$}}
-; CHECK: i32.store $drop=, 12($1), $pop0{{$}}
-; CHECK: i32.store $drop=, 8($1), $4{{$}}
-; CHECK: i32.store $drop=, 4($1), $3{{$}}
-; CHECK: i32.store $drop=, 0($1), $2{{$}}
+; CHECK: i32.store 12($1), $pop0{{$}}
+; CHECK: i32.store 8($1), $4{{$}}
+; CHECK: i32.store 4($1), $3{{$}}
+; CHECK: i32.store 0($1), $2{{$}}
define void @aggregate_load_store({i32,i32,i32,i32}* %p, {i32,i32,i32,i32}* %q) {
; volatile so that things stay in order for the tests above
%t = load volatile {i32,i32,i32,i32}, {i32, i32,i32,i32}* %p
@@ -398,8 +398,9 @@ define void @aggregate_load_store({i32,i32,i32,i32}* %p, {i32,i32,i32,i32}* %q)
; CHECK-LABEL: aggregate_return:
; CHECK: i64.const $push[[L0:[0-9]+]]=, 0{{$}}
-; CHECK: i64.store $push[[L1:[0-9]+]]=, 8($0):p2align=2, $pop[[L0]]{{$}}
-; CHECK: i64.store $drop=, 0($0):p2align=2, $pop[[L1]]{{$}}
+; CHECK: i64.store 8($0):p2align=2, $pop[[L0]]{{$}}
+; CHECK: i64.const $push[[L1:[0-9]+]]=, 0{{$}}
+; CHECK: i64.store 0($0):p2align=2, $pop[[L1]]{{$}}
define {i32,i32,i32,i32} @aggregate_return() {
ret {i32,i32,i32,i32} zeroinitializer
}
@@ -409,11 +410,13 @@ define {i32,i32,i32,i32} @aggregate_return() {
; CHECK-LABEL: aggregate_return_without_merge:
; CHECK: i32.const $push[[L0:[0-9]+]]=, 0{{$}}
-; CHECK: i32.store8 $push[[L1:[0-9]+]]=, 14($0), $pop[[L0]]{{$}}
-; CHECK: i32.store16 $push[[L2:[0-9]+]]=, 12($0), $pop[[L1]]{{$}}
-; CHECK: i32.store $drop=, 8($0), $pop[[L2]]{{$}}
+; CHECK: i32.store8 14($0), $pop[[L0]]{{$}}
+; CHECK: i32.const $push[[L1:[0-9]+]]=, 0{{$}}
+; CHECK: i32.store16 12($0), $pop[[L1]]{{$}}
+; CHECK: i32.const $push[[L2:[0-9]+]]=, 0{{$}}
+; CHECK: i32.store 8($0), $pop[[L2]]{{$}}
; CHECK: i64.const $push[[L3:[0-9]+]]=, 0{{$}}
-; CHECK: i64.store $drop=, 0($0), $pop[[L3]]{{$}}
+; CHECK: i64.store 0($0), $pop[[L3]]{{$}}
define {i64,i32,i16,i8} @aggregate_return_without_merge() {
ret {i64,i32,i16,i8} zeroinitializer
}
diff --git a/test/CodeGen/WebAssembly/reg-stackify.ll b/test/CodeGen/WebAssembly/reg-stackify.ll
index 23cbd03aa080..00469132c953 100644
--- a/test/CodeGen/WebAssembly/reg-stackify.ll
+++ b/test/CodeGen/WebAssembly/reg-stackify.ll
@@ -84,7 +84,7 @@ define i32 @no_sink_readonly_call(i32 %x, i32 %y, i32* %p) {
; CHECK-LABEL: stack_uses:
; CHECK: .param i32, i32, i32, i32{{$}}
; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: block{{$}}
+; CHECK-NEXT: block {{$}}
; CHECK-NEXT: i32.const $push[[L13:[0-9]+]]=, 1{{$}}
; CHECK-NEXT: i32.lt_s $push[[L0:[0-9]+]]=, $0, $pop[[L13]]{{$}}
; CHECK-NEXT: i32.const $push[[L1:[0-9]+]]=, 2{{$}}
@@ -127,14 +127,14 @@ false:
; CHECK-LABEL: multiple_uses:
; CHECK: .param i32, i32, i32{{$}}
; CHECK-NEXT: .local i32{{$}}
-; CHECK-NEXT: block{{$}}
+; CHECK-NEXT: block {{$}}
; CHECK-NEXT: i32.load $push[[NUM0:[0-9]+]]=, 0($2){{$}}
; CHECK-NEXT: tee_local $push[[NUM1:[0-9]+]]=, $3=, $pop[[NUM0]]{{$}}
; CHECK-NEXT: i32.ge_u $push[[NUM2:[0-9]+]]=, $pop[[NUM1]], $1{{$}}
; CHECK-NEXT: br_if 0, $pop[[NUM2]]{{$}}
; CHECK-NEXT: i32.lt_u $push[[NUM3:[0-9]+]]=, $3, $0{{$}}
; CHECK-NEXT: br_if 0, $pop[[NUM3]]{{$}}
-; CHECK-NEXT: i32.store $drop=, 0($2), $3{{$}}
+; CHECK-NEXT: i32.store 0($2), $3{{$}}
; CHECK-NEXT: .LBB8_3:
; CHECK-NEXT: end_block{{$}}
; CHECK-NEXT: return{{$}}
@@ -166,7 +166,7 @@ return:
; CHECK: side_effects:
; CHECK: store
; CHECK-NEXT: call
-; CHECK-NEXT: store
+; CHECK: store
; CHECK-NEXT: call
declare void @evoke_side_effects()
define hidden void @stackify_store_across_side_effects(double* nocapture %d) {
@@ -377,9 +377,9 @@ define i32 @no_stackify_call_past_load() {
; Don't move stores past loads if there may be aliasing
; CHECK-LABEL: no_stackify_store_past_load
-; CHECK: i32.store $[[L0:[0-9]+]]=, 0($1), $0
+; CHECK: i32.store 0($1), $0
; CHECK: i32.load {{.*}}, 0($2)
-; CHECK: i32.call {{.*}}, callee@FUNCTION, $[[L0]]{{$}}
+; CHECK: i32.call {{.*}}, callee@FUNCTION, $0{{$}}
define i32 @no_stackify_store_past_load(i32 %a, i32* %p1, i32* %p2) {
store i32 %a, i32* %p1
%b = load i32, i32* %p2, align 4
@@ -389,8 +389,8 @@ define i32 @no_stackify_store_past_load(i32 %a, i32* %p1, i32* %p2) {
; Can still stackify past invariant loads.
; CHECK-LABEL: store_past_invar_load
-; CHECK: i32.store $push{{.*}}, 0($1), $0
-; CHECK: i32.call {{.*}}, callee@FUNCTION, $pop
+; CHECK: i32.store 0($1), $0
+; CHECK: i32.call {{.*}}, callee@FUNCTION, $0
; CHECK: i32.load $push{{.*}}, 0($2)
; CHECK: return $pop
define i32 @store_past_invar_load(i32 %a, i32* %p1, i32* dereferenceable(4) %p2) {
@@ -450,7 +450,7 @@ bb10: ; preds = %bb9, %bb
; CHECK-LABEL: stackpointer_dependency:
; CHECK: call {{.+}}, stackpointer_callee@FUNCTION,
; CHECK: i32.const $push[[L0:.+]]=, 0
-; CHECK-NEXT: i32.store $drop=, __stack_pointer($pop[[L0]]),
+; CHECK-NEXT: i32.store __stack_pointer($pop[[L0]]),
declare i32 @stackpointer_callee(i8* readnone, i8* readnone)
declare i8* @llvm.frameaddress(i32)
define i32 @stackpointer_dependency(i8* readnone) {
@@ -459,6 +459,25 @@ define i32 @stackpointer_dependency(i8* readnone) {
ret i32 %3
}
+; Stackify a call_indirect with respect to its ordering
+
+; CHECK-LABEL: call_indirect_stackify:
+; CHECK: i32.load $push[[L4:.+]]=, 0($0)
+; CHECK-NEXT: tee_local $push[[L3:.+]]=, $0=, $pop[[L4]]
+; CHECK-NEXT: i32.load $push[[L0:.+]]=, 0($0)
+; CHECK-NEXT: i32.load $push[[L1:.+]]=, 0($pop[[L0]])
+; CHECK-NEXT: i32.call_indirect $push{{.+}}=, $pop[[L3]], $1, $pop[[L1]]
+%class.call_indirect = type { i32 (...)** }
+define i32 @call_indirect_stackify(%class.call_indirect** %objptr, i32 %arg) {
+ %obj = load %class.call_indirect*, %class.call_indirect** %objptr
+ %addr = bitcast %class.call_indirect* %obj to i32(%class.call_indirect*, i32)***
+ %vtable = load i32(%class.call_indirect*, i32)**, i32(%class.call_indirect*, i32)*** %addr
+ %vfn = getelementptr inbounds i32(%class.call_indirect*, i32)*, i32(%class.call_indirect*, i32)** %vtable, i32 0
+ %f = load i32(%class.call_indirect*, i32)*, i32(%class.call_indirect*, i32)** %vfn
+ %ret = call i32 %f(%class.call_indirect* %obj, i32 %arg)
+ ret i32 %ret
+}
+
!llvm.module.flags = !{!0}
!llvm.dbg.cu = !{!1}
diff --git a/test/CodeGen/WebAssembly/simd-arith.ll b/test/CodeGen/WebAssembly/simd-arith.ll
new file mode 100644
index 000000000000..f0e71f2cc104
--- /dev/null
+++ b/test/CodeGen/WebAssembly/simd-arith.ll
@@ -0,0 +1,158 @@
+; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -mattr=+simd128 | FileCheck %s --check-prefixes CHECK,SIMD128
+; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -mattr=+simd128 -fast-isel | FileCheck %s --check-prefixes CHECK,SIMD128
+; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -mattr=-simd128 | FileCheck %s --check-prefixes CHECK,NO-SIMD128
+; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -mattr=-simd128 -fast-isel | FileCheck %s --check-prefixes CHECK,NO-SIMD128
+
+; Test that basic SIMD128 arithmetic operations assemble as expected.
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+declare i32 @llvm.ctlz.i32(i32, i1)
+declare i32 @llvm.cttz.i32(i32, i1)
+declare i32 @llvm.ctpop.i32(i32)
+
+; ==============================================================================
+; 16 x i8
+; ==============================================================================
+; CHECK-LABEL: add_v16i8
+; NO-SIMD128-NOT: i8x16
+; SIMD128: .param v128, v128{{$}}
+; SIMD128: .result v128{{$}}
+; SIMD128: i8x16.add $push0=, $0, $1{{$}}
+; SIMD128: return $pop0{{$}}
+define <16 x i8> @add_v16i8(<16 x i8> %x, <16 x i8> %y) {
+ %a = add <16 x i8> %x, %y
+ ret <16 x i8> %a
+}
+
+; CHECK-LABEL: sub_v16i8
+; NO-SIMD128-NOT: i8x16
+; SIMD128: .param v128, v128{{$}}
+; SIMD128: .result v128{{$}}
+; SIMD128: i8x16.sub $push0=, $0, $1{{$}}
+; SIMD128: return $pop0{{$}}
+define <16 x i8> @sub_v16i8(<16 x i8> %x, <16 x i8> %y) {
+ %a = sub <16 x i8> %x, %y
+ ret <16 x i8> %a
+}
+
+; CHECK-LABEL: mul_v16i8
+; NO-SIMD128-NOT: i8x16
+; SIMD128: .param v128, v128{{$}}
+; SIMD128: .result v128{{$}}
+; SIMD128: i8x16.mul $push0=, $0, $1{{$}}
+; SIMD128: return $pop0{{$}}
+define <16 x i8> @mul_v16i8(<16 x i8> %x, <16 x i8> %y) {
+ %a = mul <16 x i8> %x, %y
+ ret <16 x i8> %a
+}
+
+; ==============================================================================
+; 8 x i16
+; ==============================================================================
+; CHECK-LABEL: add_v8i16
+; NO-SIMD128-NOT: i16x8
+; SIMD128: .param v128, v128{{$}}
+; SIMD128: .result v128{{$}}
+; SIMD128: i16x8.add $push0=, $0, $1{{$}}
+; SIMD128: return $pop0{{$}}
+define <8 x i16> @add_v8i16(<8 x i16> %x, <8 x i16> %y) {
+ %a = add <8 x i16> %x, %y
+ ret <8 x i16> %a
+}
+
+; CHECK-LABEL: sub_v8i16
+; NO-SIMD128-NOT: i16x8
+; SIMD128: .param v128, v128{{$}}
+; SIMD128: .result v128{{$}}
+; SIMD128: i16x8.sub $push0=, $0, $1{{$}}
+; SIMD128: return $pop0{{$}}
+define <8 x i16> @sub_v8i16(<8 x i16> %x, <8 x i16> %y) {
+ %a = sub <8 x i16> %x, %y
+ ret <8 x i16> %a
+}
+
+; CHECK-LABEL: mul_v8i16
+; NO-SIMD128-NOT: i16x8
+; SIMD128: .param v128, v128{{$}}
+; SIMD128: .result v128{{$}}
+; SIMD128: i16x8.mul $push0=, $0, $1{{$}}
+; SIMD128: return $pop0{{$}}
+define <8 x i16> @mul_v8i16(<8 x i16> %x, <8 x i16> %y) {
+ %a = mul <8 x i16> %x, %y
+ ret <8 x i16> %a
+}
+
+; ==============================================================================
+; 4 x i32
+; ==============================================================================
+; CHECK-LABEL: add_v4i32
+; NO-SIMD128-NOT: i32x4
+; SIMD128: .param v128, v128{{$}}
+; SIMD128: .result v128{{$}}
+; SIMD128: i32x4.add $push0=, $0, $1{{$}}
+; SIMD128: return $pop0{{$}}
+define <4 x i32> @add_v4i32(<4 x i32> %x, <4 x i32> %y) {
+ %a = add <4 x i32> %x, %y
+ ret <4 x i32> %a
+}
+
+; CHECK-LABEL: sub_v4i32
+; NO-SIMD128-NOT: i32x4
+; SIMD128: .param v128, v128{{$}}
+; SIMD128: .result v128{{$}}
+; SIMD128: i32x4.sub $push0=, $0, $1{{$}}
+; SIMD128: return $pop0{{$}}
+define <4 x i32> @sub_v4i32(<4 x i32> %x, <4 x i32> %y) {
+ %a = sub <4 x i32> %x, %y
+ ret <4 x i32> %a
+}
+
+; CHECK-LABEL: mul_v4i32
+; NO-SIMD128-NOT: i32x4
+; SIMD128: .param v128, v128{{$}}
+; SIMD128: .result v128{{$}}
+; SIMD128: i32x4.mul $push0=, $0, $1{{$}}
+; SIMD128: return $pop0{{$}}
+define <4 x i32> @mul_v4i32(<4 x i32> %x, <4 x i32> %y) {
+ %a = mul <4 x i32> %x, %y
+ ret <4 x i32> %a
+}
+
+; ==============================================================================
+; 4 x float
+; ==============================================================================
+; CHECK-LABEL: add_v4f32
+; NO-SIMD128-NOT: f32x4
+; SIMD128: .param v128, v128{{$}}
+; SIMD128: .result v128{{$}}
+; SIMD128: f32x4.add $push0=, $0, $1{{$}}
+; SIMD128: return $pop0{{$}}
+define <4 x float> @add_v4f32(<4 x float> %x, <4 x float> %y) {
+ %a = fadd <4 x float> %x, %y
+ ret <4 x float> %a
+}
+
+; CHECK-LABEL: sub_v4f32
+; NO-SIMD128-NOT: f32x4
+; SIMD128: .param v128, v128{{$}}
+; SIMD128: .result v128{{$}}
+; SIMD128: f32x4.sub $push0=, $0, $1{{$}}
+; SIMD128: return $pop0{{$}}
+define <4 x float> @sub_v4f32(<4 x float> %x, <4 x float> %y) {
+ %a = fsub <4 x float> %x, %y
+ ret <4 x float> %a
+}
+
+; CHECK-LABEL: mul_v4f32
+; NO-SIMD128-NOT: f32x4
+; SIMD128: .param v128, v128{{$}}
+; SIMD128: .result v128{{$}}
+; SIMD128: f32x4.mul $push0=, $0, $1{{$}}
+; SIMD128: return $pop0{{$}}
+define <4 x float> @mul_v4f32(<4 x float> %x, <4 x float> %y) {
+ %a = fmul <4 x float> %x, %y
+ ret <4 x float> %a
+}
+
diff --git a/test/CodeGen/WebAssembly/stack-alignment.ll b/test/CodeGen/WebAssembly/stack-alignment.ll
new file mode 100644
index 000000000000..3bb6617f8779
--- /dev/null
+++ b/test/CodeGen/WebAssembly/stack-alignment.ll
@@ -0,0 +1,137 @@
+; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+declare void @somefunc(i32*)
+
+; CHECK-LABEL: underalign:
+; CHECK: i32.load $push[[L1:.+]]=, __stack_pointer{{.+}}
+; CHECK-NEXT: i32.const $push[[L2:.+]]=, 16
+; CHECK-NEXT: i32.sub $push[[L10:.+]]=, $pop[[L1]], $pop[[L2]]
+; CHECK-NEXT: tee_local $push{{.+}}=, $[[SP:.+]]=, $pop[[L10]]
+
+; CHECK: i32.add $push[[underaligned:.+]]=, $[[SP]], $pop{{.+}}
+; CHECK-NEXT: call somefunc@FUNCTION, $pop[[underaligned]]
+
+; CHECK: i32.add $push[[L5:.+]]=, $[[SP]], $pop{{.+}}
+; CHECK-NEXT: i32.store __stack_pointer($pop{{.+}}), $pop[[L5]]
+define void @underalign() {
+entry:
+ %underaligned = alloca i32, align 8
+ call void @somefunc(i32* %underaligned)
+ ret void
+}
+
+; CHECK-LABEL: overalign:
+; CHECK: i32.load $push[[L10:.+]]=, __stack_pointer
+; CHECK-NEXT: tee_local $push[[L9:.+]]=, $[[BP:.+]]=, $pop[[L10]]
+; CHECK-NEXT: i32.const $push[[L2:.+]]=, 32
+; CHECK-NEXT: i32.sub $push[[L8:.+]]=, $pop[[L9]], $pop[[L2]]
+; CHECK-NEXT: i32.const $push[[L3:.+]]=, -32
+; CHECK-NEXT: i32.and $push[[L7:.+]]=, $pop[[L8]], $pop[[L3]]
+; CHECK-NEXT: tee_local $push{{.+}}=, $[[SP:.+]]=, $pop[[L7]]
+
+; CHECK: call somefunc@FUNCTION, $[[SP]]
+
+; CHECK: copy_local $push[[L5:.+]]=, $[[BP]]
+; CHECK-NEXT: i32.store __stack_pointer($pop{{.+}}), $pop[[L5]]
+define void @overalign() {
+entry:
+ %overaligned = alloca i32, align 32
+ call void @somefunc(i32* %overaligned)
+ ret void
+}
+
+; CHECK-LABEL: over_and_normal_align:
+; CHECK: i32.load $push[[L14:.+]]=, __stack_pointer
+; CHECK-NEXT: tee_local $push[[L13:.+]]=, $[[BP:.+]]=, $pop[[L14]]
+; CHECK: i32.sub $push[[L12:.+]]=, $pop[[L13]], $pop{{.+}}
+; CHECK: i32.and $push[[L11:.+]]=, $pop[[L12]], $pop{{.+}}
+; CHECK-NEXT: tee_local $push{{.+}}=, $[[SP]]=, $pop[[L11]]
+
+; CHECK: i32.add $push[[L6:.+]]=, $[[SP]], $pop{{.+}}
+; CHECK-NEXT: call somefunc@FUNCTION, $pop[[L6]]
+; CHECK: i32.add $push[[L8:.+]]=, $[[SP]], $pop{{.+}}
+; CHECK-NEXT: call somefunc@FUNCTION, $pop[[L8]]
+
+; CHECK: copy_local $push[[L9:.+]]=, $[[BP]]
+; CHECK-NEXT: i32.store __stack_pointer({{.+}}), $pop[[L9]]
+define void @over_and_normal_align() {
+entry:
+ %over = alloca i32, align 32
+ %normal = alloca i32
+ call void @somefunc(i32* %over)
+ call void @somefunc(i32* %normal)
+ ret void
+}
+
+; CHECK-LABEL: dynamic_overalign:
+; CHECK: i32.load $push[[L18:.+]]=, __stack_pointer
+; CHECK-NEXT: tee_local $push[[L17:.+]]=, $[[SP:.+]]=, $pop[[L18]]
+; CHECK-NEXT: copy_local $[[BP:.+]]=, $pop[[L17]]
+; CHECK: tee_local $push{{.+}}=, $[[SP_2:.+]]=, $pop{{.+}}
+
+; CHECK: call somefunc@FUNCTION, $[[SP_2]]
+
+; CHECK: i32.store __stack_pointer($pop{{.+}}), $[[BP]]
+define void @dynamic_overalign(i32 %num) {
+entry:
+ %dynamic = alloca i32, i32 %num, align 32
+ call void @somefunc(i32* %dynamic)
+ ret void
+}
+
+; CHECK-LABEL: overalign_and_dynamic:
+; CHECK: i32.load $push[[L21:.+]]=, __stack_pointer
+; CHECK-NEXT: tee_local $push[[L20:.+]]=, $[[BP:.+]]=, $pop[[L21]]
+; CHECK: i32.sub $push[[L19:.+]]=, $pop[[L20]], $pop{{.+}}
+; CHECK: i32.and $push[[L18:.+]]=, $pop[[L19]], $pop{{.+}}
+; CHECK: tee_local $push{{.+}}=, $[[FP:.+]]=, $pop[[L18]]
+; CHECK: i32.sub $push[[L16:.+]]=, $[[FP]], $pop{{.+}}
+; CHECK-NEXT: tee_local $push{{.+}}=, $[[SP:.+]]=, $pop[[L16]]
+
+; CHECK: copy_local $push[[over:.+]]=, $[[FP]]
+; CHECK-NEXT: call somefunc@FUNCTION, $pop[[over]]
+; CHECK-NEXT: call somefunc@FUNCTION, $[[SP]]
+
+; CHECK: copy_local $push[[L12:.+]]=, $[[BP]]
+; CHECK-NEXT: i32.store __stack_pointer($pop{{.+}}), $pop[[L12]]
+define void @overalign_and_dynamic(i32 %num) {
+entry:
+ %over = alloca i32, align 32
+ %dynamic = alloca i32, i32 %num
+ call void @somefunc(i32* %over)
+ call void @somefunc(i32* %dynamic)
+ ret void
+}
+
+; CHECK-LABEL: overalign_static_and_dynamic:
+; CHECK: i32.load $push[[L26:.+]]=, __stack_pointer
+; CHECK-NEXT: tee_local $push[[L25:.+]]=, $[[BP:.+]]=, $pop[[L26]]
+; CHECK: i32.sub $push[[L24:.+]]=, $pop[[L25]], $pop{{.+}}
+; CHECK: i32.and $push[[L23:.+]]=, $pop[[L24]], $pop{{.+}}
+; CHECK: tee_local $push{{.+}}=, $[[FP:.+]]=, $pop[[L23]]
+; CHECK: i32.sub $push[[L21:.+]]=, $[[FP]], $pop{{.+}}
+; CHECK-NEXT: tee_local $push{{.+}}=, $[[SP:.+]]=, $pop[[L21]]
+
+; CHECK: copy_local $push[[L19:.+]]=, $[[FP]]
+; CHECK: tee_local $push[[L18:.+]]=, $[[FP_2:.+]]=, $pop[[L19]]
+; CHECK: i32.add $push[[over:.+]]=, $pop[[L18]], $pop{{.+}}
+; CHECK-NEXT: call somefunc@FUNCTION, $pop[[over]]
+; CHECK: call somefunc@FUNCTION, $[[SP]]
+; CHECK: i32.add $push[[static:.+]]=, $[[FP_2]], $pop{{.+}}
+; CHECK-NEXT: call somefunc@FUNCTION, $pop[[static]]
+
+; CHECK: copy_local $push[[L16:.+]]=, $[[BP]]
+; CHECK-NEXT: i32.store __stack_pointer({{.+}}), $pop[[L16]]
+define void @overalign_static_and_dynamic(i32 %num) {
+entry:
+ %over = alloca i32, align 32
+ %dynamic = alloca i32, i32 %num
+ %static = alloca i32
+ call void @somefunc(i32* %over)
+ call void @somefunc(i32* %dynamic)
+ call void @somefunc(i32* %static)
+ ret void
+}
diff --git a/test/CodeGen/WebAssembly/store-results.ll b/test/CodeGen/WebAssembly/store-results.ll
deleted file mode 100644
index 121ee910f853..000000000000
--- a/test/CodeGen/WebAssembly/store-results.ll
+++ /dev/null
@@ -1,72 +0,0 @@
-; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
-
-; Test that the wasm-store-results pass makes users of stored values use the
-; result of store expressions to reduce get_local/set_local traffic.
-
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
-
-; CHECK-LABEL: single_block:
-; CHECK-NOT: local
-; CHECK: i32.const $push{{[0-9]+}}=, 0{{$}}
-; CHECK: i32.store $push[[STORE:[0-9]+]]=, 0($0), $pop{{[0-9]+}}{{$}}
-; CHECK: return $pop[[STORE]]{{$}}
-define i32 @single_block(i32* %p) {
-entry:
- store i32 0, i32* %p
- ret i32 0
-}
-
-; Test interesting corner cases for wasm-store-results, in which the operand of
-; a store ends up getting used by a phi, which needs special handling in the
-; dominance test, since phis use their operands on their incoming edges.
-
-%class.Vec3 = type { float, float, float }
-
-@pos = global %class.Vec3 zeroinitializer, align 4
-
-; CHECK-LABEL: foo:
-; CHECK: i32.store $drop=, pos($pop{{[0-9]+}}), $pop{{[0-9]+}}{{$}}
-define void @foo() {
-for.body.i:
- br label %for.body5.i
-
-for.body5.i:
- %i.0168.i = phi i32 [ 0, %for.body.i ], [ %inc.i, %for.body5.i ]
- %conv6.i = sitofp i32 %i.0168.i to float
- store volatile float 0.0, float* getelementptr inbounds (%class.Vec3, %class.Vec3* @pos, i32 0, i32 0)
- %inc.i = add nuw nsw i32 %i.0168.i, 1
- %exitcond.i = icmp eq i32 %inc.i, 256
- br i1 %exitcond.i, label %for.cond.cleanup4.i, label %for.body5.i
-
-for.cond.cleanup4.i:
- ret void
-}
-
-; CHECK-LABEL: bar:
-; CHECK: i32.store $drop=, pos($pop{{[0-9]+}}), $pop{{[0-9]+}}{{$}}
-define void @bar() {
-for.body.i:
- br label %for.body5.i
-
-for.body5.i:
- %i.0168.i = phi float [ 0.0, %for.body.i ], [ %inc.i, %for.body5.i ]
- store volatile float 0.0, float* getelementptr inbounds (%class.Vec3, %class.Vec3* @pos, i32 0, i32 0)
- %inc.i = fadd float %i.0168.i, 1.0
- %exitcond.i = fcmp oeq float %inc.i, 256.0
- br i1 %exitcond.i, label %for.cond.cleanup4.i, label %for.body5.i
-
-for.cond.cleanup4.i:
- ret void
-}
-
-; CHECK-LABEL: fi_ret:
-; CHECK: i32.store $push0=,
-; CHECK: return $pop0{{$}}
-define hidden i8* @fi_ret(i8** %addr) {
-entry:
- %buf = alloca [27 x i8], align 16
- %0 = getelementptr inbounds [27 x i8], [27 x i8]* %buf, i32 0, i32 0
- store i8* %0, i8** %addr
- ret i8* %0
-}
diff --git a/test/CodeGen/WebAssembly/store-trunc.ll b/test/CodeGen/WebAssembly/store-trunc.ll
index 75d87ef45b4d..436933880481 100644
--- a/test/CodeGen/WebAssembly/store-trunc.ll
+++ b/test/CodeGen/WebAssembly/store-trunc.ll
@@ -6,7 +6,7 @@ target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-unknown"
; CHECK-LABEL: trunc_i8_i32:
-; CHECK: i32.store8 $drop=, 0($0), $1{{$}}
+; CHECK: i32.store8 0($0), $1{{$}}
define void @trunc_i8_i32(i8 *%p, i32 %v) {
%t = trunc i32 %v to i8
store i8 %t, i8* %p
@@ -14,7 +14,7 @@ define void @trunc_i8_i32(i8 *%p, i32 %v) {
}
; CHECK-LABEL: trunc_i16_i32:
-; CHECK: i32.store16 $drop=, 0($0), $1{{$}}
+; CHECK: i32.store16 0($0), $1{{$}}
define void @trunc_i16_i32(i16 *%p, i32 %v) {
%t = trunc i32 %v to i16
store i16 %t, i16* %p
@@ -22,7 +22,7 @@ define void @trunc_i16_i32(i16 *%p, i32 %v) {
}
; CHECK-LABEL: trunc_i8_i64:
-; CHECK: i64.store8 $drop=, 0($0), $1{{$}}
+; CHECK: i64.store8 0($0), $1{{$}}
define void @trunc_i8_i64(i8 *%p, i64 %v) {
%t = trunc i64 %v to i8
store i8 %t, i8* %p
@@ -30,7 +30,7 @@ define void @trunc_i8_i64(i8 *%p, i64 %v) {
}
; CHECK-LABEL: trunc_i16_i64:
-; CHECK: i64.store16 $drop=, 0($0), $1{{$}}
+; CHECK: i64.store16 0($0), $1{{$}}
define void @trunc_i16_i64(i16 *%p, i64 %v) {
%t = trunc i64 %v to i16
store i16 %t, i16* %p
@@ -38,7 +38,7 @@ define void @trunc_i16_i64(i16 *%p, i64 %v) {
}
; CHECK-LABEL: trunc_i32_i64:
-; CHECK: i64.store32 $drop=, 0($0), $1{{$}}
+; CHECK: i64.store32 0($0), $1{{$}}
define void @trunc_i32_i64(i32 *%p, i64 %v) {
%t = trunc i64 %v to i32
store i32 %t, i32* %p
diff --git a/test/CodeGen/WebAssembly/store.ll b/test/CodeGen/WebAssembly/store.ll
index 3ff84889a712..3852b6e420ca 100644
--- a/test/CodeGen/WebAssembly/store.ll
+++ b/test/CodeGen/WebAssembly/store.ll
@@ -8,7 +8,7 @@ target triple = "wasm32-unknown-unknown"
; CHECK-LABEL: sti32:
; CHECK-NEXT: .param i32, i32{{$}}
-; CHECK-NEXT: i32.store $drop=, 0($0), $1{{$}}
+; CHECK-NEXT: i32.store 0($0), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti32(i32 *%p, i32 %v) {
store i32 %v, i32* %p
@@ -17,7 +17,7 @@ define void @sti32(i32 *%p, i32 %v) {
; CHECK-LABEL: sti64:
; CHECK-NEXT: .param i32, i64{{$}}
-; CHECK-NEXT: i64.store $drop=, 0($0), $1{{$}}
+; CHECK-NEXT: i64.store 0($0), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @sti64(i64 *%p, i64 %v) {
store i64 %v, i64* %p
@@ -26,7 +26,7 @@ define void @sti64(i64 *%p, i64 %v) {
; CHECK-LABEL: stf32:
; CHECK-NEXT: .param i32, f32{{$}}
-; CHECK-NEXT: f32.store $drop=, 0($0), $1{{$}}
+; CHECK-NEXT: f32.store 0($0), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @stf32(float *%p, float %v) {
store float %v, float* %p
@@ -35,7 +35,7 @@ define void @stf32(float *%p, float %v) {
; CHECK-LABEL: stf64:
; CHECK-NEXT: .param i32, f64{{$}}
-; CHECK-NEXT: f64.store $drop=, 0($0), $1{{$}}
+; CHECK-NEXT: f64.store 0($0), $1{{$}}
; CHECK-NEXT: return{{$}}
define void @stf64(double *%p, double %v) {
store double %v, double* %p
diff --git a/test/CodeGen/WebAssembly/switch.ll b/test/CodeGen/WebAssembly/switch.ll
index 8355bc8562d6..c6354baa57a6 100644
--- a/test/CodeGen/WebAssembly/switch.ll
+++ b/test/CodeGen/WebAssembly/switch.ll
@@ -14,13 +14,13 @@ declare void @foo4()
declare void @foo5()
; CHECK-LABEL: bar32:
-; CHECK: block{{$}}
-; CHECK: block{{$}}
-; CHECK: block{{$}}
-; CHECK: block{{$}}
-; CHECK: block{{$}}
-; CHECK: block{{$}}
-; CHECK: block{{$}}
+; CHECK: block {{$}}
+; CHECK: block {{$}}
+; CHECK: block {{$}}
+; CHECK: block {{$}}
+; CHECK: block {{$}}
+; CHECK: block {{$}}
+; CHECK: block {{$}}
; CHECK: br_table {{[^,]+}}, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 4, 5, 0{{$}}
; CHECK: .LBB0_2:
; CHECK: call foo0@FUNCTION{{$}}
@@ -94,13 +94,13 @@ sw.epilog: ; preds = %entry, %sw.bb.5, %s
}
; CHECK-LABEL: bar64:
-; CHECK: block{{$}}
-; CHECK: block{{$}}
-; CHECK: block{{$}}
-; CHECK: block{{$}}
-; CHECK: block{{$}}
-; CHECK: block{{$}}
-; CHECK: block{{$}}
+; CHECK: block {{$}}
+; CHECK: block {{$}}
+; CHECK: block {{$}}
+; CHECK: block {{$}}
+; CHECK: block {{$}}
+; CHECK: block {{$}}
+; CHECK: block {{$}}
; CHECK: br_table {{[^,]+}}, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 4, 5, 0{{$}}
; CHECK: .LBB1_2:
; CHECK: call foo0@FUNCTION{{$}}
diff --git a/test/CodeGen/WebAssembly/userstack.ll b/test/CodeGen/WebAssembly/userstack.ll
index 66ac2cce7079..a163f879f6df 100644
--- a/test/CodeGen/WebAssembly/userstack.ll
+++ b/test/CodeGen/WebAssembly/userstack.ll
@@ -14,17 +14,17 @@ define void @alloca32() noredzone {
; CHECK: i32.const $push[[L1:.+]]=, 0{{$}}
; CHECK-NEXT: i32.load $push[[L2:.+]]=, __stack_pointer($pop[[L1]])
; CHECK-NEXT: i32.const $push[[L3:.+]]=, 16
- ; CHECK-NEXT: i32.sub $push[[L8:.+]]=, $pop[[L2]], $pop[[L3]]
- ; CHECK-NEXT: i32.store $push[[L10:.+]]=, __stack_pointer($pop[[L4]]), $pop[[L8]]{{$}}
- ; CHECK-NEXT: tee_local $push[[L9:.+]]=, $[[SP:.+]]=, $pop[[L10]]{{$}}
+ ; CHECK-NEXT: i32.sub $push[[L9:.+]]=, $pop[[L2]], $pop[[L3]]
+ ; CHECK-NEXT: tee_local $push[[L8:.+]]=, $[[SP:.+]]=, $pop[[L9]]{{$}}
+ ; CHECK-NEXT: i32.store __stack_pointer($pop[[L4]]), $pop[[L8]]{{$}}
%retval = alloca i32
; CHECK: i32.const $push[[L0:.+]]=, 0
- ; CHECK: i32.store {{.*}}=, 12($pop[[L9]]), $pop[[L0]]
+ ; CHECK: i32.store 12($[[SP]]), $pop[[L0]]
store i32 0, i32* %retval
; CHECK: i32.const $push[[L6:.+]]=, 0
; CHECK-NEXT: i32.const $push[[L5:.+]]=, 16
; CHECK-NEXT: i32.add $push[[L7:.+]]=, $[[SP]], $pop[[L5]]
- ; CHECK-NEXT: i32.store $drop=, __stack_pointer($pop[[L6]]), $pop[[L7]]
+ ; CHECK-NEXT: i32.store __stack_pointer($pop[[L6]]), $pop[[L7]]
ret void
}
@@ -39,10 +39,10 @@ define void @alloca3264() {
%r1 = alloca i32
%r2 = alloca double
; CHECK-NEXT: i32.const $push[[L0:.+]]=, 0
- ; CHECK-NEXT: i32.store $drop=, 12($pop[[L5]]), $pop[[L0]]
+ ; CHECK-NEXT: i32.store 12($pop[[L5]]), $pop[[L0]]
store i32 0, i32* %r1
; CHECK-NEXT: i64.const $push[[L1:.+]]=, 0
- ; CHECK-NEXT: i64.store $drop=, 0($[[SP]]), $pop[[L1]]
+ ; CHECK-NEXT: i64.store 0($[[SP]]), $pop[[L1]]
store double 0.0, double* %r2
; CHECK-NEXT: return
ret void
@@ -51,43 +51,45 @@ define void @alloca3264() {
; CHECK-LABEL: allocarray:
; CHECK: .local i32{{$}}
define void @allocarray() {
- ; CHECK: i32.const $push[[L7:.+]]=, 0{{$}}
- ; CHECK: i32.const $push[[L4:.+]]=, 0{{$}}
- ; CHECK-NEXT: i32.load $push[[L5:.+]]=, __stack_pointer($pop[[L4]])
- ; CHECK-NEXT: i32.const $push[[L6:.+]]=, 144{{$}}
- ; CHECK-NEXT: i32.sub $push[[L11:.+]]=, $pop[[L5]], $pop[[L6]]
- ; CHECK-NEXT: i32.store ${{.+}}=, __stack_pointer($pop[[L7]]), $pop[[L11]]
+ ; CHECK: i32.const $push[[L6:.+]]=, 0{{$}}
+ ; CHECK: i32.const $push[[L3:.+]]=, 0{{$}}
+ ; CHECK-NEXT: i32.load $push[[L4:.+]]=, __stack_pointer($pop[[L3]])
+ ; CHECK-NEXT: i32.const $push[[L5:.+]]=, 144{{$}}
+ ; CHECK-NEXT: i32.sub $push[[L12:.+]]=, $pop[[L4]], $pop[[L5]]
+ ; CHECK-NEXT: tee_local $push[[L11:.+]]=, $0=, $pop[[L12]]
+ ; CHECK-NEXT: i32.store __stack_pointer($pop[[L6]]), $pop[[L11]]
%r = alloca [33 x i32]
; CHECK: i32.const $push{{.+}}=, 24
; CHECK-NEXT: i32.add $push[[L3:.+]]=, $[[SP]], $pop{{.+}}
; CHECK-NEXT: i32.const $push[[L1:.+]]=, 1{{$}}
- ; CHECK-NEXT: i32.store $push[[L0:.+]]=, 0($pop[[L3]]), $pop[[L1]]{{$}}
- ; CHECK-NEXT: i32.store $drop=, 12(${{.+}}), $pop[[L0]]{{$}}
+ ; CHECK-NEXT: i32.store 0($pop[[L3]]), $pop[[L1]]{{$}}
+ ; CHECK-NEXT: i32.const $push[[L10:.+]]=, 1{{$}}
+ ; CHECK-NEXT: i32.store 12(${{.+}}), $pop[[L10]]{{$}}
%p = getelementptr [33 x i32], [33 x i32]* %r, i32 0, i32 0
store i32 1, i32* %p
%p2 = getelementptr [33 x i32], [33 x i32]* %r, i32 0, i32 3
store i32 1, i32* %p2
- ; CHECK: i32.const $push[[L10:.+]]=, 0{{$}}
- ; CHECK-NEXT: i32.const $push[[L8:.+]]=, 144
- ; CHECK-NEXT: i32.add $push[[L19:.+]]=, $[[SP]], $pop[[L8]]
- ; CHECK-NEXT: i32.store $drop=, __stack_pointer($pop[[L10]]), $pop[[L9]]
+ ; CHECK: i32.const $push[[L9:.+]]=, 0{{$}}
+ ; CHECK-NEXT: i32.const $push[[L7:.+]]=, 144
+ ; CHECK-NEXT: i32.add $push[[L8:.+]]=, $[[SP]], $pop[[L7]]
+ ; CHECK-NEXT: i32.store __stack_pointer($pop[[L9]]), $pop[[L8]]
ret void
}
; CHECK-LABEL: non_mem_use
define void @non_mem_use(i8** %addr) {
- ; CHECK: i32.const $push[[L1:.+]]=, 48
- ; CHECK-NEXT: i32.sub $push[[L11:.+]]=, {{.+}}, $pop[[L1]]
- ; CHECK-NEXT: i32.store $[[SP:.+]]=, {{.+}}, $pop[[L11]]
+ ; CHECK: i32.const $push[[L2:.+]]=, 48
+ ; CHECK-NEXT: i32.sub $push[[L12:.+]]=, {{.+}}, $pop[[L2]]
+ ; CHECK-NEXT: tee_local $push[[L11:.+]]=, $[[SP:.+]]=, $pop[[L12]]
+ ; CHECK-NEXT: i32.store {{.+}}, $pop[[L11]]
%buf = alloca [27 x i8], align 16
%r = alloca i64
%r2 = alloca i64
; %r is at SP+8
- ; CHECK: tee_local $push[[L12:.+]]=, $[[SP:.+]]=, $pop{{.+}}
; CHECK: i32.const $push[[OFF:.+]]=, 8
- ; CHECK-NEXT: i32.add $push[[ARG1:.+]]=, $pop[[L12]], $pop[[OFF]]
+ ; CHECK-NEXT: i32.add $push[[ARG1:.+]]=, $[[SP]], $pop[[OFF]]
; CHECK-NEXT: call ext_func@FUNCTION, $pop[[ARG1]]
call void @ext_func(i64* %r)
; %r2 is at SP+0, no add needed
@@ -97,7 +99,7 @@ define void @non_mem_use(i8** %addr) {
; %buf is at SP+16
; CHECK: i32.const $push[[OFF:.+]]=, 16
; CHECK-NEXT: i32.add $push[[VAL:.+]]=, $[[SP]], $pop[[OFF]]
- ; CHECK-NEXT: i32.store {{.*}}=, 0($0), $pop[[VAL]]
+ ; CHECK-NEXT: i32.store 0($0), $pop[[VAL]]
%gep = getelementptr inbounds [27 x i8], [27 x i8]* %buf, i32 0, i32 0
store i8* %gep, i8** %addr
ret void
@@ -106,19 +108,20 @@ define void @non_mem_use(i8** %addr) {
; CHECK-LABEL: allocarray_inbounds:
; CHECK: .local i32{{$}}
define void @allocarray_inbounds() {
- ; CHECK: i32.const $push[[L6:.+]]=, 0{{$}}
- ; CHECK: i32.const $push[[L3:.+]]=, 0{{$}}
- ; CHECK-NEXT: i32.load $push[[L4:.+]]=, __stack_pointer($pop[[L3]])
- ; CHECK-NEXT: i32.const $push[[L5:.+]]=, 32{{$}}
- ; CHECK-NEXT: i32.sub $push[[L10:.+]]=, $pop[[L4]], $pop[[L5]]
- ; CHECK-NEXT: i32.store ${{.+}}=, __stack_pointer($pop[[L6]]), $pop[[L10]]{{$}}
+ ; CHECK: i32.const $push[[L5:.+]]=, 0{{$}}
+ ; CHECK: i32.const $push[[L2:.+]]=, 0{{$}}
+ ; CHECK-NEXT: i32.load $push[[L3:.+]]=, __stack_pointer($pop[[L2]])
+ ; CHECK-NEXT: i32.const $push[[L4:.+]]=, 32{{$}}
+ ; CHECK-NEXT: i32.sub $push[[L11:.+]]=, $pop[[L3]], $pop[[L4]]
+ ; CHECK-NEXT: tee_local $push[[L10:.+]]=, $[[SP:.+]]=, $pop[[L11]]
+ ; CHECK-NEXT: i32.store __stack_pointer($pop[[L5]]), $pop[[L10]]{{$}}
%r = alloca [5 x i32]
; CHECK: i32.const $push[[L3:.+]]=, 1
- ; CHECK-DAG: i32.store $push{{.*}}=, 24(${{.+}}), $pop[[L3]]
+ ; CHECK-DAG: i32.store 24(${{.+}}), $pop[[L3]]
%p = getelementptr inbounds [5 x i32], [5 x i32]* %r, i32 0, i32 0
store i32 1, i32* %p
; This store should have both the GEP and the FI folded into it.
- ; CHECK-DAG: i32.store {{.*}}=, 12(${{.+}}), $pop
+ ; CHECK-DAG: i32.store 12(${{.+}}), $pop
%p2 = getelementptr inbounds [5 x i32], [5 x i32]* %r, i32 0, i32 3
store i32 1, i32* %p2
call void @ext_func(i64* null);
@@ -126,7 +129,7 @@ define void @allocarray_inbounds() {
; CHECK: i32.const $push[[L6:.+]]=, 0{{$}}
; CHECK-NEXT: i32.const $push[[L5:.+]]=, 32{{$}}
; CHECK-NEXT: i32.add $push[[L7:.+]]=, ${{.+}}, $pop[[L5]]
- ; CHECK-NEXT: i32.store $drop=, __stack_pointer($pop[[L6]]), $pop[[L7]]
+ ; CHECK-NEXT: i32.store __stack_pointer($pop[[L6]]), $pop[[L7]]
ret void
}
@@ -139,13 +142,13 @@ define void @dynamic_alloca(i32 %alloc) {
; Target independent codegen bumps the stack pointer.
; CHECK: i32.sub
; Check that SP is written back to memory after decrement
- ; CHECK: i32.store $drop=, __stack_pointer($pop{{.+}}),
+ ; CHECK: i32.store __stack_pointer($pop{{.+}}),
%r = alloca i32, i32 %alloc
; Target-independent codegen also calculates the store addr
; CHECK: call ext_func_i32@FUNCTION
call void @ext_func_i32(i32* %r)
; CHECK: i32.const $push[[L3:.+]]=, 0{{$}}
- ; CHECK: i32.store $drop=, __stack_pointer($pop[[L3]]), $pop{{.+}}
+ ; CHECK: i32.store __stack_pointer($pop[[L3]]), $pop{{.+}}
ret void
}
@@ -161,7 +164,7 @@ define void @dynamic_alloca_redzone(i32 %alloc) {
; CHECK-NEXT: tee_local $push[[L8:.+]]=, $0=, $pop
; CHECK-NEXT: copy_local $drop=, $pop[[L8]]{{$}}
; CHECK-NEXT: i32.const $push[[L6:.+]]=, 0{{$}}
- ; CHECK-NEXT: i32.store $drop=, 0($0), $pop[[L6]]{{$}}
+ ; CHECK-NEXT: i32.store 0($0), $pop[[L6]]{{$}}
store i32 0, i32* %r
; CHECK-NEXT: return
ret void
@@ -170,22 +173,98 @@ define void @dynamic_alloca_redzone(i32 %alloc) {
; CHECK-LABEL: dynamic_static_alloca:
define void @dynamic_static_alloca(i32 %alloc) noredzone {
; Decrement SP in the prolog by the static amount and writeback to memory.
- ; CHECK: i32.const $push[[L7:.+]]=, 0{{$}}
- ; CHECK: i32.const $push[[L8:.+]]=, 0{{$}}
- ; CHECK: i32.const $push[[L9:.+]]=, 0{{$}}
- ; CHECK-NEXT: i32.load $push[[L10:.+]]=, __stack_pointer($pop[[L9]])
- ; CHECK-NEXT: i32.const $push[[L11:.+]]=, 16
- ; CHECK-NEXT: i32.sub $push[[L20:.+]]=, $pop[[L10]], $pop[[L11]]
- ; CHECK-NEXT: tee_local $push[[L19:.+]]=, $[[FP:.+]]=, $pop[[L20]]
- ; CHECK: i32.store $push[[L0:.+]]=, __stack_pointer($pop{{.+}}), $pop{{.+}}
+ ; CHECK: i32.const $push[[L13:.+]]=, 0{{$}}
+ ; CHECK: i32.const $push[[L10:.+]]=, 0{{$}}
+ ; CHECK-NEXT: i32.load $push[[L11:.+]]=, __stack_pointer($pop[[L10]])
+ ; CHECK-NEXT: i32.const $push[[L12:.+]]=, 16
+ ; CHECK-NEXT: i32.sub $push[[L23:.+]]=, $pop[[L11]], $pop[[L12]]
+ ; CHECK-NEXT: tee_local $push[[L22:.+]]=, $[[SP:.+]]=, $pop[[L23]]
+ ; CHECK-NEXT: i32.store __stack_pointer($pop{{.+}}), $pop[[L22]]
+
+ ; Alloc and write to a static alloca
+ ; CHECK: copy_local $push[[L21:.+]]=, $[[SP]]
+ ; CHECK-NEXT: tee_local $push[[pushedFP:.+]]=, $[[FP:.+]]=, $pop[[L21]]
+ ; CHECK-NEXT: i32.const $push[[L0:.+]]=, 101
+ ; CHECK-NEXT: i32.store [[static_offset:.+]]($pop[[pushedFP]]), $pop[[L0]]
+ %static = alloca i32
+ store volatile i32 101, i32* %static
+
+ ; Decrement SP in the body by the dynamic amount.
+ ; CHECK: i32.sub
+ ; CHECK: tee_local $push{{.+}}=, $[[dynamic_local:.+]]=, $pop{{.+}}
+ ; CHECK: i32.store __stack_pointer
+ %dynamic = alloca i32, i32 %alloc
+
+ ; Ensure we don't modify the frame pointer after assigning it.
+ ; CHECK-NOT: $[[FP]]=
+
+ ; Ensure the static address doesn't change after modifying the stack pointer.
+ ; CHECK: i32.const $push[[L7:.+]]=, 102
+ ; CHECK-NEXT: i32.store [[static_offset]]($[[FP]]), $pop[[L7]]
+ ; CHECK-NEXT: i32.const $push[[L8:.+]]=, 103
+ ; CHECK-NEXT: i32.store 0($[[dynamic_local]]), $pop[[L8]]
+ store volatile i32 102, i32* %static
+ store volatile i32 103, i32* %dynamic
+
; Decrement SP in the body by the dynamic amount.
; CHECK: i32.sub
+ ; CHECK: tee_local $push{{.+}}=, $[[dynamic2_local:.+]]=, $pop{{.+}}
+ %dynamic.2 = alloca i32, i32 %alloc
+
+ ; CHECK-NOT: $[[FP]]=
+
+ ; Ensure neither the static nor dynamic address changes after the second
+ ; modification of the stack pointer.
+ ; CHECK: i32.const $push[[L9:.+]]=, 104
+ ; CHECK-NEXT: i32.store [[static_offset]]($[[FP]]), $pop[[L9]]
+ ; CHECK-NEXT: i32.const $push[[L10:.+]]=, 105
+ ; CHECK-NEXT: i32.store 0($[[dynamic_local]]), $pop[[L10]]
+ ; CHECK-NEXT: i32.const $push[[L11:.+]]=, 106
+ ; CHECK-NEXT: i32.store 0($[[dynamic2_local]]), $pop[[L11]]
+ store volatile i32 104, i32* %static
+ store volatile i32 105, i32* %dynamic
+ store volatile i32 106, i32* %dynamic.2
+
; Writeback to memory.
- ; CHECK: i32.store $drop=, __stack_pointer($pop{{.+}}), $pop{{.+}}
- %r1 = alloca i32
- %r = alloca i32, i32 %alloc
- store i32 0, i32* %r
- ; CHEC: i32.store $drop=, 0($pop{{.+}}), $pop{{.+}}
+ ; CHECK: i32.const $push[[L17:.+]]=, 16
+ ; CHECK-NEXT: i32.add $push[[L18:.+]]=, $[[FP]], $pop[[L17]]
+ ; CHECK-NEXT: i32.store __stack_pointer($pop{{.+}}), $pop[[L18]]
+ ret void
+}
+
+declare i8* @llvm.stacksave()
+declare void @llvm.stackrestore(i8*)
+
+; CHECK-LABEL: llvm_stack_builtins:
+define void @llvm_stack_builtins(i32 %alloc) noredzone {
+ ; CHECK: i32.load $push[[L11:.+]]=, __stack_pointer($pop{{.+}})
+ ; CHECK-NEXT: tee_local $push[[L10:.+]]=, ${{.+}}=, $pop[[L11]]
+ ; CHECK-NEXT: copy_local $[[STACK:.+]]=, $pop[[L10]]
+ %stack = call i8* @llvm.stacksave()
+
+ ; Ensure we don't reassign the stacksave local
+ ; CHECK-NOT: $[[STACK]]=
+ %dynamic = alloca i32, i32 %alloc
+
+ ; CHECK: i32.store __stack_pointer($pop{{.+}}), $[[STACK]]
+ call void @llvm.stackrestore(i8* %stack)
+
+ ret void
+}
+
+; Not actually using the alloca'd variables exposed an issue with register
+; stackification, where copying the stack pointer into the frame pointer was
+; moved after the stack pointer was updated for the dynamic alloca.
+; CHECK-LABEL: dynamic_alloca_nouse:
+define void @dynamic_alloca_nouse(i32 %alloc) noredzone {
+ ; CHECK: i32.load $push[[L11:.+]]=, __stack_pointer($pop{{.+}})
+ ; CHECK-NEXT: tee_local $push[[L10:.+]]=, ${{.+}}=, $pop[[L11]]
+ ; CHECK-NEXT: copy_local $[[FP:.+]]=, $pop[[L10]]
+ %dynamic = alloca i32, i32 %alloc
+
+ ; CHECK-NOT: $[[FP]]=,
+
+ ; CHECK: i32.store __stack_pointer($pop{{.+}}), $[[FP]]
ret void
}
@@ -204,7 +283,7 @@ entry:
body:
%a = phi i32* [%addr, %entry], [%b, %body]
store i32 1, i32* %a
- ; CHECK: i32.store {{.*}}, 0([[COPY]]),
+ ; CHECK: i32.store 0([[COPY]]),
br i1 %cond, label %body, label %exit
exit:
ret void
@@ -221,7 +300,7 @@ declare i8* @llvm.frameaddress(i32)
; CHECK-NEXT: tee_local $push[[L2:.+]]=, $[[FP:.+]]=, $pop[[L4]]{{$}}
; CHECK-NEXT: call use_i8_star@FUNCTION, $pop[[L2]]
; CHECK-NEXT: i32.const $push[[L1:.+]]=, 0{{$}}
-; CHECK-NEXT: i32.store $drop=, __stack_pointer($pop[[L1]]), $[[FP]]
+; CHECK-NEXT: i32.store __stack_pointer($pop[[L1]]), $[[FP]]
define void @frameaddress_0() {
%t = call i8* @llvm.frameaddress(i32 0)
call void @use_i8_star(i8* %t)
diff --git a/test/CodeGen/WebAssembly/varargs.ll b/test/CodeGen/WebAssembly/varargs.ll
index 483d452624a8..c77ed10c2584 100644
--- a/test/CodeGen/WebAssembly/varargs.ll
+++ b/test/CodeGen/WebAssembly/varargs.ll
@@ -15,7 +15,7 @@ define void @start(i8** %ap, ...) {
entry:
%0 = bitcast i8** %ap to i8*
; Store the second argument (the hidden vararg buffer pointer) into ap
-; CHECK: i32.store $drop=, 0($0), $1
+; CHECK: i32.store 0($0), $1
call void @llvm.va_start(i8* %0)
ret void
}
@@ -37,7 +37,7 @@ entry:
; CHECK-LABEL: copy:
; CHECK-NEXT: .param i32, i32{{$}}
; CHECK-NEXT: i32.load $push0=, 0($1){{$}}
-; CHECK-NEXT: i32.store $drop=, 0($0), $pop0{{$}}
+; CHECK-NEXT: i32.store 0($0), $pop0{{$}}
; CHECK-NEXT: return{{$}}
define void @copy(i8** %ap, i8** %bp) {
entry:
@@ -57,7 +57,7 @@ entry:
; CHECK-NEXT: tee_local $push[[NUM1:[0-9]+]]=, $1=, $pop[[NUM0]]{{$}}
; CHECK-NEXT: i32.const $push[[NUM2:[0-9]+]]=, 4{{$}}
; CHECK-NEXT: i32.add $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
-; CHECK-NEXT: i32.store $drop=, 0($0), $pop[[NUM3]]{{$}}
+; CHECK-NEXT: i32.store 0($0), $pop[[NUM3]]{{$}}
; CHECK-NEXT: i32.load $push[[NUM4:[0-9]+]]=, 0($1){{$}}
; CHECK-NEXT: return $pop[[NUM4]]{{$}}
define i8 @arg_i8(i8** %ap) {
@@ -80,7 +80,7 @@ entry:
; CHECK-NEXT: tee_local $push[[NUM5:[0-9]+]]=, $1=, $pop[[NUM4]]{{$}}
; CHECK-NEXT: i32.const $push[[NUM6:[0-9]+]]=, 4{{$}}
; CHECK-NEXT: i32.add $push[[NUM7:[0-9]+]]=, $pop[[NUM5]], $pop[[NUM6]]{{$}}
-; CHECK-NEXT: i32.store $drop=, 0($0), $pop[[NUM7]]{{$}}
+; CHECK-NEXT: i32.store 0($0), $pop[[NUM7]]{{$}}
; CHECK-NEXT: i32.load $push[[NUM8:[0-9]+]]=, 0($1){{$}}
; CHECK-NEXT: return $pop[[NUM8]]{{$}}
define i32 @arg_i32(i8** %ap) {
@@ -141,7 +141,7 @@ bb0:
bb1:
%0 = bitcast i8** %ap to i8*
; Store the second argument (the hidden vararg buffer pointer) into ap
-; CHECK: i32.store $drop=, 0($1), $2
+; CHECK: i32.store 0($1), $2
call void @llvm.va_start(i8* %0)
ret void
}