1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 03:02:36 +01:00

[WebAssembly] Disable the store-results optimization.

The WebAssemly spec removing the return value from store instructions, so
remove the associated optimization from LLVM.

This patch leaves the store instruction operands in place for now, so stores
now always write to "$drop"; these will be removed in a seperate patch.

llvm-svn: 279100
This commit is contained in:
Dan Gohman 2016-08-18 17:51:27 +00:00
parent 6e2f9dbe22
commit 1386262329
7 changed files with 70 additions and 154 deletions

View File

@ -139,15 +139,6 @@ static bool ReplaceDominatedUses(MachineBasicBlock &MBB, MachineInstr &MI,
return Changed;
}
static bool optimizeStore(MachineBasicBlock &MBB, MachineInstr &MI,
const MachineRegisterInfo &MRI,
MachineDominatorTree &MDT,
LiveIntervals &LIS) {
unsigned ToReg = MI.getOperand(0).getReg();
unsigned FromReg = MI.getOperand(WebAssembly::StoreValueOperandNo).getReg();
return ReplaceDominatedUses(MBB, MI, FromReg, ToReg, MRI, MDT, LIS);
}
static bool optimizeCall(MachineBasicBlock &MBB, MachineInstr &MI,
const MachineRegisterInfo &MRI,
MachineDominatorTree &MDT,
@ -202,17 +193,6 @@ bool WebAssemblyStoreResults::runOnMachineFunction(MachineFunction &MF) {
switch (MI.getOpcode()) {
default:
break;
case WebAssembly::STORE8_I32:
case WebAssembly::STORE16_I32:
case WebAssembly::STORE8_I64:
case WebAssembly::STORE16_I64:
case WebAssembly::STORE32_I64:
case WebAssembly::STORE_F32:
case WebAssembly::STORE_F64:
case WebAssembly::STORE_I32:
case WebAssembly::STORE_I64:
Changed |= optimizeStore(MBB, MI, MRI, MDT, LIS);
break;
case WebAssembly::CALL_I32:
case WebAssembly::CALL_I64:
Changed |= optimizeCall(MBB, MI, MRI, MDT, LIS, TLI, LibInfo);

View File

@ -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 $drop=, __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 $drop=, 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]]{{$}}
@ -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 $drop=, __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 $drop=, 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,9 +73,9 @@ 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 $drop=, {{.+}}, $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)
@ -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 $drop=, __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]

View File

@ -207,12 +207,12 @@ exit:
; CHECK: block{{$}}
; CHECK: br_if 0, $1{{$}}
; CHECK: .LBB4_2:
; CHECK: return ${{[0-9]+}}{{$}}
; CHECK: return
; OPT-LABEL: triangle:
; 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
@ -329,7 +329,7 @@ exit:
; CHECK: br_if 0, $1{{$}}
; CHECK: .LBB9_3:
; CHECK: .LBB9_4:
; CHECK: return ${{[0-9]+}}{{$}}
; CHECK: return
; OPT-LABEL: doubletriangle:
; OPT: block{{$}}
; OPT: br_if 0, $0{{$}}
@ -337,7 +337,7 @@ exit:
; 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
@ -965,6 +965,7 @@ bb6:
; CHECK: br_if 0, {{[^,]+}}{{$}}
; CHECK-NOT: block
; CHECK: block{{$}}
; CHECK-NEXT: i32.const
; CHECK-NEXT: br_if 0, {{[^,]+}}{{$}}
; CHECK-NOT: block
; CHECK: br_if 2, {{[^,]+}}{{$}}
@ -996,7 +997,8 @@ bb6:
; OPT: br_if 0, $pop{{[0-9]+}}{{$}}
; OPT-NOT: block
; OPT: block{{$}}
; OPT-NEXT: br_if 0, $0{{$}}
; OPT-NEXT: i32.const
; OPT-NEXT: br_if 0, {{[^,]+}}{{$}}
; OPT-NOT: block
; OPT: br_if 2, {{[^,]+}}{{$}}
; OPT-NEXT: .LBB20_3:

View File

@ -398,7 +398,8 @@ 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=, 8($0):p2align=2, $pop[[L0]]{{$}}
; CHECK: i64.const $push[[L1:[0-9]+]]=, 0{{$}}
; CHECK: i64.store $drop=, 0($0):p2align=2, $pop[[L1]]{{$}}
define {i32,i32,i32,i32} @aggregate_return() {
ret {i32,i32,i32,i32} zeroinitializer
@ -409,8 +410,10 @@ 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.store8 $drop=, 14($0), $pop[[L0]]{{$}}
; CHECK: i32.const $push[[L1:[0-9]+]]=, 0{{$}}
; CHECK: i32.store16 $drop=, 12($0), $pop[[L1]]{{$}}
; CHECK: i32.const $push[[L2:[0-9]+]]=, 0{{$}}
; CHECK: i32.store $drop=, 8($0), $pop[[L2]]{{$}}
; CHECK: i64.const $push[[L3:[0-9]+]]=, 0{{$}}
; CHECK: i64.store $drop=, 0($0), $pop[[L3]]{{$}}

View File

@ -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 $drop=, 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 $drop=, 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) {

View File

@ -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
}

View File

@ -14,12 +14,12 @@ 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 $drop=, __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 $drop=, 12($[[SP]]), $pop[[L0]]
store i32 0, i32* %retval
; CHECK: i32.const $push[[L6:.+]]=, 0
; CHECK-NEXT: i32.const $push[[L5:.+]]=, 16
@ -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 $drop=, __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 $drop=, 0($pop[[L3]]), $pop[[L1]]{{$}}
; CHECK-NEXT: i32.const $push[[L10:.+]]=, 1{{$}}
; CHECK-NEXT: i32.store $drop=, 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 $drop=, __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 $drop=, {{.+}}, $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 $drop=, 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,15 +108,16 @@ 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 $drop=, __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 $drop=, 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.
@ -170,14 +173,13 @@ 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[[L11:.+]]=, 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: i32.load $push[[L9:.+]]=, __stack_pointer($pop[[L8]])
; CHECK-NEXT: i32.const $push[[L10:.+]]=, 16
; CHECK-NEXT: i32.sub $push[[L20:.+]]=, $pop[[L9]], $pop[[L10]]
; CHECK-NEXT: tee_local $push[[L19:.+]]=, $[[FP:.+]]=, $pop[[L20]]
; CHECK: i32.store $push[[L0:.+]]=, __stack_pointer($pop{{.+}}), $pop{{.+}}
; CHECK: i32.store $drop=, __stack_pointer($pop{{.+}}), $pop{{.+}}
; Decrement SP in the body by the dynamic amount.
; CHECK: i32.sub
; Writeback to memory.