diff options
-rw-r--r-- | src/ir/possible-contents.cpp | 15 | ||||
-rw-r--r-- | test/lit/passes/gufa-refs.wast | 54 |
2 files changed, 63 insertions, 6 deletions
diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index 48a632576..7079a9446 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -1564,6 +1564,15 @@ void Flower::readFromData(HeapType declaredHeapType, return; } + if (refContents.isLiteral()) { + // The only reference literals we have are nulls (handled above) and + // ref.func. ref.func will trap in struct|array.get, so nothing will be read + // here (when we finish optimizing all instructions like BrOn then + // ref.funcs should get filtered out before arriving here TODO). + assert(refContents.getType().isFunction()); + return; + } + #if defined(POSSIBLE_CONTENTS_DEBUG) && POSSIBLE_CONTENTS_DEBUG >= 2 std::cout << " add special reads\n"; #endif @@ -1586,12 +1595,6 @@ void Flower::readFromData(HeapType declaredHeapType, // represent them as ExactType). // See the test TODO with text "We optimize some of this, but stop at // reading from the immutable global" - // Note that this cannot be a Literal, since this is a reference, and the - // only reference literals we have are nulls (handled above) and ref.func. - // ref.func is not valid in struct|array.get, so the code would trap at - // runtime, and also it would never reach here as because of wasm validation - // it would be cast to a struct/array type, and our special ref.cast code - // would filter it out. assert(refContents.isMany() || refContents.isGlobal()); // We create a ConeReadLocation for the canonical cone of this type, to diff --git a/test/lit/passes/gufa-refs.wast b/test/lit/passes/gufa-refs.wast index ddd10e7f9..d8fb51e50 100644 --- a/test/lit/passes/gufa-refs.wast +++ b/test/lit/passes/gufa-refs.wast @@ -938,6 +938,8 @@ ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (elem declare func $func) + ;; CHECK: (func $func (type $none_=>_none) ;; CHECK-NEXT: (local $child (ref null $child)) ;; CHECK-NEXT: (local $parent (ref null $parent)) @@ -977,6 +979,35 @@ ;; CHECK-NEXT: (ref.null $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block $parent (result (ref $parent)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block (result (ref $none_=>_none)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (br_on_cast_static $parent $parent + ;; CHECK-NEXT: (ref.func $func) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.func $func) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $func (local $child (ref null $child)) @@ -1013,6 +1044,29 @@ (local.get $parent) ) ) + ;; A ref.func is cast to a struct type, and then we read from that. The cast + ;; will trap at runtime, of course; for here, we should not error and also + ;; we can optimize these to unreachables. atm we filter out trapping + ;; contents in ref.cast, but not br_on_cast, so test both. + (drop + (struct.get $parent 0 + (ref.cast_static $parent + (ref.func $func) + ) + ) + ) + (drop + (struct.get $parent 0 + (block $parent (result (ref $parent)) + (drop + (br_on_cast_static $parent $parent + (ref.func $func) + ) + ) + (unreachable) + ) + ) + ) ) ;; CHECK: (func $nulls (type $none_=>_none) |