Skip to content

Commit 4913080

Browse files
authored
Fix Heap2Local on pops inside of newly-created blocks (#6938)
1 parent 29d30fa commit 4913080

2 files changed

Lines changed: 141 additions & 0 deletions

File tree

src/passes/Heap2Local.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@
152152

153153
#include "ir/bits.h"
154154
#include "ir/branch-utils.h"
155+
#include "ir/eh-utils.h"
155156
#include "ir/find_all.h"
156157
#include "ir/local-graph.h"
157158
#include "ir/parents.h"
@@ -1191,9 +1192,16 @@ struct Heap2Local {
11911192
// some cases, so to be careful here use a fairly small limit.
11921193
return size < 20;
11931194
}
1195+
1196+
// Also note if a pop exists here, as they may require fixups.
1197+
bool hasPop = false;
1198+
1199+
void visitPop(Pop* curr) { hasPop = true; }
11941200
} finder;
11951201
finder.walk(func->body);
11961202

1203+
bool optimized = false;
1204+
11971205
// First, lower non-escaping arrays into structs. That allows us to handle
11981206
// arrays in a single place, and let all the rest of this pass assume we are
11991207
// working on structs. We are in fact only optimizing struct-like arrays
@@ -1215,6 +1223,7 @@ struct Heap2Local {
12151223
auto* structNew =
12161224
Array2Struct(allocation, analyzer, func, wasm).structNew;
12171225
Struct2Local(structNew, analyzer, func, wasm);
1226+
optimized = true;
12181227
}
12191228
}
12201229

@@ -1231,8 +1240,16 @@ struct Heap2Local {
12311240
localGraph, parents, branchTargets, passOptions, wasm);
12321241
if (!analyzer.escapes(allocation)) {
12331242
Struct2Local(allocation, analyzer, func, wasm);
1243+
optimized = true;
12341244
}
12351245
}
1246+
1247+
// We conservatively run the EH pop fixup if this function has a 'pop' and
1248+
// if we have ever optimized, as all of the things we do here involve
1249+
// creating blocks, so we might have moved pops into the blocks.
1250+
if (finder.hasPop && optimized) {
1251+
EHUtils::handleBlockNestedPops(func, wasm);
1252+
}
12361253
}
12371254

