//===-- ScalarTest.cpp ----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "gtest/gtest.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Endian.h" #include "lldb/Utility/Scalar.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" #include "llvm/Testing/Support/Error.h" using namespace lldb_private; using llvm::APFloat; using llvm::APInt; using llvm::Failed; using llvm::Succeeded; template bool checkInequality(T c1, T c2) { return (Scalar(c1) != Scalar(c2)); } template bool checkEquality(T c1, T c2) { return (Scalar(c1) == Scalar(c2)); } TEST(ScalarTest, Equality) { ASSERT_TRUE(checkInequality(23, 24)); ASSERT_TRUE(checkEquality(96, 96)); ASSERT_TRUE(checkInequality(4.0f, 4.5f)); ASSERT_TRUE(checkEquality(4.0f, 4.0f)); auto apint1 = APInt(64, 234); auto apint2 = APInt(64, 246); ASSERT_TRUE(checkInequality(apint1, apint2)); ASSERT_TRUE(checkEquality(apint1, apint1)); Scalar void1; Scalar void2; float f1 = 2.0; ASSERT_TRUE(void1 == void2); ASSERT_FALSE(void1 == Scalar(f1)); } TEST(ScalarTest, Comparison) { auto s1 = Scalar(23); auto s2 = Scalar(46); ASSERT_TRUE(s1 < s2); ASSERT_TRUE(s1 <= s2); ASSERT_TRUE(s2 > s1); ASSERT_TRUE(s2 >= s1); } TEST(ScalarTest, ComparisonFloat) { auto s1 = Scalar(23.0f); auto s2 = Scalar(46.0f); ASSERT_TRUE(s1 < s2); ASSERT_TRUE(s1 <= s2); ASSERT_TRUE(s2 > s1); ASSERT_TRUE(s2 >= s1); } template static void CheckConversion(T val) { SCOPED_TRACE("val = " + std::to_string(val)); EXPECT_EQ((signed char)val, Scalar(val).SChar()); EXPECT_EQ((unsigned char)val, Scalar(val).UChar()); EXPECT_EQ((short)val, Scalar(val).SShort()); EXPECT_EQ((unsigned short)val, Scalar(val).UShort()); EXPECT_EQ((int)val, Scalar(val).SInt()); EXPECT_EQ((unsigned)val, Scalar(val).UInt()); EXPECT_EQ((long)val, Scalar(val).SLong()); EXPECT_EQ((unsigned long)val, Scalar(val).ULong()); EXPECT_EQ((long long)val, Scalar(val).SLongLong()); EXPECT_EQ((unsigned long long)val, Scalar(val).ULongLong()); EXPECT_NEAR((float)val, Scalar(val).Float(), std::abs(val / 1e6)); EXPECT_NEAR((double)val, Scalar(val).Double(), std::abs(val / 1e12)); EXPECT_NEAR((long double)val, Scalar(val).LongDouble(), std::abs(val / 1e12)); } TEST(ScalarTest, Getters) { CheckConversion(0x87654321); CheckConversion(0x87654321u); CheckConversion(0x87654321l); CheckConversion(0x87654321ul); CheckConversion(0x8765432112345678ll); CheckConversion(0x8765432112345678ull); CheckConversion(42.25f); CheckConversion(42.25); CheckConversion(42.25L); EXPECT_EQ(APInt(128, 1) << 70, Scalar(std::pow(2.0f, 70.0f)).SInt128(APInt())); EXPECT_EQ(APInt(128, -1, true) << 70, Scalar(-std::pow(2.0f, 70.0f)).SInt128(APInt())); EXPECT_EQ(APInt(128, 1) << 70, Scalar(std::pow(2.0f, 70.0f)).UInt128(APInt())); EXPECT_EQ(APInt(128, 0), Scalar(-std::pow(2.0f, 70.0f)).UInt128(APInt())); EXPECT_EQ(APInt(128, 1) << 70, Scalar(std::pow(2.0, 70.0)).SInt128(APInt())); EXPECT_EQ(APInt(128, -1, true) << 70, Scalar(-std::pow(2.0, 70.0)).SInt128(APInt())); EXPECT_EQ(APInt(128, 1) << 70, Scalar(std::pow(2.0, 70.0)).UInt128(APInt())); EXPECT_EQ(APInt(128, 0), Scalar(-std::pow(2.0, 70.0)).UInt128(APInt())); } TEST(ScalarTest, RightShiftOperator) { int a = 0x00001000; int b = 0xFFFFFFFF; int c = 4; Scalar a_scalar(a); Scalar b_scalar(b); Scalar c_scalar(c); ASSERT_EQ(a >> c, a_scalar >> c_scalar); ASSERT_EQ(b >> c, b_scalar >> c_scalar); } TEST(ScalarTest, GetBytes) { uint8_t Storage[256]; int a = 0x01020304; long long b = 0x0102030405060708LL; float c = 1234567.89e32f; double d = 1234567.89e42; char e[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; char f[32] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}; Scalar a_scalar(a); Scalar b_scalar(b); Scalar c_scalar(c); Scalar d_scalar(d); Scalar e_scalar; Scalar f_scalar; DataExtractor e_data(e, sizeof(e), endian::InlHostByteOrder(), sizeof(void *)); DataExtractor f_data(f, sizeof(f), endian::InlHostByteOrder(), sizeof(void *)); a_scalar.GetBytes(Storage); ASSERT_EQ(0, memcmp(&a, Storage, sizeof(a))); b_scalar.GetBytes(Storage); ASSERT_EQ(0, memcmp(&b, Storage, sizeof(b))); c_scalar.GetBytes(Storage); ASSERT_EQ(0, memcmp(&c, Storage, sizeof(c))); d_scalar.GetBytes(Storage); ASSERT_EQ(0, memcmp(&d, Storage, sizeof(d))); ASSERT_THAT_ERROR( e_scalar.SetValueFromData(e_data, lldb::eEncodingUint, sizeof(e)) .ToError(), llvm::Succeeded()); e_scalar.GetBytes(Storage); ASSERT_EQ(0, memcmp(e, Storage, sizeof(e))); ASSERT_THAT_ERROR( f_scalar.SetValueFromData(f_data, lldb::eEncodingUint, sizeof(f)) .ToError(), llvm::Succeeded()); f_scalar.GetBytes(Storage); ASSERT_EQ(0, memcmp(f, Storage, sizeof(f))); } TEST(ScalarTest, SetValueFromData) { uint8_t a[] = {1, 2, 3, 4}; Scalar s; ASSERT_THAT_ERROR( s.SetValueFromData( DataExtractor(a, sizeof(a), lldb::eByteOrderLittle, sizeof(void *)), lldb::eEncodingSint, sizeof(a)) .ToError(), llvm::Succeeded()); EXPECT_EQ(0x04030201, s); ASSERT_THAT_ERROR( s.SetValueFromData( DataExtractor(a, sizeof(a), lldb::eByteOrderBig, sizeof(void *)), lldb::eEncodingSint, sizeof(a)) .ToError(), llvm::Succeeded()); EXPECT_EQ(0x01020304, s); } TEST(ScalarTest, CastOperations) { long long a = 0xf1f2f3f4f5f6f7f8LL; Scalar a_scalar(a); EXPECT_EQ((signed char)a, a_scalar.SChar()); EXPECT_EQ((unsigned char)a, a_scalar.UChar()); EXPECT_EQ((signed short)a, a_scalar.SShort()); EXPECT_EQ((unsigned short)a, a_scalar.UShort()); EXPECT_EQ((signed int)a, a_scalar.SInt()); EXPECT_EQ((unsigned int)a, a_scalar.UInt()); EXPECT_EQ((signed long)a, a_scalar.SLong()); EXPECT_EQ((unsigned long)a, a_scalar.ULong()); EXPECT_EQ((signed long long)a, a_scalar.SLongLong()); EXPECT_EQ((unsigned long long)a, a_scalar.ULongLong()); int a2 = 23; Scalar a2_scalar(a2); EXPECT_EQ((float)a2, a2_scalar.Float()); EXPECT_EQ((double)a2, a2_scalar.Double()); EXPECT_EQ((long double)a2, a2_scalar.LongDouble()); EXPECT_EQ(std::numeric_limits::min(), Scalar(-1.0f).UInt()); EXPECT_EQ(std::numeric_limits::max(), Scalar(1e11f).UInt()); EXPECT_EQ(std::numeric_limits::min(), Scalar(-1.0).ULongLong()); EXPECT_EQ(std::numeric_limits::max(), Scalar(1e22).ULongLong()); EXPECT_EQ(std::numeric_limits::min(), Scalar(-1e11f).SInt()); EXPECT_EQ(std::numeric_limits::max(), Scalar(1e11f).SInt()); EXPECT_EQ(std::numeric_limits::min(), Scalar(-1e22).SLongLong()); EXPECT_EQ(std::numeric_limits::max(), Scalar(1e22).SLongLong()); } TEST(ScalarTest, ExtractBitfield) { uint32_t len = sizeof(long long) * 8; long long a1 = 0xf1f2f3f4f5f6f7f8LL; long long b1 = 0xff1f2f3f4f5f6f7fLL; Scalar s_scalar(a1); ASSERT_TRUE(s_scalar.ExtractBitfield(0, 0)); EXPECT_EQ(s_scalar, a1); ASSERT_TRUE(s_scalar.ExtractBitfield(len, 0)); EXPECT_EQ(s_scalar, a1); ASSERT_TRUE(s_scalar.ExtractBitfield(len - 4, 4)); EXPECT_EQ(s_scalar, b1); unsigned long long a2 = 0xf1f2f3f4f5f6f7f8ULL; unsigned long long b2 = 0x0f1f2f3f4f5f6f7fULL; Scalar u_scalar(a2); ASSERT_TRUE(u_scalar.ExtractBitfield(0, 0)); EXPECT_EQ(u_scalar, a2); ASSERT_TRUE(u_scalar.ExtractBitfield(len, 0)); EXPECT_EQ(u_scalar, a2); ASSERT_TRUE(u_scalar.ExtractBitfield(len - 4, 4)); EXPECT_EQ(u_scalar, b2); } template static std::string ScalarGetValue(T value) { StreamString stream; Scalar(value).GetValue(&stream, false); return std::string(stream.GetString()); } TEST(ScalarTest, GetValue) { EXPECT_EQ("12345", ScalarGetValue(12345)); EXPECT_EQ("-12345", ScalarGetValue(-12345)); EXPECT_EQ("12345", ScalarGetValue(12345)); EXPECT_EQ(std::to_string(std::numeric_limits::max()), ScalarGetValue(std::numeric_limits::max())); EXPECT_EQ("12345", ScalarGetValue(12345)); EXPECT_EQ("-12345", ScalarGetValue(-12345)); EXPECT_EQ("12345", ScalarGetValue(12345)); EXPECT_EQ(std::to_string(std::numeric_limits::max()), ScalarGetValue(std::numeric_limits::max())); EXPECT_EQ("12345678", ScalarGetValue(12345678L)); EXPECT_EQ("-12345678", ScalarGetValue(-12345678L)); EXPECT_EQ("12345678", ScalarGetValue(12345678UL)); EXPECT_EQ(std::to_string(std::numeric_limits::max()), ScalarGetValue(std::numeric_limits::max())); EXPECT_EQ("1234567890123", ScalarGetValue(1234567890123LL)); EXPECT_EQ("-1234567890123", ScalarGetValue(-1234567890123LL)); EXPECT_EQ("1234567890123", ScalarGetValue(1234567890123ULL)); EXPECT_EQ(std::to_string(std::numeric_limits::max()), ScalarGetValue(std::numeric_limits::max())); } TEST(ScalarTest, LongLongAssigmentOperator) { Scalar ull; ull = std::numeric_limits::max(); EXPECT_EQ(std::numeric_limits::max(), ull.ULongLong()); Scalar sll; sll = std::numeric_limits::max(); EXPECT_EQ(std::numeric_limits::max(), sll.SLongLong()); } TEST(ScalarTest, Division) { Scalar lhs(5.0); Scalar rhs(2.0); Scalar r = lhs / rhs; EXPECT_TRUE(r.IsValid()); EXPECT_EQ(r, Scalar(2.5)); } TEST(ScalarTest, Promotion) { Scalar a(47); EXPECT_TRUE(a.IntegralPromote(64, true)); EXPECT_TRUE(a.IsSigned()); EXPECT_EQ(APInt(64, 47), a.UInt128(APInt())); EXPECT_FALSE(a.IntegralPromote(32, true)); EXPECT_FALSE(a.IntegralPromote(32, false)); EXPECT_TRUE(a.IsSigned()); EXPECT_TRUE(a.IntegralPromote(64, false)); EXPECT_FALSE(a.IsSigned()); EXPECT_EQ(APInt(64, 47), a.UInt128(APInt())); EXPECT_FALSE(a.IntegralPromote(64, true)); EXPECT_TRUE(a.FloatPromote(APFloat::IEEEdouble())); EXPECT_EQ(Scalar::e_float, a.GetType()); EXPECT_EQ(47.0, a.Double()); EXPECT_FALSE(a.FloatPromote(APFloat::IEEEsingle())); EXPECT_TRUE(a.FloatPromote(APFloat::x87DoubleExtended())); EXPECT_EQ(47.0L, a.LongDouble()); } TEST(ScalarTest, SetValueFromCString) { Scalar a; EXPECT_THAT_ERROR( a.SetValueFromCString("1234567890123", lldb::eEncodingUint, 8).ToError(), Succeeded()); EXPECT_EQ(1234567890123ull, a); EXPECT_THAT_ERROR( a.SetValueFromCString("-1234567890123", lldb::eEncodingSint, 8).ToError(), Succeeded()); EXPECT_EQ(-1234567890123ll, a); EXPECT_THAT_ERROR( a.SetValueFromCString("asdf", lldb::eEncodingSint, 8).ToError(), Failed()); EXPECT_THAT_ERROR( a.SetValueFromCString("asdf", lldb::eEncodingUint, 8).ToError(), Failed()); EXPECT_THAT_ERROR( a.SetValueFromCString("1234567890123", lldb::eEncodingUint, 4).ToError(), Failed()); EXPECT_THAT_ERROR(a.SetValueFromCString("123456789012345678901234567890", lldb::eEncodingUint, 8) .ToError(), Failed()); EXPECT_THAT_ERROR( a.SetValueFromCString("-123", lldb::eEncodingUint, 8).ToError(), Failed()); EXPECT_THAT_ERROR( a.SetValueFromCString("-2147483648", lldb::eEncodingSint, 4).ToError(), Succeeded()); EXPECT_EQ(-2147483648, a); EXPECT_THAT_ERROR( a.SetValueFromCString("-2147483649", lldb::eEncodingSint, 4).ToError(), Failed()); EXPECT_THAT_ERROR( a.SetValueFromCString("47.25", lldb::eEncodingIEEE754, 4).ToError(), Succeeded()); EXPECT_EQ(47.25f, a); EXPECT_THAT_ERROR( a.SetValueFromCString("asdf", lldb::eEncodingIEEE754, 4).ToError(), Failed()); } TEST(ScalarTest, APIntConstructor) { for (auto &width : {8, 16, 32}) { Scalar A(APInt(width, 24)); EXPECT_TRUE(A.IsSigned()); EXPECT_EQ(A.GetType(), Scalar::e_int); EXPECT_EQ(APInt(width, 24), A.UInt128(APInt())); } } TEST(ScalarTest, Scalar_512) { Scalar Z(APInt(512, 0)); ASSERT_TRUE(Z.IsZero()); Z.MakeUnsigned(); ASSERT_TRUE(Z.IsZero()); Scalar S(APInt(512, 2000)); ASSERT_STREQ(S.GetTypeAsCString(), "int"); ASSERT_TRUE(S.MakeUnsigned()); EXPECT_EQ(S.GetType(), Scalar::e_int); EXPECT_FALSE(S.IsSigned()); ASSERT_STREQ(S.GetTypeAsCString(), "int"); EXPECT_EQ(S.GetByteSize(), 64U); ASSERT_TRUE(S.MakeSigned()); EXPECT_EQ(S.GetType(), Scalar::e_int); EXPECT_TRUE(S.IsSigned()); EXPECT_EQ(S.GetByteSize(), 64U); } TEST(ScalarTest, TruncOrExtendTo) { Scalar S(0xffff); S.TruncOrExtendTo(12, true); EXPECT_EQ(S.UInt128(APInt()), APInt(12, 0xfffu)); S.TruncOrExtendTo(20, true); EXPECT_EQ(S.UInt128(APInt()), APInt(20, 0xfffffu)); S.TruncOrExtendTo(24, false); EXPECT_EQ(S.UInt128(APInt()), APInt(24, 0x0fffffu)); S.TruncOrExtendTo(16, false); EXPECT_EQ(S.UInt128(APInt()), APInt(16, 0xffffu)); }