Skip to content

Commit 01ec379

Browse files
committed
Merge remote-tracking branch 'origin/main' into optimzied
2 parents 71c3c5b + 0bb686f commit 01ec379

6 files changed

Lines changed: 179 additions & 40 deletions

File tree

src/ir/possible-contents.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3136,31 +3136,33 @@ void Flower::filterPackedDataReads(PossibleContents& contents,
31363136
Expression* ref;
31373137
Index index;
31383138
unsigned bytes = 0;
3139-
Type resultType = Type::none;
31403139
if (auto* get = expr->dynCast<StructGet>()) {
31413140
signed_ = get->signed_;
31423141
ref = get->ref;
31433142
index = get->index;
3144-
resultType = get->type;
31453143
} else if (auto* get = expr->dynCast<ArrayGet>()) {
31463144
signed_ = get->signed_;
31473145
ref = get->ref;
31483146
// Arrays are treated as having a single field.
31493147
index = 0;
3150-
resultType = get->type;
31513148
} else if (auto* load = expr->dynCast<ArrayLoad>()) {
31523149
signed_ = load->signed_;
31533150
ref = load->ref;
31543151
index = 0;
31553152
bytes = load->bytes;
3156-
resultType = load->type;
31573153
} else {
31583154
WASM_UNREACHABLE("bad packed read");
31593155
}
31603156
if (!signed_) {
31613157
return;
31623158
}
31633159

3160+
Type resultType = expr->type;
3161+
if (resultType == Type::unreachable) {
3162+
// This read never executes.
3163+
return;
3164+
}
3165+
31643166
// If there is no struct or array to read, no value will ever be returned.
31653167
if (ref->type.isNull()) {
31663168
contents = PossibleContents::none();

src/passes/Heap2Local.cpp

Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -461,40 +461,31 @@ struct EscapeAnalyzer {
461461
}
462462
}
463463
void visitArraySet(ArraySet* curr) {
464-
if (!curr->index->is<Const>()) {
465-
// Array operations on nonconstant indexes do not escape in the normal
466-
// sense, but they do escape from our being able to analyze them, so
467-
// stop as soon as we see one.
468-
return;
469-
}
470-
471-
// As StructGet.
472-
if (curr->ref == child) {
464+
// Arrays flowing into array operations on nonconstant indexes do not
465+
// escape in the normal sense, but they do escape from our being able to
466+
// analyze them, so stop as soon as we see one.
467+
if (child == curr->ref && curr->index->is<Const>()) {
473468
escapes = false;
474469
fullyConsumes = true;
475470
}
476471
}
477472
void visitArrayGet(ArrayGet* curr) {
478-
if (!curr->index->is<Const>()) {
479-
return;
473+
if (child == curr->ref && curr->index->is<Const>()) {
474+
escapes = false;
475+
fullyConsumes = true;
480476
}
481-
escapes = false;
482-
fullyConsumes = true;
483477
}
484478
void visitArrayRMW(ArrayRMW* curr) {
485-
if (!curr->index->is<Const>()) {
486-
return;
487-
}
488-
if (curr->ref == child) {
479+
if (child == curr->ref && curr->index->is<Const>()) {
489480
escapes = false;
490481
fullyConsumes = true;
491482
}
492483
}
493484
void visitArrayCmpxchg(ArrayCmpxchg* curr) {
494-
if (!curr->index->is<Const>()) {
495-
return;
496-
}
497-
if (curr->ref == child || curr->expected == child) {
485+
// Allocations flowing into `expected` are fully consumed and
486+
// optimizable even if the index is not constant.
487+
if (child == curr->expected ||
488+
(child == curr->ref && curr->index->is<Const>())) {
498489
escapes = false;
499490
fullyConsumes = true;
500491
}
@@ -1233,9 +1224,15 @@ struct Struct2Local : PostWalker<Struct2Local> {
12331224
auto refScratch = builder.addVar(func, refType);
12341225
auto* setRefScratch = builder.makeLocalSet(refScratch, curr->ref);
12351226
auto* getRefScratch = builder.makeLocalGet(refScratch, refType);
1227+
1228+
auto indexScratch = builder.addVar(func, Type::i32);
1229+
auto* setIndexScratch = builder.makeLocalSet(indexScratch, curr->index);
1230+
auto* getIndexScratch = builder.makeLocalGet(indexScratch, Type::i32);
1231+
12361232
auto* arrayGet = builder.makeArrayGet(
1237-
getRefScratch, curr->index, curr->order, curr->type);
1233+
getRefScratch, getIndexScratch, curr->order, curr->type);
12381234
auto* block = builder.makeBlock({setRefScratch,
1235+
setIndexScratch,
12391236
builder.makeDrop(curr->expected),
12401237
builder.makeDrop(curr->replacement),
12411238
arrayGet});
@@ -1467,19 +1464,19 @@ struct Array2Struct : PostWalker<Array2Struct> {
14671464
return;
14681465
}
14691466

1470-
auto index = getIndex(curr->index);
1471-
if (index >= numFields) {
1472-
replaceCurrent(builder.makeBlock({builder.makeDrop(curr->ref),
1473-
builder.makeDrop(curr->expected),
1474-
builder.makeDrop(curr->replacement),
1475-
builder.makeUnreachable()}));
1476-
refinalize = true;
1477-
return;
1478-
}
1479-
14801467
// The allocation might flow into `ref` or `expected`, but not
14811468
// `replacement`, because then it would be considered to have escaped.
14821469
if (analyzer.getInteraction(curr->ref) == ParentChildInteraction::Flows) {
1470+
auto index = getIndex(curr->index);
1471+
if (index >= numFields) {
1472+
replaceCurrent(builder.makeBlock({builder.makeDrop(curr->ref),
1473+
builder.makeDrop(curr->expected),
1474+
builder.makeDrop(curr->replacement),
1475+
builder.makeUnreachable()}));
1476+
refinalize = true;
1477+
return;
1478+
}
1479+
14831480
// The accessed array is being optimized. Convert the ArrayCmpxchg into a
14841481
// StructCmpxchg.
14851482
replaceCurrent(builder.makeStructCmpxchg(

src/wasm-stack.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ class BinaryInstWriter : public OverriddenVisitor<BinaryInstWriter> {
150150
std::unordered_map<Type, size_t> numLocalsByType;
151151

152152
void noteLocalType(Type type, Index count = 1);
153+
Index getNumLocalsForType(Type type);
153154

154155
// Keeps track of the binary index of the scratch locals used to lower
155156
// tuple.extract. If there are multiple scratch locals of the same type, they

src/wasm/wasm-stack.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3245,7 +3245,7 @@ void BinaryInstWriter::mapLocalsAndEmitHeader() {
32453245
Index baseIndex = func->getVarIndexBase();
32463246
for (auto& type : localTypes) {
32473247
nextFreeIndex[type] = baseIndex;
3248-
baseIndex += numLocalsByType[type];
3248+
baseIndex += getNumLocalsForType(type);
32493249
}
32503250

32513251
// Map the IR index pairs to indices.
@@ -3261,21 +3261,36 @@ void BinaryInstWriter::mapLocalsAndEmitHeader() {
32613261
scratchLocals[type] = nextFreeIndex[type];
32623262
}
32633263

3264-
o << U32LEB(numLocalsByType.size());
3264+
o << U32LEB(localTypes.size());
32653265
for (auto& localType : localTypes) {
3266-
o << U32LEB(numLocalsByType.at(localType));
3266+
o << U32LEB(getNumLocalsForType(localType));
32673267
parent.writeType(localType);
32683268
}
32693269
}
32703270

32713271
void BinaryInstWriter::noteLocalType(Type type, Index count) {
3272+
// Group locals by the type they will eventually be written out as. For
3273+
// example, we do not need to differentiate exact and inexact versions of the
3274+
// same reference type if custom descriptors is not enabled and the type will
3275+
// be written as inexact either way.
3276+
auto feats = parent.getModule()->features;
3277+
type = type.asWrittenGivenFeatures(feats);
32723278
auto& num = numLocalsByType[type];
32733279
if (num == 0) {
32743280
localTypes.push_back(type);
32753281
}
32763282
num += count;
32773283
}
32783284

3285+
Index BinaryInstWriter::getNumLocalsForType(Type type) {
3286+
auto feats = parent.getModule()->features;
3287+
type = type.asWrittenGivenFeatures(feats);
3288+
if (auto it = numLocalsByType.find(type); it != numLocalsByType.end()) {
3289+
return it->second;
3290+
}
3291+
return 0;
3292+
}
3293+
32793294
InsertOrderedMap<Type, Index> BinaryInstWriter::countScratchLocals() {
32803295
struct ScratchLocalFinder : PostWalker<ScratchLocalFinder> {
32813296
BinaryInstWriter& parent;

test/lit/passes/gufa-refs.wast

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6141,6 +6141,25 @@
61416141
)
61426142
)
61436143
)
6144+
6145+
;; CHECK: (func $unreachable (type $1)
6146+
;; CHECK-NEXT: (array.get_s $array
6147+
;; CHECK-NEXT: (array.new_default $array
6148+
;; CHECK-NEXT: (i32.const 0)
6149+
;; CHECK-NEXT: )
6150+
;; CHECK-NEXT: (unreachable)
6151+
;; CHECK-NEXT: )
6152+
;; CHECK-NEXT: )
6153+
(func $unreachable
6154+
;; This array.get is unreachable, and when handling packing we should not
6155+
;; error.
6156+
(array.get_s $array
6157+
(array.new_default $array
6158+
(i32.const 0)
6159+
)
6160+
(unreachable)
6161+
)
6162+
)
61446163
)
61456164

61466165
;; Atomic accesses require special handling

test/lit/passes/heap2local-rmw.wast

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1465,11 +1465,15 @@
14651465
;; CHECK: (func $array-cmpxchg-expected (type $1) (param $array (ref $array))
14661466
;; CHECK-NEXT: (local $1 eqref)
14671467
;; CHECK-NEXT: (local $2 (ref null $array))
1468+
;; CHECK-NEXT: (local $3 i32)
14681469
;; CHECK-NEXT: (drop
14691470
;; CHECK-NEXT: (block (result eqref)
14701471
;; CHECK-NEXT: (local.set $2
14711472
;; CHECK-NEXT: (local.get $array)
14721473
;; CHECK-NEXT: )
1474+
;; CHECK-NEXT: (local.set $3
1475+
;; CHECK-NEXT: (i32.const 0)
1476+
;; CHECK-NEXT: )
14731477
;; CHECK-NEXT: (drop
14741478
;; CHECK-NEXT: (block (result nullref)
14751479
;; CHECK-NEXT: (local.set $1
@@ -1483,7 +1487,7 @@
14831487
;; CHECK-NEXT: )
14841488
;; CHECK-NEXT: (array.atomic.get $array
14851489
;; CHECK-NEXT: (local.get $2)
1486-
;; CHECK-NEXT: (i32.const 0)
1490+
;; CHECK-NEXT: (local.get $3)
14871491
;; CHECK-NEXT: )
14881492
;; CHECK-NEXT: )
14891493
;; CHECK-NEXT: )
@@ -1504,3 +1508,104 @@
15041508
)
15051509
)
15061510
)
1511+
1512+
(module
1513+
;; CHECK: (type $array (array (mut eqref)))
1514+
(type $array (array (mut eqref)))
1515+
;; CHECK: (type $1 (func (param (ref $array))))
1516+
1517+
;; CHECK: (type $2 (func (result i32)))
1518+
1519+
;; CHECK: (type $3 (func (result eqref)))
1520+
1521+
;; CHECK: (import "" "" (func $effect-i32 (type $2) (result i32)))
1522+
(import "" "" (func $effect-i32 (result i32)))
1523+
;; CHECK: (import "" "" (func $effect-eq (type $3) (result eqref)))
1524+
(import "" "" (func $effect-eq (result eqref)))
1525+
1526+
;; CHECK: (func $array-cmpxchg-expected-index-effect (type $1) (param $array (ref $array))
1527+
;; CHECK-NEXT: (local $1 eqref)
1528+
;; CHECK-NEXT: (local $2 (ref null $array))
1529+
;; CHECK-NEXT: (local $3 i32)
1530+
;; CHECK-NEXT: (drop
1531+
;; CHECK-NEXT: (block (result eqref)
1532+
;; CHECK-NEXT: (local.set $2
1533+
;; CHECK-NEXT: (local.get $array)
1534+
;; CHECK-NEXT: )
1535+
;; CHECK-NEXT: (local.set $3
1536+
;; CHECK-NEXT: (call $effect-i32)
1537+
;; CHECK-NEXT: )
1538+
;; CHECK-NEXT: (drop
1539+
;; CHECK-NEXT: (block (result nullref)
1540+
;; CHECK-NEXT: (local.set $1
1541+
;; CHECK-NEXT: (ref.null none)
1542+
;; CHECK-NEXT: )
1543+
;; CHECK-NEXT: (ref.null none)
1544+
;; CHECK-NEXT: )
1545+
;; CHECK-NEXT: )
1546+
;; CHECK-NEXT: (drop
1547+
;; CHECK-NEXT: (call $effect-eq)
1548+
;; CHECK-NEXT: )
1549+
;; CHECK-NEXT: (array.atomic.get $array
1550+
;; CHECK-NEXT: (local.get $2)
1551+
;; CHECK-NEXT: (local.get $3)
1552+
;; CHECK-NEXT: )
1553+
;; CHECK-NEXT: )
1554+
;; CHECK-NEXT: )
1555+
;; CHECK-NEXT: )
1556+
(func $array-cmpxchg-expected-index-effect (param $array (ref $array))
1557+
(drop
1558+
;; The index is non-constant, but we can still optimize the expected
1559+
;; field. We must preserve the index and the order of its effects.
1560+
(array.atomic.rmw.cmpxchg $array
1561+
(local.get $array)
1562+
(call $effect-i32)
1563+
(array.new_default $array (i32.const 1))
1564+
(call $effect-eq)
1565+
)
1566+
)
1567+
)
1568+
1569+
;; CHECK: (func $array-cmpxchg-expected-index-oob (type $1) (param $array (ref $array))
1570+
;; CHECK-NEXT: (local $1 eqref)
1571+
;; CHECK-NEXT: (local $2 (ref null $array))
1572+
;; CHECK-NEXT: (local $3 i32)
1573+
;; CHECK-NEXT: (drop
1574+
;; CHECK-NEXT: (block (result eqref)
1575+
;; CHECK-NEXT: (local.set $2
1576+
;; CHECK-NEXT: (local.get $array)
1577+
;; CHECK-NEXT: )
1578+
;; CHECK-NEXT: (local.set $3
1579+
;; CHECK-NEXT: (i32.const -1)
1580+
;; CHECK-NEXT: )
1581+
;; CHECK-NEXT: (drop
1582+
;; CHECK-NEXT: (block (result nullref)
1583+
;; CHECK-NEXT: (local.set $1
1584+
;; CHECK-NEXT: (ref.null none)
1585+
;; CHECK-NEXT: )
1586+
;; CHECK-NEXT: (ref.null none)
1587+
;; CHECK-NEXT: )
1588+
;; CHECK-NEXT: )
1589+
;; CHECK-NEXT: (drop
1590+
;; CHECK-NEXT: (call $effect-eq)
1591+
;; CHECK-NEXT: )
1592+
;; CHECK-NEXT: (array.atomic.get $array
1593+
;; CHECK-NEXT: (local.get $2)
1594+
;; CHECK-NEXT: (local.get $3)
1595+
;; CHECK-NEXT: )
1596+
;; CHECK-NEXT: )
1597+
;; CHECK-NEXT: )
1598+
;; CHECK-NEXT: )
1599+
(func $array-cmpxchg-expected-index-oob (param $array (ref $array))
1600+
(drop
1601+
;; Now the index is constant but surely out-of-bounds. We still optimize
1602+
;; the same, way leaving the array.atomic.get to trap.
1603+
(array.atomic.rmw.cmpxchg $array
1604+
(local.get $array)
1605+
(i32.const -1)
1606+
(array.new_default $array (i32.const 1))
1607+
(call $effect-eq)
1608+
)
1609+
)
1610+
)
1611+
)

0 commit comments

Comments
 (0)