Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 30 additions & 33 deletions src/passes/Heap2Local.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,40 +461,31 @@ struct EscapeAnalyzer {
}
}
void visitArraySet(ArraySet* curr) {
if (!curr->index->is<Const>()) {
// Array operations on nonconstant indexes do not escape in the normal
// sense, but they do escape from our being able to analyze them, so
// stop as soon as we see one.
return;
}

// As StructGet.
if (curr->ref == child) {
// Arrays flowing into array operations on nonconstant indexes do not
// escape in the normal sense, but they do escape from our being able to
// analyze them, so stop as soon as we see one.
if (child == curr->ref && curr->index->is<Const>()) {
escapes = false;
fullyConsumes = true;
}
}
void visitArrayGet(ArrayGet* curr) {
if (!curr->index->is<Const>()) {
return;
if (child == curr->ref && curr->index->is<Const>()) {
escapes = false;
fullyConsumes = true;
}
escapes = false;
fullyConsumes = true;
}
void visitArrayRMW(ArrayRMW* curr) {
if (!curr->index->is<Const>()) {
return;
}
if (curr->ref == child) {
if (child == curr->ref && curr->index->is<Const>()) {
escapes = false;
fullyConsumes = true;
}
}
void visitArrayCmpxchg(ArrayCmpxchg* curr) {
if (!curr->index->is<Const>()) {
return;
}
if (curr->ref == child || curr->expected == child) {
// Allocations flowing into `expected` are fully consumed and
// optimizable even if the index is not constant.
if (child == curr->expected ||
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth a comment here I think, as in the PR description.

(child == curr->ref && curr->index->is<Const>())) {
escapes = false;
fullyConsumes = true;
}
Expand Down Expand Up @@ -1233,9 +1224,15 @@ struct Struct2Local : PostWalker<Struct2Local> {
auto refScratch = builder.addVar(func, refType);
auto* setRefScratch = builder.makeLocalSet(refScratch, curr->ref);
auto* getRefScratch = builder.makeLocalGet(refScratch, refType);

auto indexScratch = builder.addVar(func, Type::i32);
auto* setIndexScratch = builder.makeLocalSet(indexScratch, curr->index);
auto* getIndexScratch = builder.makeLocalGet(indexScratch, Type::i32);

auto* arrayGet = builder.makeArrayGet(
getRefScratch, curr->index, curr->order, curr->type);
getRefScratch, getIndexScratch, curr->order, curr->type);
auto* block = builder.makeBlock({setRefScratch,
setIndexScratch,
builder.makeDrop(curr->expected),
builder.makeDrop(curr->replacement),
arrayGet});
Expand Down Expand Up @@ -1467,20 +1464,20 @@ struct Array2Struct : PostWalker<Array2Struct> {
return;
}

auto index = getIndex(curr->index);
if (index >= numFields) {
replaceCurrent(builder.makeBlock({builder.makeDrop(curr->ref),
builder.makeDrop(curr->expected),
builder.makeDrop(curr->replacement),
builder.makeUnreachable()}));
refinalize = true;
return;
}

// The allocation might flow into `ref` or `expected`, but not
// `replacement`, because then it would be considered to have escaped.
if (analyzer.getInteraction(curr->ref) == ParentChildInteraction::Flows) {
// The accessed array is being optimzied. Convert the ArrayCmpxchg into a
auto index = getIndex(curr->index);
if (index >= numFields) {
replaceCurrent(builder.makeBlock({builder.makeDrop(curr->ref),
builder.makeDrop(curr->expected),
builder.makeDrop(curr->replacement),
builder.makeUnreachable()}));
refinalize = true;
return;
}

// The accessed array is being optimized. Convert the ArrayCmpxchg into a
// StructCmpxchg.
replaceCurrent(builder.makeStructCmpxchg(
index, curr->ref, curr->expected, curr->replacement, curr->order));
Expand Down
107 changes: 106 additions & 1 deletion test/lit/passes/heap2local-rmw.wast
Original file line number Diff line number Diff line change
Expand Up @@ -1465,11 +1465,15 @@
;; CHECK: (func $array-cmpxchg-expected (type $1) (param $array (ref $array))
;; CHECK-NEXT: (local $1 eqref)
;; CHECK-NEXT: (local $2 (ref null $array))
;; CHECK-NEXT: (local $3 i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result eqref)
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (local.get $array)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $3
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result nullref)
;; CHECK-NEXT: (local.set $1
Expand All @@ -1483,7 +1487,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: (array.atomic.get $array
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (local.get $3)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
Expand All @@ -1504,3 +1508,104 @@
)
)
)

(module
;; CHECK: (type $array (array (mut eqref)))
(type $array (array (mut eqref)))
;; CHECK: (type $1 (func (param (ref $array))))

;; CHECK: (type $2 (func (result i32)))

;; CHECK: (type $3 (func (result eqref)))

;; CHECK: (import "" "" (func $effect-i32 (type $2) (result i32)))
(import "" "" (func $effect-i32 (result i32)))
;; CHECK: (import "" "" (func $effect-eq (type $3) (result eqref)))
(import "" "" (func $effect-eq (result eqref)))

;; CHECK: (func $array-cmpxchg-expected-index-effect (type $1) (param $array (ref $array))
;; CHECK-NEXT: (local $1 eqref)
;; CHECK-NEXT: (local $2 (ref null $array))
;; CHECK-NEXT: (local $3 i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result eqref)
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (local.get $array)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $3
;; CHECK-NEXT: (call $effect-i32)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result nullref)
;; CHECK-NEXT: (local.set $1
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $effect-eq)
;; CHECK-NEXT: )
;; CHECK-NEXT: (array.atomic.get $array
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: (local.get $3)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $array-cmpxchg-expected-index-effect (param $array (ref $array))
(drop
;; The index is non-constant, but we can still optimize the expected
;; field. We must preserve the index and the order of its effects.
(array.atomic.rmw.cmpxchg $array
(local.get $array)
(call $effect-i32)
(array.new_default $array (i32.const 1))
(call $effect-eq)
)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a test for array.atomic.rmw.cmpxchg where we optimize the expected field but the index is out of bounds?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The output will look the same, but I will add a test where the index is an OOB constant.

)
)

;; CHECK: (func $array-cmpxchg-expected-index-oob (type $1) (param $array (ref $array))
;; CHECK-NEXT: (local $1 eqref)
;; CHECK-NEXT: (local $2 (ref null $array))
;; CHECK-NEXT: (local $3 i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result eqref)
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (local.get $array)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $3
;; CHECK-NEXT: (i32.const -1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result nullref)
;; CHECK-NEXT: (local.set $1
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $effect-eq)
;; CHECK-NEXT: )
;; CHECK-NEXT: (array.atomic.get $array
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: (local.get $3)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $array-cmpxchg-expected-index-oob (param $array (ref $array))
(drop
;; Now the index is constant but surely out-of-bounds. We still optimize
;; the same, way leaving the array.atomic.get to trap.
(array.atomic.rmw.cmpxchg $array
(local.get $array)
(i32.const -1)
(array.new_default $array (i32.const 1))
(call $effect-eq)
)
)
)
)
Loading