blob: 36e0e871153a76d8a86b9807ceab47443fbe1b00 [file] [edit]
// Copyright 2026 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.
#include "support/int128.h"
#include "gtest/gtest.h"
#include <limits>
using namespace wasm;
class Int128MulWideSTest
: public ::testing::TestWithParam<Int128 (*)(uint64_t, uint64_t)> {};
TEST_P(Int128MulWideSTest, Basic) {
auto mul_s = GetParam();
// Simple cases
EXPECT_EQ(mul_s(0, 0), (Int128{0, 0}));
EXPECT_EQ(mul_s(1, 1), (Int128{0, 1}));
// Mixed sign
EXPECT_EQ(mul_s(-1, 1),
(Int128{0xffffffffffffffffULL, 0xffffffffffffffffULL}));
EXPECT_EQ(mul_s(1, -1),
(Int128{0xffffffffffffffffULL, 0xffffffffffffffffULL}));
// Double negative
EXPECT_EQ(mul_s(-1, -1), (Int128{0, 1}));
int64_t maxInt = std::numeric_limits<int64_t>::max();
// Fits in the lower half because the signed bit now goes in the upper half.
EXPECT_EQ(mul_s(maxInt, 2), (Int128{0, 0xfffffffffffffffeULL}));
EXPECT_EQ(mul_s(maxInt, maxInt), (Int128{0x3fffffffffffffffULL, 1}));
// Min Ints (0x8000000000000000)
int64_t minInt = std::numeric_limits<int64_t>::min();
EXPECT_EQ(mul_s(minInt, 2), (Int128{0xffffffffffffffffULL, 0}));
EXPECT_EQ(mul_s(minInt, minInt), (Int128{0x4000000000000000ULL, 0}));
}
// Test that our fallback implementation is commutative
Int128 mul_wide_s_fallback_reversed(uint64_t lhs, uint64_t rhs) {
return detail::mul_wide_s_fallback(rhs, lhs);
}
INSTANTIATE_TEST_SUITE_P(Int128,
Int128MulWideSTest,
::testing::Values(mul_wide_s,
detail::mul_wide_s_fallback,
mul_wide_s_fallback_reversed));
class Int128MulWideUTest
: public ::testing::TestWithParam<Int128 (*)(uint64_t, uint64_t)> {};
TEST_P(Int128MulWideUTest, Basic) {
auto mul_u = GetParam();
// Simple cases
EXPECT_EQ(mul_u(0, 0), (Int128{0, 0}));
EXPECT_EQ(mul_u(1, 0), (Int128{0, 0}));
EXPECT_EQ(mul_u(1, 1), (Int128{0, 1}));
// Max Uint (0xffffffffffffffff)
uint64_t maxUint = std::numeric_limits<uint64_t>::max();
EXPECT_EQ(mul_u(maxUint, 2), (Int128{1, 0xfffffffffffffffeULL}));
EXPECT_EQ(mul_u(maxUint, maxUint), (Int128{0xfffffffffffffffeULL, 1}));
// Max 32-bit uint (0xffffffff)
EXPECT_EQ(mul_u(0xffffffffULL, 0xffffffffULL),
(Int128{0, 0xfffffffe00000001ULL}));
// Exactly 2^32 (0x100000000) - Tests a 1 in the lowest bit of the high half
EXPECT_EQ(mul_u(0x100000000ULL, 0x100000000ULL), (Int128{1, 0}));
// Mixed boundaries
EXPECT_EQ(mul_u(0xffffffffULL, 0x100000000ULL),
(Int128{0, 0xffffffff00000000ULL}));
// Upper half filled, lower half empty
uint64_t highOnly = 0xffffffff00000000ULL;
EXPECT_EQ(mul_u(highOnly, 2), (Int128{1, 0xfffffffe00000000ULL}));
// Lower half filled, upper half empty
uint64_t lowOnly = 0x00000000ffffffffULL;
EXPECT_EQ(mul_u(lowOnly, lowOnly), (Int128{0, 0xfffffffe00000001ULL}));
}
// Test that our fallback implementation is commutative
Int128 mul_wide_u_fallback_reversed(uint64_t lhs, uint64_t rhs) {
return detail::mul_wide_u_fallback(rhs, lhs);
}
INSTANTIATE_TEST_SUITE_P(Int128,
Int128MulWideUTest,
::testing::Values(mul_wide_u,
detail::mul_wide_u_fallback,
mul_wide_u_fallback_reversed));