From cf0d21a35c13bd9479921bfd4d4b8d4318d20d67 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Fri, 19 Jul 2024 15:25:32 -0700 Subject: [PATCH] [threads] Calculate shared heap type depths in subtypes.h Fixes #6776. --- src/ir/subtypes.h | 21 ++++++++++----- test/gtest/type-builder.cpp | 51 +++++++++++++++++++++++++---------- test/lit/passes/gufa-tnh.wast | 29 ++++++++++++++++++++ 3 files changed, 80 insertions(+), 21 deletions(-) diff --git a/src/ir/subtypes.h b/src/ir/subtypes.h index 8645afb9898..767c79fd7ca 100644 --- a/src/ir/subtypes.h +++ b/src/ir/subtypes.h @@ -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; } diff --git a/test/gtest/type-builder.cpp b/test/gtest/type-builder.cpp index 2ad43d18980..97943551f5b 100644 --- a/test/gtest/type-builder.cpp +++ b/test/gtest/type-builder.cpp @@ -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); @@ -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. diff --git a/test/lit/passes/gufa-tnh.wast b/test/lit/passes/gufa-tnh.wast index d276421f888..ecf031bbf9c 100644 --- a/test/lit/passes/gufa-tnh.wast +++ b/test/lit/passes/gufa-tnh.wast @@ -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) + ) + ) + ) +)