Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "src/wasm/asm-types.h" | |
| 6 | |
| 7 #include <unordered_map> | |
| 8 #include <unordered_set> | |
| 9 | |
| 10 #include "src/base/macros.h" | |
| 11 #include "test/unittests/test-utils.h" | |
| 12 #include "testing/gmock/include/gmock/gmock.h" | |
| 13 #include "testing/gtest/include/gtest/gtest.h" | |
| 14 | |
| 15 namespace v8 { | |
| 16 namespace internal { | |
| 17 namespace wasm { | |
| 18 namespace { | |
| 19 | |
| 20 using ::testing::StrEq; | |
| 21 | |
| 22 class AsmTypeTest : public TestWithZone { | |
| 23 public: | |
| 24 using Type = AsmType; | |
| 25 | |
| 26 AsmTypeTest() | |
| 27 : parents_{ | |
| 28 {Type::Uint8Array(), {Type::Heap()}}, | |
| 29 {Type::Int8Array(), {Type::Heap()}}, | |
| 30 {Type::Uint16Array(), {Type::Heap()}}, | |
| 31 {Type::Int16Array(), {Type::Heap()}}, | |
| 32 {Type::Uint32Array(), {Type::Heap()}}, | |
| 33 {Type::Int32Array(), {Type::Heap()}}, | |
| 34 {Type::Float32Array(), {Type::Heap()}}, | |
| 35 {Type::Float64Array(), {Type::Heap()}}, | |
| 36 {Type::FloatishDoubleQ(), {Type::Floatish(), Type::DoubleQ()}}, | |
| 37 {Type::FloatQDoubleQ(), | |
| 38 {Type::FloatQ(), Type::Floatish(), Type::DoubleQ()}}, | |
| 39 {Type::Float(), {Type::FloatQ(), Type::Floatish()}}, | |
| 40 {Type::FloatQ(), {Type::Floatish()}}, | |
| 41 {Type::FixNum(), | |
| 42 {Type::Signed(), Type::Extern(), Type::Unsigned(), Type::Int(), | |
| 43 Type::Intish()}}, | |
| 44 {Type::Unsigned(), {Type::Int(), Type::Intish()}}, | |
| 45 {Type::Signed(), {Type::Extern(), Type::Int(), Type::Intish()}}, | |
| 46 {Type::Int(), {Type::Intish()}}, | |
| 47 {Type::Double(), {Type::DoubleQ(), Type::Extern()}}, | |
| 48 } {} | |
| 49 | |
| 50 protected: | |
| 51 std::unordered_set<Type*> ParentsOf(Type* derived) const { | |
| 52 const auto parents_iter = parents_.find(derived); | |
| 53 if (parents_iter == parents_.end()) { | |
| 54 return std::unordered_set<Type*>(); | |
| 55 } | |
| 56 return parents_iter->second; | |
| 57 } | |
| 58 | |
| 59 class FunctionTypeBuilder { | |
| 60 public: | |
| 61 FunctionTypeBuilder(FunctionTypeBuilder&&) = default; | |
| 62 FunctionTypeBuilder& operator=(FunctionTypeBuilder&&) = default; | |
| 63 FunctionTypeBuilder(Zone* zone, Type* return_type) | |
| 64 : function_type_(Type::Function(zone, return_type)) {} | |
| 65 | |
| 66 private: | |
| 67 static void AddAllArguments(AsmFunctionType*) {} | |
| 68 | |
| 69 template <typename Arg, typename... Others> | |
| 70 static void AddAllArguments(AsmFunctionType* function_type, Arg* arg, | |
| 71 Others... others) { | |
| 72 CHECK(function_type != nullptr); | |
| 73 function_type->AddArgument((*arg)()); | |
| 74 AddAllArguments(function_type, others...); | |
| 75 } | |
| 76 | |
| 77 public: | |
| 78 template <typename... Args> | |
| 79 Type* operator()(Args... args) && { | |
| 80 Type* ret = function_type_; | |
| 81 function_type_ = nullptr; | |
| 82 AddAllArguments(ret->AsFunctionType(), args...); | |
| 83 return ret; | |
| 84 } | |
| 85 | |
| 86 private: | |
| 87 Type* function_type_; | |
| 88 }; | |
| 89 | |
| 90 FunctionTypeBuilder Function(Type* (*return_type)()) { | |
| 91 return FunctionTypeBuilder(zone(), (*return_type)()); | |
| 92 } | |
| 93 | |
| 94 template <typename... Overloads> | |
| 95 Type* Overload(Overloads... overloads) { | |
| 96 auto* ret = Type::OverloadedFunction(zone()); | |
| 97 AddAllOverloads(ret->AsOverloadedFunctionType(), overloads...); | |
| 98 return ret; | |
| 99 } | |
| 100 | |
| 101 private: | |
| 102 static void AddAllOverloads(AsmOverloadedFunctionType*) {} | |
| 103 | |
| 104 template <typename Overload, typename... Others> | |
| 105 static void AddAllOverloads(AsmOverloadedFunctionType* function, | |
| 106 Overload* overload, Others... others) { | |
| 107 CHECK(function != nullptr); | |
| 108 function->AddOverload(overload); | |
| 109 AddAllOverloads(function, others...); | |
| 110 } | |
| 111 | |
| 112 const std::unordered_map<Type*, std::unordered_set<Type*>> parents_; | |
| 113 }; | |
| 114 | |
| 115 // AsmValueTypeParents expose the bitmasks for the parents for each value type | |
| 116 // in asm's type system. It inherits from AsmValueType so that the kAsm<Foo> | |
| 117 // members are available when expanding the FOR_EACH_ASM_VALUE_TYPE_LIST macro. | |
| 118 class AsmValueTypeParents : private AsmValueType { | |
| 119 public: | |
| 120 #define V(CamelName, string_name, number, parent_types) \ | |
| 121 static constexpr uint32_t CamelName = parent_types; | |
| 122 FOR_EACH_ASM_VALUE_TYPE_LIST(V) | |
| 123 #undef V | |
| 124 | |
| 125 private: | |
| 126 DISALLOW_IMPLICIT_CONSTRUCTORS(AsmValueTypeParents); | |
| 127 }; | |
| 128 | |
| 129 TEST_F(AsmTypeTest, ValidateBits) { | |
| 130 // Generic validation tests for the bits in the type system's type | |
| 131 // definitions. | |
| 132 | |
| 133 std::unordered_set<Type*> seen_types; | |
| 134 std::unordered_set<uint32_t> seen_numbers; | |
| 135 uint32_t total_types = 0; | |
| 136 #define V(CamelName, string_name, number, parent_types) \ | |
| 137 do { \ | |
| 138 ++total_types; \ | |
| 139 seen_types.insert(Type::CamelName()); \ | |
| 140 seen_numbers.insert(number); \ | |
| 141 /* Every ASM type must have a valid number. */ \ | |
| 142 EXPECT_NE(0, number) << Type::CamelName()->Name(); \ | |
| 143 /* Inheritance cycles - unlikely, but we're paranoid and check for it */ \ | |
| 144 /* anyways.*/ \ | |
| 145 EXPECT_EQ(0, (1 << (number)) & AsmValueTypeParents::CamelName); \ | |
| 146 } while (0); | |
| 147 FOR_EACH_ASM_VALUE_TYPE_LIST(V) | |
| 148 #undef V | |
| 149 | |
| 150 // At least one type was expanded. | |
| 151 EXPECT_GT(total_types, 0); | |
| 152 | |
| 153 // Each value type is unique. | |
| 154 EXPECT_EQ(total_types, seen_types.size()); | |
| 155 | |
| 156 // Each number is unique. | |
| 157 EXPECT_EQ(total_types, seen_numbers.size()); | |
| 158 } | |
| 159 | |
| 160 TEST_F(AsmTypeTest, SaneParentsMap) { | |
| 161 // This test ensures our parents map contains all the parents types that are | |
| 162 // specified in the types' declaration. It does not report bogus inheritance. | |
| 163 | |
| 164 // Handy-dandy lambda for counting bits. Code borrowed from stack overflow. | |
| 165 auto NumberOfSetBits = [](uintptr_t parent_mask) -> uint32_t { | |
| 166 uint32_t parent_mask32 = static_cast<uint32_t>(parent_mask); | |
| 167 CHECK_EQ(parent_mask, parent_mask32); | |
| 168 parent_mask32 = parent_mask32 - ((parent_mask32 >> 1) & 0x55555555); | |
| 169 parent_mask32 = | |
| 170 (parent_mask32 & 0x33333333) + ((parent_mask32 >> 2) & 0x33333333); | |
| 171 return (((parent_mask32 + (parent_mask32 >> 4)) & 0x0F0F0F0F) * | |
| 172 0x01010101) >> | |
| 173 24; | |
| 174 }; | |
| 175 | |
| 176 #define V(CamelName, string_name, number, parent_types) \ | |
| 177 do { \ | |
| 178 const uintptr_t parents = \ | |
| 179 reinterpret_cast<uintptr_t>(Type::CamelName()) & ~(1 << (number)); \ | |
| 180 EXPECT_EQ(NumberOfSetBits(parents), \ | |
| 181 1 + ParentsOf(Type::CamelName()).size()) \ | |
| 182 << Type::CamelName()->Name() << ", parents " \ | |
| 183 << reinterpret_cast<void*>(parents) << ", type " \ | |
| 184 << static_cast<void*>(Type::CamelName()); \ | |
| 185 } while (0); | |
| 186 FOR_EACH_ASM_VALUE_TYPE_LIST(V) | |
| 187 #undef V | |
| 188 } | |
| 189 | |
| 190 TEST_F(AsmTypeTest, Names) { | |
| 191 #define V(CamelName, string_name, number, parent_types) \ | |
| 192 do { \ | |
| 193 EXPECT_THAT(Type::CamelName()->Name(), StrEq(string_name)); \ | |
| 194 } while (0); | |
| 195 FOR_EACH_ASM_VALUE_TYPE_LIST(V) | |
| 196 #undef V | |
| 197 | |
| 198 EXPECT_THAT(Function(Type::Int)(Type::Double, Type::Float)->Name(), | |
| 199 StrEq("(double, float) -> int")); | |
| 200 | |
| 201 EXPECT_THAT(Overload(Function(Type::Int)(Type::Double, Type::Float), | |
| 202 Function(Type::Int)(Type::Int)) | |
| 203 ->Name(), | |
| 204 StrEq("(double, float) -> int /\\ (int) -> int")); | |
| 205 | |
| 206 EXPECT_THAT(Type::FroundType(zone(), Type::Int())->Name(), | |
| 207 StrEq("(int) -> float")); | |
| 208 EXPECT_THAT(Type::FroundType(zone(), Type::Floatish())->Name(), | |
| 209 StrEq("(floatish) -> float")); | |
| 210 EXPECT_THAT(Type::FroundType(zone(), Type::DoubleQ())->Name(), | |
| 211 StrEq("(double?) -> float")); | |
| 212 | |
| 213 EXPECT_THAT(Type::MinMaxType(zone(), Type::Int())->Name(), | |
| 214 StrEq("(int, int...) -> int")); | |
| 215 EXPECT_THAT(Type::MinMaxType(zone(), Type::Floatish())->Name(), | |
| 216 StrEq("(floatish, floatish...) -> floatish")); | |
| 217 EXPECT_THAT(Type::MinMaxType(zone(), Type::DoubleQ())->Name(), | |
| 218 StrEq("(double?, double?...) -> double?")); | |
| 219 } | |
| 220 | |
| 221 TEST_F(AsmTypeTest, IsExactly) { | |
| 222 Type* test_types[] = { | |
| 223 #define CREATE(CamelName, string_name, number, parent_types) Type::CamelName(), | |
| 224 FOR_EACH_ASM_VALUE_TYPE_LIST(CREATE) | |
| 225 #undef CREATE | |
| 226 Function(Type::Int)(Type::Double), | |
| 227 Function(Type::Int)(Type::DoubleQ), | |
| 228 Overload(Function(Type::Int)(Type::Double)), | |
| 229 Function(Type::Int)(Type::Int, Type::Int), | |
|
ahaas
2016/06/13 16:27:03
If you duplicate the line "Function(Type::Int)(Typ
John
2016/06/13 17:32:27
Yes, because (as I mentioned before) function type
| |
| 230 Type::MinMaxType(zone(), Type::Int()), Function(Type::Int)(Type::Float), | |
| 231 Type::FroundType(zone(), Type::Int()), | |
| 232 }; | |
| 233 | |
| 234 for (size_t ii = 0; ii < arraysize(test_types); ++ii) { | |
| 235 for (size_t jj = 0; jj < arraysize(test_types); ++jj) { | |
| 236 EXPECT_EQ(ii == jj, test_types[ii]->IsExactly(test_types[jj])) | |
| 237 << test_types[ii]->Name() | |
| 238 << ((ii == jj) ? " is not exactly " : " is exactly ") | |
| 239 << test_types[jj]->Name(); | |
| 240 } | |
| 241 } | |
| 242 } | |
| 243 | |
| 244 TEST_F(AsmTypeTest, IsA) { | |
| 245 Type* test_types[] = { | |
| 246 #define CREATE(CamelName, string_name, number, parent_types) Type::CamelName(), | |
| 247 FOR_EACH_ASM_VALUE_TYPE_LIST(CREATE) | |
| 248 #undef CREATE | |
| 249 Function(Type::Int)(Type::Double), | |
| 250 Function(Type::Int)(Type::DoubleQ), | |
| 251 Overload(Function(Type::Int)(Type::Double)), | |
| 252 Function(Type::Int)(Type::Int, Type::Int), | |
| 253 Type::MinMaxType(zone(), Type::Int()), Function(Type::Int)(Type::Float), | |
| 254 Type::FroundType(zone(), Type::Int()), | |
| 255 }; | |
| 256 | |
| 257 for (size_t ii = 0; ii < arraysize(test_types); ++ii) { | |
| 258 for (size_t jj = 0; jj < arraysize(test_types); ++jj) { | |
| 259 const bool Expected = | |
| 260 (ii == jj) || ParentsOf(test_types[ii]).count(test_types[jj]) != 0; | |
| 261 EXPECT_EQ(Expected, test_types[ii]->IsA(test_types[jj])) | |
| 262 << test_types[ii]->Name() << (Expected ? " is not a " : " is a ") | |
| 263 << test_types[jj]->Name(); | |
| 264 } | |
| 265 } | |
| 266 } | |
| 267 | |
| 268 TEST_F(AsmTypeTest, ValidateCall) { | |
| 269 auto* min_max_int = Type::MinMaxType(zone(), Type::Int()); | |
| 270 auto* i2i = Function(Type::Int)(Type::Int); | |
| 271 auto* ii2i = Function(Type::Int)(Type::Int, Type::Int); | |
| 272 auto* iii2i = Function(Type::Int)(Type::Int, Type::Int, Type::Int); | |
| 273 auto* iiii2i = | |
| 274 Function(Type::Int)(Type::Int, Type::Int, Type::Int, Type::Int); | |
| 275 | |
| 276 EXPECT_EQ(Type::Int(), | |
| 277 min_max_int->AsCallableType()->ValidateCall(min_max_int)); | |
| 278 EXPECT_EQ(Type::Int(), min_max_int->AsCallableType()->ValidateCall(ii2i)); | |
| 279 EXPECT_EQ(Type::Int(), min_max_int->AsCallableType()->ValidateCall(iii2i)); | |
| 280 EXPECT_EQ(Type::Int(), min_max_int->AsCallableType()->ValidateCall(iiii2i)); | |
| 281 EXPECT_EQ(Type::None(), min_max_int->AsCallableType()->ValidateCall(i2i)); | |
| 282 | |
| 283 auto* min_max_double = Type::MinMaxType(zone(), Type::Double()); | |
| 284 auto* d2d = Function(Type::Double)(Type::Double); | |
| 285 auto* dd2d = Function(Type::Double)(Type::Double, Type::Double); | |
| 286 auto* ddd2d = | |
| 287 Function(Type::Double)(Type::Double, Type::Double, Type::Double); | |
| 288 auto* dddd2d = Function(Type::Double)(Type::Double, Type::Double, | |
| 289 Type::Double, Type::Double); | |
| 290 EXPECT_EQ(Type::Double(), | |
| 291 min_max_double->AsCallableType()->ValidateCall(min_max_double)); | |
| 292 EXPECT_EQ(Type::Double(), | |
| 293 min_max_double->AsCallableType()->ValidateCall(dd2d)); | |
| 294 EXPECT_EQ(Type::Double(), | |
| 295 min_max_double->AsCallableType()->ValidateCall(ddd2d)); | |
| 296 EXPECT_EQ(Type::Double(), | |
| 297 min_max_double->AsCallableType()->ValidateCall(dddd2d)); | |
| 298 EXPECT_EQ(Type::None(), min_max_double->AsCallableType()->ValidateCall(d2d)); | |
| 299 | |
| 300 auto* min_max = Overload(min_max_int, min_max_double); | |
| 301 EXPECT_EQ(Type::None(), min_max->AsCallableType()->ValidateCall(min_max)); | |
| 302 EXPECT_EQ(Type::None(), min_max->AsCallableType()->ValidateCall(i2i)); | |
| 303 EXPECT_EQ(Type::None(), min_max->AsCallableType()->ValidateCall(d2d)); | |
| 304 EXPECT_EQ(Type::Int(), min_max->AsCallableType()->ValidateCall(min_max_int)); | |
| 305 EXPECT_EQ(Type::Int(), min_max->AsCallableType()->ValidateCall(ii2i)); | |
| 306 EXPECT_EQ(Type::Int(), min_max->AsCallableType()->ValidateCall(iii2i)); | |
| 307 EXPECT_EQ(Type::Int(), min_max->AsCallableType()->ValidateCall(iiii2i)); | |
| 308 EXPECT_EQ(Type::Double(), | |
| 309 min_max->AsCallableType()->ValidateCall(min_max_double)); | |
| 310 EXPECT_EQ(Type::Double(), min_max->AsCallableType()->ValidateCall(dd2d)); | |
| 311 EXPECT_EQ(Type::Double(), min_max->AsCallableType()->ValidateCall(ddd2d)); | |
| 312 EXPECT_EQ(Type::Double(), min_max->AsCallableType()->ValidateCall(dddd2d)); | |
| 313 | |
| 314 auto* fround_floatish = Type::FroundType(zone(), Type::Floatish()); | |
| 315 auto* fround_floatq = Type::FroundType(zone(), Type::FloatQ()); | |
| 316 auto* fround_float = Type::FroundType(zone(), Type::Float()); | |
| 317 auto* fround_doubleq = Type::FroundType(zone(), Type::DoubleQ()); | |
| 318 auto* fround_double = Type::FroundType(zone(), Type::Double()); | |
| 319 auto* fround_signed = Type::FroundType(zone(), Type::Signed()); | |
| 320 auto* fround_unsigned = Type::FroundType(zone(), Type::Unsigned()); | |
| 321 auto* fround_fixnum = Type::FroundType(zone(), Type::FixNum()); | |
| 322 auto* fround = | |
| 323 Overload(fround_floatish, fround_floatq, fround_float, fround_doubleq, | |
| 324 fround_double, fround_signed, fround_unsigned, fround_fixnum); | |
| 325 | |
| 326 EXPECT_EQ(Type::Float(), fround->AsCallableType()->ValidateCall( | |
| 327 Function(Type::Float)(Type::Floatish))); | |
| 328 EXPECT_EQ(Type::Float(), fround->AsCallableType()->ValidateCall( | |
| 329 Function(Type::Float)(Type::FloatQ))); | |
| 330 EXPECT_EQ(Type::Float(), fround->AsCallableType()->ValidateCall( | |
| 331 Function(Type::Float)(Type::Float))); | |
| 332 EXPECT_EQ(Type::Float(), fround->AsCallableType()->ValidateCall( | |
| 333 Function(Type::Float)(Type::DoubleQ))); | |
| 334 EXPECT_EQ(Type::Float(), fround->AsCallableType()->ValidateCall( | |
| 335 Function(Type::Float)(Type::Double))); | |
| 336 EXPECT_EQ(Type::Float(), fround->AsCallableType()->ValidateCall( | |
| 337 Function(Type::Float)(Type::Signed))); | |
| 338 EXPECT_EQ(Type::Float(), fround->AsCallableType()->ValidateCall( | |
| 339 Function(Type::Float)(Type::Unsigned))); | |
| 340 EXPECT_EQ(Type::Float(), fround->AsCallableType()->ValidateCall( | |
| 341 Function(Type::Float)(Type::FixNum))); | |
| 342 | |
| 343 auto* idf2v = Function(Type::Void)(Type::Int, Type::Double, Type::Float); | |
| 344 auto* i2d = Function(Type::Double)(Type::Int); | |
| 345 auto* i2f = Function(Type::Float)(Type::Int); | |
| 346 auto* fi2d = Function(Type::Double)(Type::Float, Type::Int); | |
| 347 auto* idif2i = | |
| 348 Function(Type::Int)(Type::Int, Type::Double, Type::Int, Type::Float); | |
| 349 auto* overload = Overload(idf2v, i2f, /*i2d missing, */ fi2d, idif2i); | |
| 350 EXPECT_EQ(Type::Void(), overload->AsCallableType()->ValidateCall(idf2v)); | |
| 351 EXPECT_EQ(Type::Float(), overload->AsCallableType()->ValidateCall(i2f)); | |
| 352 EXPECT_EQ(Type::Double(), overload->AsCallableType()->ValidateCall(fi2d)); | |
| 353 EXPECT_EQ(Type::Int(), overload->AsCallableType()->ValidateCall(idif2i)); | |
| 354 EXPECT_EQ(Type::None(), overload->AsCallableType()->ValidateCall(i2d)); | |
| 355 EXPECT_EQ(Type::None(), i2f->AsCallableType()->ValidateCall(i2d)); | |
| 356 } | |
| 357 | |
| 358 TEST_F(AsmTypeTest, IsReturnType) { | |
| 359 Type* test_types[] = { | |
| 360 #define CREATE(CamelName, string_name, number, parent_types) Type::CamelName(), | |
| 361 FOR_EACH_ASM_VALUE_TYPE_LIST(CREATE) | |
| 362 #undef CREATE | |
| 363 Function(Type::Int)(Type::Double), | |
| 364 Function(Type::Int)(Type::DoubleQ), | |
| 365 Overload(Function(Type::Int)(Type::Double)), | |
| 366 Function(Type::Int)(Type::Int, Type::Int), | |
| 367 Type::MinMaxType(zone(), Type::Int()), Function(Type::Int)(Type::Float), | |
| 368 Type::FroundType(zone(), Type::Int()), | |
| 369 }; | |
| 370 | |
| 371 std::unordered_set<Type*> return_types{ | |
| 372 Type::Double(), Type::Signed(), Type::Float(), Type::Void(), | |
| 373 }; | |
| 374 | |
| 375 for (size_t ii = 0; ii < arraysize(test_types); ++ii) { | |
| 376 const bool IsReturnType = return_types.count(test_types[ii]); | |
| 377 EXPECT_EQ(IsReturnType, test_types[ii]->IsReturnType()) | |
| 378 << test_types[ii]->Name() | |
| 379 << (IsReturnType ? " is not a return type" : " is a return type"); | |
| 380 } | |
| 381 } | |
| 382 | |
| 383 TEST_F(AsmTypeTest, IsParameterType) { | |
| 384 Type* test_types[] = { | |
| 385 #define CREATE(CamelName, string_name, number, parent_types) Type::CamelName(), | |
| 386 FOR_EACH_ASM_VALUE_TYPE_LIST(CREATE) | |
| 387 #undef CREATE | |
| 388 Function(Type::Int)(Type::Double), | |
| 389 Function(Type::Int)(Type::DoubleQ), | |
| 390 Overload(Function(Type::Int)(Type::Double)), | |
| 391 Function(Type::Int)(Type::Int, Type::Int), | |
| 392 Type::MinMaxType(zone(), Type::Int()), Function(Type::Int)(Type::Float), | |
| 393 Type::FroundType(zone(), Type::Int()), | |
| 394 }; | |
| 395 | |
| 396 std::unordered_set<Type*> parameter_types{ | |
| 397 Type::Double(), Type::Int(), Type::Float(), | |
| 398 }; | |
| 399 | |
| 400 for (size_t ii = 0; ii < arraysize(test_types); ++ii) { | |
| 401 const bool IsParameterType = parameter_types.count(test_types[ii]); | |
| 402 EXPECT_EQ(IsParameterType, test_types[ii]->IsParameterType()) | |
| 403 << test_types[ii]->Name() | |
| 404 << (IsParameterType ? " is not a parameter type" | |
| 405 : " is a parameter type"); | |
| 406 } | |
| 407 } | |
| 408 | |
| 409 TEST_F(AsmTypeTest, IsComparableType) { | |
| 410 Type* test_types[] = { | |
| 411 #define CREATE(CamelName, string_name, number, parent_types) Type::CamelName(), | |
| 412 FOR_EACH_ASM_VALUE_TYPE_LIST(CREATE) | |
| 413 #undef CREATE | |
| 414 Function(Type::Int)(Type::Double), | |
| 415 Function(Type::Int)(Type::DoubleQ), | |
| 416 Overload(Function(Type::Int)(Type::Double)), | |
| 417 Function(Type::Int)(Type::Int, Type::Int), | |
| 418 Type::MinMaxType(zone(), Type::Int()), Function(Type::Int)(Type::Float), | |
| 419 Type::FroundType(zone(), Type::Int()), | |
| 420 }; | |
| 421 | |
| 422 std::unordered_set<Type*> comparable_types{ | |
| 423 Type::Double(), Type::Signed(), Type::Unsigned(), Type::Float(), | |
| 424 }; | |
| 425 | |
| 426 for (size_t ii = 0; ii < arraysize(test_types); ++ii) { | |
| 427 const bool IsComparableType = comparable_types.count(test_types[ii]); | |
| 428 EXPECT_EQ(IsComparableType, test_types[ii]->IsComparableType()) | |
| 429 << test_types[ii]->Name() | |
| 430 << (IsComparableType ? " is not a comparable type" | |
| 431 : " is a comparable type"); | |
| 432 } | |
| 433 } | |
| 434 | |
| 435 TEST_F(AsmTypeTest, ElementSizeInBytes) { | |
| 436 Type* test_types[] = { | |
| 437 #define CREATE(CamelName, string_name, number, parent_types) Type::CamelName(), | |
| 438 FOR_EACH_ASM_VALUE_TYPE_LIST(CREATE) | |
| 439 #undef CREATE | |
| 440 Function(Type::Int)(Type::Double), | |
| 441 Function(Type::Int)(Type::DoubleQ), | |
| 442 Overload(Function(Type::Int)(Type::Double)), | |
| 443 Function(Type::Int)(Type::Int, Type::Int), | |
| 444 Type::MinMaxType(zone(), Type::Int()), Function(Type::Int)(Type::Float), | |
| 445 Type::FroundType(zone(), Type::Int()), | |
| 446 }; | |
| 447 | |
| 448 auto ElementSizeInBytesForType = [](Type* type) -> int32_t { | |
| 449 if (type == Type::Int8Array() || type == Type::Uint8Array()) { | |
| 450 return 1; | |
| 451 } | |
| 452 if (type == Type::Int16Array() || type == Type::Uint16Array()) { | |
| 453 return 2; | |
| 454 } | |
| 455 if (type == Type::Int32Array() || type == Type::Uint32Array() || | |
| 456 type == Type::Float32Array()) { | |
| 457 return 4; | |
| 458 } | |
| 459 if (type == Type::Float64Array()) { | |
| 460 return 8; | |
| 461 } | |
| 462 return -1; | |
| 463 }; | |
| 464 | |
| 465 for (size_t ii = 0; ii < arraysize(test_types); ++ii) { | |
| 466 EXPECT_EQ(ElementSizeInBytesForType(test_types[ii]), | |
| 467 test_types[ii]->ElementSizeInBytes()); | |
| 468 } | |
| 469 } | |
| 470 | |
| 471 TEST_F(AsmTypeTest, LoadType) { | |
| 472 Type* test_types[] = { | |
| 473 #define CREATE(CamelName, string_name, number, parent_types) Type::CamelName(), | |
| 474 FOR_EACH_ASM_VALUE_TYPE_LIST(CREATE) | |
| 475 #undef CREATE | |
| 476 Function(Type::Int)(Type::Double), | |
| 477 Function(Type::Int)(Type::DoubleQ), | |
| 478 Overload(Function(Type::Int)(Type::Double)), | |
| 479 Function(Type::Int)(Type::Int, Type::Int), | |
| 480 Type::MinMaxType(zone(), Type::Int()), Function(Type::Int)(Type::Float), | |
| 481 Type::FroundType(zone(), Type::Int()), | |
| 482 }; | |
| 483 | |
| 484 auto LoadTypeForType = [](Type* type) -> Type* { | |
| 485 if (type == Type::Int8Array() || type == Type::Uint8Array() || | |
| 486 type == Type::Int16Array() || type == Type::Uint16Array() || | |
| 487 type == Type::Int32Array() || type == Type::Uint32Array()) { | |
| 488 return Type::Intish(); | |
| 489 } | |
| 490 | |
| 491 if (type == Type::Float32Array()) { | |
| 492 return Type::FloatQ(); | |
| 493 } | |
| 494 | |
| 495 if (type == Type::Float64Array()) { | |
| 496 return Type::DoubleQ(); | |
| 497 } | |
| 498 | |
| 499 return Type::None(); | |
| 500 }; | |
| 501 | |
| 502 for (size_t ii = 0; ii < arraysize(test_types); ++ii) { | |
| 503 EXPECT_EQ(LoadTypeForType(test_types[ii]), test_types[ii]->LoadType()); | |
| 504 } | |
| 505 } | |
| 506 | |
| 507 TEST_F(AsmTypeTest, StoreType) { | |
| 508 Type* test_types[] = { | |
| 509 #define CREATE(CamelName, string_name, number, parent_types) Type::CamelName(), | |
| 510 FOR_EACH_ASM_VALUE_TYPE_LIST(CREATE) | |
| 511 #undef CREATE | |
| 512 Function(Type::Int)(Type::Double), | |
| 513 Function(Type::Int)(Type::DoubleQ), | |
| 514 Overload(Function(Type::Int)(Type::Double)), | |
| 515 Function(Type::Int)(Type::Int, Type::Int), | |
| 516 Type::MinMaxType(zone(), Type::Int()), Function(Type::Int)(Type::Float), | |
| 517 Type::FroundType(zone(), Type::Int()), | |
| 518 }; | |
| 519 | |
| 520 auto StoreTypeForType = [](Type* type) -> Type* { | |
| 521 if (type == Type::Int8Array() || type == Type::Uint8Array() || | |
| 522 type == Type::Int16Array() || type == Type::Uint16Array() || | |
| 523 type == Type::Int32Array() || type == Type::Uint32Array()) { | |
| 524 return Type::Intish(); | |
| 525 } | |
| 526 | |
| 527 if (type == Type::Float32Array()) { | |
| 528 return Type::FloatishDoubleQ(); | |
| 529 } | |
| 530 | |
| 531 if (type == Type::Float64Array()) { | |
| 532 return Type::FloatQDoubleQ(); | |
| 533 } | |
| 534 | |
| 535 return Type::None(); | |
| 536 }; | |
| 537 | |
| 538 for (size_t ii = 0; ii < arraysize(test_types); ++ii) { | |
| 539 EXPECT_EQ(StoreTypeForType(test_types[ii]), test_types[ii]->StoreType()) | |
| 540 << test_types[ii]->Name(); | |
| 541 } | |
| 542 } | |
| 543 | |
| 544 } // namespace | |
| 545 } // namespace wasm | |
| 546 } // namespace internal | |
| 547 } // namespace v8 | |
| OLD | NEW |