Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -129,6 +129,7 @@ return false; } + SawStore = Def->isCall() || Def->mayStore(); // Check for memory dependencies and side effects. for (--I; I != D; --I) SawSideEffects |= !I->isSafeToMove(&AA, SawStore); Index: llvm/trunk/test/CodeGen/WebAssembly/reg-stackify.ll =================================================================== --- llvm/trunk/test/CodeGen/WebAssembly/reg-stackify.ll +++ llvm/trunk/test/CodeGen/WebAssembly/reg-stackify.ll @@ -308,4 +308,43 @@ br label %bb5 } +; Don't move calls past loads +; CHECK-LABEL: no_stackify_call_past_load: +; CHECK: i32.call $0=, red +; CHECK: i32.const $push0=, 0 +; CHECK: i32.load $1=, count($pop0) +@count = hidden global i32 0, align 4 +define i32 @no_stackify_call_past_load() { + %a = call i32 @red() + %b = load i32, i32* @count, align 4 + call i32 @callee(i32 %a) + ret i32 %b + ; use of a +} + +; Don't move stores past loads if there may be aliasing +; CHECK-LABEL: no_stackify_store_past_load +; CHECK: i32.store {{.*}}, 0($1), $0 +; CHECK: i32.load {{.*}}, 0($2) +; 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 + call i32 @callee(i32 %a) + ret i32 %b +} + +; 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.load $push{{.*}}, 0($2) +; CHECK: return $pop +define i32 @store_past_invar_load(i32 %a, i32* %p1, i32* dereferenceable(4) %p2) { + store i32 %a, i32* %p1 + %b = load i32, i32* %p2, !invariant.load !0 + call i32 @callee(i32 %a) + ret i32 %b +} + !0 = !{}