Skip to content

Commit

Permalink
[threads] Calculate shared heap type depths in subtypes.h
Browse files Browse the repository at this point in the history
Fixes #6776.
  • Loading branch information
tlively committed Jul 19, 2024
1 parent a8066e6 commit cf0d21a
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 21 deletions.
21 changes: 14 additions & 7 deletions src/ir/subtypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,20 +124,27 @@ struct SubTypes {
// Add the max depths of basic types.
for (auto type : types) {
HeapType basic;
auto share = type.getShared();
if (type.isStruct()) {
basic = HeapType::struct_;
basic = HeapTypes::struct_.getBasic(share);
} else if (type.isArray()) {
basic = HeapType::array;
basic = HeapTypes::array.getBasic(share);
} else {
assert(type.isSignature());
basic = HeapType::func;
basic = HeapTypes::func.getBasic(share);
}
depths[basic] = std::max(depths[basic], depths[type] + 1);
auto& basicDepth = depths[basic];
basicDepth = std::max(basicDepth, depths[type] + 1);
}

depths[HeapType::eq] =
std::max(depths[HeapType::struct_], depths[HeapType::array]) + 1;
depths[HeapType::any] = depths[HeapType::eq] + 1;
for (auto share : {Unshared, Shared}) {
depths[HeapTypes::eq.getBasic(share)] =
std::max(depths[HeapTypes::struct_.getBasic(share)],
depths[HeapTypes::array.getBasic(share)]) +
1;
depths[HeapTypes::any.getBasic(share)] =
depths[HeapTypes::eq.getBasic(share)] + 1;
}

return depths;
}
Expand Down
51 changes: 37 additions & 14 deletions test/gtest/type-builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1110,12 +1110,18 @@ TEST_F(TypeTest, TestSubtypeErrors) {
TEST_F(TypeTest, TestSubTypes) {
Type anyref = Type(HeapType::any, Nullable);
Type eqref = Type(HeapType::eq, Nullable);
Type sharedAnyref = Type(HeapTypes::any.getBasic(Shared), Nullable);
Type sharedEqref = Type(HeapTypes::eq.getBasic(Shared), Nullable);

// Build type types, the second of which is a subtype.
TypeBuilder builder(2);
TypeBuilder builder(4);
builder[0].setOpen() = Struct({Field(anyref, Immutable)});
builder[1].setOpen() = Struct({Field(eqref, Immutable)});
// Make shared versions, too.
builder[2].setOpen().setShared() = Array(Field(sharedAnyref, Immutable));
builder[3].setOpen().setShared() = Array(Field(sharedEqref, Immutable));
builder[1].subTypeOf(builder[0]);
builder[3].subTypeOf(builder[2]);

auto result = builder.build();
ASSERT_TRUE(result);
Expand All @@ -1125,20 +1131,37 @@ TEST_F(TypeTest, TestSubTypes) {
// SubTypes utility code.
Module wasm;
Builder wasmBuilder(wasm);
wasm.addFunction(wasmBuilder.makeFunction(
"func",
Signature(Type::none, Type::none),
{Type(built[0], Nullable), Type(built[1], Nullable)},
wasmBuilder.makeNop()));
wasm.addFunction(wasmBuilder.makeFunction("func",
Signature(Type::none, Type::none),
{Type(built[0], Nullable),
Type(built[1], Nullable),
Type(built[2], Nullable),
Type(built[3], Nullable)},
wasmBuilder.makeNop()));
SubTypes subTypes(wasm);
auto subTypes0 = subTypes.getImmediateSubTypes(built[0]);
EXPECT_TRUE(subTypes0.size() == 1 && subTypes0[0] == built[1]);
auto subTypes0Inclusive = subTypes.getSubTypes(built[0]);
EXPECT_TRUE(subTypes0Inclusive.size() == 2 &&
subTypes0Inclusive[0] == built[1] &&
subTypes0Inclusive[1] == built[0]);
auto subTypes1 = subTypes.getImmediateSubTypes(built[1]);
EXPECT_EQ(subTypes1.size(), 0u);
auto immSubTypes0 = subTypes.getImmediateSubTypes(built[0]);
ASSERT_EQ(immSubTypes0.size(), 1u);
EXPECT_EQ(immSubTypes0[0], built[1]);
auto subTypes0 = subTypes.getSubTypes(built[0]);
ASSERT_EQ(subTypes0.size(), 2u);
EXPECT_EQ(subTypes0[0], built[1]);
EXPECT_EQ(subTypes0[1], built[0]);
auto immSubTypes1 = subTypes.getImmediateSubTypes(built[1]);
EXPECT_EQ(immSubTypes1.size(), 0u);

auto depths = subTypes.getMaxDepths();
EXPECT_EQ(depths[HeapTypes::any.getBasic(Unshared)], 4u);
EXPECT_EQ(depths[HeapTypes::any.getBasic(Shared)], 4u);
EXPECT_EQ(depths[HeapTypes::eq.getBasic(Unshared)], 3u);
EXPECT_EQ(depths[HeapTypes::eq.getBasic(Shared)], 3u);
EXPECT_EQ(depths[HeapTypes::struct_.getBasic(Unshared)], 2u);
EXPECT_EQ(depths[HeapTypes::struct_.getBasic(Shared)], 0u);
EXPECT_EQ(depths[HeapTypes::array.getBasic(Unshared)], 0u);
EXPECT_EQ(depths[HeapTypes::array.getBasic(Shared)], 2u);
EXPECT_EQ(depths[built[0]], 1u);
EXPECT_EQ(depths[built[1]], 0u);
EXPECT_EQ(depths[built[2]], 1u);
EXPECT_EQ(depths[built[3]], 0u);
}

// Test reuse of a previously built type as supertype.
Expand Down
29 changes: 29 additions & 0 deletions test/lit/passes/gufa-tnh.wast
Original file line number Diff line number Diff line change
Expand Up @@ -2034,3 +2034,32 @@
)
)
)

(module
;; CHECK: (type $0 (func (param i32) (result (ref null (shared any)))))

;; CHECK: (table $0 3 3 (ref null (shared any)))
(table $0 3 3 (ref null (shared any)))
;; CHECK: (elem $0 (table $0) (i32.const 0) (ref null (shared i31)) (item (ref.i31_shared
;; CHECK-NEXT: (i32.const 999)
;; CHECK-NEXT: )))
(elem $0 (table $0) (i32.const 0) (ref null (shared i31)) (item (ref.i31_shared (i32.const 999))))
;; CHECK: (export "get" (func $0))

;; CHECK: (func $0 (type $0) (param $0 i32) (result (ref null (shared any)))
;; CHECK-NEXT: (ref.cast (ref null (shared i31))
;; CHECK-NEXT: (table.get $0
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $0 (export "get") (param $0 i32) (result (ref null (shared any)))
;; Regression test for a bug where subtypes.h did not handle shared types
;; correctly, causing this example to be misoptimized to return null.
(ref.cast (ref null (shared i31))
(table.get $0
(i32.const 0)
)
)
)
)

0 comments on commit cf0d21a

Please sign in to comment.