blob: e251242dee32da90c98d4d1f11c5cd9406fcbbde [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2013 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000029#include <iostream> // NOLINT(readability/streams)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000030
31#include "src/v8.h"
32#include "test/cctest/cctest.h"
33
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000034#include "src/base/utils/random-number-generator.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000035#include "src/macro-assembler.h"
36#include "src/mips64/macro-assembler-mips64.h"
37#include "src/mips64/simulator-mips64.h"
38
39
40using namespace v8::internal;
41
42typedef void* (*F)(int64_t x, int64_t y, int p2, int p3, int p4);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000043typedef Object* (*F1)(int x, int p1, int p2, int p3, int p4);
Ben Murdochda12d292016-06-02 14:46:10 +010044typedef Object* (*F3)(void* p, int p1, int p2, int p3, int p4);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000045
46#define __ masm->
47
48
49static byte to_non_zero(int n) {
50 return static_cast<unsigned>(n) % 255 + 1;
51}
52
53
54static bool all_zeroes(const byte* beg, const byte* end) {
55 CHECK(beg);
56 CHECK(beg <= end);
57 while (beg < end) {
58 if (*beg++ != 0)
59 return false;
60 }
61 return true;
62}
63
64
65TEST(CopyBytes) {
66 CcTest::InitializeVM();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000067 Isolate* isolate = CcTest::i_isolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000068 HandleScope handles(isolate);
69
70 const int data_size = 1 * KB;
71 size_t act_size;
72
73 // Allocate two blocks to copy data between.
74 byte* src_buffer =
75 static_cast<byte*>(v8::base::OS::Allocate(data_size, &act_size, 0));
76 CHECK(src_buffer);
77 CHECK(act_size >= static_cast<size_t>(data_size));
78 byte* dest_buffer =
79 static_cast<byte*>(v8::base::OS::Allocate(data_size, &act_size, 0));
80 CHECK(dest_buffer);
81 CHECK(act_size >= static_cast<size_t>(data_size));
82
83 // Storage for a0 and a1.
84 byte* a0_;
85 byte* a1_;
86
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000087 MacroAssembler assembler(isolate, NULL, 0,
88 v8::internal::CodeObjectRequired::kYes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000089 MacroAssembler* masm = &assembler;
90
91 // Code to be generated: The stuff in CopyBytes followed by a store of a0 and
92 // a1, respectively.
93 __ CopyBytes(a0, a1, a2, a3);
94 __ li(a2, Operand(reinterpret_cast<int64_t>(&a0_)));
95 __ li(a3, Operand(reinterpret_cast<int64_t>(&a1_)));
96 __ sd(a0, MemOperand(a2));
97 __ jr(ra);
98 __ sd(a1, MemOperand(a3));
99
100 CodeDesc desc;
101 masm->GetCode(&desc);
102 Handle<Code> code = isolate->factory()->NewCode(
103 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
104
105 ::F f = FUNCTION_CAST< ::F>(code->entry());
106
107 // Initialise source data with non-zero bytes.
108 for (int i = 0; i < data_size; i++) {
109 src_buffer[i] = to_non_zero(i);
110 }
111
112 const int fuzz = 11;
113
114 for (int size = 0; size < 600; size++) {
115 for (const byte* src = src_buffer; src < src_buffer + fuzz; src++) {
116 for (byte* dest = dest_buffer; dest < dest_buffer + fuzz; dest++) {
117 memset(dest_buffer, 0, data_size);
118 CHECK(dest + size < dest_buffer + data_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000119 (void)CALL_GENERATED_CODE(isolate, f, reinterpret_cast<int64_t>(src),
120 reinterpret_cast<int64_t>(dest), size, 0, 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000121 // a0 and a1 should point at the first byte after the copied data.
122 CHECK_EQ(src + size, a0_);
123 CHECK_EQ(dest + size, a1_);
124 // Check that we haven't written outside the target area.
125 CHECK(all_zeroes(dest_buffer, dest));
126 CHECK(all_zeroes(dest + size, dest_buffer + data_size));
127 // Check the target area.
128 CHECK_EQ(0, memcmp(src, dest, size));
129 }
130 }
131 }
132
133 // Check that the source data hasn't been clobbered.
134 for (int i = 0; i < data_size; i++) {
135 CHECK(src_buffer[i] == to_non_zero(i));
136 }
137}
138
139
140TEST(LoadConstants) {
141 CcTest::InitializeVM();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000142 Isolate* isolate = CcTest::i_isolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000143 HandleScope handles(isolate);
144
145 int64_t refConstants[64];
146 int64_t result[64];
147
148 int64_t mask = 1;
149 for (int i = 0; i < 64; i++) {
150 refConstants[i] = ~(mask << i);
151 }
152
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000153 MacroAssembler assembler(isolate, NULL, 0,
154 v8::internal::CodeObjectRequired::kYes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000155 MacroAssembler* masm = &assembler;
156
157 __ mov(a4, a0);
158 for (int i = 0; i < 64; i++) {
159 // Load constant.
160 __ li(a5, Operand(refConstants[i]));
161 __ sd(a5, MemOperand(a4));
162 __ Daddu(a4, a4, Operand(kPointerSize));
163 }
164
165 __ jr(ra);
166 __ nop();
167
168 CodeDesc desc;
169 masm->GetCode(&desc);
170 Handle<Code> code = isolate->factory()->NewCode(
171 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
172
173 ::F f = FUNCTION_CAST< ::F>(code->entry());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000174 (void)CALL_GENERATED_CODE(isolate, f, reinterpret_cast<int64_t>(result), 0, 0,
175 0, 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000176 // Check results.
177 for (int i = 0; i < 64; i++) {
178 CHECK(refConstants[i] == result[i]);
179 }
180}
181
182
183TEST(LoadAddress) {
184 CcTest::InitializeVM();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000185 Isolate* isolate = CcTest::i_isolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000186 HandleScope handles(isolate);
187
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000188 MacroAssembler assembler(isolate, NULL, 0,
189 v8::internal::CodeObjectRequired::kYes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000190 MacroAssembler* masm = &assembler;
191 Label to_jump, skip;
192 __ mov(a4, a0);
193
194 __ Branch(&skip);
195 __ bind(&to_jump);
196 __ nop();
197 __ nop();
198 __ jr(ra);
199 __ nop();
200 __ bind(&skip);
201 __ li(a4, Operand(masm->jump_address(&to_jump)), ADDRESS_LOAD);
202 int check_size = masm->InstructionsGeneratedSince(&skip);
203 CHECK_EQ(check_size, 4);
204 __ jr(a4);
205 __ nop();
206 __ stop("invalid");
207 __ stop("invalid");
208 __ stop("invalid");
209 __ stop("invalid");
210 __ stop("invalid");
211
212
213 CodeDesc desc;
214 masm->GetCode(&desc);
215 Handle<Code> code = isolate->factory()->NewCode(
216 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
217
218 ::F f = FUNCTION_CAST< ::F>(code->entry());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000219 (void)CALL_GENERATED_CODE(isolate, f, 0, 0, 0, 0, 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000220 // Check results.
221}
222
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000223
224TEST(jump_tables4) {
225 // Similar to test-assembler-mips jump_tables1, with extra test for branch
226 // trampoline required before emission of the dd table (where trampolines are
227 // blocked), and proper transition to long-branch mode.
228 // Regression test for v8:4294.
229 CcTest::InitializeVM();
230 Isolate* isolate = CcTest::i_isolate();
231 HandleScope scope(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100232 MacroAssembler assembler(isolate, nullptr, 0,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000233 v8::internal::CodeObjectRequired::kYes);
234 MacroAssembler* masm = &assembler;
235
236 const int kNumCases = 512;
237 int values[kNumCases];
238 isolate->random_number_generator()->NextBytes(values, sizeof(values));
239 Label labels[kNumCases];
Ben Murdoch097c5b22016-05-18 11:27:45 +0100240 Label near_start, end, done;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000241
Ben Murdoch097c5b22016-05-18 11:27:45 +0100242 __ Push(ra);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000243 __ mov(v0, zero_reg);
244
245 __ Branch(&end);
246 __ bind(&near_start);
247
248 // Generate slightly less than 32K instructions, which will soon require
249 // trampoline for branch distance fixup.
250 for (int i = 0; i < 32768 - 256; ++i) {
251 __ addiu(v0, v0, 1);
252 }
253
Ben Murdoch097c5b22016-05-18 11:27:45 +0100254 __ GenerateSwitchTable(a0, kNumCases,
255 [&labels](size_t i) { return labels + i; });
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000256
257 for (int i = 0; i < kNumCases; ++i) {
258 __ bind(&labels[i]);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100259 __ li(v0, values[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000260 __ Branch(&done);
261 }
262
263 __ bind(&done);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100264 __ Pop(ra);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000265 __ jr(ra);
266 __ nop();
267
268 __ bind(&end);
269 __ Branch(&near_start);
270
271 CodeDesc desc;
272 masm->GetCode(&desc);
273 Handle<Code> code = isolate->factory()->NewCode(
274 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
275#ifdef OBJECT_PRINT
276 code->Print(std::cout);
277#endif
278 F1 f = FUNCTION_CAST<F1>(code->entry());
279 for (int i = 0; i < kNumCases; ++i) {
280 int64_t res = reinterpret_cast<int64_t>(
281 CALL_GENERATED_CODE(isolate, f, i, 0, 0, 0, 0));
282 ::printf("f(%d) = %" PRId64 "\n", i, res);
283 CHECK_EQ(values[i], res);
284 }
285}
286
287
288TEST(jump_tables5) {
289 if (kArchVariant != kMips64r6) return;
290
291 // Similar to test-assembler-mips jump_tables1, with extra test for emitting a
292 // compact branch instruction before emission of the dd table.
293 CcTest::InitializeVM();
294 Isolate* isolate = CcTest::i_isolate();
295 HandleScope scope(isolate);
296 MacroAssembler assembler(isolate, nullptr, 0,
297 v8::internal::CodeObjectRequired::kYes);
298 MacroAssembler* masm = &assembler;
299
300 const int kNumCases = 512;
301 int values[kNumCases];
302 isolate->random_number_generator()->NextBytes(values, sizeof(values));
303 Label labels[kNumCases];
304 Label done;
305
Ben Murdoch097c5b22016-05-18 11:27:45 +0100306 __ Push(ra);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000307
Ben Murdoch097c5b22016-05-18 11:27:45 +0100308 // Opposite of Align(8) as we have unaligned number of instructions in the
309 // following block before the first dd().
310 if ((masm->pc_offset() & 7) == 0) {
311 __ nop();
312 }
313
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000314 {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100315 __ BlockTrampolinePoolFor(kNumCases * 2 + 6 + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000316 PredictableCodeSizeScope predictable(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100317 masm, kNumCases * kPointerSize + ((6 + 1) * Assembler::kInstrSize));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000318
Ben Murdoch097c5b22016-05-18 11:27:45 +0100319 __ addiupc(at, 6 + 1);
Ben Murdochda12d292016-06-02 14:46:10 +0100320 __ Dlsa(at, at, a0, 3);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100321 __ ld(at, MemOperand(at));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000322 __ jalr(at);
323 __ nop(); // Branch delay slot nop.
324 __ bc(&done);
325 // A nop instruction must be generated by the forbidden slot guard
326 // (Assembler::dd(Label*)) so the first label goes to an 8 bytes aligned
327 // location.
328 for (int i = 0; i < kNumCases; ++i) {
329 __ dd(&labels[i]);
330 }
331 }
332
333 for (int i = 0; i < kNumCases; ++i) {
334 __ bind(&labels[i]);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100335 __ li(v0, values[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000336 __ jr(ra);
337 __ nop();
338 }
339
340 __ bind(&done);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100341 __ Pop(ra);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000342 __ jr(ra);
343 __ nop();
344
345 CodeDesc desc;
346 masm->GetCode(&desc);
347 Handle<Code> code = isolate->factory()->NewCode(
348 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
349#ifdef OBJECT_PRINT
350 code->Print(std::cout);
351#endif
352 F1 f = FUNCTION_CAST<F1>(code->entry());
353 for (int i = 0; i < kNumCases; ++i) {
354 int64_t res = reinterpret_cast<int64_t>(
355 CALL_GENERATED_CODE(isolate, f, i, 0, 0, 0, 0));
356 ::printf("f(%d) = %" PRId64 "\n", i, res);
357 CHECK_EQ(values[i], res);
358 }
359}
360
361
362static uint64_t run_lsa(uint32_t rt, uint32_t rs, int8_t sa) {
363 Isolate* isolate = CcTest::i_isolate();
364 HandleScope scope(isolate);
365 MacroAssembler assembler(isolate, nullptr, 0,
366 v8::internal::CodeObjectRequired::kYes);
367 MacroAssembler* masm = &assembler;
368
369 __ Lsa(v0, a0, a1, sa);
370 __ jr(ra);
371 __ nop();
372
373 CodeDesc desc;
374 assembler.GetCode(&desc);
375 Handle<Code> code = isolate->factory()->NewCode(
376 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
377
378 F1 f = FUNCTION_CAST<F1>(code->entry());
379
380 uint64_t res = reinterpret_cast<uint64_t>(
381 CALL_GENERATED_CODE(isolate, f, rt, rs, 0, 0, 0));
382
383 return res;
384}
385
386
387TEST(Lsa) {
388 CcTest::InitializeVM();
389 struct TestCaseLsa {
390 int32_t rt;
391 int32_t rs;
392 uint8_t sa;
393 uint64_t expected_res;
394 };
395
396 struct TestCaseLsa tc[] = {// rt, rs, sa, expected_res
397 {0x4, 0x1, 1, 0x6},
398 {0x4, 0x1, 2, 0x8},
399 {0x4, 0x1, 3, 0xc},
400 {0x4, 0x1, 4, 0x14},
401 {0x4, 0x1, 5, 0x24},
402 {0x0, 0x1, 1, 0x2},
403 {0x0, 0x1, 2, 0x4},
404 {0x0, 0x1, 3, 0x8},
405 {0x0, 0x1, 4, 0x10},
406 {0x0, 0x1, 5, 0x20},
407 {0x4, 0x0, 1, 0x4},
408 {0x4, 0x0, 2, 0x4},
409 {0x4, 0x0, 3, 0x4},
410 {0x4, 0x0, 4, 0x4},
411 {0x4, 0x0, 5, 0x4},
412
413 // Shift overflow.
414 {0x4, INT32_MAX, 1, 0x2},
415 {0x4, INT32_MAX >> 1, 2, 0x0},
416 {0x4, INT32_MAX >> 2, 3, 0xfffffffffffffffc},
417 {0x4, INT32_MAX >> 3, 4, 0xfffffffffffffff4},
418 {0x4, INT32_MAX >> 4, 5, 0xffffffffffffffe4},
419
420 // Signed addition overflow.
421 {INT32_MAX - 1, 0x1, 1, 0xffffffff80000000},
422 {INT32_MAX - 3, 0x1, 2, 0xffffffff80000000},
423 {INT32_MAX - 7, 0x1, 3, 0xffffffff80000000},
424 {INT32_MAX - 15, 0x1, 4, 0xffffffff80000000},
425 {INT32_MAX - 31, 0x1, 5, 0xffffffff80000000},
426
427 // Addition overflow.
428 {-2, 0x1, 1, 0x0},
429 {-4, 0x1, 2, 0x0},
430 {-8, 0x1, 3, 0x0},
431 {-16, 0x1, 4, 0x0},
432 {-32, 0x1, 5, 0x0}};
433
434 size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseLsa);
435 for (size_t i = 0; i < nr_test_cases; ++i) {
436 uint64_t res = run_lsa(tc[i].rt, tc[i].rs, tc[i].sa);
437 PrintF("0x%" PRIx64 " =? 0x%" PRIx64 " == Lsa(v0, %x, %x, %hhu)\n",
438 tc[i].expected_res, res, tc[i].rt, tc[i].rs, tc[i].sa);
439 CHECK_EQ(tc[i].expected_res, res);
440 }
441}
442
443
444static uint64_t run_dlsa(uint64_t rt, uint64_t rs, int8_t sa) {
445 Isolate* isolate = CcTest::i_isolate();
446 HandleScope scope(isolate);
447 MacroAssembler assembler(isolate, nullptr, 0,
448 v8::internal::CodeObjectRequired::kYes);
449 MacroAssembler* masm = &assembler;
450
451 __ Dlsa(v0, a0, a1, sa);
452 __ jr(ra);
453 __ nop();
454
455 CodeDesc desc;
456 assembler.GetCode(&desc);
457 Handle<Code> code = isolate->factory()->NewCode(
458 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
459
460 ::F f = FUNCTION_CAST<::F>(code->entry());
461
462 uint64_t res = reinterpret_cast<uint64_t>(
463 CALL_GENERATED_CODE(isolate, f, rt, rs, 0, 0, 0));
464
465 return res;
466}
467
468
469TEST(Dlsa) {
470 CcTest::InitializeVM();
471 struct TestCaseLsa {
472 int64_t rt;
473 int64_t rs;
474 uint8_t sa;
475 uint64_t expected_res;
476 };
477
478 struct TestCaseLsa tc[] = {// rt, rs, sa, expected_res
479 {0x4, 0x1, 1, 0x6},
480 {0x4, 0x1, 2, 0x8},
481 {0x4, 0x1, 3, 0xc},
482 {0x4, 0x1, 4, 0x14},
483 {0x4, 0x1, 5, 0x24},
484 {0x0, 0x1, 1, 0x2},
485 {0x0, 0x1, 2, 0x4},
486 {0x0, 0x1, 3, 0x8},
487 {0x0, 0x1, 4, 0x10},
488 {0x0, 0x1, 5, 0x20},
489 {0x4, 0x0, 1, 0x4},
490 {0x4, 0x0, 2, 0x4},
491 {0x4, 0x0, 3, 0x4},
492 {0x4, 0x0, 4, 0x4},
493 {0x4, 0x0, 5, 0x4},
494
495 // Shift overflow.
496 {0x4, INT64_MAX, 1, 0x2},
497 {0x4, INT64_MAX >> 1, 2, 0x0},
498 {0x4, INT64_MAX >> 2, 3, 0xfffffffffffffffc},
499 {0x4, INT64_MAX >> 3, 4, 0xfffffffffffffff4},
500 {0x4, INT64_MAX >> 4, 5, 0xffffffffffffffe4},
501
502 // Signed addition overflow.
503 {INT64_MAX - 1, 0x1, 1, 0x8000000000000000},
504 {INT64_MAX - 3, 0x1, 2, 0x8000000000000000},
505 {INT64_MAX - 7, 0x1, 3, 0x8000000000000000},
506 {INT64_MAX - 15, 0x1, 4, 0x8000000000000000},
507 {INT64_MAX - 31, 0x1, 5, 0x8000000000000000},
508
509 // Addition overflow.
510 {-2, 0x1, 1, 0x0},
511 {-4, 0x1, 2, 0x0},
512 {-8, 0x1, 3, 0x0},
513 {-16, 0x1, 4, 0x0},
514 {-32, 0x1, 5, 0x0}};
515
516 size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseLsa);
517 for (size_t i = 0; i < nr_test_cases; ++i) {
518 uint64_t res = run_dlsa(tc[i].rt, tc[i].rs, tc[i].sa);
519 PrintF("0x%" PRIx64 " =? 0x%" PRIx64 " == Dlsa(v0, %" PRIx64 ", %" PRIx64
520 ", %hhu)\n",
521 tc[i].expected_res, res, tc[i].rt, tc[i].rs, tc[i].sa);
522 CHECK_EQ(tc[i].expected_res, res);
523 }
524}
525
Ben Murdochda12d292016-06-02 14:46:10 +0100526static const std::vector<uint32_t> uint32_test_values() {
527 static const uint32_t kValues[] = {0x00000000, 0x00000001, 0x00ffff00,
528 0x7fffffff, 0x80000000, 0x80000001,
529 0x80ffff00, 0x8fffffff, 0xffffffff};
530 return std::vector<uint32_t>(&kValues[0], &kValues[arraysize(kValues)]);
531}
532
533static const std::vector<int32_t> int32_test_values() {
534 static const int32_t kValues[] = {
535 static_cast<int32_t>(0x00000000), static_cast<int32_t>(0x00000001),
536 static_cast<int32_t>(0x00ffff00), static_cast<int32_t>(0x7fffffff),
537 static_cast<int32_t>(0x80000000), static_cast<int32_t>(0x80000001),
538 static_cast<int32_t>(0x80ffff00), static_cast<int32_t>(0x8fffffff),
539 static_cast<int32_t>(0xffffffff)};
540 return std::vector<int32_t>(&kValues[0], &kValues[arraysize(kValues)]);
541}
542
543static const std::vector<uint64_t> uint64_test_values() {
544 static const uint64_t kValues[] = {
545 0x0000000000000000, 0x0000000000000001, 0x0000ffffffff0000,
546 0x7fffffffffffffff, 0x8000000000000000, 0x8000000000000001,
547 0x8000ffffffff0000, 0x8fffffffffffffff, 0xffffffffffffffff};
548 return std::vector<uint64_t>(&kValues[0], &kValues[arraysize(kValues)]);
549}
550
551static const std::vector<int64_t> int64_test_values() {
552 static const int64_t kValues[] = {static_cast<int64_t>(0x0000000000000000),
553 static_cast<int64_t>(0x0000000000000001),
554 static_cast<int64_t>(0x0000ffffffff0000),
555 static_cast<int64_t>(0x7fffffffffffffff),
556 static_cast<int64_t>(0x8000000000000000),
557 static_cast<int64_t>(0x8000000000000001),
558 static_cast<int64_t>(0x8000ffffffff0000),
559 static_cast<int64_t>(0x8fffffffffffffff),
560 static_cast<int64_t>(0xffffffffffffffff)};
561 return std::vector<int64_t>(&kValues[0], &kValues[arraysize(kValues)]);
562}
563
564// Helper macros that can be used in FOR_INT32_INPUTS(i) { ... *i ... }
565#define FOR_INPUTS(ctype, itype, var) \
566 std::vector<ctype> var##_vec = itype##_test_values(); \
567 for (std::vector<ctype>::iterator var = var##_vec.begin(); \
568 var != var##_vec.end(); ++var)
569
570#define FOR_INT32_INPUTS(var) FOR_INPUTS(int32_t, int32, var)
571#define FOR_INT64_INPUTS(var) FOR_INPUTS(int64_t, int64, var)
572#define FOR_UINT32_INPUTS(var) FOR_INPUTS(uint32_t, uint32, var)
573#define FOR_UINT64_INPUTS(var) FOR_INPUTS(uint64_t, uint64, var)
574
575template <typename RET_TYPE, typename IN_TYPE, typename Func>
576RET_TYPE run_Cvt(IN_TYPE x, Func GenerateConvertInstructionFunc) {
577 typedef RET_TYPE (*F_CVT)(IN_TYPE x0, int x1, int x2, int x3, int x4);
578
579 Isolate* isolate = CcTest::i_isolate();
580 HandleScope scope(isolate);
581 MacroAssembler assm(isolate, nullptr, 0,
582 v8::internal::CodeObjectRequired::kYes);
583 MacroAssembler* masm = &assm;
584
585 GenerateConvertInstructionFunc(masm);
586 __ dmfc1(v0, f2);
587 __ jr(ra);
588 __ nop();
589
590 CodeDesc desc;
591 assm.GetCode(&desc);
592 Handle<Code> code = isolate->factory()->NewCode(
593 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
594
595 F_CVT f = FUNCTION_CAST<F_CVT>(code->entry());
596
597 return reinterpret_cast<RET_TYPE>(
598 CALL_GENERATED_CODE(isolate, f, x, 0, 0, 0, 0));
599}
600
601TEST(Cvt_s_uw_Trunc_uw_s) {
602 CcTest::InitializeVM();
603 FOR_UINT32_INPUTS(i) {
604 uint32_t input = *i;
605 CHECK_EQ(static_cast<float>(input),
606 run_Cvt<uint64_t>(input, [](MacroAssembler* masm) {
607 __ Cvt_s_uw(f0, a0);
608 __ mthc1(zero_reg, f2);
609 __ Trunc_uw_s(f2, f0, f1);
610 }));
611 }
612}
613
614TEST(Cvt_s_ul_Trunc_ul_s) {
615 CcTest::InitializeVM();
616 FOR_UINT64_INPUTS(i) {
617 uint64_t input = *i;
618 CHECK_EQ(static_cast<float>(input),
619 run_Cvt<uint64_t>(input, [](MacroAssembler* masm) {
620 __ Cvt_s_ul(f0, a0);
621 __ Trunc_ul_s(f2, f0, f1, v0);
622 }));
623 }
624}
625
626TEST(Cvt_d_ul_Trunc_ul_d) {
627 CcTest::InitializeVM();
628 FOR_UINT64_INPUTS(i) {
629 uint64_t input = *i;
630 CHECK_EQ(static_cast<double>(input),
631 run_Cvt<uint64_t>(input, [](MacroAssembler* masm) {
632 __ Cvt_d_ul(f0, a0);
633 __ Trunc_ul_d(f2, f0, f1, v0);
634 }));
635 }
636}
637
638TEST(cvt_d_l_Trunc_l_d) {
639 CcTest::InitializeVM();
640 FOR_INT64_INPUTS(i) {
641 int64_t input = *i;
642 CHECK_EQ(static_cast<double>(input),
643 run_Cvt<int64_t>(input, [](MacroAssembler* masm) {
644 __ dmtc1(a0, f4);
645 __ cvt_d_l(f0, f4);
646 __ Trunc_l_d(f2, f0);
647 }));
648 }
649}
650
651TEST(cvt_d_l_Trunc_l_ud) {
652 CcTest::InitializeVM();
653 FOR_INT64_INPUTS(i) {
654 int64_t input = *i;
655 uint64_t abs_input = (input < 0) ? -input : input;
656 CHECK_EQ(static_cast<double>(abs_input),
657 run_Cvt<uint64_t>(input, [](MacroAssembler* masm) {
658 __ dmtc1(a0, f4);
659 __ cvt_d_l(f0, f4);
660 __ Trunc_l_ud(f2, f0, f6);
661 }));
662 }
663}
664
665TEST(cvt_d_w_Trunc_w_d) {
666 CcTest::InitializeVM();
667 FOR_INT32_INPUTS(i) {
668 int32_t input = *i;
669 CHECK_EQ(static_cast<double>(input),
670 run_Cvt<int64_t>(input, [](MacroAssembler* masm) {
671 __ mtc1(a0, f4);
672 __ cvt_d_w(f0, f4);
673 __ Trunc_w_d(f2, f0);
674 __ mfc1(v1, f2);
675 __ dmtc1(v1, f2);
676 }));
677 }
678}
679
680TEST(min_max_nan) {
681 CcTest::InitializeVM();
682 Isolate* isolate = CcTest::i_isolate();
683 HandleScope scope(isolate);
684 MacroAssembler assembler(isolate, nullptr, 0,
685 v8::internal::CodeObjectRequired::kYes);
686 MacroAssembler* masm = &assembler;
687
688 struct TestFloat {
689 double a;
690 double b;
691 double c;
692 double d;
693 float e;
694 float f;
695 float g;
696 float h;
697 };
698
699 TestFloat test;
700 const double dnan = std::numeric_limits<double>::quiet_NaN();
701 const double dinf = std::numeric_limits<double>::infinity();
702 const double dminf = -std::numeric_limits<double>::infinity();
703 const float fnan = std::numeric_limits<float>::quiet_NaN();
704 const float finf = std::numeric_limits<float>::infinity();
705 const float fminf = std::numeric_limits<float>::infinity();
706 const int kTableLength = 13;
707
708 double inputsa[kTableLength] = {2.0, 3.0, -0.0, 0.0, 42.0, dinf, dminf,
709 dinf, dnan, 3.0, dinf, dnan, dnan};
710 double inputsb[kTableLength] = {3.0, 2.0, 0.0, -0.0, dinf, 42.0, dinf,
711 dminf, 3.0, dnan, dnan, dinf, dnan};
712 double outputsdmin[kTableLength] = {2.0, 2.0, -0.0, -0.0, 42.0,
713 42.0, dminf, dminf, dnan, dnan,
714 dnan, dnan, dnan};
715 double outputsdmax[kTableLength] = {3.0, 3.0, 0.0, 0.0, dinf, dinf, dinf,
716 dinf, dnan, dnan, dnan, dnan, dnan};
717
718 float inputse[kTableLength] = {2.0, 3.0, -0.0, 0.0, 42.0, finf, fminf,
719 finf, fnan, 3.0, finf, fnan, fnan};
720 float inputsf[kTableLength] = {3.0, 2.0, 0.0, -0.0, finf, 42.0, finf,
721 fminf, 3.0, fnan, fnan, finf, fnan};
722 float outputsfmin[kTableLength] = {2.0, 2.0, -0.0, -0.0, 42.0, 42.0, fminf,
723 fminf, fnan, fnan, fnan, fnan, fnan};
724 float outputsfmax[kTableLength] = {3.0, 3.0, 0.0, 0.0, finf, finf, finf,
725 finf, fnan, fnan, fnan, fnan, fnan};
726
727 auto handle_dnan = [masm](FPURegister dst, Label* nan, Label* back) {
728 __ bind(nan);
729 __ LoadRoot(at, Heap::kNanValueRootIndex);
730 __ ldc1(dst, FieldMemOperand(at, HeapNumber::kValueOffset));
731 __ Branch(back);
732 };
733
734 auto handle_snan = [masm, fnan](FPURegister dst, Label* nan, Label* back) {
735 __ bind(nan);
736 __ Move(dst, fnan);
737 __ Branch(back);
738 };
739
740 Label handle_mind_nan, handle_maxd_nan, handle_mins_nan, handle_maxs_nan;
741 Label back_mind_nan, back_maxd_nan, back_mins_nan, back_maxs_nan;
742
743 __ push(s6);
744 __ InitializeRootRegister();
745 __ ldc1(f4, MemOperand(a0, offsetof(TestFloat, a)));
746 __ ldc1(f8, MemOperand(a0, offsetof(TestFloat, b)));
747 __ lwc1(f2, MemOperand(a0, offsetof(TestFloat, e)));
748 __ lwc1(f6, MemOperand(a0, offsetof(TestFloat, f)));
749 __ MinNaNCheck_d(f10, f4, f8, &handle_mind_nan);
750 __ bind(&back_mind_nan);
751 __ MaxNaNCheck_d(f12, f4, f8, &handle_maxd_nan);
752 __ bind(&back_maxd_nan);
753 __ MinNaNCheck_s(f14, f2, f6, &handle_mins_nan);
754 __ bind(&back_mins_nan);
755 __ MaxNaNCheck_s(f16, f2, f6, &handle_maxs_nan);
756 __ bind(&back_maxs_nan);
757 __ sdc1(f10, MemOperand(a0, offsetof(TestFloat, c)));
758 __ sdc1(f12, MemOperand(a0, offsetof(TestFloat, d)));
759 __ swc1(f14, MemOperand(a0, offsetof(TestFloat, g)));
760 __ swc1(f16, MemOperand(a0, offsetof(TestFloat, h)));
761 __ pop(s6);
762 __ jr(ra);
763 __ nop();
764
765 handle_dnan(f10, &handle_mind_nan, &back_mind_nan);
766 handle_dnan(f12, &handle_maxd_nan, &back_maxd_nan);
767 handle_snan(f14, &handle_mins_nan, &back_mins_nan);
768 handle_snan(f16, &handle_maxs_nan, &back_maxs_nan);
769
770 CodeDesc desc;
771 masm->GetCode(&desc);
772 Handle<Code> code = isolate->factory()->NewCode(
773 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
774 ::F3 f = FUNCTION_CAST<::F3>(code->entry());
775 for (int i = 0; i < kTableLength; i++) {
776 test.a = inputsa[i];
777 test.b = inputsb[i];
778 test.e = inputse[i];
779 test.f = inputsf[i];
780
781 CALL_GENERATED_CODE(isolate, f, &test, 0, 0, 0, 0);
782
783 CHECK_EQ(0, memcmp(&test.c, &outputsdmin[i], sizeof(test.c)));
784 CHECK_EQ(0, memcmp(&test.d, &outputsdmax[i], sizeof(test.d)));
785 CHECK_EQ(0, memcmp(&test.g, &outputsfmin[i], sizeof(test.g)));
786 CHECK_EQ(0, memcmp(&test.h, &outputsfmax[i], sizeof(test.h)));
787 }
788}
789
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000790#undef __