12381255
bool canHandleAsLocal(const Field& field) {

test/lit/passes/heap2local.wast

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4485,3 +4485,127 @@
44854485
)
44864486
)
44874487
)
4488+
4489+
;; Pops require fixups.
4490+
(module
4491+
(type $struct (struct (field (mut i32))))
4492+
4493+
(type $array (array (mut i32)))
4494+
4495+
;; CHECK: (type $0 (func))
4496+
4497+
;; CHECK: (type $1 (func (param i32)))
4498+
4499+
;; CHECK: (type $2 (struct (field (mut i32)) (field (mut i32)) (field (mut i32))))
4500+
4501+
;; CHECK: (tag $tag (param i32))
4502+
(tag $tag (param i32))
4503+
4504+
;; CHECK: (func $struct-with-pop (type $0)
4505+
;; CHECK-NEXT: (local $0 i32)
4506+
;; CHECK-NEXT: (local $1 i32)
4507+
;; CHECK-NEXT: (local $2 i32)
4508+
;; CHECK-NEXT: (try
4509+
;; CHECK-NEXT: (do
4510+
;; CHECK-NEXT: (nop)
4511+
;; CHECK-NEXT: )
4512+
;; CHECK-NEXT: (catch $tag
4513+
;; CHECK-NEXT: (local.set $2
4514+
;; CHECK-NEXT: (pop i32)
4515+
;; CHECK-NEXT: )
4516+
;; CHECK-NEXT: (drop
4517+
;; CHECK-NEXT: (block (result nullref)
4518+
;; CHECK-NEXT: (local.set $1
4519+
;; CHECK-NEXT: (local.get $2)
4520+
;; CHECK-NEXT: )
4521+
;; CHECK-NEXT: (local.set $0
4522+
;; CHECK-NEXT: (local.get $1)
4523+
;; CHECK-NEXT: )
4524+
;; CHECK-NEXT: (ref.null none)
4525+
;; CHECK-NEXT: )
4526+
;; CHECK-NEXT: )
4527+
;; CHECK-NEXT: )
4528+
;; CHECK-NEXT: )
4529+
;; CHECK-NEXT: )
4530+
(func $struct-with-pop
4531+
(try
4532+
(do
4533+
(nop)
4534+
)
4535+
(catch $tag
4536+
(drop
4537+
;; We create a block when we replace the struct with locals, which the
4538+
;; pop must be moved out of.
4539+
(struct.new $struct
4540+
(pop i32)
4541+
)
4542+
)
4543+
)
4544+
)
4545+
)
4546+
4547+
;; CHECK: (func $array-with-pop (type $0)
4548+
;; CHECK-NEXT: (local $0 i32)
4549+
;; CHECK-NEXT: (local $1 i32)
4550+
;; CHECK-NEXT: (local $2 i32)
4551+
;; CHECK-NEXT: (local $3 i32)
4552+
;; CHECK-NEXT: (local $4 i32)
4553+
;; CHECK-NEXT: (local $5 i32)
4554+
;; CHECK-NEXT: (local $6 i32)
4555+
;; CHECK-NEXT: (local $7 i32)
4556+
;; CHECK-NEXT: (try
4557+
;; CHECK-NEXT: (do
4558+
;; CHECK-NEXT: (nop)
4559+
;; CHECK-NEXT: )
4560+
;; CHECK-NEXT: (catch $tag
4561+
;; CHECK-NEXT: (local.set $7
4562+
;; CHECK-NEXT: (pop i32)
4563+
;; CHECK-NEXT: )
4564+
;; CHECK-NEXT: (drop
4565+
;; CHECK-NEXT: (block (result (ref null $2))
4566+
;; CHECK-NEXT: (local.set $0
4567+
;; CHECK-NEXT: (local.get $7)
4568+
;; CHECK-NEXT: )
4569+
;; CHECK-NEXT: (block (result nullref)
4570+
;; CHECK-NEXT: (local.set $4
4571+
;; CHECK-NEXT: (local.get $0)
4572+
;; CHECK-NEXT: )
4573+
;; CHECK-NEXT: (local.set $5
4574+
;; CHECK-NEXT: (local.get $0)
4575+
;; CHECK-NEXT: )
4576+
;; CHECK-NEXT: (local.set $6
4577+
;; CHECK-NEXT: (local.get $0)
4578+
;; CHECK-NEXT: )
4579+
;; CHECK-NEXT: (local.set $1
4580+
;; CHECK-NEXT: (local.get $4)
4581+
;; CHECK-NEXT: )
4582+
;; CHECK-NEXT: (local.set $2
4583+
;; CHECK-NEXT: (local.get $5)
4584+
;; CHECK-NEXT: )
4585+
;; CHECK-NEXT: (local.set $3
4586+
;; CHECK-NEXT: (local.get $6)
4587+
;; CHECK-NEXT: )
4588+
;; CHECK-NEXT: (ref.null none)
4589+
;; CHECK-NEXT: )
4590+
;; CHECK-NEXT: )
4591+
;; CHECK-NEXT: )
4592+
;; CHECK-NEXT: )
4593+
;; CHECK-NEXT: )
4594+
;; CHECK-NEXT: )
4595+
(func $array-with-pop
4596+
(try
4597+
(do
4598+
(nop)
4599+
)
4600+
(catch $tag
4601+
(drop
4602+
;; As above, but with an array
4603+
(array.new $array
4604+
(pop i32)
4605+
(i32.const 3)
4606+
)
4607+
)
4608+
)
4609+
)
4610+
)
4611+
)

0 commit comments

Comments
 (0)