blob: 9b29362537225f1978f96974816700f5183b1c47 [file] [log] [blame]
Ben Murdoch61f157c2016-09-16 13:49:30 +01001// 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
15namespace v8 {
16namespace internal {
17namespace wasm {
18namespace {
19
20using ::testing::StrEq;
21
22class 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&& b)
62 : function_type_(b.function_type_) {
63 b.function_type_ = nullptr;
64 }
65
66 FunctionTypeBuilder& operator=(FunctionTypeBuilder&& b) {
67 if (this != &b) {
68 function_type_ = b.function_type_;
69 b.function_type_ = nullptr;
70 }
71 return *this;
72 }
73
74 FunctionTypeBuilder(Zone* zone, Type* return_type)
75 : function_type_(Type::Function(zone, return_type)) {}
76
77 private:
78 static void AddAllArguments(AsmFunctionType*) {}
79
80 template <typename Arg, typename... Others>
81 static void AddAllArguments(AsmFunctionType* function_type, Arg* arg,
82 Others... others) {
83 CHECK(function_type != nullptr);
84 function_type->AddArgument((*arg)());
85 AddAllArguments(function_type, others...);
86 }
87
88 public:
89 template <typename... Args>
90 Type* operator()(Args... args) {
91 Type* ret = function_type_;
92 function_type_ = nullptr;
93 AddAllArguments(ret->AsFunctionType(), args...);
94 return ret;
95 }
96
97 private:
98 Type* function_type_;
99 };
100
101 FunctionTypeBuilder Function(Type* (*return_type)()) {
102 return FunctionTypeBuilder(zone(), (*return_type)());
103 }
104
105 template <typename... Overloads>
106 Type* Overload(Overloads... overloads) {
107 auto* ret = Type::OverloadedFunction(zone());
108 AddAllOverloads(ret->AsOverloadedFunctionType(), overloads...);
109 return ret;
110 }
111
112 private:
113 static void AddAllOverloads(AsmOverloadedFunctionType*) {}
114
115 template <typename Overload, typename... Others>
116 static void AddAllOverloads(AsmOverloadedFunctionType* function,
117 Overload* overload, Others... others) {
118 CHECK(function != nullptr);
119 function->AddOverload(overload);
120 AddAllOverloads(function, others...);
121 }
122
123 const std::unordered_map<Type*, std::unordered_set<Type*>> parents_;
124};
125
126// AsmValueTypeParents expose the bitmasks for the parents for each value type
127// in asm's type system. It inherits from AsmValueType so that the kAsm<Foo>
128// members are available when expanding the FOR_EACH_ASM_VALUE_TYPE_LIST macro.
129class AsmValueTypeParents : private AsmValueType {
130 public:
131 enum : uint32_t {
132#define V(CamelName, string_name, number, parent_types) \
133 CamelName = parent_types,
134 FOR_EACH_ASM_VALUE_TYPE_LIST(V)
135#undef V
136 };
137
138 private:
139 DISALLOW_IMPLICIT_CONSTRUCTORS(AsmValueTypeParents);
140};
141
142TEST_F(AsmTypeTest, ValidateBits) {
143 // Generic validation tests for the bits in the type system's type
144 // definitions.
145
146 std::unordered_set<Type*> seen_types;
147 std::unordered_set<uint32_t> seen_numbers;
148 uint32_t total_types = 0;
149#define V(CamelName, string_name, number, parent_types) \
150 do { \
151 ++total_types; \
152 if (AsmValueTypeParents::CamelName != 0) { \
153 EXPECT_NE(0, ParentsOf(AsmType::CamelName()).size()) << #CamelName; \
154 } \
155 seen_types.insert(Type::CamelName()); \
156 seen_numbers.insert(number); \
157 /* Every ASM type must have a valid number. */ \
158 EXPECT_NE(0, number) << Type::CamelName()->Name(); \
159 /* Inheritance cycles - unlikely, but we're paranoid and check for it */ \
160 /* anyways.*/ \
161 EXPECT_EQ(0, (1 << (number)) & AsmValueTypeParents::CamelName); \
162 } while (0);
163 FOR_EACH_ASM_VALUE_TYPE_LIST(V)
164#undef V
165
166 // At least one type was expanded.
167 EXPECT_GT(total_types, 0u);
168
169 // Each value type is unique.
170 EXPECT_EQ(total_types, seen_types.size());
171
172 // Each number is unique.
173 EXPECT_EQ(total_types, seen_numbers.size());
174}
175
176TEST_F(AsmTypeTest, SaneParentsMap) {
177 // This test ensures our parents map contains all the parents types that are
178 // specified in the types' declaration. It does not report bogus inheritance.
179
180 // Handy-dandy lambda for counting bits. Code borrowed from stack overflow.
181 auto NumberOfSetBits = [](uintptr_t parent_mask) -> uint32_t {
182 uint32_t parent_mask32 = static_cast<uint32_t>(parent_mask);
183 CHECK_EQ(parent_mask, parent_mask32);
184 parent_mask32 = parent_mask32 - ((parent_mask32 >> 1) & 0x55555555);
185 parent_mask32 =
186 (parent_mask32 & 0x33333333) + ((parent_mask32 >> 2) & 0x33333333);
187 return (((parent_mask32 + (parent_mask32 >> 4)) & 0x0F0F0F0F) *
188 0x01010101) >>
189 24;
190 };
191
192#define V(CamelName, string_name, number, parent_types) \
193 do { \
194 const uintptr_t parents = \
195 reinterpret_cast<uintptr_t>(Type::CamelName()) & ~(1 << (number)); \
196 EXPECT_EQ(NumberOfSetBits(parents), \
197 1 + ParentsOf(Type::CamelName()).size()) \
198 << Type::CamelName()->Name() << ", parents " \
199 << reinterpret_cast<void*>(parents) << ", type " \
200 << static_cast<void*>(Type::CamelName()); \
201 } while (0);
202 FOR_EACH_ASM_VALUE_TYPE_LIST(V)
203#undef V
204}
205
206TEST_F(AsmTypeTest, Names) {
207#define V(CamelName, string_name, number, parent_types) \
208 do { \
209 EXPECT_THAT(Type::CamelName()->Name(), StrEq(string_name)); \
210 } while (0);
211 FOR_EACH_ASM_VALUE_TYPE_LIST(V)
212#undef V
213
214 EXPECT_THAT(Function(Type::Int)(Type::Double, Type::Float)->Name(),
215 StrEq("(double, float) -> int"));
216
217 EXPECT_THAT(Overload(Function(Type::Int)(Type::Double, Type::Float),
218 Function(Type::Int)(Type::Int))
219 ->Name(),
220 StrEq("(double, float) -> int /\\ (int) -> int"));
221
222 EXPECT_THAT(Type::FroundType(zone())->Name(), StrEq("fround"));
223
224 EXPECT_THAT(Type::MinMaxType(zone(), Type::Signed(), Type::Int())->Name(),
225 StrEq("(int, int...) -> signed"));
226 EXPECT_THAT(Type::MinMaxType(zone(), Type::Float(), Type::Floatish())->Name(),
227 StrEq("(floatish, floatish...) -> float"));
228 EXPECT_THAT(Type::MinMaxType(zone(), Type::Double(), Type::DoubleQ())->Name(),
229 StrEq("(double?, double?...) -> double"));
230
231 EXPECT_THAT(Type::FFIType(zone())->Name(), StrEq("Function"));
232
233 auto* ft =
234 Type::FunctionTableType(zone(), 15, Function(Type::Double)(Type::Int));
235 EXPECT_THAT(ft->Name(), StrEq("(int) -> double[15]"));
236}
237
238TEST_F(AsmTypeTest, IsExactly) {
239 Type* test_types[] = {
240#define CREATE(CamelName, string_name, number, parent_types) Type::CamelName(),
241 FOR_EACH_ASM_VALUE_TYPE_LIST(CREATE)
242#undef CREATE
243 Function(Type::Int)(Type::Double),
244 Function(Type::Int)(Type::DoubleQ),
245 Overload(Function(Type::Int)(Type::Double)),
246 Function(Type::Int)(Type::Int, Type::Int),
247 Type::MinMaxType(zone(), Type::Signed(), Type::Int()),
248 Function(Type::Int)(Type::Float), Type::FroundType(zone()),
249 Type::FFIType(zone()),
250 Type::FunctionTableType(zone(), 10, Function(Type::Void)()),
251 };
252
253 for (size_t ii = 0; ii < arraysize(test_types); ++ii) {
254 for (size_t jj = 0; jj < arraysize(test_types); ++jj) {
255 EXPECT_EQ(ii == jj, test_types[ii]->IsExactly(test_types[jj]))
256 << test_types[ii]->Name()
257 << ((ii == jj) ? " is not exactly " : " is exactly ")
258 << test_types[jj]->Name();
259 }
260 }
261}
262
263TEST_F(AsmTypeTest, IsA) {
264 Type* test_types[] = {
265#define CREATE(CamelName, string_name, number, parent_types) Type::CamelName(),
266 FOR_EACH_ASM_VALUE_TYPE_LIST(CREATE)
267#undef CREATE
268 Function(Type::Int)(Type::Double),
269 Function(Type::Int)(Type::DoubleQ),
270 Overload(Function(Type::Int)(Type::Double)),
271 Function(Type::Int)(Type::Int, Type::Int),
272 Type::MinMaxType(zone(), Type::Signed(), Type::Int()),
273 Function(Type::Int)(Type::Float), Type::FroundType(zone()),
274 Type::FFIType(zone()),
275 Type::FunctionTableType(zone(), 10, Function(Type::Void)()),
276 };
277
278 for (size_t ii = 0; ii < arraysize(test_types); ++ii) {
279 for (size_t jj = 0; jj < arraysize(test_types); ++jj) {
280 const bool Expected =
281 (ii == jj) || ParentsOf(test_types[ii]).count(test_types[jj]) != 0;
282 EXPECT_EQ(Expected, test_types[ii]->IsA(test_types[jj]))
283 << test_types[ii]->Name() << (Expected ? " is not a " : " is a ")
284 << test_types[jj]->Name();
285 }
286 }
287}
288
289TEST_F(AsmTypeTest, ValidateCall) {
290 auto* min_max_int = Type::MinMaxType(zone(), Type::Signed(), Type::Int());
291 auto* i2s = Function(Type::Signed)(Type::Int);
292 auto* ii2s = Function(Type::Signed)(Type::Int, Type::Int);
293 auto* iii2s = Function(Type::Signed)(Type::Int, Type::Int, Type::Int);
294 auto* iiii2s =
295 Function(Type::Signed)(Type::Int, Type::Int, Type::Int, Type::Int);
296
297 EXPECT_EQ(Type::Signed(), min_max_int->AsCallableType()->ValidateCall(
298 min_max_int->AsFunctionType()->ReturnType(),
299 min_max_int->AsFunctionType()->Arguments()));
300 EXPECT_EQ(Type::Signed(), min_max_int->AsCallableType()->ValidateCall(
301 ii2s->AsFunctionType()->ReturnType(),
302 ii2s->AsFunctionType()->Arguments()));
303 EXPECT_EQ(Type::Signed(), min_max_int->AsCallableType()->ValidateCall(
304 iii2s->AsFunctionType()->ReturnType(),
305 iii2s->AsFunctionType()->Arguments()));
306 EXPECT_EQ(Type::Signed(), min_max_int->AsCallableType()->ValidateCall(
307 iiii2s->AsFunctionType()->ReturnType(),
308 iiii2s->AsFunctionType()->Arguments()));
309 EXPECT_EQ(Type::None(), min_max_int->AsCallableType()->ValidateCall(
310 i2s->AsFunctionType()->ReturnType(),
311 i2s->AsFunctionType()->Arguments()));
312
313 auto* min_max_double =
314 Type::MinMaxType(zone(), Type::Double(), Type::Double());
315 auto* d2d = Function(Type::Double)(Type::Double);
316 auto* dd2d = Function(Type::Double)(Type::Double, Type::Double);
317 auto* ddd2d =
318 Function(Type::Double)(Type::Double, Type::Double, Type::Double);
319 auto* dddd2d = Function(Type::Double)(Type::Double, Type::Double,
320 Type::Double, Type::Double);
321 EXPECT_EQ(Type::Double(), min_max_double->AsCallableType()->ValidateCall(
322 min_max_double->AsFunctionType()->ReturnType(),
323 min_max_double->AsFunctionType()->Arguments()));
324 EXPECT_EQ(Type::Double(), min_max_double->AsCallableType()->ValidateCall(
325 dd2d->AsFunctionType()->ReturnType(),
326 dd2d->AsFunctionType()->Arguments()));
327 EXPECT_EQ(Type::Double(), min_max_double->AsCallableType()->ValidateCall(
328 ddd2d->AsFunctionType()->ReturnType(),
329 ddd2d->AsFunctionType()->Arguments()));
330 EXPECT_EQ(Type::Double(), min_max_double->AsCallableType()->ValidateCall(
331 dddd2d->AsFunctionType()->ReturnType(),
332 dddd2d->AsFunctionType()->Arguments()));
333 EXPECT_EQ(Type::None(), min_max_double->AsCallableType()->ValidateCall(
334 d2d->AsFunctionType()->ReturnType(),
335 d2d->AsFunctionType()->Arguments()));
336
337 auto* min_max = Overload(min_max_int, min_max_double);
338 EXPECT_EQ(Type::None(), min_max->AsCallableType()->ValidateCall(
339 i2s->AsFunctionType()->ReturnType(),
340 i2s->AsFunctionType()->Arguments()));
341 EXPECT_EQ(Type::None(), min_max->AsCallableType()->ValidateCall(
342 d2d->AsFunctionType()->ReturnType(),
343 d2d->AsFunctionType()->Arguments()));
344 EXPECT_EQ(Type::Signed(), min_max->AsCallableType()->ValidateCall(
345 min_max_int->AsFunctionType()->ReturnType(),
346 min_max_int->AsFunctionType()->Arguments()));
347 EXPECT_EQ(Type::Signed(), min_max->AsCallableType()->ValidateCall(
348 ii2s->AsFunctionType()->ReturnType(),
349 ii2s->AsFunctionType()->Arguments()));
350 EXPECT_EQ(Type::Signed(), min_max->AsCallableType()->ValidateCall(
351 iii2s->AsFunctionType()->ReturnType(),
352 iii2s->AsFunctionType()->Arguments()));
353 EXPECT_EQ(Type::Signed(), min_max->AsCallableType()->ValidateCall(
354 iiii2s->AsFunctionType()->ReturnType(),
355 iiii2s->AsFunctionType()->Arguments()));
356 EXPECT_EQ(Type::Double(), min_max->AsCallableType()->ValidateCall(
357 min_max_double->AsFunctionType()->ReturnType(),
358 min_max_double->AsFunctionType()->Arguments()));
359 EXPECT_EQ(Type::Double(), min_max->AsCallableType()->ValidateCall(
360 dd2d->AsFunctionType()->ReturnType(),
361 dd2d->AsFunctionType()->Arguments()));
362 EXPECT_EQ(Type::Double(), min_max->AsCallableType()->ValidateCall(
363 ddd2d->AsFunctionType()->ReturnType(),
364 ddd2d->AsFunctionType()->Arguments()));
365 EXPECT_EQ(Type::Double(), min_max->AsCallableType()->ValidateCall(
366 dddd2d->AsFunctionType()->ReturnType(),
367 dddd2d->AsFunctionType()->Arguments()));
368
369 auto* fround = Type::FroundType(zone());
370
371 ZoneVector<AsmType*> arg(zone());
372 arg.push_back(Type::Floatish());
373 EXPECT_EQ(Type::Float(),
374 fround->AsCallableType()->ValidateCall(Type::Float(), arg));
375 arg.clear();
376 arg.push_back(Type::FloatQ());
377 EXPECT_EQ(Type::Float(),
378 fround->AsCallableType()->ValidateCall(Type::Float(), arg));
379 arg.clear();
380 arg.push_back(Type::Float());
381 EXPECT_EQ(Type::Float(),
382 fround->AsCallableType()->ValidateCall(Type::Float(), arg));
383 arg.clear();
384 arg.push_back(Type::DoubleQ());
385 EXPECT_EQ(Type::Float(),
386 fround->AsCallableType()->ValidateCall(Type::Float(), arg));
387 arg.clear();
388 arg.push_back(Type::Double());
389 EXPECT_EQ(Type::Float(),
390 fround->AsCallableType()->ValidateCall(Type::Float(), arg));
391 arg.clear();
392 arg.push_back(Type::Signed());
393 EXPECT_EQ(Type::Float(),
394 fround->AsCallableType()->ValidateCall(Type::Float(), arg));
395 arg.clear();
396 arg.push_back(Type::Unsigned());
397 EXPECT_EQ(Type::Float(),
398 fround->AsCallableType()->ValidateCall(Type::Float(), arg));
399 arg.clear();
400 arg.push_back(Type::FixNum());
401 EXPECT_EQ(Type::Float(),
402 fround->AsCallableType()->ValidateCall(Type::Float(), arg));
403
404 auto* idf2v = Function(Type::Void)(Type::Int, Type::Double, Type::Float);
405 auto* i2d = Function(Type::Double)(Type::Int);
406 auto* i2f = Function(Type::Float)(Type::Int);
407 auto* fi2d = Function(Type::Double)(Type::Float, Type::Int);
408 auto* idif2i =
409 Function(Type::Int)(Type::Int, Type::Double, Type::Int, Type::Float);
410 auto* overload = Overload(idf2v, i2f, /*i2d missing, */ fi2d, idif2i);
411 EXPECT_EQ(Type::Void(), overload->AsCallableType()->ValidateCall(
412 idf2v->AsFunctionType()->ReturnType(),
413 idf2v->AsFunctionType()->Arguments()));
414 EXPECT_EQ(Type::Float(), overload->AsCallableType()->ValidateCall(
415 i2f->AsFunctionType()->ReturnType(),
416 i2f->AsFunctionType()->Arguments()));
417 EXPECT_EQ(Type::Double(), overload->AsCallableType()->ValidateCall(
418 fi2d->AsFunctionType()->ReturnType(),
419 fi2d->AsFunctionType()->Arguments()));
420 EXPECT_EQ(Type::Int(), overload->AsCallableType()->ValidateCall(
421 idif2i->AsFunctionType()->ReturnType(),
422 idif2i->AsFunctionType()->Arguments()));
423 EXPECT_EQ(Type::None(), overload->AsCallableType()->ValidateCall(
424 i2d->AsFunctionType()->ReturnType(),
425 i2d->AsFunctionType()->Arguments()));
426 EXPECT_EQ(Type::None(), i2f->AsCallableType()->ValidateCall(
427 i2d->AsFunctionType()->ReturnType(),
428 i2d->AsFunctionType()->Arguments()));
429
430 auto* ffi = Type::FFIType(zone());
431 AsmType* (*kReturnTypes[])() = {
432 Type::Void, Type::Double, Type::Signed,
433 };
434 AsmType* (*kParameterTypes[])() = {
435 Type::Double, Type::Signed, Type::FixNum,
436 };
437 for (size_t ii = 0; ii < arraysize(kReturnTypes); ++ii) {
438 for (size_t jj = 0; jj < arraysize(kParameterTypes); ++jj) {
439 auto* f = Function(kReturnTypes[ii])(kParameterTypes[jj]);
440 EXPECT_EQ(kReturnTypes[ii](), ffi->AsCallableType()->ValidateCall(
441 f->AsFunctionType()->ReturnType(),
442 f->AsFunctionType()->Arguments()))
443 << kReturnTypes[ii]()->Name();
444
445 // Call with non-parameter type type should fail.
446 f = Function(kReturnTypes[ii])(kParameterTypes[jj], Type::Int);
447 EXPECT_EQ(Type::None(), ffi->AsCallableType()->ValidateCall(
448 f->AsFunctionType()->ReturnType(),
449 f->AsFunctionType()->Arguments()))
450 << kReturnTypes[ii]()->Name();
451 }
452 }
453
454 auto* ft0 = Type::FunctionTableType(zone(), 10, fi2d);
455 EXPECT_EQ(Type::Double(), ft0->AsCallableType()->ValidateCall(
456 fi2d->AsFunctionType()->ReturnType(),
457 fi2d->AsFunctionType()->Arguments()));
458 EXPECT_EQ(Type::None(), ft0->AsCallableType()->ValidateCall(
459 i2d->AsFunctionType()->ReturnType(),
460 i2d->AsFunctionType()->Arguments()));
461}
462
463TEST_F(AsmTypeTest, ToReturnType) {
464 std::unordered_map<AsmType*, AsmType*> kToReturnType = {
465 {Type::Signed(), Type::Signed()}, {Type::FixNum(), Type::Signed()},
466 {Type::Double(), Type::Double()}, {Type::Float(), Type::Float()},
467 {Type::Void(), Type::Void()},
468 };
469
470 Type* test_types[] = {
471#define CREATE(CamelName, string_name, number, parent_types) Type::CamelName(),
472 FOR_EACH_ASM_VALUE_TYPE_LIST(CREATE)
473#undef CREATE
474 Function(Type::Int)(Type::Double),
475 Function(Type::Int)(Type::DoubleQ),
476 Overload(Function(Type::Int)(Type::Double)),
477 Function(Type::Int)(Type::Int, Type::Int),
478 Type::MinMaxType(zone(), Type::Signed(), Type::Int()),
479 Function(Type::Int)(Type::Float), Type::FroundType(zone()),
480 Type::FFIType(zone()),
481 Type::FunctionTableType(zone(), 10, Function(Type::Void)()),
482 };
483
484 for (size_t ii = 0; ii < arraysize(test_types); ++ii) {
485 auto* return_type = Type::None();
486 auto to_return_type_iter = kToReturnType.find(test_types[ii]);
487 if (to_return_type_iter != kToReturnType.end()) {
488 return_type = to_return_type_iter->second;
489 }
490 EXPECT_EQ(return_type, test_types[ii]->ToReturnType())
491 << return_type->Name() << " != " << test_types[ii]->ToReturnType();
492 }
493}
494
495TEST_F(AsmTypeTest, IsReturnType) {
496 Type* test_types[] = {
497#define CREATE(CamelName, string_name, number, parent_types) Type::CamelName(),
498 FOR_EACH_ASM_VALUE_TYPE_LIST(CREATE)
499#undef CREATE
500 Function(Type::Int)(Type::Double),
501 Function(Type::Int)(Type::DoubleQ),
502 Overload(Function(Type::Int)(Type::Double)),
503 Function(Type::Int)(Type::Int, Type::Int),
504 Type::MinMaxType(zone(), Type::Signed(), Type::Int()),
505 Function(Type::Int)(Type::Float), Type::FroundType(zone()),
506 Type::FFIType(zone()),
507 Type::FunctionTableType(zone(), 10, Function(Type::Void)()),
508 };
509
510 std::unordered_set<Type*> return_types{
511 Type::Double(), Type::Signed(), Type::Float(), Type::Void(),
512 };
513
514 for (size_t ii = 0; ii < arraysize(test_types); ++ii) {
515 const bool IsReturnType = return_types.count(test_types[ii]);
516 EXPECT_EQ(IsReturnType, test_types[ii]->IsReturnType())
517 << test_types[ii]->Name()
518 << (IsReturnType ? " is not a return type" : " is a return type");
519 }
520}
521
522TEST_F(AsmTypeTest, ToParameterType) {
523 std::unordered_map<AsmType*, AsmType*> kToParameterType = {
524 {Type::Int(), Type::Int()}, {Type::Signed(), Type::Int()},
525 {Type::Unsigned(), Type::Int()}, {Type::FixNum(), Type::Int()},
526 {Type::Double(), Type::Double()}, {Type::Float(), Type::Float()},
527 };
528
529 Type* test_types[] = {
530#define CREATE(CamelName, string_name, number, parent_types) Type::CamelName(),
531 FOR_EACH_ASM_VALUE_TYPE_LIST(CREATE)
532#undef CREATE
533 Function(Type::Int)(Type::Double),
534 Function(Type::Int)(Type::DoubleQ),
535 Overload(Function(Type::Int)(Type::Double)),
536 Function(Type::Int)(Type::Int, Type::Int),
537 Type::MinMaxType(zone(), Type::Signed(), Type::Int()),
538 Function(Type::Int)(Type::Float), Type::FroundType(zone()),
539 Type::FFIType(zone()),
540 Type::FunctionTableType(zone(), 10, Function(Type::Void)()),
541 };
542
543 for (size_t ii = 0; ii < arraysize(test_types); ++ii) {
544 auto* parameter_type = Type::None();
545 auto to_parameter_type_iter = kToParameterType.find(test_types[ii]);
546 if (to_parameter_type_iter != kToParameterType.end()) {
547 parameter_type = to_parameter_type_iter->second;
548 }
549 EXPECT_EQ(parameter_type, test_types[ii]->ToParameterType())
550 << parameter_type->Name()
551 << " != " << test_types[ii]->ToParameterType();
552 }
553}
554
555TEST_F(AsmTypeTest, IsParameterType) {
556 Type* test_types[] = {
557#define CREATE(CamelName, string_name, number, parent_types) Type::CamelName(),
558 FOR_EACH_ASM_VALUE_TYPE_LIST(CREATE)
559#undef CREATE
560 Function(Type::Int)(Type::Double),
561 Function(Type::Int)(Type::DoubleQ),
562 Overload(Function(Type::Int)(Type::Double)),
563 Function(Type::Int)(Type::Int, Type::Int),
564 Type::MinMaxType(zone(), Type::Signed(), Type::Int()),
565 Function(Type::Int)(Type::Float), Type::FroundType(zone()),
566 Type::FFIType(zone()),
567 Type::FunctionTableType(zone(), 10, Function(Type::Void)()),
568 };
569
570 std::unordered_set<Type*> parameter_types{
571 Type::Double(), Type::Int(), Type::Float(),
572 };
573
574 for (size_t ii = 0; ii < arraysize(test_types); ++ii) {
575 const bool IsParameterType = parameter_types.count(test_types[ii]);
576 EXPECT_EQ(IsParameterType, test_types[ii]->IsParameterType())
577 << test_types[ii]->Name()
578 << (IsParameterType ? " is not a parameter type"
579 : " is a parameter type");
580 }
581}
582
583TEST_F(AsmTypeTest, IsComparableType) {
584 Type* test_types[] = {
585#define CREATE(CamelName, string_name, number, parent_types) Type::CamelName(),
586 FOR_EACH_ASM_VALUE_TYPE_LIST(CREATE)
587#undef CREATE
588 Function(Type::Int)(Type::Double),
589 Function(Type::Int)(Type::DoubleQ),
590 Overload(Function(Type::Int)(Type::Double)),
591 Function(Type::Int)(Type::Int, Type::Int),
592 Type::MinMaxType(zone(), Type::Signed(), Type::Int()),
593 Function(Type::Int)(Type::Float), Type::FroundType(zone()),
594 Type::FFIType(zone()),
595 Type::FunctionTableType(zone(), 10, Function(Type::Void)()),
596 };
597
598 std::unordered_set<Type*> comparable_types{
599 Type::Double(), Type::Signed(), Type::Unsigned(), Type::Float(),
600 };
601
602 for (size_t ii = 0; ii < arraysize(test_types); ++ii) {
603 const bool IsComparableType = comparable_types.count(test_types[ii]);
604 EXPECT_EQ(IsComparableType, test_types[ii]->IsComparableType())
605 << test_types[ii]->Name()
606 << (IsComparableType ? " is not a comparable type"
607 : " is a comparable type");
608 }
609}
610
611TEST_F(AsmTypeTest, ElementSizeInBytes) {
612 Type* test_types[] = {
613#define CREATE(CamelName, string_name, number, parent_types) Type::CamelName(),
614 FOR_EACH_ASM_VALUE_TYPE_LIST(CREATE)
615#undef CREATE
616 Function(Type::Int)(Type::Double),
617 Function(Type::Int)(Type::DoubleQ),
618 Overload(Function(Type::Int)(Type::Double)),
619 Function(Type::Int)(Type::Int, Type::Int),
620 Type::MinMaxType(zone(), Type::Signed(), Type::Int()),
621 Function(Type::Int)(Type::Float), Type::FroundType(zone()),
622 Type::FFIType(zone()),
623 Type::FunctionTableType(zone(), 10, Function(Type::Void)()),
624 };
625
626 auto ElementSizeInBytesForType = [](Type* type) -> int32_t {
627 if (type == Type::Int8Array() || type == Type::Uint8Array()) {
628 return 1;
629 }
630 if (type == Type::Int16Array() || type == Type::Uint16Array()) {
631 return 2;
632 }
633 if (type == Type::Int32Array() || type == Type::Uint32Array() ||
634 type == Type::Float32Array()) {
635 return 4;
636 }
637 if (type == Type::Float64Array()) {
638 return 8;
639 }
640 return -1;
641 };
642
643 for (size_t ii = 0; ii < arraysize(test_types); ++ii) {
644 EXPECT_EQ(ElementSizeInBytesForType(test_types[ii]),
645 test_types[ii]->ElementSizeInBytes());
646 }
647}
648
649TEST_F(AsmTypeTest, LoadType) {
650 Type* test_types[] = {
651#define CREATE(CamelName, string_name, number, parent_types) Type::CamelName(),
652 FOR_EACH_ASM_VALUE_TYPE_LIST(CREATE)
653#undef CREATE
654 Function(Type::Int)(Type::Double),
655 Function(Type::Int)(Type::DoubleQ),
656 Overload(Function(Type::Int)(Type::Double)),
657 Function(Type::Int)(Type::Int, Type::Int),
658 Type::MinMaxType(zone(), Type::Signed(), Type::Int()),
659 Function(Type::Int)(Type::Float), Type::FroundType(zone()),
660 Type::FFIType(zone()),
661 Type::FunctionTableType(zone(), 10, Function(Type::Void)()),
662 };
663
664 auto LoadTypeForType = [](Type* type) -> Type* {
665 if (type == Type::Int8Array() || type == Type::Uint8Array() ||
666 type == Type::Int16Array() || type == Type::Uint16Array() ||
667 type == Type::Int32Array() || type == Type::Uint32Array()) {
668 return Type::Intish();
669 }
670
671 if (type == Type::Float32Array()) {
672 return Type::FloatQ();
673 }
674
675 if (type == Type::Float64Array()) {
676 return Type::DoubleQ();
677 }
678
679 return Type::None();
680 };
681
682 for (size_t ii = 0; ii < arraysize(test_types); ++ii) {
683 EXPECT_EQ(LoadTypeForType(test_types[ii]), test_types[ii]->LoadType());
684 }
685}
686
687TEST_F(AsmTypeTest, StoreType) {
688 Type* test_types[] = {
689#define CREATE(CamelName, string_name, number, parent_types) Type::CamelName(),
690 FOR_EACH_ASM_VALUE_TYPE_LIST(CREATE)
691#undef CREATE
692 Function(Type::Int)(Type::Double),
693 Function(Type::Int)(Type::DoubleQ),
694 Overload(Function(Type::Int)(Type::Double)),
695 Function(Type::Int)(Type::Int, Type::Int),
696 Type::MinMaxType(zone(), Type::Signed(), Type::Int()),
697 Function(Type::Int)(Type::Float), Type::FroundType(zone()),
698 Type::FFIType(zone()),
699 Type::FunctionTableType(zone(), 10, Function(Type::Void)()),
700 };
701
702 auto StoreTypeForType = [](Type* type) -> Type* {
703 if (type == Type::Int8Array() || type == Type::Uint8Array() ||
704 type == Type::Int16Array() || type == Type::Uint16Array() ||
705 type == Type::Int32Array() || type == Type::Uint32Array()) {
706 return Type::Intish();
707 }
708
709 if (type == Type::Float32Array()) {
710 return Type::FloatishDoubleQ();
711 }
712
713 if (type == Type::Float64Array()) {
714 return Type::FloatQDoubleQ();
715 }
716
717 return Type::None();
718 };
719
720 for (size_t ii = 0; ii < arraysize(test_types); ++ii) {
721 EXPECT_EQ(StoreTypeForType(test_types[ii]), test_types[ii]->StoreType())
722 << test_types[ii]->Name();
723 }
724}
725
726} // namespace
727} // namespace wasm
728} // namespace internal
729} // namespace v8