| #include <cassert> | |
| #include <iostream> | |
| #include "ir/stack-utils.h" | |
| #include "literal.h" | |
| #include "support/mixed_arena.h" | |
| #include "wasm-builder.h" | |
| #include "wasm-type.h" | |
| #include "wasm.h" | |
| using namespace wasm; | |
| Module module; | |
| Builder builder(module); | |
| void test_remove_nops() { | |
| std::cout << ";; Test removeNops\n"; | |
| auto* block = builder.makeBlock( | |
| { | |
| builder.makeNop(), | |
| builder.makeConst(Literal(int32_t(0))), | |
| builder.makeNop(), | |
| builder.makeConst(Literal(int64_t(0))), | |
| builder.makeNop(), | |
| builder.makeNop(), | |
| }, | |
| Type{Type::i32, Type::i64}); | |
| std::cout << *block << '\n'; | |
| StackUtils::removeNops(block); | |
| std::cout << *block << '\n'; | |
| } | |
| void test_stack_signatures() { | |
| std::cout << ";; Test stack signatures\n"; | |
| // Typed block | |
| auto* block = builder.makeBlock({builder.makeUnreachable()}, Type::f32); | |
| assert(StackSignature(block) == | |
| (StackSignature{Type::none, Type::f32, StackSignature::Fixed})); | |
| // Unreachable block | |
| auto* unreachable = | |
| builder.makeBlock({builder.makeUnreachable()}, Type::unreachable); | |
| assert(StackSignature(unreachable) == | |
| (StackSignature{Type::none, Type::none, StackSignature::Polymorphic})); | |
| { | |
| // Typed loop | |
| auto* loop = builder.makeLoop("loop", unreachable, Type::f32); | |
| assert(StackSignature(loop) == | |
| (StackSignature{Type::none, Type::f32, StackSignature::Fixed})); | |
| } | |
| { | |
| // Unreachable loop | |
| auto* loop = builder.makeLoop("loop", unreachable, Type::unreachable); | |
| assert( | |
| StackSignature(loop) == | |
| (StackSignature{Type::none, Type::none, StackSignature::Polymorphic})); | |
| } | |
| { | |
| // If (no else) | |
| auto* if_ = builder.makeIf( | |
| builder.makePop(Type::i32), unreachable, nullptr, Type::none); | |
| assert(StackSignature(if_) == | |
| (StackSignature{Type::i32, Type::none, StackSignature::Fixed})); | |
| } | |
| { | |
| // If (with else) | |
| auto* if_ = | |
| builder.makeIf(builder.makePop(Type::i32), block, block, Type::f32); | |
| assert(StackSignature(if_) == | |
| (StackSignature{Type::i32, Type::f32, StackSignature::Fixed})); | |
| } | |
| { | |
| // Call | |
| auto* call = | |
| builder.makeCall("foo", | |
| {builder.makePop(Type::i32), builder.makePop(Type::f32)}, | |
| {Type::i64, Type::f64}); | |
| assert(StackSignature(call) == (StackSignature{{Type::i32, Type::f32}, | |
| {Type::i64, Type::f64}, | |
| StackSignature::Fixed})); | |
| } | |
| { | |
| // Return Call | |
| auto* call = | |
| builder.makeCall("bar", | |
| {builder.makePop(Type::i32), builder.makePop(Type::f32)}, | |
| Type::unreachable, | |
| StackSignature::Polymorphic); | |
| assert(StackSignature(call) == | |
| (StackSignature{ | |
| {Type::i32, Type::f32}, Type::none, StackSignature::Polymorphic})); | |
| } | |
| { | |
| // Return | |
| auto* ret = builder.makeReturn(builder.makePop(Type::i32)); | |
| assert( | |
| StackSignature(ret) == | |
| (StackSignature{Type::i32, Type::none, StackSignature::Polymorphic})); | |
| } | |
| { | |
| // Multivalue return | |
| auto* ret = builder.makeReturn(builder.makePop({Type::i32, Type::f32})); | |
| assert(StackSignature(ret) == | |
| (StackSignature{ | |
| {Type::i32, Type::f32}, Type::none, StackSignature::Polymorphic})); | |
| } | |
| } | |
| void test_signature_composition() { | |
| std::cout << ";; Test stack signature composition\n"; | |
| // No unreachables | |
| { | |
| StackSignature a{Type::none, {Type::f32, Type::i32}, StackSignature::Fixed}; | |
| StackSignature b{{Type::f32, Type::i32}, Type::none, StackSignature::Fixed}; | |
| assert(a.composes(b)); | |
| assert(a + b == | |
| (StackSignature{Type::none, Type::none, StackSignature::Fixed})); | |
| } | |
| { | |
| StackSignature a{Type::none, Type::i32, StackSignature::Fixed}; | |
| StackSignature b{{Type::f32, Type::i32}, Type::none, StackSignature::Fixed}; | |
| assert(a.composes(b)); | |
| assert(a + b == | |
| StackSignature(Type::f32, Type::none, StackSignature::Fixed)); | |
| } | |
| { | |
| StackSignature a{Type::none, {Type::f32, Type::i32}, StackSignature::Fixed}; | |
| StackSignature b{Type::i32, Type::none, StackSignature::Fixed}; | |
| assert(a.composes(b)); | |
| assert(a + b == | |
| (StackSignature{Type::none, Type::f32, StackSignature::Fixed})); | |
| } | |
| { | |
| StackSignature a{Type::none, Type::f32, StackSignature::Fixed}; | |
| StackSignature b{{Type::f32, Type::i32}, Type::none, StackSignature::Fixed}; | |
| assert(!a.composes(b)); | |
| } | |
| { | |
| StackSignature a{Type::none, {Type::f32, Type::i32}, StackSignature::Fixed}; | |
| StackSignature b{Type::f32, Type::none, StackSignature::Fixed}; | |
| assert(!a.composes(b)); | |
| } | |
| // First unreachable | |
| { | |
| StackSignature a{ | |
| Type::none, {Type::f32, Type::i32}, StackSignature::Polymorphic}; | |
| StackSignature b{{Type::f32, Type::i32}, Type::none, StackSignature::Fixed}; | |
| assert(a.composes(b)); | |
| assert(a + b == (StackSignature{ | |
| Type::none, Type::none, StackSignature::Polymorphic})); | |
| } | |
| { | |
| StackSignature a{Type::none, Type::i32, StackSignature::Polymorphic}; | |
| StackSignature b{{Type::f32, Type::i32}, Type::none, StackSignature::Fixed}; | |
| assert(a.composes(b)); | |
| assert(a + b == | |
| StackSignature(Type::none, Type::none, StackSignature::Polymorphic)); | |
| } | |
| { | |
| StackSignature a{ | |
| Type::none, {Type::f32, Type::i32}, StackSignature::Polymorphic}; | |
| StackSignature b{Type::i32, Type::none, StackSignature::Fixed}; | |
| assert(a.composes(b)); | |
| assert(a + b == (StackSignature{ | |
| Type::none, Type::f32, StackSignature::Polymorphic})); | |
| } | |
| { | |
| StackSignature a{Type::none, Type::f32, StackSignature::Polymorphic}; | |
| StackSignature b{{Type::f32, Type::i32}, Type::none, StackSignature::Fixed}; | |
| assert(!a.composes(b)); | |
| } | |
| { | |
| StackSignature a{ | |
| Type::none, {Type::f32, Type::i32}, StackSignature::Polymorphic}; | |
| StackSignature b{Type::f32, Type::none, StackSignature::Fixed}; | |
| assert(!a.composes(b)); | |
| } | |
| // Second unreachable | |
| { | |
| StackSignature a{Type::none, {Type::f32, Type::i32}, StackSignature::Fixed}; | |
| StackSignature b{ | |
| {Type::f32, Type::i32}, Type::none, StackSignature::Polymorphic}; | |
| assert(a.composes(b)); | |
| assert(a + b == (StackSignature{ | |
| Type::none, Type::none, StackSignature::Polymorphic})); | |
| } | |
| { | |
| StackSignature a{Type::none, Type::i32, StackSignature::Fixed}; | |
| StackSignature b{ | |
| {Type::f32, Type::i32}, Type::none, StackSignature::Polymorphic}; | |
| assert(a.composes(b)); | |
| assert(a + b == | |
| StackSignature(Type::f32, Type::none, StackSignature::Polymorphic)); | |
| } | |
| { | |
| StackSignature a{Type::none, {Type::f32, Type::i32}, StackSignature::Fixed}; | |
| StackSignature b{Type::i32, Type::none, StackSignature::Polymorphic}; | |
| assert(a.composes(b)); | |
| assert(a + b == (StackSignature{ | |
| Type::none, Type::none, StackSignature::Polymorphic})); | |
| } | |
| { | |
| StackSignature a{Type::none, Type::f32, StackSignature::Fixed}; | |
| StackSignature b{ | |
| {Type::f32, Type::i32}, Type::none, StackSignature::Polymorphic}; | |
| assert(!a.composes(b)); | |
| } | |
| { | |
| StackSignature a{Type::none, {Type::f32, Type::i32}, StackSignature::Fixed}; | |
| StackSignature b{Type::f32, Type::none, StackSignature::Polymorphic}; | |
| assert(!a.composes(b)); | |
| } | |
| // Both unreachable | |
| { | |
| StackSignature a{ | |
| Type::none, {Type::f32, Type::i32}, StackSignature::Polymorphic}; | |
| StackSignature b{ | |
| {Type::f32, Type::i32}, Type::none, StackSignature::Polymorphic}; | |
| assert(a.composes(b)); | |
| assert(a + b == (StackSignature{ | |
| Type::none, Type::none, StackSignature::Polymorphic})); | |
| } | |
| { | |
| StackSignature a{Type::none, Type::i32, StackSignature::Polymorphic}; | |
| StackSignature b{ | |
| {Type::f32, Type::i32}, Type::none, StackSignature::Polymorphic}; | |
| assert(a.composes(b)); | |
| assert(a + b == | |
| StackSignature(Type::none, Type::none, StackSignature::Polymorphic)); | |
| } | |
| { | |
| StackSignature a{ | |
| Type::none, {Type::f32, Type::i32}, StackSignature::Polymorphic}; | |
| StackSignature b{Type::i32, Type::none, StackSignature::Polymorphic}; | |
| assert(a.composes(b)); | |
| assert(a + b == (StackSignature{ | |
| Type::none, Type::none, StackSignature::Polymorphic})); | |
| } | |
| { | |
| StackSignature a{Type::none, Type::f32, StackSignature::Polymorphic}; | |
| StackSignature b{ | |
| {Type::f32, Type::i32}, Type::none, StackSignature::Polymorphic}; | |
| assert(!a.composes(b)); | |
| } | |
| { | |
| StackSignature a{ | |
| Type::none, {Type::f32, Type::i32}, StackSignature::Polymorphic}; | |
| StackSignature b{Type::f32, Type::none, StackSignature::Polymorphic}; | |
| assert(!a.composes(b)); | |
| } | |
| } | |
| void test_signature_subtype() { | |
| Type eqref = Type(HeapType::eq, Nullable); | |
| Type anyref = Type(HeapType::any, Nullable); | |
| std::cout << ";; Test stack signature subtyping\n"; | |
| // Differences in unreachability only | |
| { | |
| StackSignature a(Type::none, Type::none, StackSignature::Polymorphic); | |
| StackSignature b(Type::none, Type::none, StackSignature::Fixed); | |
| assert(StackSignature::isSubType(a, b)); | |
| assert(!StackSignature::isSubType(b, a)); | |
| } | |
| // Covariance of results | |
| { | |
| StackSignature a(Type::none, eqref, StackSignature::Fixed); | |
| StackSignature b(Type::none, anyref, StackSignature::Fixed); | |
| assert(StackSignature::isSubType(a, b)); | |
| assert(!StackSignature::isSubType(b, a)); | |
| } | |
| // Contravariance of params | |
| { | |
| StackSignature a(anyref, Type::none, StackSignature::Fixed); | |
| StackSignature b(eqref, Type::none, StackSignature::Fixed); | |
| assert(StackSignature::isSubType(a, b)); | |
| assert(!StackSignature::isSubType(b, a)); | |
| } | |
| // First not unreachable | |
| { | |
| StackSignature a(Type::i32, Type::f32, StackSignature::Fixed); | |
| StackSignature b(Type::i32, Type::f32, StackSignature::Fixed); | |
| assert(StackSignature::isSubType(a, b)); | |
| } | |
| { | |
| StackSignature a(Type::i32, Type::f32, StackSignature::Fixed); | |
| StackSignature b( | |
| {Type::i64, Type::i32}, {Type::i64, Type::f32}, StackSignature::Fixed); | |
| assert(StackSignature::isSubType(a, b)); | |
| } | |
| { | |
| StackSignature a(Type::i32, Type::f32, StackSignature::Fixed); | |
| StackSignature b({Type::i64, Type::i32}, | |
| {Type::i64, Type::i64, Type::f32}, | |
| StackSignature::Fixed); | |
| assert(!StackSignature::isSubType(a, b)); | |
| } | |
| { | |
| StackSignature a(Type::i32, Type::f32, StackSignature::Fixed); | |
| StackSignature b( | |
| {Type::i64, Type::i32}, {Type::f64, Type::f32}, StackSignature::Fixed); | |
| assert(!StackSignature::isSubType(a, b)); | |
| } | |
| { | |
| StackSignature a(Type::i32, Type::f32, StackSignature::Fixed); | |
| StackSignature b(Type::none, Type::f32, StackSignature::Fixed); | |
| assert(!StackSignature::isSubType(a, b)); | |
| } | |
| { | |
| StackSignature a(Type::i32, Type::f32, StackSignature::Fixed); | |
| StackSignature b(Type::i32, Type::none, StackSignature::Fixed); | |
| assert(!StackSignature::isSubType(a, b)); | |
| } | |
| { | |
| StackSignature a(Type::i32, Type::f32, StackSignature::Fixed); | |
| StackSignature b(Type::f32, Type::i32, StackSignature::Fixed); | |
| assert(!StackSignature::isSubType(a, b)); | |
| } | |
| // First unreachable | |
| { | |
| StackSignature a(Type::i32, Type::f32, StackSignature::Polymorphic); | |
| StackSignature b(Type::i32, Type::f32, StackSignature::Fixed); | |
| assert(StackSignature::isSubType(a, b)); | |
| } | |
| { | |
| StackSignature a(Type::i32, Type::f32, StackSignature::Polymorphic); | |
| StackSignature b( | |
| {Type::i64, Type::i32}, {Type::i64, Type::f32}, StackSignature::Fixed); | |
| assert(StackSignature::isSubType(a, b)); | |
| } | |
| { | |
| StackSignature a(Type::i32, Type::f32, StackSignature::Polymorphic); | |
| StackSignature b({Type::i64, Type::i32}, | |
| {Type::i64, Type::i64, Type::f32}, | |
| StackSignature::Fixed); | |
| assert(StackSignature::isSubType(a, b)); | |
| } | |
| { | |
| StackSignature a(Type::i32, Type::f32, StackSignature::Polymorphic); | |
| StackSignature b( | |
| {Type::i64, Type::i32}, {Type::f64, Type::f32}, StackSignature::Fixed); | |
| assert(StackSignature::isSubType(a, b)); | |
| } | |
| { | |
| StackSignature a(Type::i32, Type::f32, StackSignature::Polymorphic); | |
| StackSignature b(Type::none, Type::f32, StackSignature::Fixed); | |
| assert(!StackSignature::isSubType(a, b)); | |
| } | |
| { | |
| StackSignature a(Type::i32, Type::f32, StackSignature::Polymorphic); | |
| StackSignature b(Type::i32, Type::none, StackSignature::Fixed); | |
| assert(!StackSignature::isSubType(a, b)); | |
| } | |
| { | |
| StackSignature a(Type::i32, Type::f32, StackSignature::Polymorphic); | |
| StackSignature b(Type::f32, Type::i32, StackSignature::Fixed); | |
| assert(!StackSignature::isSubType(a, b)); | |
| } | |
| } | |
| void test_signature_lub() { | |
| Type eqref = Type(HeapType::eq, Nullable); | |
| Type anyref = Type(HeapType::any, Nullable); | |
| 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, anyref, StackSignature::Polymorphic}; | |
| StackSignature b{Type::none, eqref, StackSignature::Polymorphic}; | |
| assert(StackSignature::haveLeastUpperBound(a, b)); | |
| assert(StackSignature::getLeastUpperBound(a, b) == | |
| (StackSignature{Type::none, anyref, StackSignature::Polymorphic})); | |
| } | |
| { | |
| StackSignature a{anyref, Type::none, StackSignature::Polymorphic}; | |
| StackSignature b{eqref, Type::none, StackSignature::Polymorphic}; | |
| // assert(StackSignature::haveLeastUpperBound(a, b)); | |
| // assert(StackSignature::getLeastUpperBound(a, b) == | |
| // (StackSignature{eqref, Type::none, | |
| // StackSignature::Polymorphic})); | |
| } | |
| { | |
| StackSignature a{{Type::i32, eqref}, eqref, StackSignature::Polymorphic}; | |
| StackSignature b{eqref, {Type::f32, anyref}, StackSignature::Polymorphic}; | |
| assert(StackSignature::haveLeastUpperBound(a, b)); | |
| assert(StackSignature::getLeastUpperBound(a, b) == | |
| (StackSignature{{Type::i32, eqref}, | |
| {Type::f32, 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"; | |
| { | |
| // Simple case: | |
| // foo | |
| // │i32 | |
| // bar | |
| // │f32 | |
| // end | |
| auto* foo = builder.makeCall("foo", {}, Type::i32); | |
| auto* bar = | |
| builder.makeCall("bar", {builder.makePop(Type::i32)}, Type::f32); | |
| auto* block = builder.makeBlock({foo, bar}, Type::f32); | |
| StackFlow flow(block); | |
| auto fooSrcs = flow.srcs.find(foo); | |
| assert(fooSrcs != flow.srcs.end()); | |
| assert(fooSrcs->second.size() == 0); | |
| auto fooDests = flow.dests.find(foo); | |
| assert(fooDests != flow.dests.end()); | |
| assert(fooDests->second.size() == 1); | |
| assert(fooDests->second[0] == | |
| (StackFlow::Location{bar, 0, Type::i32, false})); | |
| auto barSrcs = flow.srcs.find(bar); | |
| assert(barSrcs != flow.dests.end()); | |
| assert(barSrcs->second.size() == 1); | |
| assert(barSrcs->second[0] == | |
| (StackFlow::Location{foo, 0, Type::i32, false})); | |
| auto barDests = flow.dests.find(bar); | |
| assert(barDests != flow.dests.end()); | |
| assert(barDests->second.size() == 1); | |
| assert(barDests->second[0] == | |
| (StackFlow::Location{block, 0, Type::f32, false})); | |
| auto blockSrcs = flow.srcs.find(block); | |
| assert(blockSrcs != flow.srcs.end()); | |
| assert(blockSrcs->second.size() == 1); | |
| assert(blockSrcs->second[0] == | |
| (StackFlow::Location{bar, 0, Type::f32, false})); | |
| } | |
| { | |
| // Interesting case: | |
| // foo | |
| // ├─────┬─────┐ | |
| // │i32 │f32 │i64 | |
| // │ │ bar | |
| // │ │ │f64 | |
| // │ baz╶───┘ | |
| // │ ├─────┐ | |
| // ╵ ╵i64 │f32 | |
| // ret╶─────────┘ | |
| // ╷ ╷ ╷ | |
| // │i64 │f64 │i32 | |
| // │ quux╶──┘ | |
| // end | |
| auto* foo = builder.makeCall("foo", {}, {Type::i32, Type::f32, Type::i64}); | |
| auto* bar = | |
| builder.makeCall("bar", {builder.makePop(Type::i64)}, Type::f64); | |
| auto* baz = | |
| builder.makeCall("baz", | |
| {builder.makePop(Type::f32), builder.makePop(Type::f64)}, | |
| {Type::i64, Type::f32}); | |
| auto* ret = builder.makeReturn(builder.makePop(Type::f32)); | |
| auto* quux = | |
| builder.makeCall("quux", | |
| {builder.makePop(Type::f64), builder.makePop(Type::i32)}, | |
| Type::none); | |
| auto* block = builder.makeBlock({foo, bar, baz, ret, quux}, Type::i64); | |
| StackFlow flow(block); | |
| assert(flow.srcs.find(foo)->second.size() == 0); | |
| const auto& fooDests = flow.dests[foo]; | |
| assert(fooDests.size() == 3); | |
| assert(fooDests[0] == (StackFlow::Location{ret, 0, Type::i32, true})); | |
| assert(fooDests[1] == (StackFlow::Location{baz, 0, Type::f32, false})); | |
| assert(fooDests[2] == (StackFlow::Location{bar, 0, Type::i64, false})); | |
| const auto& barSrcs = flow.srcs[bar]; | |
| assert(barSrcs.size() == 1); | |
| assert(barSrcs[0] == (StackFlow::Location{foo, 2, Type::i64, false})); | |
| const auto& barDests = flow.dests[bar]; | |
| assert(barDests.size() == 1); | |
| assert(barDests[0] == (StackFlow::Location{baz, 1, Type::f64, false})); | |
| const auto& bazSrcs = flow.srcs[baz]; | |
| assert(bazSrcs.size() == 2); | |
| assert(bazSrcs[0] == (StackFlow::Location{foo, 1, Type::f32, false})); | |
| assert(bazSrcs[1] == (StackFlow::Location{bar, 0, Type::f64, false})); | |
| const auto& bazDests = flow.dests[baz]; | |
| assert(bazDests.size() == 2); | |
| assert(bazDests[0] == (StackFlow::Location{ret, 1, Type::i64, true})); | |
| assert(bazDests[1] == (StackFlow::Location{ret, 2, Type::f32, false})); | |
| const auto& retSrcs = flow.srcs[ret]; | |
| assert(retSrcs.size() == 3); | |
| assert(retSrcs[0] == (StackFlow::Location{foo, 0, Type::i32, false})); | |
| assert(retSrcs[1] == (StackFlow::Location{baz, 0, Type::i64, false})); | |
| assert(retSrcs[2] == (StackFlow::Location{baz, 1, Type::f32, false})); | |
| const auto& retDests = flow.dests[ret]; | |
| assert(retDests.size() == 3); | |
| assert(retDests[0] == (StackFlow::Location{block, 0, Type::i64, false})); | |
| assert(retDests[1] == (StackFlow::Location{quux, 0, Type::f64, false})); | |
| assert(retDests[2] == (StackFlow::Location{quux, 1, Type::i32, false})); | |
| const auto& quuxSrcs = flow.srcs[quux]; | |
| assert(quuxSrcs.size() == 2); | |
| assert(quuxSrcs[0] == (StackFlow::Location{ret, 1, Type::f64, true})); | |
| assert(quuxSrcs[1] == (StackFlow::Location{ret, 2, Type::i32, true})); | |
| const auto& quuxDests = flow.dests[quux]; | |
| assert(quuxDests.size() == 0); | |
| const auto& blockSrcs = flow.srcs[block]; | |
| assert(blockSrcs.size() == 1); | |
| assert(blockSrcs[0] == (StackFlow::Location{ret, 0, Type::i64, true})); | |
| assert(flow.getSignature(foo) == StackSignature(foo)); | |
| assert(flow.getSignature(bar) == StackSignature(bar)); | |
| assert(flow.getSignature(baz) == StackSignature(baz)); | |
| assert(flow.getSignature(ret) == | |
| (StackSignature{{Type::i32, Type::i64, Type::f32}, | |
| {Type::i64, Type::f64, Type::i32}, | |
| StackSignature::Polymorphic})); | |
| assert(flow.getSignature(quux) == StackSignature(quux)); | |
| } | |
| } | |
| int main() { | |
| test_remove_nops(); | |
| test_stack_signatures(); | |
| test_signature_composition(); | |
| test_signature_subtype(); | |
| test_signature_lub(); | |
| test_stack_flow(); | |
| } |