| /* | |
| * Copyright 2025 WebAssembly Community Group participants | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| // TODO: Replace this test file with spec tests as soon as possible. | |
| #include "interpreter/interpreter.h" | |
| #include "interpreter/store.h" | |
| #include "literal.h" | |
| #include "wasm-ir-builder.h" | |
| #include "wasm.h" | |
| #include "gtest/gtest.h" | |
| using namespace wasm; | |
| // Int32 | |
| TEST(InterpreterTest, AddI32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(AddInt32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint32_t(3))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, SubI32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(SubInt32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint32_t(-1))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, MulI32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(MulInt32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint32_t(2))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, EqI32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(EqInt32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint32_t(0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, AndI32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(0))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(AndInt32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint32_t(0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, OrI32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(4))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(OrInt32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint32_t(6))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, XorI32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(3))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(XorInt32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint32_t(2))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, ShlI32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(3))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(4))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(ShlInt32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint32_t(48))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, RotLI32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(4))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(RotLInt32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint32_t(16))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, RotRI32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(3))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(RotRInt32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint32_t(1073741824))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| // uInt32 | |
| TEST(InterpreterTest, LtUI32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(LtUInt32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint32_t(1))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, GtUI32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(GtUInt32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint32_t(0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, ShrUI32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(ShrUInt32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint32_t(0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| // sInt32 | |
| TEST(InterpreterTest, LtSI32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(int32_t(-1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(int32_t(-2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(LtSInt32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(int32_t(0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, GtSI32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(int32_t(-3))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(int32_t(-4))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(GtSInt32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(int32_t(1))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, ShrSI32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint32_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(ShrSInt32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint32_t(0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| // Int64 | |
| TEST(InterpreterTest, AddI64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(AddInt64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint64_t(3))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, SubI64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(SubInt64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint64_t(-1))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, MulI64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(MulInt64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint64_t(2))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, EqI64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(EqInt64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint32_t(0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, AndI64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(AndInt64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint64_t(0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, OrI64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(OrInt64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint64_t(3))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, XorI64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(XorInt64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint64_t(3))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, ShlI64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(ShlInt64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint64_t(4))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, RotLI64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(RotLInt64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint64_t(4))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, RotRI64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(RotRInt64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint64_t(4611686018427387904))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| // uInt64 | |
| TEST(InterpreterTest, LtUI64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(LtSInt64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint32_t(1))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, GtUI64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(GtSInt64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint32_t(0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, ShrUI64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(ShrUInt64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint64_t(0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| // sInt64 | |
| TEST(InterpreterTest, LtSI64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(int64_t(-1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(int64_t(-2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(LtSInt64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(int32_t(0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, GtSI64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(int64_t(-3))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(int64_t(-4))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(GtSInt64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(int32_t(1))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, ShrSI64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(1))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(uint64_t(2))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(ShrSInt64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint64_t(0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| // Float32 | |
| TEST(InterpreterTest, AddF32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(float(0.0))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(float(1.0))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(AddFloat32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(float(1.0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, SubF32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(float(1.0))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(float(2.0))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(SubFloat32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(float(-1.0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, MulF32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(float(1.5))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(float(2.0))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(MulFloat32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(float(3.0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, DivF32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(float(5.0))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(float(2.0))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(DivFloat32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(float(2.5))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, EqF32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(float(1.0))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(float(2.0))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(EqFloat32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint32_t(0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, SqrtF32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(float(5.0))).getErr()); | |
| ASSERT_FALSE(builder.makeUnary(SqrtFloat32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(float(2.2360679775))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, SqrtF32Neg) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(float(-5.0))).getErr()); | |
| ASSERT_FALSE(builder.makeUnary(SqrtFloat32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(std::nanf("0x400000"))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, CeilF32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(float(1.5))).getErr()); | |
| ASSERT_FALSE(builder.makeUnary(CeilFloat32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(float(2.0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, FloorF32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(float(1.5))).getErr()); | |
| ASSERT_FALSE(builder.makeUnary(FloorFloat32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(float(1.0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, TruncF32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(float(2.017281))).getErr()); | |
| ASSERT_FALSE(builder.makeUnary(TruncFloat32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(float(2.0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, NearF32) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(float(2.5))).getErr()); | |
| ASSERT_FALSE(builder.makeUnary(NearestFloat32).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(float(2.0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| // Float 64 | |
| TEST(InterpreterTest, AddF64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(double(0.0))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(double(1.0))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(AddFloat64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(double(1.0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, SubF64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(double(1.0))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(double(2.0))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(SubFloat64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(double(-1.0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, MulF64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(double(1.5))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(double(2.0))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(MulFloat64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(double(3.0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, DivF64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(double(5.0))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(double(2.0))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(DivFloat64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(double(2.5))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, EqF64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(double(1.0))).getErr()); | |
| ASSERT_FALSE(builder.makeConst(Literal(double(2.0))).getErr()); | |
| ASSERT_FALSE(builder.makeBinary(EqFloat64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(uint32_t(0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, SqrtF64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(double(5.0))).getErr()); | |
| ASSERT_FALSE(builder.makeUnary(SqrtFloat64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(double(2.23606797749979))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, SqrtF64Neg) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(double(-5.0))).getErr()); | |
| ASSERT_FALSE(builder.makeUnary(SqrtFloat64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(std::nan("0x8000000000000"))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, CeilF64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(double(1.5))).getErr()); | |
| ASSERT_FALSE(builder.makeUnary(CeilFloat64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(double(2.0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, FloorF64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(double(1.5))).getErr()); | |
| ASSERT_FALSE(builder.makeUnary(FloorFloat64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(double(1.0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, TruncF64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(double(2.017281))).getErr()); | |
| ASSERT_FALSE(builder.makeUnary(TruncFloat64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(double(2.0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, NearF64) { | |
| Module wasm; | |
| IRBuilder builder(wasm); | |
| ASSERT_FALSE(builder.makeConst(Literal(double(2.5))).getErr()); | |
| ASSERT_FALSE(builder.makeUnary(NearestFloat64).getErr()); | |
| auto expr = builder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| auto results = Interpreter{}.runTest(*expr); | |
| std::vector<Literal> expected{Literal(double(2.0))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, GlobalI32) { | |
| auto wasm = std::make_shared<Module>(); | |
| Builder builder(*wasm); | |
| IRBuilder irBuilder(*wasm); | |
| wasm->addGlobal( | |
| builder.makeGlobal("global", | |
| Type::i32, | |
| builder.makeConst(Literal::makeZero(Type::i32)), | |
| Builder::Mutable)); | |
| ASSERT_FALSE( | |
| irBuilder.makeBlock(Name{}, Signature(Type::none, Type::i32)).getErr()); | |
| ASSERT_FALSE(irBuilder.makeConst(Literal(int32_t(5))).getErr()); | |
| ASSERT_FALSE(irBuilder.makeGlobalSet("global").getErr()); | |
| ASSERT_FALSE(irBuilder.makeGlobalGet("global").getErr()); | |
| ASSERT_FALSE(irBuilder.visitEnd().getErr()); | |
| auto expr = irBuilder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| Interpreter interpreter; | |
| auto result = interpreter.addInstance(wasm); | |
| auto results = interpreter.runTest(*expr); | |
| std::vector<Literal> expected{Literal(int32_t(5))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, ImportedGlobalI32) { | |
| auto wasm = std::make_shared<Module>(); | |
| Builder builder(*wasm); | |
| auto importedGlobal = | |
| builder.makeGlobal("g", Type::i32, nullptr, Builder::Immutable); | |
| importedGlobal->module = "env"; | |
| importedGlobal->base = "g"; | |
| wasm->addGlobal(std::move(importedGlobal)); | |
| Interpreter interpreter; | |
| auto result = interpreter.addInstance(wasm); | |
| EXPECT_FALSE(result.getErr()); | |
| } | |
| TEST(InterpreterTest, MixedImportedAndLocalGlobals) { | |
| auto wasm = std::make_shared<Module>(); | |
| Builder builder(*wasm); | |
| IRBuilder irBuilder(*wasm); | |
| auto importedGlobal = | |
| builder.makeGlobal("imported", Type::i32, nullptr, Builder::Immutable); | |
| importedGlobal->module = "env"; | |
| importedGlobal->base = "imported"; | |
| wasm->addGlobal(std::move(importedGlobal)); | |
| wasm->addGlobal(builder.makeGlobal("local", | |
| Type::i32, | |
| builder.makeConst(Literal(int32_t(42))), | |
| Builder::Mutable)); | |
| ASSERT_FALSE( | |
| irBuilder.makeBlock(Name{}, Signature(Type::none, Type::i32)).getErr()); | |
| ASSERT_FALSE(irBuilder.makeGlobalGet("local").getErr()); | |
| ASSERT_FALSE(irBuilder.visitEnd().getErr()); | |
| auto expr = irBuilder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| Interpreter interpreter; | |
| auto result = interpreter.addInstance(wasm); | |
| ASSERT_FALSE(result.getErr()); | |
| auto results = interpreter.runTest(*expr); | |
| std::vector<Literal> expected{Literal(int32_t(42))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, GlobalInitI32) { | |
| auto wasm = std::make_shared<Module>(); | |
| Builder builder(*wasm); | |
| IRBuilder irBuilder(*wasm); | |
| wasm->addGlobal(builder.makeGlobal( | |
| "global", | |
| Type::i32, | |
| builder.makeBinary( | |
| AddInt32, builder.makeConst(int32_t(2)), builder.makeConst(int32_t(3))), | |
| Builder::Mutable)); | |
| ASSERT_FALSE( | |
| irBuilder.makeBlock(Name{}, Signature(Type::none, Type::i32)).getErr()); | |
| ASSERT_FALSE(irBuilder.makeGlobalGet("global").getErr()); | |
| ASSERT_FALSE(irBuilder.visitEnd().getErr()); | |
| auto expr = irBuilder.build(); | |
| ASSERT_FALSE(expr.getErr()); | |
| Interpreter interpreter; | |
| auto result = interpreter.addInstance(wasm); | |
| auto results = interpreter.runTest(*expr); | |
| std::vector<Literal> expected{Literal(int32_t(5))}; | |
| EXPECT_EQ(results, expected); | |
| } | |
| TEST(InterpreterTest, InstanceReferenceStability) { | |
| using namespace interpreter; | |
| auto module = std::make_shared<Module>(); | |
| WasmStore store; | |
| store.instances.emplace_back(module); | |
| store.instances[0].globalValues["x"] = Literal(int32_t(42)); | |
| Instance* addrBefore = &store.instances[0]; | |
| ExpressionIterator emptyIter; | |
| store.callStack.emplace_back(store.instances[0], std::move(emptyIter)); | |
| // Add many more instances to exercise container growth. | |
| for (int i = 0; i < 100; ++i) { | |
| store.instances.emplace_back(module); | |
| } | |
| // With std::deque, existing elements are never relocated. | |
| Instance* addrAfter = &store.instances[0]; | |
| EXPECT_EQ(addrBefore, addrAfter); | |
| // The frame's Instance& reference is still valid. | |
| EXPECT_EQ(store.callStack.back().instance.globalValues["x"], | |
| Literal(int32_t(42))); | |
| } |