summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/example/stack-utils.cpp113
-rw-r--r--test/example/stack-utils.txt1
-rw-r--r--test/example/type-builder.cpp219
-rw-r--r--test/example/type-builder.txt1
-rw-r--r--test/example/typeinfo.cpp38
-rw-r--r--test/lit/passes/remove-unused-brs.wast29
-rw-r--r--test/passes/remove-unused-brs_all-features.txt6
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