blob: 748198b1715e9786b05cf08bd341656023376842 [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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000031#include "src/base/utils/random-number-generator.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000032#include "src/macro-assembler.h"
33#include "src/mips/macro-assembler-mips.h"
34#include "src/mips/simulator-mips.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000035#include "src/v8.h"
36#include "test/cctest/cctest.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000037
38
39using namespace v8::internal;
40
41typedef void* (*F)(int x, int y, int p2, int p3, int p4);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000042typedef Object* (*F1)(int x, int p1, int p2, int p3, int p4);
Ben Murdochda12d292016-06-02 14:46:10 +010043typedef Object* (*F3)(void* p, int p1, int p2, int p3, int p4);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000044
45#define __ masm->
46
47
48static byte to_non_zero(int n) {
49 return static_cast<unsigned>(n) % 255 + 1;
50}
51
52
53static bool all_zeroes(const byte* beg, const byte* end) {
54 CHECK(beg);
55 CHECK(beg <= end);
56 while (beg < end) {
57 if (*beg++ != 0)
58 return false;
59 }
60 return true;
61}
62
Ben Murdoch61f157c2016-09-16 13:49:30 +010063TEST(BYTESWAP) {
64 CcTest::InitializeVM();
65 Isolate* isolate = CcTest::i_isolate();
66 HandleScope handles(isolate);
67
68 struct T {
69 int32_t r1;
70 int32_t r2;
71 int32_t r3;
72 int32_t r4;
73 int32_t r5;
74 };
75 T t;
76
77 MacroAssembler assembler(isolate, NULL, 0,
78 v8::internal::CodeObjectRequired::kYes);
79 MacroAssembler* masm = &assembler;
80
81 __ lw(a2, MemOperand(a0, offsetof(T, r1)));
82 __ nop();
83 __ ByteSwapSigned(a2, 4);
84 __ sw(a2, MemOperand(a0, offsetof(T, r1)));
85
86 __ lw(a2, MemOperand(a0, offsetof(T, r2)));
87 __ nop();
88 __ ByteSwapSigned(a2, 2);
89 __ sw(a2, MemOperand(a0, offsetof(T, r2)));
90
91 __ lw(a2, MemOperand(a0, offsetof(T, r3)));
92 __ nop();
93 __ ByteSwapSigned(a2, 1);
94 __ sw(a2, MemOperand(a0, offsetof(T, r3)));
95
96 __ lw(a2, MemOperand(a0, offsetof(T, r4)));
97 __ nop();
98 __ ByteSwapUnsigned(a2, 1);
99 __ sw(a2, MemOperand(a0, offsetof(T, r4)));
100
101 __ lw(a2, MemOperand(a0, offsetof(T, r5)));
102 __ nop();
103 __ ByteSwapUnsigned(a2, 2);
104 __ sw(a2, MemOperand(a0, offsetof(T, r5)));
105
106 __ jr(ra);
107 __ nop();
108
109 CodeDesc desc;
110 masm->GetCode(&desc);
111 Handle<Code> code = isolate->factory()->NewCode(
112 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
113 ::F3 f = FUNCTION_CAST<::F3>(code->entry());
114 t.r1 = 0x781A15C3;
115 t.r2 = 0x2CDE;
116 t.r3 = 0x9F;
117 t.r4 = 0x9F;
118 t.r5 = 0x2CDE;
119 Object* dummy = CALL_GENERATED_CODE(isolate, f, &t, 0, 0, 0, 0);
120 USE(dummy);
121
122 CHECK_EQ(static_cast<int32_t>(0xC3151A78), t.r1);
123 CHECK_EQ(static_cast<int32_t>(0xDE2C0000), t.r2);
124 CHECK_EQ(static_cast<int32_t>(0x9FFFFFFF), t.r3);
125 CHECK_EQ(static_cast<int32_t>(0x9F000000), t.r4);
126 CHECK_EQ(static_cast<int32_t>(0xDE2C0000), t.r5);
127}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000128
129TEST(CopyBytes) {
130 CcTest::InitializeVM();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000131 Isolate* isolate = CcTest::i_isolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000132 HandleScope handles(isolate);
133
134 const int data_size = 1 * KB;
135 size_t act_size;
136
137 // Allocate two blocks to copy data between.
138 byte* src_buffer =
139 static_cast<byte*>(v8::base::OS::Allocate(data_size, &act_size, 0));
140 CHECK(src_buffer);
141 CHECK(act_size >= static_cast<size_t>(data_size));
142 byte* dest_buffer =
143 static_cast<byte*>(v8::base::OS::Allocate(data_size, &act_size, 0));
144 CHECK(dest_buffer);
145 CHECK(act_size >= static_cast<size_t>(data_size));
146
147 // Storage for a0 and a1.
148 byte* a0_;
149 byte* a1_;
150
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000151 MacroAssembler assembler(isolate, NULL, 0,
152 v8::internal::CodeObjectRequired::kYes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000153 MacroAssembler* masm = &assembler;
154
155 // Code to be generated: The stuff in CopyBytes followed by a store of a0 and
156 // a1, respectively.
157 __ CopyBytes(a0, a1, a2, a3);
158 __ li(a2, Operand(reinterpret_cast<int>(&a0_)));
159 __ li(a3, Operand(reinterpret_cast<int>(&a1_)));
160 __ sw(a0, MemOperand(a2));
161 __ jr(ra);
162 __ sw(a1, MemOperand(a3));
163
164 CodeDesc desc;
165 masm->GetCode(&desc);
166 Handle<Code> code = isolate->factory()->NewCode(
167 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
168
169 ::F f = FUNCTION_CAST< ::F>(code->entry());
170
171 // Initialise source data with non-zero bytes.
172 for (int i = 0; i < data_size; i++) {
173 src_buffer[i] = to_non_zero(i);
174 }
175
176 const int fuzz = 11;
177
178 for (int size = 0; size < 600; size++) {
179 for (const byte* src = src_buffer; src < src_buffer + fuzz; src++) {
180 for (byte* dest = dest_buffer; dest < dest_buffer + fuzz; dest++) {
181 memset(dest_buffer, 0, data_size);
182 CHECK(dest + size < dest_buffer + data_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000183 (void)CALL_GENERATED_CODE(isolate, f, reinterpret_cast<int>(src),
184 reinterpret_cast<int>(dest), size, 0, 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000185 // a0 and a1 should point at the first byte after the copied data.
186 CHECK_EQ(src + size, a0_);
187 CHECK_EQ(dest + size, a1_);
188 // Check that we haven't written outside the target area.
189 CHECK(all_zeroes(dest_buffer, dest));
190 CHECK(all_zeroes(dest + size, dest_buffer + data_size));
191 // Check the target area.
192 CHECK_EQ(0, memcmp(src, dest, size));
193 }
194 }
195 }
196
197 // Check that the source data hasn't been clobbered.
198 for (int i = 0; i < data_size; i++) {
199 CHECK(src_buffer[i] == to_non_zero(i));
200 }
201}
202
203
204static void TestNaN(const char *code) {
205 // NaN value is different on MIPS and x86 architectures, and TEST(NaNx)
206 // tests checks the case where a x86 NaN value is serialized into the
207 // snapshot on the simulator during cross compilation.
208 v8::HandleScope scope(CcTest::isolate());
209 v8::Local<v8::Context> context = CcTest::NewContext(PRINT_EXTENSION);
210 v8::Context::Scope context_scope(context);
211
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000212 v8::Local<v8::Script> script =
213 v8::Script::Compile(context, v8_str(code)).ToLocalChecked();
214 v8::Local<v8::Object> result =
215 v8::Local<v8::Object>::Cast(script->Run(context).ToLocalChecked());
216 i::Handle<i::JSReceiver> o = v8::Utils::OpenHandle(*result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000217 i::Handle<i::JSArray> array1(reinterpret_cast<i::JSArray*>(*o));
218 i::FixedDoubleArray* a = i::FixedDoubleArray::cast(array1->elements());
219 double value = a->get_scalar(0);
220 CHECK(std::isnan(value) &&
221 bit_cast<uint64_t>(value) ==
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000222 bit_cast<uint64_t>(std::numeric_limits<double>::quiet_NaN()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000223}
224
225
226TEST(NaN0) {
227 TestNaN(
228 "var result;"
229 "for (var i = 0; i < 2; i++) {"
230 " result = new Array(Number.NaN, Number.POSITIVE_INFINITY);"
231 "}"
232 "result;");
233}
234
235
236TEST(NaN1) {
237 TestNaN(
238 "var result;"
239 "for (var i = 0; i < 2; i++) {"
240 " result = [NaN];"
241 "}"
242 "result;");
243}
244
245
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000246TEST(jump_tables4) {
247 // Similar to test-assembler-mips jump_tables1, with extra test for branch
248 // trampoline required before emission of the dd table (where trampolines are
249 // blocked), and proper transition to long-branch mode.
250 // Regression test for v8:4294.
251 CcTest::InitializeVM();
252 Isolate* isolate = CcTest::i_isolate();
253 HandleScope scope(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100254 MacroAssembler assembler(isolate, nullptr, 0,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000255 v8::internal::CodeObjectRequired::kYes);
256 MacroAssembler* masm = &assembler;
257
258 const int kNumCases = 512;
259 int values[kNumCases];
260 isolate->random_number_generator()->NextBytes(values, sizeof(values));
261 Label labels[kNumCases];
Ben Murdoch097c5b22016-05-18 11:27:45 +0100262 Label near_start, end, done;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000263
Ben Murdoch097c5b22016-05-18 11:27:45 +0100264 __ Push(ra);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000265 __ mov(v0, zero_reg);
266
267 __ Branch(&end);
268 __ bind(&near_start);
269
270 // Generate slightly less than 32K instructions, which will soon require
271 // trampoline for branch distance fixup.
272 for (int i = 0; i < 32768 - 256; ++i) {
273 __ addiu(v0, v0, 1);
274 }
275
Ben Murdoch097c5b22016-05-18 11:27:45 +0100276 __ GenerateSwitchTable(a0, kNumCases,
277 [&labels](size_t i) { return labels + i; });
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000278
279 for (int i = 0; i < kNumCases; ++i) {
280 __ bind(&labels[i]);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100281 __ li(v0, values[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000282 __ Branch(&done);
283 }
284
285 __ bind(&done);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100286 __ Pop(ra);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000287 __ jr(ra);
288 __ nop();
289
290 __ bind(&end);
291 __ Branch(&near_start);
292
293 CodeDesc desc;
294 masm->GetCode(&desc);
295 Handle<Code> code = isolate->factory()->NewCode(
296 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
297#ifdef OBJECT_PRINT
298 code->Print(std::cout);
299#endif
300 F1 f = FUNCTION_CAST<F1>(code->entry());
301 for (int i = 0; i < kNumCases; ++i) {
302 int res =
303 reinterpret_cast<int>(CALL_GENERATED_CODE(isolate, f, i, 0, 0, 0, 0));
304 ::printf("f(%d) = %d\n", i, res);
305 CHECK_EQ(values[i], res);
306 }
307}
308
309
310TEST(jump_tables5) {
311 if (!IsMipsArchVariant(kMips32r6)) return;
312
313 // Similar to test-assembler-mips jump_tables1, with extra test for emitting a
314 // compact branch instruction before emission of the dd table.
315 CcTest::InitializeVM();
316 Isolate* isolate = CcTest::i_isolate();
317 HandleScope scope(isolate);
318 MacroAssembler assembler(isolate, nullptr, 0,
319 v8::internal::CodeObjectRequired::kYes);
320 MacroAssembler* masm = &assembler;
321
322 const int kNumCases = 512;
323 int values[kNumCases];
324 isolate->random_number_generator()->NextBytes(values, sizeof(values));
325 Label labels[kNumCases];
326 Label done;
327
Ben Murdoch097c5b22016-05-18 11:27:45 +0100328 __ Push(ra);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000329
330 {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100331 __ BlockTrampolinePoolFor(kNumCases + 6 + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000332 PredictableCodeSizeScope predictable(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100333 masm, kNumCases * kPointerSize + ((6 + 1) * Assembler::kInstrSize));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000334
Ben Murdoch097c5b22016-05-18 11:27:45 +0100335 __ addiupc(at, 6 + 1);
Ben Murdochda12d292016-06-02 14:46:10 +0100336 __ Lsa(at, at, a0, 2);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100337 __ lw(at, MemOperand(at));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000338 __ jalr(at);
339 __ nop(); // Branch delay slot nop.
340 __ bc(&done);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100341 // A nop instruction must be generated by the forbidden slot guard
342 // (Assembler::dd(Label*)).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000343 for (int i = 0; i < kNumCases; ++i) {
344 __ dd(&labels[i]);
345 }
346 }
347
348 for (int i = 0; i < kNumCases; ++i) {
349 __ bind(&labels[i]);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100350 __ li(v0, values[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000351 __ jr(ra);
352 __ nop();
353 }
354
355 __ bind(&done);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100356 __ Pop(ra);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000357 __ jr(ra);
358 __ nop();
359
360 CodeDesc desc;
361 masm->GetCode(&desc);
362 Handle<Code> code = isolate->factory()->NewCode(
363 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
364#ifdef OBJECT_PRINT
365 code->Print(std::cout);
366#endif
367 F1 f = FUNCTION_CAST<F1>(code->entry());
368 for (int i = 0; i < kNumCases; ++i) {
369 int32_t res = reinterpret_cast<int32_t>(
370 CALL_GENERATED_CODE(isolate, f, i, 0, 0, 0, 0));
371 ::printf("f(%d) = %d\n", i, res);
372 CHECK_EQ(values[i], res);
373 }
374}
375
376
377static uint32_t run_lsa(uint32_t rt, uint32_t rs, int8_t sa) {
378 Isolate* isolate = CcTest::i_isolate();
379 HandleScope scope(isolate);
380 MacroAssembler assembler(isolate, nullptr, 0,
381 v8::internal::CodeObjectRequired::kYes);
382 MacroAssembler* masm = &assembler;
383
384 __ Lsa(v0, a0, a1, sa);
385 __ jr(ra);
386 __ nop();
387
388 CodeDesc desc;
389 assembler.GetCode(&desc);
390 Handle<Code> code = isolate->factory()->NewCode(
391 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
392
393 F1 f = FUNCTION_CAST<F1>(code->entry());
394
395 uint32_t res = reinterpret_cast<uint32_t>(
396 CALL_GENERATED_CODE(isolate, f, rt, rs, 0, 0, 0));
397
398 return res;
399}
400
401
402TEST(Lsa) {
403 CcTest::InitializeVM();
404 struct TestCaseLsa {
405 int32_t rt;
406 int32_t rs;
407 uint8_t sa;
408 uint32_t expected_res;
409 };
410
411 struct TestCaseLsa tc[] = {// rt, rs, sa, expected_res
412 {0x4, 0x1, 1, 0x6},
413 {0x4, 0x1, 2, 0x8},
414 {0x4, 0x1, 3, 0xc},
415 {0x4, 0x1, 4, 0x14},
416 {0x4, 0x1, 5, 0x24},
417 {0x0, 0x1, 1, 0x2},
418 {0x0, 0x1, 2, 0x4},
419 {0x0, 0x1, 3, 0x8},
420 {0x0, 0x1, 4, 0x10},
421 {0x0, 0x1, 5, 0x20},
422 {0x4, 0x0, 1, 0x4},
423 {0x4, 0x0, 2, 0x4},
424 {0x4, 0x0, 3, 0x4},
425 {0x4, 0x0, 4, 0x4},
426 {0x4, 0x0, 5, 0x4},
427
428 // Shift overflow.
429 {0x4, INT32_MAX, 1, 0x2},
430 {0x4, INT32_MAX >> 1, 2, 0x0},
431 {0x4, INT32_MAX >> 2, 3, 0xfffffffc},
432 {0x4, INT32_MAX >> 3, 4, 0xfffffff4},
433 {0x4, INT32_MAX >> 4, 5, 0xffffffe4},
434
435 // Signed addition overflow.
436 {INT32_MAX - 1, 0x1, 1, 0x80000000},
437 {INT32_MAX - 3, 0x1, 2, 0x80000000},
438 {INT32_MAX - 7, 0x1, 3, 0x80000000},
439 {INT32_MAX - 15, 0x1, 4, 0x80000000},
440 {INT32_MAX - 31, 0x1, 5, 0x80000000},
441
442 // Addition overflow.
443 {-2, 0x1, 1, 0x0},
444 {-4, 0x1, 2, 0x0},
445 {-8, 0x1, 3, 0x0},
446 {-16, 0x1, 4, 0x0},
447 {-32, 0x1, 5, 0x0}};
448
449 size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseLsa);
450 for (size_t i = 0; i < nr_test_cases; ++i) {
451 uint32_t res = run_lsa(tc[i].rt, tc[i].rs, tc[i].sa);
452 PrintF("0x%x =? 0x%x == lsa(v0, %x, %x, %hhu)\n", tc[i].expected_res, res,
453 tc[i].rt, tc[i].rs, tc[i].sa);
454 CHECK_EQ(tc[i].expected_res, res);
455 }
456}
457
Ben Murdochc5610432016-08-08 18:44:38 +0100458static const std::vector<uint32_t> cvt_trunc_uint32_test_values() {
Ben Murdochda12d292016-06-02 14:46:10 +0100459 static const uint32_t kValues[] = {0x00000000, 0x00000001, 0x00ffff00,
460 0x7fffffff, 0x80000000, 0x80000001,
461 0x80ffff00, 0x8fffffff, 0xffffffff};
462 return std::vector<uint32_t>(&kValues[0], &kValues[arraysize(kValues)]);
463}
464
Ben Murdochc5610432016-08-08 18:44:38 +0100465static const std::vector<int32_t> cvt_trunc_int32_test_values() {
Ben Murdochda12d292016-06-02 14:46:10 +0100466 static const int32_t kValues[] = {
467 static_cast<int32_t>(0x00000000), static_cast<int32_t>(0x00000001),
468 static_cast<int32_t>(0x00ffff00), static_cast<int32_t>(0x7fffffff),
469 static_cast<int32_t>(0x80000000), static_cast<int32_t>(0x80000001),
470 static_cast<int32_t>(0x80ffff00), static_cast<int32_t>(0x8fffffff),
471 static_cast<int32_t>(0xffffffff)};
472 return std::vector<int32_t>(&kValues[0], &kValues[arraysize(kValues)]);
473}
474
475// Helper macros that can be used in FOR_INT32_INPUTS(i) { ... *i ... }
Ben Murdochc5610432016-08-08 18:44:38 +0100476#define FOR_INPUTS(ctype, itype, var, test_vector) \
477 std::vector<ctype> var##_vec = test_vector(); \
Ben Murdochda12d292016-06-02 14:46:10 +0100478 for (std::vector<ctype>::iterator var = var##_vec.begin(); \
479 var != var##_vec.end(); ++var)
480
Ben Murdochc5610432016-08-08 18:44:38 +0100481#define FOR_INPUTS2(ctype, itype, var, var2, test_vector) \
482 std::vector<ctype> var##_vec = test_vector(); \
483 std::vector<ctype>::iterator var; \
484 std::vector<ctype>::reverse_iterator var2; \
485 for (var = var##_vec.begin(), var2 = var##_vec.rbegin(); \
486 var != var##_vec.end(); ++var, ++var2)
487
488#define FOR_ENUM_INPUTS(var, type, test_vector) \
489 FOR_INPUTS(enum type, type, var, test_vector)
490#define FOR_STRUCT_INPUTS(var, type, test_vector) \
491 FOR_INPUTS(struct type, type, var, test_vector)
492#define FOR_UINT32_INPUTS(var, test_vector) \
493 FOR_INPUTS(uint32_t, uint32, var, test_vector)
494#define FOR_INT32_INPUTS(var, test_vector) \
495 FOR_INPUTS(int32_t, int32, var, test_vector)
496#define FOR_INT32_INPUTS2(var, var2, test_vector) \
497 FOR_INPUTS2(int32_t, int32, var, var2, test_vector)
498
499#define FOR_UINT64_INPUTS(var, test_vector) \
500 FOR_INPUTS(uint64_t, uint32, var, test_vector)
Ben Murdochda12d292016-06-02 14:46:10 +0100501
502template <typename RET_TYPE, typename IN_TYPE, typename Func>
503RET_TYPE run_Cvt(IN_TYPE x, Func GenerateConvertInstructionFunc) {
504 typedef RET_TYPE (*F_CVT)(IN_TYPE x0, int x1, int x2, int x3, int x4);
505
506 Isolate* isolate = CcTest::i_isolate();
507 HandleScope scope(isolate);
508 MacroAssembler assm(isolate, nullptr, 0,
509 v8::internal::CodeObjectRequired::kYes);
510 MacroAssembler* masm = &assm;
511
512 __ mtc1(a0, f4);
513 GenerateConvertInstructionFunc(masm);
514 __ mfc1(v0, f2);
515 __ jr(ra);
516 __ nop();
517
518 CodeDesc desc;
519 assm.GetCode(&desc);
520 Handle<Code> code = isolate->factory()->NewCode(
521 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
522
523 F_CVT f = FUNCTION_CAST<F_CVT>(code->entry());
524
525 return reinterpret_cast<RET_TYPE>(
526 CALL_GENERATED_CODE(isolate, f, x, 0, 0, 0, 0));
527}
528
529TEST(cvt_s_w_Trunc_uw_s) {
530 CcTest::InitializeVM();
Ben Murdochc5610432016-08-08 18:44:38 +0100531 FOR_UINT32_INPUTS(i, cvt_trunc_uint32_test_values) {
Ben Murdochda12d292016-06-02 14:46:10 +0100532 uint32_t input = *i;
533 CHECK_EQ(static_cast<float>(input),
534 run_Cvt<uint32_t>(input, [](MacroAssembler* masm) {
535 __ cvt_s_w(f0, f4);
536 __ Trunc_uw_s(f2, f0, f1);
537 }));
538 }
539}
540
541TEST(cvt_d_w_Trunc_w_d) {
542 CcTest::InitializeVM();
Ben Murdochc5610432016-08-08 18:44:38 +0100543 FOR_INT32_INPUTS(i, cvt_trunc_int32_test_values) {
Ben Murdochda12d292016-06-02 14:46:10 +0100544 int32_t input = *i;
545 CHECK_EQ(static_cast<double>(input),
546 run_Cvt<int32_t>(input, [](MacroAssembler* masm) {
547 __ cvt_d_w(f0, f4);
548 __ Trunc_w_d(f2, f0);
549 }));
550 }
551}
552
Ben Murdochc5610432016-08-08 18:44:38 +0100553static const std::vector<int32_t> overflow_int32_test_values() {
554 static const int32_t kValues[] = {
555 static_cast<int32_t>(0xf0000000), static_cast<int32_t>(0x00000001),
556 static_cast<int32_t>(0xff000000), static_cast<int32_t>(0x0000f000),
557 static_cast<int32_t>(0x0f000000), static_cast<int32_t>(0x991234ab),
558 static_cast<int32_t>(0xb0ffff01), static_cast<int32_t>(0x00006fff),
559 static_cast<int32_t>(0xffffffff)};
560 return std::vector<int32_t>(&kValues[0], &kValues[arraysize(kValues)]);
561}
562
563enum OverflowBranchType {
564 kAddBranchOverflow,
565 kSubBranchOverflow,
566};
567
568struct OverflowRegisterCombination {
569 Register dst;
570 Register left;
571 Register right;
572 Register scratch;
573};
574
575static const std::vector<enum OverflowBranchType> overflow_branch_type() {
576 static const enum OverflowBranchType kValues[] = {kAddBranchOverflow,
577 kSubBranchOverflow};
578 return std::vector<enum OverflowBranchType>(&kValues[0],
579 &kValues[arraysize(kValues)]);
580}
581
582static const std::vector<struct OverflowRegisterCombination>
583overflow_register_combination() {
584 static const struct OverflowRegisterCombination kValues[] = {
585 {t0, t1, t2, t3}, {t0, t0, t2, t3}, {t0, t1, t0, t3}, {t0, t1, t1, t3}};
586 return std::vector<struct OverflowRegisterCombination>(
587 &kValues[0], &kValues[arraysize(kValues)]);
588}
589
590template <typename T>
591static bool IsAddOverflow(T x, T y) {
592 DCHECK(std::numeric_limits<T>::is_integer);
593 T max = std::numeric_limits<T>::max();
594 T min = std::numeric_limits<T>::min();
595
596 return (x > 0 && y > (max - x)) || (x < 0 && y < (min - x));
597}
598
599template <typename T>
600static bool IsSubOverflow(T x, T y) {
601 DCHECK(std::numeric_limits<T>::is_integer);
602 T max = std::numeric_limits<T>::max();
603 T min = std::numeric_limits<T>::min();
604
605 return (y > 0 && x < (min + y)) || (y < 0 && x > (max + y));
606}
607
608template <typename IN_TYPE, typename Func>
609static bool runOverflow(IN_TYPE valLeft, IN_TYPE valRight,
610 Func GenerateOverflowInstructions) {
611 typedef int32_t (*F_CVT)(char* x0, int x1, int x2, int x3, int x4);
612
613 Isolate* isolate = CcTest::i_isolate();
614 HandleScope scope(isolate);
615 MacroAssembler assm(isolate, nullptr, 0,
616 v8::internal::CodeObjectRequired::kYes);
617 MacroAssembler* masm = &assm;
618
619 GenerateOverflowInstructions(masm, valLeft, valRight);
620 __ jr(ra);
621 __ nop();
622
623 CodeDesc desc;
624 assm.GetCode(&desc);
625 Handle<Code> code = isolate->factory()->NewCode(
626 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
627
628 F_CVT f = FUNCTION_CAST<F_CVT>(code->entry());
629
630 int32_t r =
631 reinterpret_cast<int32_t>(CALL_GENERATED_CODE(isolate, f, 0, 0, 0, 0, 0));
632
633 DCHECK(r == 0 || r == 1);
634 return r;
635}
636
637TEST(BranchOverflowInt32BothLabels) {
638 FOR_INT32_INPUTS(i, overflow_int32_test_values) {
639 FOR_INT32_INPUTS(j, overflow_int32_test_values) {
640 FOR_ENUM_INPUTS(br, OverflowBranchType, overflow_branch_type) {
641 FOR_STRUCT_INPUTS(regComb, OverflowRegisterCombination,
642 overflow_register_combination) {
643 int32_t ii = *i;
644 int32_t jj = *j;
645 enum OverflowBranchType branchType = *br;
646 struct OverflowRegisterCombination rc = *regComb;
647
648 // If left and right register are same then left and right
649 // test values must also be same, otherwise we skip the test
650 if (rc.left.code() == rc.right.code()) {
651 if (ii != jj) {
652 continue;
653 }
654 }
655
656 bool res1 = runOverflow<int32_t>(
657 ii, jj, [branchType, rc](MacroAssembler* masm, int32_t valLeft,
658 int32_t valRight) {
659 Label overflow, no_overflow, end;
660 __ li(rc.left, valLeft);
661 __ li(rc.right, valRight);
662 switch (branchType) {
663 case kAddBranchOverflow:
664 __ AddBranchOvf(rc.dst, rc.left, rc.right, &overflow,
665 &no_overflow, rc.scratch);
666 break;
667 case kSubBranchOverflow:
668 __ SubBranchOvf(rc.dst, rc.left, rc.right, &overflow,
669 &no_overflow, rc.scratch);
670 break;
671 }
672 __ li(v0, 2);
673 __ Branch(&end);
674 __ bind(&overflow);
675 __ li(v0, 1);
676 __ Branch(&end);
677 __ bind(&no_overflow);
678 __ li(v0, 0);
679 __ bind(&end);
680 });
681
682 bool res2 = runOverflow<int32_t>(
683 ii, jj, [branchType, rc](MacroAssembler* masm, int32_t valLeft,
684 int32_t valRight) {
685 Label overflow, no_overflow, end;
686 __ li(rc.left, valLeft);
687 switch (branchType) {
688 case kAddBranchOverflow:
689 __ AddBranchOvf(rc.dst, rc.left, Operand(valRight),
690 &overflow, &no_overflow, rc.scratch);
691 break;
692 case kSubBranchOverflow:
693 __ SubBranchOvf(rc.dst, rc.left, Operand(valRight),
694 &overflow, &no_overflow, rc.scratch);
695 break;
696 }
697 __ li(v0, 2);
698 __ Branch(&end);
699 __ bind(&overflow);
700 __ li(v0, 1);
701 __ Branch(&end);
702 __ bind(&no_overflow);
703 __ li(v0, 0);
704 __ bind(&end);
705 });
706
707 switch (branchType) {
708 case kAddBranchOverflow:
709 CHECK_EQ(IsAddOverflow<int32_t>(ii, jj), res1);
710 CHECK_EQ(IsAddOverflow<int32_t>(ii, jj), res2);
711 break;
712 case kSubBranchOverflow:
713 CHECK_EQ(IsSubOverflow<int32_t>(ii, jj), res1);
714 CHECK_EQ(IsSubOverflow<int32_t>(ii, jj), res2);
715 break;
716 default:
717 UNREACHABLE();
718 }
719 }
720 }
721 }
722 }
723}
724
725TEST(BranchOverflowInt32LeftLabel) {
726 FOR_INT32_INPUTS(i, overflow_int32_test_values) {
727 FOR_INT32_INPUTS(j, overflow_int32_test_values) {
728 FOR_ENUM_INPUTS(br, OverflowBranchType, overflow_branch_type) {
729 FOR_STRUCT_INPUTS(regComb, OverflowRegisterCombination,
730 overflow_register_combination) {
731 int32_t ii = *i;
732 int32_t jj = *j;
733 enum OverflowBranchType branchType = *br;
734 struct OverflowRegisterCombination rc = *regComb;
735
736 // If left and right register are same then left and right
737 // test values must also be same, otherwise we skip the test
738 if (rc.left.code() == rc.right.code()) {
739 if (ii != jj) {
740 continue;
741 }
742 }
743
744 bool res1 = runOverflow<int32_t>(
745 ii, jj, [branchType, rc](MacroAssembler* masm, int32_t valLeft,
746 int32_t valRight) {
747 Label overflow, end;
748 __ li(rc.left, valLeft);
749 __ li(rc.right, valRight);
750 switch (branchType) {
751 case kAddBranchOverflow:
752 __ AddBranchOvf(rc.dst, rc.left, rc.right, &overflow, NULL,
753 rc.scratch);
754 break;
755 case kSubBranchOverflow:
756 __ SubBranchOvf(rc.dst, rc.left, rc.right, &overflow, NULL,
757 rc.scratch);
758 break;
759 }
760 __ li(v0, 0);
761 __ Branch(&end);
762 __ bind(&overflow);
763 __ li(v0, 1);
764 __ bind(&end);
765 });
766
767 bool res2 = runOverflow<int32_t>(
768 ii, jj, [branchType, rc](MacroAssembler* masm, int32_t valLeft,
769 int32_t valRight) {
770 Label overflow, end;
771 __ li(rc.left, valLeft);
772 switch (branchType) {
773 case kAddBranchOverflow:
774 __ AddBranchOvf(rc.dst, rc.left, Operand(valRight),
775 &overflow, NULL, rc.scratch);
776 break;
777 case kSubBranchOverflow:
778 __ SubBranchOvf(rc.dst, rc.left, Operand(valRight),
779 &overflow, NULL, rc.scratch);
780 break;
781 }
782 __ li(v0, 0);
783 __ Branch(&end);
784 __ bind(&overflow);
785 __ li(v0, 1);
786 __ bind(&end);
787 });
788
789 switch (branchType) {
790 case kAddBranchOverflow:
791 CHECK_EQ(IsAddOverflow<int32_t>(ii, jj), res1);
792 CHECK_EQ(IsAddOverflow<int32_t>(ii, jj), res2);
793 break;
794 case kSubBranchOverflow:
795 CHECK_EQ(IsSubOverflow<int32_t>(ii, jj), res1);
796 CHECK_EQ(IsSubOverflow<int32_t>(ii, jj), res2);
797 break;
798 default:
799 UNREACHABLE();
800 }
801 }
802 }
803 }
804 }
805}
806
807TEST(BranchOverflowInt32RightLabel) {
808 FOR_INT32_INPUTS(i, overflow_int32_test_values) {
809 FOR_INT32_INPUTS(j, overflow_int32_test_values) {
810 FOR_ENUM_INPUTS(br, OverflowBranchType, overflow_branch_type) {
811 FOR_STRUCT_INPUTS(regComb, OverflowRegisterCombination,
812 overflow_register_combination) {
813 int32_t ii = *i;
814 int32_t jj = *j;
815 enum OverflowBranchType branchType = *br;
816 struct OverflowRegisterCombination rc = *regComb;
817
818 // If left and right register are same then left and right
819 // test values must also be same, otherwise we skip the test
820 if (rc.left.code() == rc.right.code()) {
821 if (ii != jj) {
822 continue;
823 }
824 }
825
826 bool res1 = runOverflow<int32_t>(
827 ii, jj, [branchType, rc](MacroAssembler* masm, int32_t valLeft,
828 int32_t valRight) {
829 Label no_overflow, end;
830 __ li(rc.left, valLeft);
831 __ li(rc.right, valRight);
832 switch (branchType) {
833 case kAddBranchOverflow:
834 __ AddBranchOvf(rc.dst, rc.left, rc.right, NULL,
835 &no_overflow, rc.scratch);
836 break;
837 case kSubBranchOverflow:
838 __ SubBranchOvf(rc.dst, rc.left, rc.right, NULL,
839 &no_overflow, rc.scratch);
840 break;
841 }
842 __ li(v0, 1);
843 __ Branch(&end);
844 __ bind(&no_overflow);
845 __ li(v0, 0);
846 __ bind(&end);
847 });
848
849 bool res2 = runOverflow<int32_t>(
850 ii, jj, [branchType, rc](MacroAssembler* masm, int32_t valLeft,
851 int32_t valRight) {
852 Label no_overflow, end;
853 __ li(rc.left, valLeft);
854 switch (branchType) {
855 case kAddBranchOverflow:
856 __ AddBranchOvf(rc.dst, rc.left, Operand(valRight), NULL,
857 &no_overflow, rc.scratch);
858 break;
859 case kSubBranchOverflow:
860 __ SubBranchOvf(rc.dst, rc.left, Operand(valRight), NULL,
861 &no_overflow, rc.scratch);
862 break;
863 }
864 __ li(v0, 1);
865 __ Branch(&end);
866 __ bind(&no_overflow);
867 __ li(v0, 0);
868 __ bind(&end);
869 });
870
871 switch (branchType) {
872 case kAddBranchOverflow:
873 CHECK_EQ(IsAddOverflow<int32_t>(ii, jj), res1);
874 CHECK_EQ(IsAddOverflow<int32_t>(ii, jj), res2);
875 break;
876 case kSubBranchOverflow:
877 CHECK_EQ(IsSubOverflow<int32_t>(ii, jj), res1);
878 CHECK_EQ(IsSubOverflow<int32_t>(ii, jj), res2);
879 break;
880 default:
881 UNREACHABLE();
882 }
883 }
884 }
885 }
886 }
887}
888
Ben Murdochda12d292016-06-02 14:46:10 +0100889TEST(min_max_nan) {
890 CcTest::InitializeVM();
891 Isolate* isolate = CcTest::i_isolate();
892 HandleScope scope(isolate);
893 MacroAssembler assembler(isolate, nullptr, 0,
894 v8::internal::CodeObjectRequired::kYes);
895 MacroAssembler* masm = &assembler;
896
897 struct TestFloat {
898 double a;
899 double b;
900 double c;
901 double d;
902 float e;
903 float f;
904 float g;
905 float h;
906 };
907
908 TestFloat test;
909 const double dnan = std::numeric_limits<double>::quiet_NaN();
910 const double dinf = std::numeric_limits<double>::infinity();
911 const double dminf = -std::numeric_limits<double>::infinity();
912 const float fnan = std::numeric_limits<float>::quiet_NaN();
913 const float finf = std::numeric_limits<float>::infinity();
914 const float fminf = std::numeric_limits<float>::infinity();
915 const int kTableLength = 13;
916
917 double inputsa[kTableLength] = {2.0, 3.0, -0.0, 0.0, 42.0, dinf, dminf,
918 dinf, dnan, 3.0, dinf, dnan, dnan};
919 double inputsb[kTableLength] = {3.0, 2.0, 0.0, -0.0, dinf, 42.0, dinf,
920 dminf, 3.0, dnan, dnan, dinf, dnan};
921 double outputsdmin[kTableLength] = {2.0, 2.0, -0.0, -0.0, 42.0,
922 42.0, dminf, dminf, dnan, dnan,
923 dnan, dnan, dnan};
924 double outputsdmax[kTableLength] = {3.0, 3.0, 0.0, 0.0, dinf, dinf, dinf,
925 dinf, dnan, dnan, dnan, dnan, dnan};
926
927 float inputse[kTableLength] = {2.0, 3.0, -0.0, 0.0, 42.0, finf, fminf,
928 finf, fnan, 3.0, finf, fnan, fnan};
929 float inputsf[kTableLength] = {3.0, 2.0, 0.0, -0.0, finf, 42.0, finf,
930 fminf, 3.0, fnan, fnan, finf, fnan};
931 float outputsfmin[kTableLength] = {2.0, 2.0, -0.0, -0.0, 42.0, 42.0, fminf,
932 fminf, fnan, fnan, fnan, fnan, fnan};
933 float outputsfmax[kTableLength] = {3.0, 3.0, 0.0, 0.0, finf, finf, finf,
934 finf, fnan, fnan, fnan, fnan, fnan};
935
936 auto handle_dnan = [masm](FPURegister dst, Label* nan, Label* back) {
937 __ bind(nan);
938 __ LoadRoot(at, Heap::kNanValueRootIndex);
939 __ ldc1(dst, FieldMemOperand(at, HeapNumber::kValueOffset));
940 __ Branch(back);
941 };
942
943 auto handle_snan = [masm, fnan](FPURegister dst, Label* nan, Label* back) {
944 __ bind(nan);
945 __ Move(dst, fnan);
946 __ Branch(back);
947 };
948
949 Label handle_mind_nan, handle_maxd_nan, handle_mins_nan, handle_maxs_nan;
950 Label back_mind_nan, back_maxd_nan, back_mins_nan, back_maxs_nan;
951
952 __ push(s6);
953 __ InitializeRootRegister();
954 __ ldc1(f4, MemOperand(a0, offsetof(TestFloat, a)));
955 __ ldc1(f8, MemOperand(a0, offsetof(TestFloat, b)));
956 __ lwc1(f2, MemOperand(a0, offsetof(TestFloat, e)));
957 __ lwc1(f6, MemOperand(a0, offsetof(TestFloat, f)));
958 __ MinNaNCheck_d(f10, f4, f8, &handle_mind_nan);
959 __ bind(&back_mind_nan);
960 __ MaxNaNCheck_d(f12, f4, f8, &handle_maxd_nan);
961 __ bind(&back_maxd_nan);
962 __ MinNaNCheck_s(f14, f2, f6, &handle_mins_nan);
963 __ bind(&back_mins_nan);
964 __ MaxNaNCheck_s(f16, f2, f6, &handle_maxs_nan);
965 __ bind(&back_maxs_nan);
966 __ sdc1(f10, MemOperand(a0, offsetof(TestFloat, c)));
967 __ sdc1(f12, MemOperand(a0, offsetof(TestFloat, d)));
968 __ swc1(f14, MemOperand(a0, offsetof(TestFloat, g)));
969 __ swc1(f16, MemOperand(a0, offsetof(TestFloat, h)));
970 __ pop(s6);
971 __ jr(ra);
972 __ nop();
973
974 handle_dnan(f10, &handle_mind_nan, &back_mind_nan);
975 handle_dnan(f12, &handle_maxd_nan, &back_maxd_nan);
976 handle_snan(f14, &handle_mins_nan, &back_mins_nan);
977 handle_snan(f16, &handle_maxs_nan, &back_maxs_nan);
978
979 CodeDesc desc;
980 masm->GetCode(&desc);
981 Handle<Code> code = isolate->factory()->NewCode(
982 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
983 ::F3 f = FUNCTION_CAST<::F3>(code->entry());
984 for (int i = 0; i < kTableLength; i++) {
985 test.a = inputsa[i];
986 test.b = inputsb[i];
987 test.e = inputse[i];
988 test.f = inputsf[i];
989
990 CALL_GENERATED_CODE(isolate, f, &test, 0, 0, 0, 0);
991
992 CHECK_EQ(0, memcmp(&test.c, &outputsdmin[i], sizeof(test.c)));
993 CHECK_EQ(0, memcmp(&test.d, &outputsdmax[i], sizeof(test.d)));
994 CHECK_EQ(0, memcmp(&test.g, &outputsfmin[i], sizeof(test.g)));
995 CHECK_EQ(0, memcmp(&test.h, &outputsfmax[i], sizeof(test.h)));
996 }
997}
998
Ben Murdochc5610432016-08-08 18:44:38 +0100999template <typename IN_TYPE, typename Func>
1000bool run_Unaligned(char* memory_buffer, int32_t in_offset, int32_t out_offset,
1001 IN_TYPE value, Func GenerateUnalignedInstructionFunc) {
1002 typedef int32_t (*F_CVT)(char* x0, int x1, int x2, int x3, int x4);
1003
1004 Isolate* isolate = CcTest::i_isolate();
1005 HandleScope scope(isolate);
1006 MacroAssembler assm(isolate, nullptr, 0,
1007 v8::internal::CodeObjectRequired::kYes);
1008 MacroAssembler* masm = &assm;
1009 IN_TYPE res;
1010
1011 GenerateUnalignedInstructionFunc(masm, in_offset, out_offset);
1012 __ jr(ra);
1013 __ nop();
1014
1015 CodeDesc desc;
1016 assm.GetCode(&desc);
1017 Handle<Code> code = isolate->factory()->NewCode(
1018 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
1019
1020 F_CVT f = FUNCTION_CAST<F_CVT>(code->entry());
1021
1022 MemCopy(memory_buffer + in_offset, &value, sizeof(IN_TYPE));
1023 CALL_GENERATED_CODE(isolate, f, memory_buffer, 0, 0, 0, 0);
1024 MemCopy(&res, memory_buffer + out_offset, sizeof(IN_TYPE));
1025
1026 return res == value;
1027}
1028
1029static const std::vector<uint64_t> unsigned_test_values() {
1030 static const uint64_t kValues[] = {
1031 0x2180f18a06384414, 0x000a714532102277, 0xbc1acccf180649f0,
1032 0x8000000080008000, 0x0000000000000001, 0xffffffffffffffff,
1033 };
1034 return std::vector<uint64_t>(&kValues[0], &kValues[arraysize(kValues)]);
1035}
1036
1037static const std::vector<int32_t> unsigned_test_offset() {
1038 static const int32_t kValues[] = {// value, offset
1039 -132 * KB, -21 * KB, 0, 19 * KB, 135 * KB};
1040 return std::vector<int32_t>(&kValues[0], &kValues[arraysize(kValues)]);
1041}
1042
1043static const std::vector<int32_t> unsigned_test_offset_increment() {
1044 static const int32_t kValues[] = {-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5};
1045 return std::vector<int32_t>(&kValues[0], &kValues[arraysize(kValues)]);
1046}
1047
1048TEST(Ulh) {
1049 CcTest::InitializeVM();
1050
1051 static const int kBufferSize = 300 * KB;
1052 char memory_buffer[kBufferSize];
1053 char* buffer_middle = memory_buffer + (kBufferSize / 2);
1054
1055 FOR_UINT64_INPUTS(i, unsigned_test_values) {
1056 FOR_INT32_INPUTS2(j1, j2, unsigned_test_offset) {
1057 FOR_INT32_INPUTS2(k1, k2, unsigned_test_offset_increment) {
1058 uint16_t value = static_cast<uint64_t>(*i & 0xFFFF);
1059 int32_t in_offset = *j1 + *k1;
1060 int32_t out_offset = *j2 + *k2;
1061
1062 CHECK_EQ(true, run_Unaligned<uint16_t>(
1063 buffer_middle, in_offset, out_offset, value,
1064 [](MacroAssembler* masm, int32_t in_offset,
1065 int32_t out_offset) {
1066 __ Ulh(v0, MemOperand(a0, in_offset));
1067 __ Ush(v0, MemOperand(a0, out_offset), v0);
1068 }));
1069 CHECK_EQ(true, run_Unaligned<uint16_t>(
1070 buffer_middle, in_offset, out_offset, value,
1071 [](MacroAssembler* masm, int32_t in_offset,
1072 int32_t out_offset) {
1073 __ mov(t0, a0);
1074 __ Ulh(a0, MemOperand(a0, in_offset));
1075 __ Ush(a0, MemOperand(t0, out_offset), v0);
1076 }));
1077 CHECK_EQ(true, run_Unaligned<uint16_t>(
1078 buffer_middle, in_offset, out_offset, value,
1079 [](MacroAssembler* masm, int32_t in_offset,
1080 int32_t out_offset) {
1081 __ mov(t0, a0);
1082 __ Ulhu(a0, MemOperand(a0, in_offset));
1083 __ Ush(a0, MemOperand(t0, out_offset), t1);
1084 }));
1085 CHECK_EQ(true, run_Unaligned<uint16_t>(
1086 buffer_middle, in_offset, out_offset, value,
1087 [](MacroAssembler* masm, int32_t in_offset,
1088 int32_t out_offset) {
1089 __ Ulhu(v0, MemOperand(a0, in_offset));
1090 __ Ush(v0, MemOperand(a0, out_offset), t1);
1091 }));
1092 }
1093 }
1094 }
1095}
1096
1097TEST(Ulh_bitextension) {
1098 CcTest::InitializeVM();
1099
1100 static const int kBufferSize = 300 * KB;
1101 char memory_buffer[kBufferSize];
1102 char* buffer_middle = memory_buffer + (kBufferSize / 2);
1103
1104 FOR_UINT64_INPUTS(i, unsigned_test_values) {
1105 FOR_INT32_INPUTS2(j1, j2, unsigned_test_offset) {
1106 FOR_INT32_INPUTS2(k1, k2, unsigned_test_offset_increment) {
1107 uint16_t value = static_cast<uint64_t>(*i & 0xFFFF);
1108 int32_t in_offset = *j1 + *k1;
1109 int32_t out_offset = *j2 + *k2;
1110
1111 CHECK_EQ(true, run_Unaligned<uint16_t>(
1112 buffer_middle, in_offset, out_offset, value,
1113 [](MacroAssembler* masm, int32_t in_offset,
1114 int32_t out_offset) {
1115 Label success, fail, end, different;
1116 __ Ulh(t0, MemOperand(a0, in_offset));
1117 __ Ulhu(t1, MemOperand(a0, in_offset));
1118 __ Branch(&different, ne, t0, Operand(t1));
1119
1120 // If signed and unsigned values are same, check
1121 // the upper bits to see if they are zero
1122 __ sra(t0, t0, 15);
1123 __ Branch(&success, eq, t0, Operand(zero_reg));
1124 __ Branch(&fail);
1125
1126 // If signed and unsigned values are different,
1127 // check that the upper bits are complementary
1128 __ bind(&different);
1129 __ sra(t1, t1, 15);
1130 __ Branch(&fail, ne, t1, Operand(1));
1131 __ sra(t0, t0, 15);
1132 __ addiu(t0, t0, 1);
1133 __ Branch(&fail, ne, t0, Operand(zero_reg));
1134 // Fall through to success
1135
1136 __ bind(&success);
1137 __ Ulh(t0, MemOperand(a0, in_offset));
1138 __ Ush(t0, MemOperand(a0, out_offset), v0);
1139 __ Branch(&end);
1140 __ bind(&fail);
1141 __ Ush(zero_reg, MemOperand(a0, out_offset), v0);
1142 __ bind(&end);
1143 }));
1144 }
1145 }
1146 }
1147}
1148
1149TEST(Ulw) {
1150 CcTest::InitializeVM();
1151
1152 static const int kBufferSize = 300 * KB;
1153 char memory_buffer[kBufferSize];
1154 char* buffer_middle = memory_buffer + (kBufferSize / 2);
1155
1156 FOR_UINT64_INPUTS(i, unsigned_test_values) {
1157 FOR_INT32_INPUTS2(j1, j2, unsigned_test_offset) {
1158 FOR_INT32_INPUTS2(k1, k2, unsigned_test_offset_increment) {
1159 uint32_t value = static_cast<uint32_t>(*i & 0xFFFFFFFF);
1160 int32_t in_offset = *j1 + *k1;
1161 int32_t out_offset = *j2 + *k2;
1162
1163 CHECK_EQ(true, run_Unaligned<uint32_t>(
1164 buffer_middle, in_offset, out_offset, value,
1165 [](MacroAssembler* masm, int32_t in_offset,
1166 int32_t out_offset) {
1167 __ Ulw(v0, MemOperand(a0, in_offset));
1168 __ Usw(v0, MemOperand(a0, out_offset));
1169 }));
1170 CHECK_EQ(true,
1171 run_Unaligned<uint32_t>(
1172 buffer_middle, in_offset, out_offset, (uint32_t)value,
1173 [](MacroAssembler* masm, int32_t in_offset,
1174 int32_t out_offset) {
1175 __ mov(t0, a0);
1176 __ Ulw(a0, MemOperand(a0, in_offset));
1177 __ Usw(a0, MemOperand(t0, out_offset));
1178 }));
1179 }
1180 }
1181 }
1182}
1183
1184TEST(Ulwc1) {
1185 CcTest::InitializeVM();
1186
1187 static const int kBufferSize = 300 * KB;
1188 char memory_buffer[kBufferSize];
1189 char* buffer_middle = memory_buffer + (kBufferSize / 2);
1190
1191 FOR_UINT64_INPUTS(i, unsigned_test_values) {
1192 FOR_INT32_INPUTS2(j1, j2, unsigned_test_offset) {
1193 FOR_INT32_INPUTS2(k1, k2, unsigned_test_offset_increment) {
1194 float value = static_cast<float>(*i & 0xFFFFFFFF);
1195 int32_t in_offset = *j1 + *k1;
1196 int32_t out_offset = *j2 + *k2;
1197
1198 CHECK_EQ(true, run_Unaligned<float>(
1199 buffer_middle, in_offset, out_offset, value,
1200 [](MacroAssembler* masm, int32_t in_offset,
1201 int32_t out_offset) {
1202 __ Ulwc1(f0, MemOperand(a0, in_offset), t0);
1203 __ Uswc1(f0, MemOperand(a0, out_offset), t0);
1204 }));
1205 }
1206 }
1207 }
1208}
1209
1210TEST(Uldc1) {
1211 CcTest::InitializeVM();
1212
1213 static const int kBufferSize = 300 * KB;
1214 char memory_buffer[kBufferSize];
1215 char* buffer_middle = memory_buffer + (kBufferSize / 2);
1216
1217 FOR_UINT64_INPUTS(i, unsigned_test_values) {
1218 FOR_INT32_INPUTS2(j1, j2, unsigned_test_offset) {
1219 FOR_INT32_INPUTS2(k1, k2, unsigned_test_offset_increment) {
1220 double value = static_cast<double>(*i);
1221 int32_t in_offset = *j1 + *k1;
1222 int32_t out_offset = *j2 + *k2;
1223
1224 CHECK_EQ(true, run_Unaligned<double>(
1225 buffer_middle, in_offset, out_offset, value,
1226 [](MacroAssembler* masm, int32_t in_offset,
1227 int32_t out_offset) {
1228 __ Uldc1(f0, MemOperand(a0, in_offset), t0);
1229 __ Usdc1(f0, MemOperand(a0, out_offset), t0);
1230 }));
1231 }
1232 }
1233 }
1234}
1235
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001236#undef __