diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/example/stack-utils.cpp | 113 | ||||
-rw-r--r-- | test/example/stack-utils.txt | 1 | ||||
-rw-r--r-- | test/example/type-builder.cpp | 219 | ||||
-rw-r--r-- | test/example/type-builder.txt | 1 | ||||
-rw-r--r-- | test/example/typeinfo.cpp | 38 | ||||
-rw-r--r-- | test/lit/passes/remove-unused-brs.wast | 29 | ||||
-rw-r--r-- | test/passes/remove-unused-brs_all-features.txt | 6 |
7 files changed, 385 insertions, 22 deletions
diff --git a/test/example/stack-utils.cpp b/test/example/stack-utils.cpp index 9ed3e1a8a..b5ac496ca 100644 --- a/test/example/stack-utils.cpp +++ b/test/example/stack-utils.cpp @@ -354,6 +354,118 @@ void test_signature_subtype() { } } +void test_signature_lub() { + std::cout << ";; Test stack signature lub\n"; + { + StackSignature a{Type::none, Type::none, StackSignature::Fixed}; + StackSignature b{Type::none, Type::none, StackSignature::Fixed}; + assert(StackSignature::haveLeastUpperBound(a, b)); + assert(StackSignature::getLeastUpperBound(a, b) == + (StackSignature{Type::none, Type::none, StackSignature::Fixed})); + } + { + StackSignature a{Type::none, Type::none, StackSignature::Polymorphic}; + StackSignature b{Type::none, Type::none, StackSignature::Fixed}; + assert(StackSignature::haveLeastUpperBound(a, b)); + assert(StackSignature::getLeastUpperBound(a, b) == + (StackSignature{Type::none, Type::none, StackSignature::Fixed})); + } + { + StackSignature a{Type::none, Type::none, StackSignature::Fixed}; + StackSignature b{Type::none, Type::none, StackSignature::Polymorphic}; + assert(StackSignature::haveLeastUpperBound(a, b)); + assert(StackSignature::getLeastUpperBound(a, b) == + (StackSignature{Type::none, Type::none, StackSignature::Fixed})); + } + { + StackSignature a{Type::i32, Type::none, StackSignature::Polymorphic}; + StackSignature b{Type::none, Type::i32, StackSignature::Polymorphic}; + assert(StackSignature::haveLeastUpperBound(a, b)); + assert(StackSignature::getLeastUpperBound(a, b) == + (StackSignature{Type::i32, Type::i32, StackSignature::Polymorphic})); + } + { + StackSignature a{Type::none, Type::i32, StackSignature::Polymorphic}; + StackSignature b{Type::i32, Type::none, StackSignature::Polymorphic}; + assert(StackSignature::haveLeastUpperBound(a, b)); + assert(StackSignature::getLeastUpperBound(a, b) == + (StackSignature{Type::i32, Type::i32, StackSignature::Polymorphic})); + } + { + StackSignature a{Type::none, Type::externref, StackSignature::Polymorphic}; + StackSignature b{Type::none, Type::funcref, StackSignature::Polymorphic}; + assert(StackSignature::haveLeastUpperBound(a, b)); + assert( + StackSignature::getLeastUpperBound(a, b) == + (StackSignature{Type::none, Type::anyref, StackSignature::Polymorphic})); + } + { + StackSignature a{Type::anyref, Type::none, StackSignature::Polymorphic}; + StackSignature b{Type::funcref, Type::none, StackSignature::Polymorphic}; + // assert(StackSignature::haveLeastUpperBound(a, b)); + // assert(StackSignature::getLeastUpperBound(a, b) == + // (StackSignature{Type::funcref, Type::none, + // StackSignature::Polymorphic})); + } + { + StackSignature a{ + {Type::i32, Type::funcref}, Type::funcref, StackSignature::Polymorphic}; + StackSignature b{ + Type::funcref, {Type::f32, Type::externref}, StackSignature::Polymorphic}; + assert(StackSignature::haveLeastUpperBound(a, b)); + assert(StackSignature::getLeastUpperBound(a, b) == + (StackSignature{{Type::i32, Type::funcref}, + {Type::f32, Type::anyref}, + StackSignature::Polymorphic})); + } + // No LUB + { + StackSignature a(Type::none, Type::i32, StackSignature::Fixed); + StackSignature b(Type::none, Type::f32, StackSignature::Fixed); + assert(!StackSignature::haveLeastUpperBound(a, b)); + } + { + StackSignature a(Type::none, Type::i32, StackSignature::Polymorphic); + StackSignature b(Type::none, Type::f32, StackSignature::Polymorphic); + assert(!StackSignature::haveLeastUpperBound(a, b)); + } + { + StackSignature a(Type::i32, Type::none, StackSignature::Fixed); + StackSignature b(Type::f32, Type::none, StackSignature::Fixed); + // assert(!StackSignature::haveLeastUpperBound(a, b)); + } + { + StackSignature a(Type::i32, Type::none, StackSignature::Polymorphic); + StackSignature b(Type::f32, Type::none, StackSignature::Polymorphic); + // assert(!StackSignature::haveLeastUpperBound(a, b)); + } + { + StackSignature a(Type::none, Type::none, StackSignature::Fixed); + StackSignature b(Type::none, Type::i32, StackSignature::Polymorphic); + assert(!StackSignature::haveLeastUpperBound(a, b)); + } + { + StackSignature a(Type::none, Type::none, StackSignature::Fixed); + StackSignature b(Type::i32, Type::none, StackSignature::Polymorphic); + assert(!StackSignature::haveLeastUpperBound(a, b)); + } + { + StackSignature a{Type::none, Type::i32, StackSignature::Fixed}; + StackSignature b{Type::i32, Type::none, StackSignature::Fixed}; + assert(!StackSignature::haveLeastUpperBound(a, b)); + } + { + StackSignature a{Type::none, Type::i32, StackSignature::Polymorphic}; + StackSignature b{Type::i32, Type::none, StackSignature::Fixed}; + assert(!StackSignature::haveLeastUpperBound(a, b)); + } + { + StackSignature a{Type::none, Type::i32, StackSignature::Fixed}; + StackSignature b{Type::i32, Type::none, StackSignature::Polymorphic}; + assert(!StackSignature::haveLeastUpperBound(a, b)); + } +} + void test_stack_flow() { std::cout << ";; Test stack flow\n"; { @@ -493,5 +605,6 @@ int main() { test_stack_signatures(); test_signature_composition(); test_signature_subtype(); + test_signature_lub(); test_stack_flow(); } diff --git a/test/example/stack-utils.txt b/test/example/stack-utils.txt index a61ed9ac5..d24119aab 100644 --- a/test/example/stack-utils.txt +++ b/test/example/stack-utils.txt @@ -14,4 +14,5 @@ ;; Test stack signatures ;; Test stack signature composition ;; Test stack signature subtyping +;; Test stack signature lub ;; Test stack flow diff --git a/test/example/type-builder.cpp b/test/example/type-builder.cpp index 29ff20f75..a228697e9 100644 --- a/test/example/type-builder.cpp +++ b/test/example/type-builder.cpp @@ -248,8 +248,227 @@ void test_recursive() { } } +void test_lub() { + std::cout << ";; Test LUBs\n"; + + auto LUB = [&](Type a, Type b) { + Type lubAB = Type::getLeastUpperBound(a, b); + Type lubBA = Type::getLeastUpperBound(b, a); + assert(lubAB == lubBA); + if (lubAB == Type::none) { + assert(!Type::hasLeastUpperBound(a, b)); + assert(!Type::hasLeastUpperBound(b, a)); + } else { + assert(Type::hasLeastUpperBound(a, b)); + assert(Type::hasLeastUpperBound(b, a)); + assert(Type::isSubType(a, lubAB)); + assert(Type::isSubType(b, lubAB)); + } + return lubAB; + }; + + { + // Basic Types + for (auto other : {Type::funcref, + Type::externref, + Type::anyref, + Type::eqref, + Type::i31ref, + Type::dataref}) { + assert(LUB(Type::anyref, other) == Type::anyref); + } + assert(LUB(Type::eqref, Type::funcref) == Type::anyref); + assert(LUB(Type::i31ref, Type::dataref) == Type(HeapType::eq, NonNullable)); + } + + { + // Nullable and non-nullable references + Type nullable(HeapType::any, Nullable); + Type nonNullable(HeapType::any, NonNullable); + assert(LUB(nullable, nullable) == nullable); + assert(LUB(nullable, nonNullable) == nullable); + assert(LUB(nonNullable, nonNullable) == nonNullable); + } + + { + // Funcref with specific signature + assert(LUB(Type::funcref, Type(Signature(), Nullable)) == Type::funcref); + } + + { + // Incompatible signatures + Type a(Signature(Type::none, Type::anyref), Nullable); + Type b(Signature(Type::anyref, Type::none), Nullable); + assert(LUB(a, b) == Type::funcref); + } + + { + // Signatures incompatible in tuple size + Type a(Signature(Type::none, {Type::anyref, Type::anyref}), Nullable); + Type b(Signature(Type::none, {Type::anyref, Type::anyref, Type::anyref}), + Nullable); + assert(LUB(a, b) == Type::funcref); + } + + // { + // // Covariance of function results + // Type a(Signature(Type::none, {Type::eqref, Type::funcref}), Nullable); + // Type b(Signature(Type::none, {Type::funcref, Type::eqref}), Nullable); + // assert(LUB(a, b) == Type(Signature(Type::none, {Type::anyref, + // Type::anyref}), Nullable)); + // } + + // TODO: Test contravariance in function parameters once that is supported. + + // { + // // Nested signatures + // Type baseA(Signature(Type::none, Type::eqref), Nullable); + // Type baseB(Signature(Type::none, Type::funcref), Nullable); + // Type a(Signature(Type::none, baseA), Nullable); + // Type b(Signature(Type::none, baseB), Nullable); + // Type baseLub(Signature(Type::none, Type::anyref), Nullable); + // Type lub(Signature(Type::none, baseLub), Nullable); + // assert(LUB(a, b) == lub); + // } + + // TODO: Test recursive signatures once signature subtyping is supported. + + { + // Mutable fields are invariant + Type a(Array(Field(Type::eqref, Mutable)), Nullable); + Type b(Array(Field(Type::funcref, Mutable)), Nullable); + assert(LUB(a, b) == Type(HeapType::data, Nullable)); + } + + { + // Immutable fields are covariant + Type a(Array(Field(Type::eqref, Immutable)), Nullable); + Type b(Array(Field(Type::funcref, Immutable)), Nullable); + Type lub(Array(Field(Type::anyref, Immutable)), Nullable); + assert(LUB(a, b) == lub); + } + + { + // Depth subtyping + Type a(Struct({Field(Type::eqref, Immutable)}), Nullable); + Type b(Struct({Field(Type::funcref, Immutable)}), Nullable); + Type lub(Struct({Field(Type::anyref, Immutable)}), Nullable); + assert(LUB(a, b) == lub); + } + + { + // Width subtyping + Type a(Struct({Field(Type::i32, Immutable)}), Nullable); + Type b(Struct({Field(Type::i32, Immutable), Field(Type::i32, Immutable)}), + Nullable); + assert(LUB(a, b) == a); + } + + { + // Width subtyping with different suffixes + Type a(Struct({Field(Type::i32, Immutable), Field(Type::i64, Immutable)}), + Nullable); + Type b(Struct({Field(Type::i32, Immutable), Field(Type::f32, Immutable)}), + Nullable); + Type lub(Struct({Field(Type::i32, Immutable)}), Nullable); + assert(LUB(a, b) == lub); + } + + { + // Width and depth subtyping with different suffixes + Type a(Struct({Field(Type::eqref, Immutable), Field(Type::i64, Immutable)}), + Nullable); + Type b( + Struct({Field(Type::funcref, Immutable), Field(Type::f32, Immutable)}), + Nullable); + Type lub(Struct({Field(Type::anyref, Immutable)}), Nullable); + assert(LUB(a, b) == lub); + } + + { + // No common prefix + Type a( + Struct({Field(Type::i32, Immutable), Field(Type::anyref, Immutable)}), + Nullable); + Type b( + Struct({Field(Type::f32, Immutable), Field(Type::anyref, Immutable)}), + Nullable); + Type lub(Struct(), Nullable); + assert(LUB(a, b) == lub); + } + + { + // Nested structs + Type innerA(Struct({Field(Type::eqref, Immutable)}), Nullable); + Type innerB(Struct({Field(Type::funcref, Immutable)}), Nullable); + Type innerLub(Struct({Field(Type::anyref, Immutable)}), Nullable); + Type a(Struct({Field(innerA, Immutable)}), Nullable); + Type b(Struct({Field(innerB, Immutable)}), Nullable); + Type lub(Struct({Field(innerLub, Immutable)}), Nullable); + assert(LUB(a, b) == lub); + } + + { + // Recursive structs + TypeBuilder builder(2); + Type tempA = builder.getTempRefType(builder[0], Nullable); + Type tempB = builder.getTempRefType(builder[1], Nullable); + builder[0] = + Struct({Field(tempB, Immutable), Field(Type::eqref, Immutable)}); + builder[1] = + Struct({Field(tempA, Immutable), Field(Type::funcref, Immutable)}); + auto built = builder.build(); + Type a(built[0], Nullable); + Type b(built[1], Nullable); + + TypeBuilder lubBuilder(1); + Type tempLub = builder.getTempRefType(lubBuilder[0], Nullable); + lubBuilder[0] = + Struct({Field(tempLub, Immutable), Field(Type::anyref, Immutable)}); + built = lubBuilder.build(); + Type lub(built[0], Nullable); + + assert(LUB(a, b) == lub); + } + + { + // Incompatible Rtts + Type a{Rtt(HeapType::eq)}; + Type b{Rtt(HeapType::func)}; + assert(LUB(a, b) == Type::none); + } + + { + // Rtts with matching depth + Type a(Rtt(42, HeapType::any)); + assert(LUB(a, a) == a); + } + + { + // Rtts with mismatched depth + Type a(Rtt(42, HeapType::any)); + Type b(Rtt(50, HeapType::any)); + Type lub{Rtt(HeapType::any)}; + assert(LUB(a, b) == lub); + } + + { + // Rtts with and without depth + Type a(Rtt(42, HeapType::any)); + Type b{Rtt(HeapType::any)}; + assert(LUB(a, b) == b); + } + + { + // Rtts without depth + Type a{Rtt(HeapType::any)}; + assert(LUB(a, a) == a); + } +} + int main() { test_builder(); test_canonicalization(); test_recursive(); + test_lub(); } diff --git a/test/example/type-builder.txt b/test/example/type-builder.txt index f65a94321..d9f469461 100644 --- a/test/example/type-builder.txt +++ b/test/example/type-builder.txt @@ -46,3 +46,4 @@ After building types: (func (param anyref) (result (ref null ...1))) (func (param anyref) (result (ref null ...1))) +;; Test LUBs diff --git a/test/example/typeinfo.cpp b/test/example/typeinfo.cpp index 94d7c2317..f4306b391 100644 --- a/test/example/typeinfo.cpp +++ b/test/example/typeinfo.cpp @@ -64,13 +64,13 @@ void test_compound() { Type(otherSignature, NonNullable).getID()); } { - Struct struct_({}); + Struct struct_{}; assert(Type(struct_, NonNullable).getID() == Type(struct_, NonNullable).getID()); assert(Type(struct_, NonNullable).getID() != Type(struct_, Nullable).getID()); - Struct sameStruct({}); + Struct sameStruct{}; assert(Type(struct_, NonNullable).getID() == Type(sameStruct, NonNullable).getID()); @@ -121,10 +121,10 @@ void test_compound() { assert(rtt != otherHeapTypeRtt); assert(Type(rtt).getID() != Type(otherHeapTypeRtt).getID()); - Rtt structRtt(0, Struct({})); + Rtt structRtt(0, Struct{}); assert(Type(structRtt).getID() == Type(structRtt).getID()); - Rtt sameStructRtt(0, Struct({})); + Rtt sameStructRtt(0, Struct{}); assert(structRtt == sameStructRtt); assert(Type(structRtt).getID() == Type(sameStructRtt).getID()); @@ -153,7 +153,7 @@ void test_printing() { std::cout << Type(HeapType::i31, Nullable) << "\n"; std::cout << Type(HeapType::i31, NonNullable) << "\n"; std::cout << HeapType(Signature(Type::none, Type::none)) << "\n"; - std::cout << HeapType(Struct({})) << "\n"; + std::cout << HeapType(Struct{}) << "\n"; std::cout << HeapType(Array({Type::i32, Immutable})) << "\n"; } { @@ -169,7 +169,7 @@ void test_printing() { } { std::cout << "\n;; Struct\n"; - Struct emptyStruct({}); + Struct emptyStruct{}; std::cout << emptyStruct << "\n"; std::cout << Type(emptyStruct, NonNullable) << "\n"; std::cout << Type(emptyStruct, Nullable) << "\n"; @@ -197,7 +197,7 @@ void test_printing() { } { std::cout << "\n;; Tuple\n"; - Tuple emptyTuple({}); + Tuple emptyTuple{}; std::cout << emptyTuple << "\n"; std::cout << Type(emptyTuple) << "\n"; Tuple tuple({ @@ -223,7 +223,7 @@ void test_printing() { Rtt signatureRtt(6, Signature(Type::none, Type::none)); std::cout << signatureRtt << "\n"; std::cout << Type(signatureRtt) << "\n"; - Rtt structRtt(7, Struct({})); + Rtt structRtt(7, Struct{}); std::cout << structRtt << "\n"; std::cout << Type(structRtt) << "\n"; Rtt arrayRtt(8, Array({Type::i32, Immutable})); @@ -232,18 +232,18 @@ void test_printing() { } { std::cout << "\n;; Signature of references (param/result)\n"; - Signature signature(Type(Struct({}), Nullable), + Signature signature(Type(Struct{}, Nullable), Type(Array({Type::i32, Mutable}), NonNullable)); std::cout << signature << "\n"; } { std::cout << "\n;; Signature of references (params/results)\n"; Signature signature(Type({ - Type(Struct({}), Nullable), + Type(Struct{}, Nullable), Type(Array({Type::i32, Mutable}), NonNullable), }), Type({ - Type(Struct({}), NonNullable), + Type(Struct{}, NonNullable), Type(Array({Type::i32, Immutable}), Nullable), })); std::cout << signature << "\n"; @@ -260,10 +260,10 @@ void test_printing() { std::cout << Type(structOfSignature, NonNullable) << "\n"; std::cout << Type(structOfSignature, Nullable) << "\n"; Struct structOfStruct({ - {Type(Struct({}), NonNullable), Immutable}, - {Type(Struct({}), NonNullable), Mutable}, - {Type(Struct({}), Nullable), Immutable}, - {Type(Struct({}), Nullable), Mutable}, + {Type(Struct{}, NonNullable), Immutable}, + {Type(Struct{}, NonNullable), Mutable}, + {Type(Struct{}, Nullable), Immutable}, + {Type(Struct{}, Nullable), Mutable}, }); std::cout << structOfStruct << "\n"; std::cout << Type(structOfStruct, NonNullable) << "\n"; @@ -280,7 +280,7 @@ void test_printing() { Struct structOfEverything({ {Type::i32, Mutable}, {Type(Signature(Type::none, Type::none), Nullable), Mutable}, - {Type(Struct({}), Nullable), Mutable}, + {Type(Struct{}, Nullable), Mutable}, {Type(Array({Type::i32, Mutable}), Nullable), Mutable}, }); std::cout << structOfEverything << "\n"; @@ -294,7 +294,7 @@ void test_printing() { std::cout << arrayOfSignature << "\n"; std::cout << Type(arrayOfSignature, NonNullable) << "\n"; std::cout << Type(arrayOfSignature, Nullable) << "\n"; - Array arrayOfStruct({Type(Struct({}), Nullable), Mutable}); + Array arrayOfStruct({Type(Struct{}, Nullable), Mutable}); std::cout << arrayOfStruct << "\n"; std::cout << Type(arrayOfStruct, NonNullable) << "\n"; std::cout << Type(arrayOfStruct, Nullable) << "\n"; @@ -309,8 +309,8 @@ void test_printing() { Tuple tuple({ Type(Signature(Type::none, Type::none), NonNullable), Type(Signature(Type::none, Type::none), Nullable), - Type(Struct({}), NonNullable), - Type(Struct({}), Nullable), + Type(Struct{}, NonNullable), + Type(Struct{}, Nullable), Type(Array({Type::i32, Immutable}), NonNullable), Type(Array({Type::i32, Immutable}), Nullable), }); diff --git a/test/lit/passes/remove-unused-brs.wast b/test/lit/passes/remove-unused-brs.wast new file mode 100644 index 000000000..bd4d80bcd --- /dev/null +++ b/test/lit/passes/remove-unused-brs.wast @@ -0,0 +1,29 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --remove-unused-brs -all -S -o - \ +;; RUN: | filecheck %s + + +(module + (type $none_=>_i32 (func (result i32))) + (type $i32_=>_none (func (param i32))) + + ;; Regression test in which we need to calculate a proper LUB. + ;; CHECK: (func $selectify-fresh-lub (param $x i32) (result anyref) + ;; CHECK-NEXT: (select (result funcref) + ;; CHECK-NEXT: (ref.null $none_=>_i32) + ;; CHECK-NEXT: (ref.null $i32_=>_none) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $selectify-fresh-lub (param $x i32) (result anyref) + (if + (local.get $x) + (return + (ref.null $none_=>_i32) + ) + (return + (ref.null $i32_=>_none) + ) + ) + ) +) diff --git a/test/passes/remove-unused-brs_all-features.txt b/test/passes/remove-unused-brs_all-features.txt index 5cf83a0d7..cd5afe595 100644 --- a/test/passes/remove-unused-brs_all-features.txt +++ b/test/passes/remove-unused-brs_all-features.txt @@ -2,8 +2,8 @@ (type $vector (array (mut i32))) (type $struct (struct (field (ref null $vector)))) (type $i32_=>_none (func (param i32))) - (type $none_=>_none (func)) (type $ref|func|_=>_none (func (param (ref func)))) + (type $none_=>_none (func)) (type $none_=>_i32 (func (result i32))) (type $none_=>_f64 (func (result f64))) (type $i32_=>_funcref (func (param i32) (result funcref))) @@ -69,7 +69,7 @@ (i32.const 2) ) (drop - (block $func (result funcref) + (block $func (result (ref $ref|func|_=>_none)) (drop (br $func (ref.func $br_on-to-br) @@ -85,7 +85,7 @@ (i32.const 4) ) (drop - (block $data (result dataref) + (block $data (result (ref $vector)) (drop (br $data (array.new_default_with_rtt $vector |