1 // Copyright 2011 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 "v8.h"
29
30 #include "disassembler.h"
31 #include "factory.h"
32 #include "arm/simulator-arm.h"
33 #include "arm/assembler-arm-inl.h"
34 #include "cctest.h"
35
36 using namespace v8::internal;
37
38
39 // Define these function prototypes to match JSEntryFunction in execution.cc.
40 typedef Object* (*F1)(int x, int p1, int p2, int p3, int p4);
41 typedef Object* (*F2)(int x, int y, int p2, int p3, int p4);
42 typedef Object* (*F3)(void* p0, int p1, int p2, int p3, int p4);
43 typedef Object* (*F4)(void* p0, void* p1, int p2, int p3, int p4);
44
45
46 static v8::Persistent<v8::Context> env;
47
48
InitializeVM()49 static void InitializeVM() {
50 if (env.IsEmpty()) {
51 env = v8::Context::New();
52 }
53 }
54
55
56 #define __ assm.
57
58 TEST(0) {
59 InitializeVM();
60 v8::HandleScope scope;
61
62 Assembler assm(Isolate::Current(), NULL, 0);
63
64 __ add(r0, r0, Operand(r1));
65 __ mov(pc, Operand(lr));
66
67 CodeDesc desc;
68 assm.GetCode(&desc);
69 Object* code = HEAP->CreateCode(
70 desc,
71 Code::ComputeFlags(Code::STUB),
72 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
73 CHECK(code->IsCode());
74 #ifdef DEBUG
75 Code::cast(code)->Print();
76 #endif
77 F2 f = FUNCTION_CAST<F2>(Code::cast(code)->entry());
78 int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 3, 4, 0, 0, 0));
79 ::printf("f() = %d\n", res);
80 CHECK_EQ(7, res);
81 }
82
83
84 TEST(1) {
85 InitializeVM();
86 v8::HandleScope scope;
87
88 Assembler assm(Isolate::Current(), NULL, 0);
89 Label L, C;
90
91 __ mov(r1, Operand(r0));
92 __ mov(r0, Operand(0, RelocInfo::NONE));
93 __ b(&C);
94
95 __ bind(&L);
96 __ add(r0, r0, Operand(r1));
97 __ sub(r1, r1, Operand(1));
98
99 __ bind(&C);
100 __ teq(r1, Operand(0, RelocInfo::NONE));
101 __ b(ne, &L);
102 __ mov(pc, Operand(lr));
103
104 CodeDesc desc;
105 assm.GetCode(&desc);
106 Object* code = HEAP->CreateCode(
107 desc,
108 Code::ComputeFlags(Code::STUB),
109 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
110 CHECK(code->IsCode());
111 #ifdef DEBUG
112 Code::cast(code)->Print();
113 #endif
114 F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry());
115 int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 100, 0, 0, 0, 0));
116 ::printf("f() = %d\n", res);
117 CHECK_EQ(5050, res);
118 }
119
120
121 TEST(2) {
122 InitializeVM();
123 v8::HandleScope scope;
124
125 Assembler assm(Isolate::Current(), NULL, 0);
126 Label L, C;
127
128 __ mov(r1, Operand(r0));
129 __ mov(r0, Operand(1));
130 __ b(&C);
131
132 __ bind(&L);
133 __ mul(r0, r1, r0);
134 __ sub(r1, r1, Operand(1));
135
136 __ bind(&C);
137 __ teq(r1, Operand(0, RelocInfo::NONE));
138 __ b(ne, &L);
139 __ mov(pc, Operand(lr));
140
141 // some relocated stuff here, not executed
142 __ RecordComment("dead code, just testing relocations");
143 __ mov(r0, Operand(FACTORY->true_value()));
144 __ RecordComment("dead code, just testing immediate operands");
145 __ mov(r0, Operand(-1));
146 __ mov(r0, Operand(0xFF000000));
147 __ mov(r0, Operand(0xF0F0F0F0));
148 __ mov(r0, Operand(0xFFF0FFFF));
149
150 CodeDesc desc;
151 assm.GetCode(&desc);
152 Object* code = HEAP->CreateCode(
153 desc,
154 Code::ComputeFlags(Code::STUB),
155 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
156 CHECK(code->IsCode());
157 #ifdef DEBUG
158 Code::cast(code)->Print();
159 #endif
160 F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry());
161 int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 10, 0, 0, 0, 0));
162 ::printf("f() = %d\n", res);
163 CHECK_EQ(3628800, res);
164 }
165
166
167 TEST(3) {
168 InitializeVM();
169 v8::HandleScope scope;
170
171 typedef struct {
172 int i;
173 char c;
174 int16_t s;
175 } T;
176 T t;
177
178 Assembler assm(Isolate::Current(), NULL, 0);
179 Label L, C;
180
181 __ mov(ip, Operand(sp));
182 __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit());
183 __ sub(fp, ip, Operand(4));
184 __ mov(r4, Operand(r0));
185 __ ldr(r0, MemOperand(r4, OFFSET_OF(T, i)));
186 __ mov(r2, Operand(r0, ASR, 1));
187 __ str(r2, MemOperand(r4, OFFSET_OF(T, i)));
188 __ ldrsb(r2, MemOperand(r4, OFFSET_OF(T, c)));
189 __ add(r0, r2, Operand(r0));
190 __ mov(r2, Operand(r2, LSL, 2));
191 __ strb(r2, MemOperand(r4, OFFSET_OF(T, c)));
192 __ ldrsh(r2, MemOperand(r4, OFFSET_OF(T, s)));
193 __ add(r0, r2, Operand(r0));
194 __ mov(r2, Operand(r2, ASR, 3));
195 __ strh(r2, MemOperand(r4, OFFSET_OF(T, s)));
196 __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
197
198 CodeDesc desc;
199 assm.GetCode(&desc);
200 Object* code = HEAP->CreateCode(
201 desc,
202 Code::ComputeFlags(Code::STUB),
203 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
204 CHECK(code->IsCode());
205 #ifdef DEBUG
206 Code::cast(code)->Print();
207 #endif
208 F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
209 t.i = 100000;
210 t.c = 10;
211 t.s = 1000;
212 int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0));
213 ::printf("f() = %d\n", res);
214 CHECK_EQ(101010, res);
215 CHECK_EQ(100000/2, t.i);
216 CHECK_EQ(10*4, t.c);
217 CHECK_EQ(1000/8, t.s);
218 }
219
220
221 TEST(4) {
222 // Test the VFP floating point instructions.
223 InitializeVM();
224 v8::HandleScope scope;
225
226 typedef struct {
227 double a;
228 double b;
229 double c;
230 double d;
231 double e;
232 double f;
233 double g;
234 double h;
235 int i;
236 double m;
237 double n;
238 float x;
239 float y;
240 } T;
241 T t;
242
243 // Create a function that accepts &t, and loads, manipulates, and stores
244 // the doubles and floats.
245 Assembler assm(Isolate::Current(), NULL, 0);
246 Label L, C;
247
248
249 if (CpuFeatures::IsSupported(VFP3)) {
250 CpuFeatures::Scope scope(VFP3);
251
252 __ mov(ip, Operand(sp));
253 __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit());
254 __ sub(fp, ip, Operand(4));
255
256 __ mov(r4, Operand(r0));
257 __ vldr(d6, r4, OFFSET_OF(T, a));
258 __ vldr(d7, r4, OFFSET_OF(T, b));
259 __ vadd(d5, d6, d7);
260 __ vstr(d5, r4, OFFSET_OF(T, c));
261
262 __ vmov(r2, r3, d5);
263 __ vmov(d4, r2, r3);
264 __ vstr(d4, r4, OFFSET_OF(T, b));
265
266 // Load t.x and t.y, switch values, and store back to the struct.
267 __ vldr(s0, r4, OFFSET_OF(T, x));
268 __ vldr(s31, r4, OFFSET_OF(T, y));
269 __ vmov(s16, s0);
270 __ vmov(s0, s31);
271 __ vmov(s31, s16);
272 __ vstr(s0, r4, OFFSET_OF(T, x));
273 __ vstr(s31, r4, OFFSET_OF(T, y));
274
275 // Move a literal into a register that can be encoded in the instruction.
276 __ vmov(d4, 1.0);
277 __ vstr(d4, r4, OFFSET_OF(T, e));
278
279 // Move a literal into a register that requires 64 bits to encode.
280 // 0x3ff0000010000000 = 1.000000059604644775390625
281 __ vmov(d4, 1.000000059604644775390625);
282 __ vstr(d4, r4, OFFSET_OF(T, d));
283
284 // Convert from floating point to integer.
285 __ vmov(d4, 2.0);
286 __ vcvt_s32_f64(s31, d4);
287 __ vstr(s31, r4, OFFSET_OF(T, i));
288
289 // Convert from integer to floating point.
290 __ mov(lr, Operand(42));
291 __ vmov(s31, lr);
292 __ vcvt_f64_s32(d4, s31);
293 __ vstr(d4, r4, OFFSET_OF(T, f));
294
295 // Test vabs.
296 __ vldr(d1, r4, OFFSET_OF(T, g));
297 __ vabs(d0, d1);
298 __ vstr(d0, r4, OFFSET_OF(T, g));
299 __ vldr(d2, r4, OFFSET_OF(T, h));
300 __ vabs(d0, d2);
301 __ vstr(d0, r4, OFFSET_OF(T, h));
302
303 // Test vneg.
304 __ vldr(d1, r4, OFFSET_OF(T, m));
305 __ vneg(d0, d1);
306 __ vstr(d0, r4, OFFSET_OF(T, m));
307 __ vldr(d1, r4, OFFSET_OF(T, n));
308 __ vneg(d0, d1);
309 __ vstr(d0, r4, OFFSET_OF(T, n));
310
311 __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
312
313 CodeDesc desc;
314 assm.GetCode(&desc);
315 Object* code = HEAP->CreateCode(
316 desc,
317 Code::ComputeFlags(Code::STUB),
318 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
319 CHECK(code->IsCode());
320 #ifdef DEBUG
321 Code::cast(code)->Print();
322 #endif
323 F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
324 t.a = 1.5;
325 t.b = 2.75;
326 t.c = 17.17;
327 t.d = 0.0;
328 t.e = 0.0;
329 t.f = 0.0;
330 t.g = -2718.2818;
331 t.h = 31415926.5;
332 t.i = 0;
333 t.m = -2718.2818;
334 t.n = 123.456;
335 t.x = 4.5;
336 t.y = 9.0;
337 Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
338 USE(dummy);
339 CHECK_EQ(4.5, t.y);
340 CHECK_EQ(9.0, t.x);
341 CHECK_EQ(-123.456, t.n);
342 CHECK_EQ(2718.2818, t.m);
343 CHECK_EQ(2, t.i);
344 CHECK_EQ(2718.2818, t.g);
345 CHECK_EQ(31415926.5, t.h);
346 CHECK_EQ(42.0, t.f);
347 CHECK_EQ(1.0, t.e);
348 CHECK_EQ(1.000000059604644775390625, t.d);
349 CHECK_EQ(4.25, t.c);
350 CHECK_EQ(4.25, t.b);
351 CHECK_EQ(1.5, t.a);
352 }
353 }
354
355
356 TEST(5) {
357 // Test the ARMv7 bitfield instructions.
358 InitializeVM();
359 v8::HandleScope scope;
360
361 Assembler assm(Isolate::Current(), NULL, 0);
362
363 if (CpuFeatures::IsSupported(ARMv7)) {
364 CpuFeatures::Scope scope(ARMv7);
365 // On entry, r0 = 0xAAAAAAAA = 0b10..10101010.
366 __ ubfx(r0, r0, 1, 12); // 0b00..010101010101 = 0x555
367 __ sbfx(r0, r0, 0, 5); // 0b11..111111110101 = -11
368 __ bfc(r0, 1, 3); // 0b11..111111110001 = -15
369 __ mov(r1, Operand(7));
370 __ bfi(r0, r1, 3, 3); // 0b11..111111111001 = -7
371 __ mov(pc, Operand(lr));
372
373 CodeDesc desc;
374 assm.GetCode(&desc);
375 Object* code = HEAP->CreateCode(
376 desc,
377 Code::ComputeFlags(Code::STUB),
378 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
379 CHECK(code->IsCode());
380 #ifdef DEBUG
381 Code::cast(code)->Print();
382 #endif
383 F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry());
384 int res = reinterpret_cast<int>(
385 CALL_GENERATED_CODE(f, 0xAAAAAAAA, 0, 0, 0, 0));
386 ::printf("f() = %d\n", res);
387 CHECK_EQ(-7, res);
388 }
389 }
390
391
392 TEST(6) {
393 // Test saturating instructions.
394 InitializeVM();
395 v8::HandleScope scope;
396
397 Assembler assm(Isolate::Current(), NULL, 0);
398
399 if (CpuFeatures::IsSupported(ARMv7)) {
400 CpuFeatures::Scope scope(ARMv7);
401 __ usat(r1, 8, Operand(r0)); // Sat 0xFFFF to 0-255 = 0xFF.
402 __ usat(r2, 12, Operand(r0, ASR, 9)); // Sat (0xFFFF>>9) to 0-4095 = 0x7F.
403 __ usat(r3, 1, Operand(r0, LSL, 16)); // Sat (0xFFFF<<16) to 0-1 = 0x0.
404 __ add(r0, r1, Operand(r2));
405 __ add(r0, r0, Operand(r3));
406 __ mov(pc, Operand(lr));
407
408 CodeDesc desc;
409 assm.GetCode(&desc);
410 Object* code = HEAP->CreateCode(
411 desc,
412 Code::ComputeFlags(Code::STUB),
413 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
414 CHECK(code->IsCode());
415 #ifdef DEBUG
416 Code::cast(code)->Print();
417 #endif
418 F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry());
419 int res = reinterpret_cast<int>(
420 CALL_GENERATED_CODE(f, 0xFFFF, 0, 0, 0, 0));
421 ::printf("f() = %d\n", res);
422 CHECK_EQ(382, res);
423 }
424 }
425
426
427 enum VCVTTypes {
428 s32_f64,
429 u32_f64
430 };
431
TestRoundingMode(VCVTTypes types,VFPRoundingMode mode,double value,int expected,bool expected_exception=false)432 static void TestRoundingMode(VCVTTypes types,
433 VFPRoundingMode mode,
434 double value,
435 int expected,
436 bool expected_exception = false) {
437 InitializeVM();
438 v8::HandleScope scope;
439
440 Assembler assm(Isolate::Current(), NULL, 0);
441
442 if (CpuFeatures::IsSupported(VFP3)) {
443 CpuFeatures::Scope scope(VFP3);
444
445 Label wrong_exception;
446
447 __ vmrs(r1);
448 // Set custom FPSCR.
449 __ bic(r2, r1, Operand(kVFPRoundingModeMask | kVFPExceptionMask));
450 __ orr(r2, r2, Operand(mode));
451 __ vmsr(r2);
452
453 // Load value, convert, and move back result to r0 if everything went well.
454 __ vmov(d1, value);
455 switch (types) {
456 case s32_f64:
457 __ vcvt_s32_f64(s0, d1, kFPSCRRounding);
458 break;
459
460 case u32_f64:
461 __ vcvt_u32_f64(s0, d1, kFPSCRRounding);
462 break;
463
464 default:
465 UNREACHABLE();
466 break;
467 }
468 // Check for vfp exceptions
469 __ vmrs(r2);
470 __ tst(r2, Operand(kVFPExceptionMask));
471 // Check that we behaved as expected.
472 __ b(&wrong_exception,
473 expected_exception ? eq : ne);
474 // There was no exception. Retrieve the result and return.
475 __ vmov(r0, s0);
476 __ mov(pc, Operand(lr));
477
478 // The exception behaviour is not what we expected.
479 // Load a special value and return.
480 __ bind(&wrong_exception);
481 __ mov(r0, Operand(11223344));
482 __ mov(pc, Operand(lr));
483
484 CodeDesc desc;
485 assm.GetCode(&desc);
486 Object* code = HEAP->CreateCode(
487 desc,
488 Code::ComputeFlags(Code::STUB),
489 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
490 CHECK(code->IsCode());
491 #ifdef DEBUG
492 Code::cast(code)->Print();
493 #endif
494 F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry());
495 int res = reinterpret_cast<int>(
496 CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
497 ::printf("res = %d\n", res);
498 CHECK_EQ(expected, res);
499 }
500 }
501
502
503 TEST(7) {
504 // Test vfp rounding modes.
505
506 // s32_f64 (double to integer).
507
508 TestRoundingMode(s32_f64, RN, 0, 0);
509 TestRoundingMode(s32_f64, RN, 0.5, 0);
510 TestRoundingMode(s32_f64, RN, -0.5, 0);
511 TestRoundingMode(s32_f64, RN, 1.5, 2);
512 TestRoundingMode(s32_f64, RN, -1.5, -2);
513 TestRoundingMode(s32_f64, RN, 123.7, 124);
514 TestRoundingMode(s32_f64, RN, -123.7, -124);
515 TestRoundingMode(s32_f64, RN, 123456.2, 123456);
516 TestRoundingMode(s32_f64, RN, -123456.2, -123456);
517 TestRoundingMode(s32_f64, RN, static_cast<double>(kMaxInt), kMaxInt);
518 TestRoundingMode(s32_f64, RN, (kMaxInt + 0.49), kMaxInt);
519 TestRoundingMode(s32_f64, RN, (kMaxInt + 1.0), kMaxInt, true);
520 TestRoundingMode(s32_f64, RN, (kMaxInt + 0.5), kMaxInt, true);
521 TestRoundingMode(s32_f64, RN, static_cast<double>(kMinInt), kMinInt);
522 TestRoundingMode(s32_f64, RN, (kMinInt - 0.5), kMinInt);
523 TestRoundingMode(s32_f64, RN, (kMinInt - 1.0), kMinInt, true);
524 TestRoundingMode(s32_f64, RN, (kMinInt - 0.51), kMinInt, true);
525
526 TestRoundingMode(s32_f64, RM, 0, 0);
527 TestRoundingMode(s32_f64, RM, 0.5, 0);
528 TestRoundingMode(s32_f64, RM, -0.5, -1);
529 TestRoundingMode(s32_f64, RM, 123.7, 123);
530 TestRoundingMode(s32_f64, RM, -123.7, -124);
531 TestRoundingMode(s32_f64, RM, 123456.2, 123456);
532 TestRoundingMode(s32_f64, RM, -123456.2, -123457);
533 TestRoundingMode(s32_f64, RM, static_cast<double>(kMaxInt), kMaxInt);
534 TestRoundingMode(s32_f64, RM, (kMaxInt + 0.5), kMaxInt);
535 TestRoundingMode(s32_f64, RM, (kMaxInt + 1.0), kMaxInt, true);
536 TestRoundingMode(s32_f64, RM, static_cast<double>(kMinInt), kMinInt);
537 TestRoundingMode(s32_f64, RM, (kMinInt - 0.5), kMinInt, true);
538 TestRoundingMode(s32_f64, RM, (kMinInt + 0.5), kMinInt);
539
540 TestRoundingMode(s32_f64, RZ, 0, 0);
541 TestRoundingMode(s32_f64, RZ, 0.5, 0);
542 TestRoundingMode(s32_f64, RZ, -0.5, 0);
543 TestRoundingMode(s32_f64, RZ, 123.7, 123);
544 TestRoundingMode(s32_f64, RZ, -123.7, -123);
545 TestRoundingMode(s32_f64, RZ, 123456.2, 123456);
546 TestRoundingMode(s32_f64, RZ, -123456.2, -123456);
547 TestRoundingMode(s32_f64, RZ, static_cast<double>(kMaxInt), kMaxInt);
548 TestRoundingMode(s32_f64, RZ, (kMaxInt + 0.5), kMaxInt);
549 TestRoundingMode(s32_f64, RZ, (kMaxInt + 1.0), kMaxInt, true);
550 TestRoundingMode(s32_f64, RZ, static_cast<double>(kMinInt), kMinInt);
551 TestRoundingMode(s32_f64, RZ, (kMinInt - 0.5), kMinInt);
552 TestRoundingMode(s32_f64, RZ, (kMinInt - 1.0), kMinInt, true);
553
554
555 // u32_f64 (double to integer).
556
557 // Negative values.
558 TestRoundingMode(u32_f64, RN, -0.5, 0);
559 TestRoundingMode(u32_f64, RN, -123456.7, 0, true);
560 TestRoundingMode(u32_f64, RN, static_cast<double>(kMinInt), 0, true);
561 TestRoundingMode(u32_f64, RN, kMinInt - 1.0, 0, true);
562
563 TestRoundingMode(u32_f64, RM, -0.5, 0, true);
564 TestRoundingMode(u32_f64, RM, -123456.7, 0, true);
565 TestRoundingMode(u32_f64, RM, static_cast<double>(kMinInt), 0, true);
566 TestRoundingMode(u32_f64, RM, kMinInt - 1.0, 0, true);
567
568 TestRoundingMode(u32_f64, RZ, -0.5, 0);
569 TestRoundingMode(u32_f64, RZ, -123456.7, 0, true);
570 TestRoundingMode(u32_f64, RZ, static_cast<double>(kMinInt), 0, true);
571 TestRoundingMode(u32_f64, RZ, kMinInt - 1.0, 0, true);
572
573 // Positive values.
574 // kMaxInt is the maximum *signed* integer: 0x7fffffff.
575 static const uint32_t kMaxUInt = 0xffffffffu;
576 TestRoundingMode(u32_f64, RZ, 0, 0);
577 TestRoundingMode(u32_f64, RZ, 0.5, 0);
578 TestRoundingMode(u32_f64, RZ, 123.7, 123);
579 TestRoundingMode(u32_f64, RZ, 123456.2, 123456);
580 TestRoundingMode(u32_f64, RZ, static_cast<double>(kMaxInt), kMaxInt);
581 TestRoundingMode(u32_f64, RZ, (kMaxInt + 0.5), kMaxInt);
582 TestRoundingMode(u32_f64, RZ, (kMaxInt + 1.0),
583 static_cast<uint32_t>(kMaxInt) + 1);
584 TestRoundingMode(u32_f64, RZ, (kMaxUInt + 0.5), kMaxUInt);
585 TestRoundingMode(u32_f64, RZ, (kMaxUInt + 1.0), kMaxUInt, true);
586
587 TestRoundingMode(u32_f64, RM, 0, 0);
588 TestRoundingMode(u32_f64, RM, 0.5, 0);
589 TestRoundingMode(u32_f64, RM, 123.7, 123);
590 TestRoundingMode(u32_f64, RM, 123456.2, 123456);
591 TestRoundingMode(u32_f64, RM, static_cast<double>(kMaxInt), kMaxInt);
592 TestRoundingMode(u32_f64, RM, (kMaxInt + 0.5), kMaxInt);
593 TestRoundingMode(u32_f64, RM, (kMaxInt + 1.0),
594 static_cast<uint32_t>(kMaxInt) + 1);
595 TestRoundingMode(u32_f64, RM, (kMaxUInt + 0.5), kMaxUInt);
596 TestRoundingMode(u32_f64, RM, (kMaxUInt + 1.0), kMaxUInt, true);
597
598 TestRoundingMode(u32_f64, RN, 0, 0);
599 TestRoundingMode(u32_f64, RN, 0.5, 0);
600 TestRoundingMode(u32_f64, RN, 1.5, 2);
601 TestRoundingMode(u32_f64, RN, 123.7, 124);
602 TestRoundingMode(u32_f64, RN, 123456.2, 123456);
603 TestRoundingMode(u32_f64, RN, static_cast<double>(kMaxInt), kMaxInt);
604 TestRoundingMode(u32_f64, RN, (kMaxInt + 0.49), kMaxInt);
605 TestRoundingMode(u32_f64, RN, (kMaxInt + 0.5),
606 static_cast<uint32_t>(kMaxInt) + 1);
607 TestRoundingMode(u32_f64, RN, (kMaxUInt + 0.49), kMaxUInt);
608 TestRoundingMode(u32_f64, RN, (kMaxUInt + 0.5), kMaxUInt, true);
609 TestRoundingMode(u32_f64, RN, (kMaxUInt + 1.0), kMaxUInt, true);
610 }
611
612 TEST(8) {
613 // Test VFP multi load/store with ia_w.
614 InitializeVM();
615 v8::HandleScope scope;
616
617 typedef struct {
618 double a;
619 double b;
620 double c;
621 double d;
622 double e;
623 double f;
624 double g;
625 double h;
626 } D;
627 D d;
628
629 typedef struct {
630 float a;
631 float b;
632 float c;
633 float d;
634 float e;
635 float f;
636 float g;
637 float h;
638 } F;
639 F f;
640
641 // Create a function that uses vldm/vstm to move some double and
642 // single precision values around in memory.
643 Assembler assm(Isolate::Current(), NULL, 0);
644
645 if (CpuFeatures::IsSupported(VFP3)) {
646 CpuFeatures::Scope scope(VFP3);
647
648 __ mov(ip, Operand(sp));
649 __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit());
650 __ sub(fp, ip, Operand(4));
651
652 __ add(r4, r0, Operand(OFFSET_OF(D, a)));
653 __ vldm(ia_w, r4, d0, d3);
654 __ vldm(ia_w, r4, d4, d7);
655
656 __ add(r4, r0, Operand(OFFSET_OF(D, a)));
657 __ vstm(ia_w, r4, d6, d7);
658 __ vstm(ia_w, r4, d0, d5);
659
660 __ add(r4, r1, Operand(OFFSET_OF(F, a)));
661 __ vldm(ia_w, r4, s0, s3);
662 __ vldm(ia_w, r4, s4, s7);
663
664 __ add(r4, r1, Operand(OFFSET_OF(F, a)));
665 __ vstm(ia_w, r4, s6, s7);
666 __ vstm(ia_w, r4, s0, s5);
667
668 __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
669
670 CodeDesc desc;
671 assm.GetCode(&desc);
672 Object* code = HEAP->CreateCode(
673 desc,
674 Code::ComputeFlags(Code::STUB),
675 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
676 CHECK(code->IsCode());
677 #ifdef DEBUG
678 Code::cast(code)->Print();
679 #endif
680 F4 fn = FUNCTION_CAST<F4>(Code::cast(code)->entry());
681 d.a = 1.1;
682 d.b = 2.2;
683 d.c = 3.3;
684 d.d = 4.4;
685 d.e = 5.5;
686 d.f = 6.6;
687 d.g = 7.7;
688 d.h = 8.8;
689
690 f.a = 1.0;
691 f.b = 2.0;
692 f.c = 3.0;
693 f.d = 4.0;
694 f.e = 5.0;
695 f.f = 6.0;
696 f.g = 7.0;
697 f.h = 8.0;
698
699 Object* dummy = CALL_GENERATED_CODE(fn, &d, &f, 0, 0, 0);
700 USE(dummy);
701
702 CHECK_EQ(7.7, d.a);
703 CHECK_EQ(8.8, d.b);
704 CHECK_EQ(1.1, d.c);
705 CHECK_EQ(2.2, d.d);
706 CHECK_EQ(3.3, d.e);
707 CHECK_EQ(4.4, d.f);
708 CHECK_EQ(5.5, d.g);
709 CHECK_EQ(6.6, d.h);
710
711 CHECK_EQ(7.0, f.a);
712 CHECK_EQ(8.0, f.b);
713 CHECK_EQ(1.0, f.c);
714 CHECK_EQ(2.0, f.d);
715 CHECK_EQ(3.0, f.e);
716 CHECK_EQ(4.0, f.f);
717 CHECK_EQ(5.0, f.g);
718 CHECK_EQ(6.0, f.h);
719 }
720 }
721
722
723 TEST(9) {
724 // Test VFP multi load/store with ia.
725 InitializeVM();
726 v8::HandleScope scope;
727
728 typedef struct {
729 double a;
730 double b;
731 double c;
732 double d;
733 double e;
734 double f;
735 double g;
736 double h;
737 } D;
738 D d;
739
740 typedef struct {
741 float a;
742 float b;
743 float c;
744 float d;
745 float e;
746 float f;
747 float g;
748 float h;
749 } F;
750 F f;
751
752 // Create a function that uses vldm/vstm to move some double and
753 // single precision values around in memory.
754 Assembler assm(Isolate::Current(), NULL, 0);
755
756 if (CpuFeatures::IsSupported(VFP3)) {
757 CpuFeatures::Scope scope(VFP3);
758
759 __ mov(ip, Operand(sp));
760 __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit());
761 __ sub(fp, ip, Operand(4));
762
763 __ add(r4, r0, Operand(OFFSET_OF(D, a)));
764 __ vldm(ia, r4, d0, d3);
765 __ add(r4, r4, Operand(4 * 8));
766 __ vldm(ia, r4, d4, d7);
767
768 __ add(r4, r0, Operand(OFFSET_OF(D, a)));
769 __ vstm(ia, r4, d6, d7);
770 __ add(r4, r4, Operand(2 * 8));
771 __ vstm(ia, r4, d0, d5);
772
773 __ add(r4, r1, Operand(OFFSET_OF(F, a)));
774 __ vldm(ia, r4, s0, s3);
775 __ add(r4, r4, Operand(4 * 4));
776 __ vldm(ia, r4, s4, s7);
777
778 __ add(r4, r1, Operand(OFFSET_OF(F, a)));
779 __ vstm(ia, r4, s6, s7);
780 __ add(r4, r4, Operand(2 * 4));
781 __ vstm(ia, r4, s0, s5);
782
783 __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
784
785 CodeDesc desc;
786 assm.GetCode(&desc);
787 Object* code = HEAP->CreateCode(
788 desc,
789 Code::ComputeFlags(Code::STUB),
790 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
791 CHECK(code->IsCode());
792 #ifdef DEBUG
793 Code::cast(code)->Print();
794 #endif
795 F4 fn = FUNCTION_CAST<F4>(Code::cast(code)->entry());
796 d.a = 1.1;
797 d.b = 2.2;
798 d.c = 3.3;
799 d.d = 4.4;
800 d.e = 5.5;
801 d.f = 6.6;
802 d.g = 7.7;
803 d.h = 8.8;
804
805 f.a = 1.0;
806 f.b = 2.0;
807 f.c = 3.0;
808 f.d = 4.0;
809 f.e = 5.0;
810 f.f = 6.0;
811 f.g = 7.0;
812 f.h = 8.0;
813
814 Object* dummy = CALL_GENERATED_CODE(fn, &d, &f, 0, 0, 0);
815 USE(dummy);
816
817 CHECK_EQ(7.7, d.a);
818 CHECK_EQ(8.8, d.b);
819 CHECK_EQ(1.1, d.c);
820 CHECK_EQ(2.2, d.d);
821 CHECK_EQ(3.3, d.e);
822 CHECK_EQ(4.4, d.f);
823 CHECK_EQ(5.5, d.g);
824 CHECK_EQ(6.6, d.h);
825
826 CHECK_EQ(7.0, f.a);
827 CHECK_EQ(8.0, f.b);
828 CHECK_EQ(1.0, f.c);
829 CHECK_EQ(2.0, f.d);
830 CHECK_EQ(3.0, f.e);
831 CHECK_EQ(4.0, f.f);
832 CHECK_EQ(5.0, f.g);
833 CHECK_EQ(6.0, f.h);
834 }
835 }
836
837
838 TEST(10) {
839 // Test VFP multi load/store with db_w.
840 InitializeVM();
841 v8::HandleScope scope;
842
843 typedef struct {
844 double a;
845 double b;
846 double c;
847 double d;
848 double e;
849 double f;
850 double g;
851 double h;
852 } D;
853 D d;
854
855 typedef struct {
856 float a;
857 float b;
858 float c;
859 float d;
860 float e;
861 float f;
862 float g;
863 float h;
864 } F;
865 F f;
866
867 // Create a function that uses vldm/vstm to move some double and
868 // single precision values around in memory.
869 Assembler assm(Isolate::Current(), NULL, 0);
870
871 if (CpuFeatures::IsSupported(VFP3)) {
872 CpuFeatures::Scope scope(VFP3);
873
874 __ mov(ip, Operand(sp));
875 __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit());
876 __ sub(fp, ip, Operand(4));
877
878 __ add(r4, r0, Operand(OFFSET_OF(D, h) + 8));
879 __ vldm(db_w, r4, d4, d7);
880 __ vldm(db_w, r4, d0, d3);
881
882 __ add(r4, r0, Operand(OFFSET_OF(D, h) + 8));
883 __ vstm(db_w, r4, d0, d5);
884 __ vstm(db_w, r4, d6, d7);
885
886 __ add(r4, r1, Operand(OFFSET_OF(F, h) + 4));
887 __ vldm(db_w, r4, s4, s7);
888 __ vldm(db_w, r4, s0, s3);
889
890 __ add(r4, r1, Operand(OFFSET_OF(F, h) + 4));
891 __ vstm(db_w, r4, s0, s5);
892 __ vstm(db_w, r4, s6, s7);
893
894 __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
895
896 CodeDesc desc;
897 assm.GetCode(&desc);
898 Object* code = HEAP->CreateCode(
899 desc,
900 Code::ComputeFlags(Code::STUB),
901 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
902 CHECK(code->IsCode());
903 #ifdef DEBUG
904 Code::cast(code)->Print();
905 #endif
906 F4 fn = FUNCTION_CAST<F4>(Code::cast(code)->entry());
907 d.a = 1.1;
908 d.b = 2.2;
909 d.c = 3.3;
910 d.d = 4.4;
911 d.e = 5.5;
912 d.f = 6.6;
913 d.g = 7.7;
914 d.h = 8.8;
915
916 f.a = 1.0;
917 f.b = 2.0;
918 f.c = 3.0;
919 f.d = 4.0;
920 f.e = 5.0;
921 f.f = 6.0;
922 f.g = 7.0;
923 f.h = 8.0;
924
925 Object* dummy = CALL_GENERATED_CODE(fn, &d, &f, 0, 0, 0);
926 USE(dummy);
927
928 CHECK_EQ(7.7, d.a);
929 CHECK_EQ(8.8, d.b);
930 CHECK_EQ(1.1, d.c);
931 CHECK_EQ(2.2, d.d);
932 CHECK_EQ(3.3, d.e);
933 CHECK_EQ(4.4, d.f);
934 CHECK_EQ(5.5, d.g);
935 CHECK_EQ(6.6, d.h);
936
937 CHECK_EQ(7.0, f.a);
938 CHECK_EQ(8.0, f.b);
939 CHECK_EQ(1.0, f.c);
940 CHECK_EQ(2.0, f.d);
941 CHECK_EQ(3.0, f.e);
942 CHECK_EQ(4.0, f.f);
943 CHECK_EQ(5.0, f.g);
944 CHECK_EQ(6.0, f.h);
945 }
946 }
947
948
949 TEST(11) {
950 // Test instructions using the carry flag.
951 InitializeVM();
952 v8::HandleScope scope;
953
954 typedef struct {
955 int32_t a;
956 int32_t b;
957 int32_t c;
958 int32_t d;
959 } I;
960 I i;
961
962 i.a = 0xabcd0001;
963 i.b = 0xabcd0000;
964
965 Assembler assm(Isolate::Current(), NULL, 0);
966
967 // Test HeapObject untagging.
968 __ ldr(r1, MemOperand(r0, OFFSET_OF(I, a)));
969 __ mov(r1, Operand(r1, ASR, 1), SetCC);
970 __ adc(r1, r1, Operand(r1), LeaveCC, cs);
971 __ str(r1, MemOperand(r0, OFFSET_OF(I, a)));
972
973 __ ldr(r2, MemOperand(r0, OFFSET_OF(I, b)));
974 __ mov(r2, Operand(r2, ASR, 1), SetCC);
975 __ adc(r2, r2, Operand(r2), LeaveCC, cs);
976 __ str(r2, MemOperand(r0, OFFSET_OF(I, b)));
977
978 // Test corner cases.
979 __ mov(r1, Operand(0xffffffff));
980 __ mov(r2, Operand(0));
981 __ mov(r3, Operand(r1, ASR, 1), SetCC); // Set the carry.
982 __ adc(r3, r1, Operand(r2));
983 __ str(r3, MemOperand(r0, OFFSET_OF(I, c)));
984
985 __ mov(r1, Operand(0xffffffff));
986 __ mov(r2, Operand(0));
987 __ mov(r3, Operand(r2, ASR, 1), SetCC); // Unset the carry.
988 __ adc(r3, r1, Operand(r2));
989 __ str(r3, MemOperand(r0, OFFSET_OF(I, d)));
990
991 __ mov(pc, Operand(lr));
992
993 CodeDesc desc;
994 assm.GetCode(&desc);
995 Object* code = HEAP->CreateCode(
996 desc,
997 Code::ComputeFlags(Code::STUB),
998 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
999 CHECK(code->IsCode());
1000 #ifdef DEBUG
1001 Code::cast(code)->Print();
1002 #endif
1003 F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
1004 Object* dummy = CALL_GENERATED_CODE(f, &i, 0, 0, 0, 0);
1005 USE(dummy);
1006
1007 CHECK_EQ(0xabcd0001, i.a);
1008 CHECK_EQ(static_cast<int32_t>(0xabcd0000) >> 1, i.b);
1009 CHECK_EQ(0x00000000, i.c);
1010 CHECK_EQ(0xffffffff, i.d);
1011 }
1012
1013
1014 TEST(12) {
1015 // Test chaining of label usages within instructions (issue 1644).
1016 InitializeVM();
1017 v8::HandleScope scope;
1018 Assembler assm(Isolate::Current(), NULL, 0);
1019
1020 Label target;
1021 __ b(eq, &target);
1022 __ b(ne, &target);
1023 __ bind(&target);
1024 __ nop();
1025 }
1026
1027 #undef __
1028