v8  3.14.5(node0.10.28)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
test-assembler-mips.cc
Go to the documentation of this file.
1 // Copyright 2012 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 "macro-assembler.h"
34 #include "mips/simulator-mips.h"
35 
36 #include "cctest.h"
37 
38 using namespace v8::internal;
39 
40 
41 // Define these function prototypes to match JSEntryFunction in execution.cc.
42 typedef Object* (*F1)(int x, int p1, int p2, int p3, int p4);
43 typedef Object* (*F2)(int x, int y, int p2, int p3, int p4);
44 typedef Object* (*F3)(void* p, int p1, int p2, int p3, int p4);
45 
46 
48 
49 
50 static void InitializeVM() {
51  // Disable compilation of natives.
52  FLAG_disable_native_files = true;
53 
54  if (env.IsEmpty()) {
55  env = v8::Context::New();
56  }
57 }
58 
59 
60 #define __ assm.
61 
62 
63 TEST(MIPS0) {
64  InitializeVM();
65  v8::HandleScope scope;
66 
67  MacroAssembler assm(Isolate::Current(), NULL, 0);
68 
69  // Addition.
70  __ addu(v0, a0, a1);
71  __ jr(ra);
72  __ nop();
73 
74  CodeDesc desc;
75  assm.GetCode(&desc);
76  Object* code = HEAP->CreateCode(
77  desc,
78  Code::ComputeFlags(Code::STUB),
79  Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
80  CHECK(code->IsCode());
81  F2 f = FUNCTION_CAST<F2>(Code::cast(code)->entry());
82  int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 0xab0, 0xc, 0, 0, 0));
83  ::printf("f() = %d\n", res);
84  CHECK_EQ(0xabc, res);
85 }
86 
87 
88 TEST(MIPS1) {
89  InitializeVM();
90  v8::HandleScope scope;
91 
92  MacroAssembler assm(Isolate::Current(), NULL, 0);
93  Label L, C;
94 
95  __ mov(a1, a0);
96  __ li(v0, 0);
97  __ b(&C);
98  __ nop();
99 
100  __ bind(&L);
101  __ addu(v0, v0, a1);
102  __ addiu(a1, a1, -1);
103 
104  __ bind(&C);
105  __ xori(v1, a1, 0);
106  __ Branch(&L, ne, v1, Operand(0));
107  __ nop();
108 
109  __ jr(ra);
110  __ nop();
111 
112  CodeDesc desc;
113  assm.GetCode(&desc);
114  Object* code = HEAP->CreateCode(
115  desc,
116  Code::ComputeFlags(Code::STUB),
117  Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
118  CHECK(code->IsCode());
119  F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry());
120  int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 50, 0, 0, 0, 0));
121  ::printf("f() = %d\n", res);
122  CHECK_EQ(1275, res);
123 }
124 
125 
126 TEST(MIPS2) {
127  InitializeVM();
128  v8::HandleScope scope;
129 
130  MacroAssembler assm(Isolate::Current(), NULL, 0);
131 
132  Label exit, error;
133 
134  // ----- Test all instructions.
135 
136  // Test lui, ori, and addiu, used in the li pseudo-instruction.
137  // This way we can then safely load registers with chosen values.
138 
139  __ ori(t0, zero_reg, 0);
140  __ lui(t0, 0x1234);
141  __ ori(t0, t0, 0);
142  __ ori(t0, t0, 0x0f0f);
143  __ ori(t0, t0, 0xf0f0);
144  __ addiu(t1, t0, 1);
145  __ addiu(t2, t1, -0x10);
146 
147  // Load values in temporary registers.
148  __ li(t0, 0x00000004);
149  __ li(t1, 0x00001234);
150  __ li(t2, 0x12345678);
151  __ li(t3, 0x7fffffff);
152  __ li(t4, 0xfffffffc);
153  __ li(t5, 0xffffedcc);
154  __ li(t6, 0xedcba988);
155  __ li(t7, 0x80000000);
156 
157  // SPECIAL class.
158  __ srl(v0, t2, 8); // 0x00123456
159  __ sll(v0, v0, 11); // 0x91a2b000
160  __ sra(v0, v0, 3); // 0xf2345600
161  __ srav(v0, v0, t0); // 0xff234560
162  __ sllv(v0, v0, t0); // 0xf2345600
163  __ srlv(v0, v0, t0); // 0x0f234560
164  __ Branch(&error, ne, v0, Operand(0x0f234560));
165  __ nop();
166 
167  __ addu(v0, t0, t1); // 0x00001238
168  __ subu(v0, v0, t0); // 0x00001234
169  __ Branch(&error, ne, v0, Operand(0x00001234));
170  __ nop();
171  __ addu(v1, t3, t0);
172  __ Branch(&error, ne, v1, Operand(0x80000003));
173  __ nop();
174  __ subu(v1, t7, t0); // 0x7ffffffc
175  __ Branch(&error, ne, v1, Operand(0x7ffffffc));
176  __ nop();
177 
178  __ and_(v0, t1, t2); // 0x00001230
179  __ or_(v0, v0, t1); // 0x00001234
180  __ xor_(v0, v0, t2); // 0x1234444c
181  __ nor(v0, v0, t2); // 0xedcba987
182  __ Branch(&error, ne, v0, Operand(0xedcba983));
183  __ nop();
184 
185  __ slt(v0, t7, t3);
186  __ Branch(&error, ne, v0, Operand(0x1));
187  __ nop();
188  __ sltu(v0, t7, t3);
189  __ Branch(&error, ne, v0, Operand(0x0));
190  __ nop();
191  // End of SPECIAL class.
192 
193  __ addiu(v0, zero_reg, 0x7421); // 0x00007421
194  __ addiu(v0, v0, -0x1); // 0x00007420
195  __ addiu(v0, v0, -0x20); // 0x00007400
196  __ Branch(&error, ne, v0, Operand(0x00007400));
197  __ nop();
198  __ addiu(v1, t3, 0x1); // 0x80000000
199  __ Branch(&error, ne, v1, Operand(0x80000000));
200  __ nop();
201 
202  __ slti(v0, t1, 0x00002000); // 0x1
203  __ slti(v0, v0, 0xffff8000); // 0x0
204  __ Branch(&error, ne, v0, Operand(0x0));
205  __ nop();
206  __ sltiu(v0, t1, 0x00002000); // 0x1
207  __ sltiu(v0, v0, 0x00008000); // 0x1
208  __ Branch(&error, ne, v0, Operand(0x1));
209  __ nop();
210 
211  __ andi(v0, t1, 0xf0f0); // 0x00001030
212  __ ori(v0, v0, 0x8a00); // 0x00009a30
213  __ xori(v0, v0, 0x83cc); // 0x000019fc
214  __ Branch(&error, ne, v0, Operand(0x000019fc));
215  __ nop();
216  __ lui(v1, 0x8123); // 0x81230000
217  __ Branch(&error, ne, v1, Operand(0x81230000));
218  __ nop();
219 
220  // Bit twiddling instructions & conditional moves.
221  // Uses t0-t7 as set above.
222  __ Clz(v0, t0); // 29
223  __ Clz(v1, t1); // 19
224  __ addu(v0, v0, v1); // 48
225  __ Clz(v1, t2); // 3
226  __ addu(v0, v0, v1); // 51
227  __ Clz(v1, t7); // 0
228  __ addu(v0, v0, v1); // 51
229  __ Branch(&error, ne, v0, Operand(51));
230  __ Movn(a0, t3, t0); // Move a0<-t3 (t0 is NOT 0).
231  __ Ins(a0, t1, 12, 8); // 0x7ff34fff
232  __ Branch(&error, ne, a0, Operand(0x7ff34fff));
233  __ Movz(a0, t6, t7); // a0 not updated (t7 is NOT 0).
234  __ Ext(a1, a0, 8, 12); // 0x34f
235  __ Branch(&error, ne, a1, Operand(0x34f));
236  __ Movz(a0, t6, v1); // a0<-t6, v0 is 0, from 8 instr back.
237  __ Branch(&error, ne, a0, Operand(t6));
238 
239  // Everything was correctly executed. Load the expected result.
240  __ li(v0, 0x31415926);
241  __ b(&exit);
242  __ nop();
243 
244  __ bind(&error);
245  // Got an error. Return a wrong result.
246  __ li(v0, 666);
247 
248  __ bind(&exit);
249  __ jr(ra);
250  __ nop();
251 
252  CodeDesc desc;
253  assm.GetCode(&desc);
254  Object* code = HEAP->CreateCode(
255  desc,
256  Code::ComputeFlags(Code::STUB),
257  Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
258  CHECK(code->IsCode());
259  F2 f = FUNCTION_CAST<F2>(Code::cast(code)->entry());
260  int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 0xab0, 0xc, 0, 0, 0));
261  ::printf("f() = %d\n", res);
262  CHECK_EQ(0x31415926, res);
263 }
264 
265 
266 TEST(MIPS3) {
267  // Test floating point instructions.
268  InitializeVM();
269  v8::HandleScope scope;
270 
271  typedef struct {
272  double a;
273  double b;
274  double c;
275  double d;
276  double e;
277  double f;
278  double g;
279  } T;
280  T t;
281 
282  // Create a function that accepts &t, and loads, manipulates, and stores
283  // the doubles t.a ... t.f.
284  MacroAssembler assm(Isolate::Current(), NULL, 0);
285  Label L, C;
286 
288  CpuFeatures::Scope scope(FPU);
289 
290  __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
291  __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
292  __ add_d(f8, f4, f6);
293  __ sdc1(f8, MemOperand(a0, OFFSET_OF(T, c)) ); // c = a + b.
294 
295  __ mov_d(f10, f8); // c
296  __ neg_d(f12, f6); // -b
297  __ sub_d(f10, f10, f12);
298  __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, d)) ); // d = c - (-b).
299 
300  __ sdc1(f4, MemOperand(a0, OFFSET_OF(T, b)) ); // b = a.
301 
302  __ li(t0, 120);
303  __ mtc1(t0, f14);
304  __ cvt_d_w(f14, f14); // f14 = 120.0.
305  __ mul_d(f10, f10, f14);
306  __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, e)) ); // e = d * 120 = 1.8066e16.
307 
308  __ div_d(f12, f10, f4);
309  __ sdc1(f12, MemOperand(a0, OFFSET_OF(T, f)) ); // f = e / a = 120.44.
310 
311  __ sqrt_d(f14, f12);
312  __ sdc1(f14, MemOperand(a0, OFFSET_OF(T, g)) );
313  // g = sqrt(f) = 10.97451593465515908537
314 
315  __ jr(ra);
316  __ nop();
317 
318  CodeDesc desc;
319  assm.GetCode(&desc);
320  Object* code = HEAP->CreateCode(
321  desc,
322  Code::ComputeFlags(Code::STUB),
323  Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
324  CHECK(code->IsCode());
325  F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
326  t.a = 1.5e14;
327  t.b = 2.75e11;
328  t.c = 0.0;
329  t.d = 0.0;
330  t.e = 0.0;
331  t.f = 0.0;
332  Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
333  USE(dummy);
334  CHECK_EQ(1.5e14, t.a);
335  CHECK_EQ(1.5e14, t.b);
336  CHECK_EQ(1.50275e14, t.c);
337  CHECK_EQ(1.50550e14, t.d);
338  CHECK_EQ(1.8066e16, t.e);
339  CHECK_EQ(120.44, t.f);
340  CHECK_EQ(10.97451593465515908537, t.g);
341  }
342 }
343 
344 
345 TEST(MIPS4) {
346  // Test moves between floating point and integer registers.
347  InitializeVM();
348  v8::HandleScope scope;
349 
350  typedef struct {
351  double a;
352  double b;
353  double c;
354  } T;
355  T t;
356 
357  Assembler assm(Isolate::Current(), NULL, 0);
358  Label L, C;
359 
361  CpuFeatures::Scope scope(FPU);
362 
363  __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
364  __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
365 
366  // Swap f4 and f6, by using four integer registers, t0-t3.
367  __ mfc1(t0, f4);
368  __ mfc1(t1, f5);
369  __ mfc1(t2, f6);
370  __ mfc1(t3, f7);
371 
372  __ mtc1(t0, f6);
373  __ mtc1(t1, f7);
374  __ mtc1(t2, f4);
375  __ mtc1(t3, f5);
376 
377  // Store the swapped f4 and f5 back to memory.
378  __ sdc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
379  __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, c)) );
380 
381  __ jr(ra);
382  __ nop();
383 
384  CodeDesc desc;
385  assm.GetCode(&desc);
386  Object* code = HEAP->CreateCode(
387  desc,
388  Code::ComputeFlags(Code::STUB),
389  Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
390  CHECK(code->IsCode());
391  F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
392  t.a = 1.5e22;
393  t.b = 2.75e11;
394  t.c = 17.17;
395  Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
396  USE(dummy);
397 
398  CHECK_EQ(2.75e11, t.a);
399  CHECK_EQ(2.75e11, t.b);
400  CHECK_EQ(1.5e22, t.c);
401  }
402 }
403 
404 
405 TEST(MIPS5) {
406  // Test conversions between doubles and integers.
407  InitializeVM();
408  v8::HandleScope scope;
409 
410  typedef struct {
411  double a;
412  double b;
413  int i;
414  int j;
415  } T;
416  T t;
417 
418  Assembler assm(Isolate::Current(), NULL, 0);
419  Label L, C;
420 
422  CpuFeatures::Scope scope(FPU);
423 
424  // Load all structure elements to registers.
425  __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
426  __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
427  __ lw(t0, MemOperand(a0, OFFSET_OF(T, i)) );
428  __ lw(t1, MemOperand(a0, OFFSET_OF(T, j)) );
429 
430  // Convert double in f4 to int in element i.
431  __ cvt_w_d(f8, f4);
432  __ mfc1(t2, f8);
433  __ sw(t2, MemOperand(a0, OFFSET_OF(T, i)) );
434 
435  // Convert double in f6 to int in element j.
436  __ cvt_w_d(f10, f6);
437  __ mfc1(t3, f10);
438  __ sw(t3, MemOperand(a0, OFFSET_OF(T, j)) );
439 
440  // Convert int in original i (t0) to double in a.
441  __ mtc1(t0, f12);
442  __ cvt_d_w(f0, f12);
443  __ sdc1(f0, MemOperand(a0, OFFSET_OF(T, a)) );
444 
445  // Convert int in original j (t1) to double in b.
446  __ mtc1(t1, f14);
447  __ cvt_d_w(f2, f14);
448  __ sdc1(f2, MemOperand(a0, OFFSET_OF(T, b)) );
449 
450  __ jr(ra);
451  __ nop();
452 
453  CodeDesc desc;
454  assm.GetCode(&desc);
455  Object* code = HEAP->CreateCode(
456  desc,
457  Code::ComputeFlags(Code::STUB),
458  Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
459  CHECK(code->IsCode());
460  F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
461  t.a = 1.5e4;
462  t.b = 2.75e8;
463  t.i = 12345678;
464  t.j = -100000;
465  Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
466  USE(dummy);
467 
468  CHECK_EQ(12345678.0, t.a);
469  CHECK_EQ(-100000.0, t.b);
470  CHECK_EQ(15000, t.i);
471  CHECK_EQ(275000000, t.j);
472  }
473 }
474 
475 
476 TEST(MIPS6) {
477  // Test simple memory loads and stores.
478  InitializeVM();
479  v8::HandleScope scope;
480 
481  typedef struct {
482  uint32_t ui;
483  int32_t si;
484  int32_t r1;
485  int32_t r2;
486  int32_t r3;
487  int32_t r4;
488  int32_t r5;
489  int32_t r6;
490  } T;
491  T t;
492 
493  Assembler assm(Isolate::Current(), NULL, 0);
494  Label L, C;
495 
496  // Basic word load/store.
497  __ lw(t0, MemOperand(a0, OFFSET_OF(T, ui)) );
498  __ sw(t0, MemOperand(a0, OFFSET_OF(T, r1)) );
499 
500  // lh with positive data.
501  __ lh(t1, MemOperand(a0, OFFSET_OF(T, ui)) );
502  __ sw(t1, MemOperand(a0, OFFSET_OF(T, r2)) );
503 
504  // lh with negative data.
505  __ lh(t2, MemOperand(a0, OFFSET_OF(T, si)) );
506  __ sw(t2, MemOperand(a0, OFFSET_OF(T, r3)) );
507 
508  // lhu with negative data.
509  __ lhu(t3, MemOperand(a0, OFFSET_OF(T, si)) );
510  __ sw(t3, MemOperand(a0, OFFSET_OF(T, r4)) );
511 
512  // lb with negative data.
513  __ lb(t4, MemOperand(a0, OFFSET_OF(T, si)) );
514  __ sw(t4, MemOperand(a0, OFFSET_OF(T, r5)) );
515 
516  // sh writes only 1/2 of word.
517  __ lui(t5, 0x3333);
518  __ ori(t5, t5, 0x3333);
519  __ sw(t5, MemOperand(a0, OFFSET_OF(T, r6)) );
520  __ lhu(t5, MemOperand(a0, OFFSET_OF(T, si)) );
521  __ sh(t5, MemOperand(a0, OFFSET_OF(T, r6)) );
522 
523  __ jr(ra);
524  __ nop();
525 
526  CodeDesc desc;
527  assm.GetCode(&desc);
528  Object* code = HEAP->CreateCode(
529  desc,
530  Code::ComputeFlags(Code::STUB),
531  Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
532  CHECK(code->IsCode());
533  F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
534  t.ui = 0x11223344;
535  t.si = 0x99aabbcc;
536  Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
537  USE(dummy);
538 
539  CHECK_EQ(0x11223344, t.r1);
540  CHECK_EQ(0x3344, t.r2);
541  CHECK_EQ(0xffffbbcc, t.r3);
542  CHECK_EQ(0x0000bbcc, t.r4);
543  CHECK_EQ(0xffffffcc, t.r5);
544  CHECK_EQ(0x3333bbcc, t.r6);
545 }
546 
547 
548 TEST(MIPS7) {
549  // Test floating point compare and branch instructions.
550  InitializeVM();
551  v8::HandleScope scope;
552 
553  typedef struct {
554  double a;
555  double b;
556  double c;
557  double d;
558  double e;
559  double f;
560  int32_t result;
561  } T;
562  T t;
563 
564  // Create a function that accepts &t, and loads, manipulates, and stores
565  // the doubles t.a ... t.f.
566  MacroAssembler assm(Isolate::Current(), NULL, 0);
567  Label neither_is_nan, less_than, outa_here;
568 
570  CpuFeatures::Scope scope(FPU);
571 
572  __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
573  __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
574  __ c(UN, D, f4, f6);
575  __ bc1f(&neither_is_nan);
576  __ nop();
577  __ sw(zero_reg, MemOperand(a0, OFFSET_OF(T, result)) );
578  __ Branch(&outa_here);
579 
580  __ bind(&neither_is_nan);
581 
582  if (kArchVariant == kLoongson) {
583  __ c(OLT, D, f6, f4);
584  __ bc1t(&less_than);
585  } else {
586  __ c(OLT, D, f6, f4, 2);
587  __ bc1t(&less_than, 2);
588  }
589  __ nop();
590  __ sw(zero_reg, MemOperand(a0, OFFSET_OF(T, result)) );
591  __ Branch(&outa_here);
592 
593  __ bind(&less_than);
594  __ Addu(t0, zero_reg, Operand(1));
595  __ sw(t0, MemOperand(a0, OFFSET_OF(T, result)) ); // Set true.
596 
597 
598  // This test-case should have additional tests.
599 
600  __ bind(&outa_here);
601 
602  __ jr(ra);
603  __ nop();
604 
605  CodeDesc desc;
606  assm.GetCode(&desc);
607  Object* code = HEAP->CreateCode(
608  desc,
609  Code::ComputeFlags(Code::STUB),
610  Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
611  CHECK(code->IsCode());
612  F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
613  t.a = 1.5e14;
614  t.b = 2.75e11;
615  t.c = 2.0;
616  t.d = -4.0;
617  t.e = 0.0;
618  t.f = 0.0;
619  t.result = 0;
620  Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
621  USE(dummy);
622  CHECK_EQ(1.5e14, t.a);
623  CHECK_EQ(2.75e11, t.b);
624  CHECK_EQ(1, t.result);
625  }
626 }
627 
628 
629 TEST(MIPS8) {
630  // Test ROTR and ROTRV instructions.
631  InitializeVM();
632  v8::HandleScope scope;
633 
634  typedef struct {
635  int32_t input;
636  int32_t result_rotr_4;
637  int32_t result_rotr_8;
638  int32_t result_rotr_12;
639  int32_t result_rotr_16;
640  int32_t result_rotr_20;
641  int32_t result_rotr_24;
642  int32_t result_rotr_28;
643  int32_t result_rotrv_4;
644  int32_t result_rotrv_8;
645  int32_t result_rotrv_12;
646  int32_t result_rotrv_16;
647  int32_t result_rotrv_20;
648  int32_t result_rotrv_24;
649  int32_t result_rotrv_28;
650  } T;
651  T t;
652 
653  MacroAssembler assm(Isolate::Current(), NULL, 0);
654 
655  // Basic word load.
656  __ lw(t0, MemOperand(a0, OFFSET_OF(T, input)) );
657 
658  // ROTR instruction (called through the Ror macro).
659  __ Ror(t1, t0, 0x0004);
660  __ Ror(t2, t0, 0x0008);
661  __ Ror(t3, t0, 0x000c);
662  __ Ror(t4, t0, 0x0010);
663  __ Ror(t5, t0, 0x0014);
664  __ Ror(t6, t0, 0x0018);
665  __ Ror(t7, t0, 0x001c);
666 
667  // Basic word store.
668  __ sw(t1, MemOperand(a0, OFFSET_OF(T, result_rotr_4)) );
669  __ sw(t2, MemOperand(a0, OFFSET_OF(T, result_rotr_8)) );
670  __ sw(t3, MemOperand(a0, OFFSET_OF(T, result_rotr_12)) );
671  __ sw(t4, MemOperand(a0, OFFSET_OF(T, result_rotr_16)) );
672  __ sw(t5, MemOperand(a0, OFFSET_OF(T, result_rotr_20)) );
673  __ sw(t6, MemOperand(a0, OFFSET_OF(T, result_rotr_24)) );
674  __ sw(t7, MemOperand(a0, OFFSET_OF(T, result_rotr_28)) );
675 
676  // ROTRV instruction (called through the Ror macro).
677  __ li(t7, 0x0004);
678  __ Ror(t1, t0, t7);
679  __ li(t7, 0x0008);
680  __ Ror(t2, t0, t7);
681  __ li(t7, 0x000C);
682  __ Ror(t3, t0, t7);
683  __ li(t7, 0x0010);
684  __ Ror(t4, t0, t7);
685  __ li(t7, 0x0014);
686  __ Ror(t5, t0, t7);
687  __ li(t7, 0x0018);
688  __ Ror(t6, t0, t7);
689  __ li(t7, 0x001C);
690  __ Ror(t7, t0, t7);
691 
692  // Basic word store.
693  __ sw(t1, MemOperand(a0, OFFSET_OF(T, result_rotrv_4)) );
694  __ sw(t2, MemOperand(a0, OFFSET_OF(T, result_rotrv_8)) );
695  __ sw(t3, MemOperand(a0, OFFSET_OF(T, result_rotrv_12)) );
696  __ sw(t4, MemOperand(a0, OFFSET_OF(T, result_rotrv_16)) );
697  __ sw(t5, MemOperand(a0, OFFSET_OF(T, result_rotrv_20)) );
698  __ sw(t6, MemOperand(a0, OFFSET_OF(T, result_rotrv_24)) );
699  __ sw(t7, MemOperand(a0, OFFSET_OF(T, result_rotrv_28)) );
700 
701  __ jr(ra);
702  __ nop();
703 
704  CodeDesc desc;
705  assm.GetCode(&desc);
706  Object* code = HEAP->CreateCode(
707  desc,
708  Code::ComputeFlags(Code::STUB),
709  Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
710  CHECK(code->IsCode());
711  F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
712  t.input = 0x12345678;
713  Object* dummy = CALL_GENERATED_CODE(f, &t, 0x0, 0, 0, 0);
714  USE(dummy);
715  CHECK_EQ(0x81234567, t.result_rotr_4);
716  CHECK_EQ(0x78123456, t.result_rotr_8);
717  CHECK_EQ(0x67812345, t.result_rotr_12);
718  CHECK_EQ(0x56781234, t.result_rotr_16);
719  CHECK_EQ(0x45678123, t.result_rotr_20);
720  CHECK_EQ(0x34567812, t.result_rotr_24);
721  CHECK_EQ(0x23456781, t.result_rotr_28);
722 
723  CHECK_EQ(0x81234567, t.result_rotrv_4);
724  CHECK_EQ(0x78123456, t.result_rotrv_8);
725  CHECK_EQ(0x67812345, t.result_rotrv_12);
726  CHECK_EQ(0x56781234, t.result_rotrv_16);
727  CHECK_EQ(0x45678123, t.result_rotrv_20);
728  CHECK_EQ(0x34567812, t.result_rotrv_24);
729  CHECK_EQ(0x23456781, t.result_rotrv_28);
730 }
731 
732 
733 TEST(MIPS9) {
734  // Test BRANCH improvements.
735  InitializeVM();
736  v8::HandleScope scope;
737 
738  MacroAssembler assm(Isolate::Current(), NULL, 0);
739  Label exit, exit2, exit3;
740 
741  __ Branch(&exit, ge, a0, Operand(0x00000000));
742  __ Branch(&exit2, ge, a0, Operand(0x00001FFF));
743  __ Branch(&exit3, ge, a0, Operand(0x0001FFFF));
744 
745  __ bind(&exit);
746  __ bind(&exit2);
747  __ bind(&exit3);
748  __ jr(ra);
749  __ nop();
750 
751  CodeDesc desc;
752  assm.GetCode(&desc);
753  Object* code = HEAP->CreateCode(
754  desc,
755  Code::ComputeFlags(Code::STUB),
756  Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
757  CHECK(code->IsCode());
758 }
759 
760 
761 TEST(MIPS10) {
762  // Test conversions between doubles and long integers.
763  // Test hos the long ints map to FP regs pairs.
764  InitializeVM();
765  v8::HandleScope scope;
766 
767  typedef struct {
768  double a;
769  double b;
770  int32_t dbl_mant;
771  int32_t dbl_exp;
772  int32_t long_hi;
773  int32_t long_lo;
774  int32_t b_long_hi;
775  int32_t b_long_lo;
776  } T;
777  T t;
778 
779  Assembler assm(Isolate::Current(), NULL, 0);
780  Label L, C;
781 
782  if (CpuFeatures::IsSupported(FPU) && kArchVariant == kMips32r2) {
783  CpuFeatures::Scope scope(FPU);
784 
785  // Load all structure elements to registers.
786  __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, a)));
787 
788  // Save the raw bits of the double.
789  __ mfc1(t0, f0);
790  __ mfc1(t1, f1);
791  __ sw(t0, MemOperand(a0, OFFSET_OF(T, dbl_mant)));
792  __ sw(t1, MemOperand(a0, OFFSET_OF(T, dbl_exp)));
793 
794  // Convert double in f0 to long, save hi/lo parts.
795  __ cvt_l_d(f0, f0);
796  __ mfc1(t0, f0); // f0 has LS 32 bits of long.
797  __ mfc1(t1, f1); // f1 has MS 32 bits of long.
798  __ sw(t0, MemOperand(a0, OFFSET_OF(T, long_lo)));
799  __ sw(t1, MemOperand(a0, OFFSET_OF(T, long_hi)));
800 
801  // Convert the b long integers to double b.
802  __ lw(t0, MemOperand(a0, OFFSET_OF(T, b_long_lo)));
803  __ lw(t1, MemOperand(a0, OFFSET_OF(T, b_long_hi)));
804  __ mtc1(t0, f8); // f8 has LS 32-bits.
805  __ mtc1(t1, f9); // f9 has MS 32-bits.
806  __ cvt_d_l(f10, f8);
807  __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, b)));
808 
809  __ jr(ra);
810  __ nop();
811 
812  CodeDesc desc;
813  assm.GetCode(&desc);
814  Object* code = HEAP->CreateCode(
815  desc,
816  Code::ComputeFlags(Code::STUB),
817  Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
818  CHECK(code->IsCode());
819  F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
820  t.a = 2.147483647e9; // 0x7fffffff -> 0x41DFFFFFFFC00000 as double.
821  t.b_long_hi = 0x000000ff; // 0xFF00FF00FF -> 0x426FE01FE01FE000 as double.
822  t.b_long_lo = 0x00ff00ff;
823  Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
824  USE(dummy);
825 
826  CHECK_EQ(0x41DFFFFF, t.dbl_exp);
827  CHECK_EQ(0xFFC00000, t.dbl_mant);
828  CHECK_EQ(0, t.long_hi);
829  CHECK_EQ(0x7fffffff, t.long_lo);
830  // 0xFF00FF00FF -> 1.095233372415e12.
831  CHECK_EQ(1.095233372415e12, t.b);
832  }
833 }
834 
835 
836 TEST(MIPS11) {
837  // Test LWL, LWR, SWL and SWR instructions.
838  InitializeVM();
839  v8::HandleScope scope;
840 
841  typedef struct {
842  int32_t reg_init;
843  int32_t mem_init;
844  int32_t lwl_0;
845  int32_t lwl_1;
846  int32_t lwl_2;
847  int32_t lwl_3;
848  int32_t lwr_0;
849  int32_t lwr_1;
850  int32_t lwr_2;
851  int32_t lwr_3;
852  int32_t swl_0;
853  int32_t swl_1;
854  int32_t swl_2;
855  int32_t swl_3;
856  int32_t swr_0;
857  int32_t swr_1;
858  int32_t swr_2;
859  int32_t swr_3;
860  } T;
861  T t;
862 
863  Assembler assm(Isolate::Current(), NULL, 0);
864 
865  // Test all combinations of LWL and vAddr.
866  __ lw(t0, MemOperand(a0, OFFSET_OF(T, reg_init)) );
867  __ lwl(t0, MemOperand(a0, OFFSET_OF(T, mem_init)) );
868  __ sw(t0, MemOperand(a0, OFFSET_OF(T, lwl_0)) );
869 
870  __ lw(t1, MemOperand(a0, OFFSET_OF(T, reg_init)) );
871  __ lwl(t1, MemOperand(a0, OFFSET_OF(T, mem_init) + 1) );
872  __ sw(t1, MemOperand(a0, OFFSET_OF(T, lwl_1)) );
873 
874  __ lw(t2, MemOperand(a0, OFFSET_OF(T, reg_init)) );
875  __ lwl(t2, MemOperand(a0, OFFSET_OF(T, mem_init) + 2) );
876  __ sw(t2, MemOperand(a0, OFFSET_OF(T, lwl_2)) );
877 
878  __ lw(t3, MemOperand(a0, OFFSET_OF(T, reg_init)) );
879  __ lwl(t3, MemOperand(a0, OFFSET_OF(T, mem_init) + 3) );
880  __ sw(t3, MemOperand(a0, OFFSET_OF(T, lwl_3)) );
881 
882  // Test all combinations of LWR and vAddr.
883  __ lw(t0, MemOperand(a0, OFFSET_OF(T, reg_init)) );
884  __ lwr(t0, MemOperand(a0, OFFSET_OF(T, mem_init)) );
885  __ sw(t0, MemOperand(a0, OFFSET_OF(T, lwr_0)) );
886 
887  __ lw(t1, MemOperand(a0, OFFSET_OF(T, reg_init)) );
888  __ lwr(t1, MemOperand(a0, OFFSET_OF(T, mem_init) + 1) );
889  __ sw(t1, MemOperand(a0, OFFSET_OF(T, lwr_1)) );
890 
891  __ lw(t2, MemOperand(a0, OFFSET_OF(T, reg_init)) );
892  __ lwr(t2, MemOperand(a0, OFFSET_OF(T, mem_init) + 2) );
893  __ sw(t2, MemOperand(a0, OFFSET_OF(T, lwr_2)) );
894 
895  __ lw(t3, MemOperand(a0, OFFSET_OF(T, reg_init)) );
896  __ lwr(t3, MemOperand(a0, OFFSET_OF(T, mem_init) + 3) );
897  __ sw(t3, MemOperand(a0, OFFSET_OF(T, lwr_3)) );
898 
899  // Test all combinations of SWL and vAddr.
900  __ lw(t0, MemOperand(a0, OFFSET_OF(T, mem_init)) );
901  __ sw(t0, MemOperand(a0, OFFSET_OF(T, swl_0)) );
902  __ lw(t0, MemOperand(a0, OFFSET_OF(T, reg_init)) );
903  __ swl(t0, MemOperand(a0, OFFSET_OF(T, swl_0)) );
904 
905  __ lw(t1, MemOperand(a0, OFFSET_OF(T, mem_init)) );
906  __ sw(t1, MemOperand(a0, OFFSET_OF(T, swl_1)) );
907  __ lw(t1, MemOperand(a0, OFFSET_OF(T, reg_init)) );
908  __ swl(t1, MemOperand(a0, OFFSET_OF(T, swl_1) + 1) );
909 
910  __ lw(t2, MemOperand(a0, OFFSET_OF(T, mem_init)) );
911  __ sw(t2, MemOperand(a0, OFFSET_OF(T, swl_2)) );
912  __ lw(t2, MemOperand(a0, OFFSET_OF(T, reg_init)) );
913  __ swl(t2, MemOperand(a0, OFFSET_OF(T, swl_2) + 2) );
914 
915  __ lw(t3, MemOperand(a0, OFFSET_OF(T, mem_init)) );
916  __ sw(t3, MemOperand(a0, OFFSET_OF(T, swl_3)) );
917  __ lw(t3, MemOperand(a0, OFFSET_OF(T, reg_init)) );
918  __ swl(t3, MemOperand(a0, OFFSET_OF(T, swl_3) + 3) );
919 
920  // Test all combinations of SWR and vAddr.
921  __ lw(t0, MemOperand(a0, OFFSET_OF(T, mem_init)) );
922  __ sw(t0, MemOperand(a0, OFFSET_OF(T, swr_0)) );
923  __ lw(t0, MemOperand(a0, OFFSET_OF(T, reg_init)) );
924  __ swr(t0, MemOperand(a0, OFFSET_OF(T, swr_0)) );
925 
926  __ lw(t1, MemOperand(a0, OFFSET_OF(T, mem_init)) );
927  __ sw(t1, MemOperand(a0, OFFSET_OF(T, swr_1)) );
928  __ lw(t1, MemOperand(a0, OFFSET_OF(T, reg_init)) );
929  __ swr(t1, MemOperand(a0, OFFSET_OF(T, swr_1) + 1) );
930 
931  __ lw(t2, MemOperand(a0, OFFSET_OF(T, mem_init)) );
932  __ sw(t2, MemOperand(a0, OFFSET_OF(T, swr_2)) );
933  __ lw(t2, MemOperand(a0, OFFSET_OF(T, reg_init)) );
934  __ swr(t2, MemOperand(a0, OFFSET_OF(T, swr_2) + 2) );
935 
936  __ lw(t3, MemOperand(a0, OFFSET_OF(T, mem_init)) );
937  __ sw(t3, MemOperand(a0, OFFSET_OF(T, swr_3)) );
938  __ lw(t3, MemOperand(a0, OFFSET_OF(T, reg_init)) );
939  __ swr(t3, MemOperand(a0, OFFSET_OF(T, swr_3) + 3) );
940 
941  __ jr(ra);
942  __ nop();
943 
944  CodeDesc desc;
945  assm.GetCode(&desc);
946  Object* code = HEAP->CreateCode(
947  desc,
948  Code::ComputeFlags(Code::STUB),
949  Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
950  CHECK(code->IsCode());
951  F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
952  t.reg_init = 0xaabbccdd;
953  t.mem_init = 0x11223344;
954 
955  Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
956  USE(dummy);
957 
958  CHECK_EQ(0x44bbccdd, t.lwl_0);
959  CHECK_EQ(0x3344ccdd, t.lwl_1);
960  CHECK_EQ(0x223344dd, t.lwl_2);
961  CHECK_EQ(0x11223344, t.lwl_3);
962 
963  CHECK_EQ(0x11223344, t.lwr_0);
964  CHECK_EQ(0xaa112233, t.lwr_1);
965  CHECK_EQ(0xaabb1122, t.lwr_2);
966  CHECK_EQ(0xaabbcc11, t.lwr_3);
967 
968  CHECK_EQ(0x112233aa, t.swl_0);
969  CHECK_EQ(0x1122aabb, t.swl_1);
970  CHECK_EQ(0x11aabbcc, t.swl_2);
971  CHECK_EQ(0xaabbccdd, t.swl_3);
972 
973  CHECK_EQ(0xaabbccdd, t.swr_0);
974  CHECK_EQ(0xbbccdd44, t.swr_1);
975  CHECK_EQ(0xccdd3344, t.swr_2);
976  CHECK_EQ(0xdd223344, t.swr_3);
977 }
978 
979 
980 TEST(MIPS12) {
981  InitializeVM();
982  v8::HandleScope scope;
983 
984  typedef struct {
985  int32_t x;
986  int32_t y;
987  int32_t y1;
988  int32_t y2;
989  int32_t y3;
990  int32_t y4;
991  } T;
992  T t;
993 
994  MacroAssembler assm(Isolate::Current(), NULL, 0);
995 
996  __ mov(t6, fp); // Save frame pointer.
997  __ mov(fp, a0); // Access struct T by fp.
998  __ lw(t0, MemOperand(a0, OFFSET_OF(T, y)) );
999  __ lw(t3, MemOperand(a0, OFFSET_OF(T, y4)) );
1000 
1001  __ addu(t1, t0, t3);
1002  __ subu(t4, t0, t3);
1003  __ nop();
1004  __ push(t0); // These instructions disappear after opt.
1005  __ Pop();
1006  __ addu(t0, t0, t0);
1007  __ nop();
1008  __ Pop(); // These instructions disappear after opt.
1009  __ push(t3);
1010  __ nop();
1011  __ push(t3); // These instructions disappear after opt.
1012  __ pop(t3);
1013  __ nop();
1014  __ push(t3);
1015  __ pop(t4);
1016  __ nop();
1017  __ sw(t0, MemOperand(fp, OFFSET_OF(T, y)) );
1018  __ lw(t0, MemOperand(fp, OFFSET_OF(T, y)) );
1019  __ nop();
1020  __ sw(t0, MemOperand(fp, OFFSET_OF(T, y)) );
1021  __ lw(t1, MemOperand(fp, OFFSET_OF(T, y)) );
1022  __ nop();
1023  __ push(t1);
1024  __ lw(t1, MemOperand(fp, OFFSET_OF(T, y)) );
1025  __ pop(t1);
1026  __ nop();
1027  __ push(t1);
1028  __ lw(t2, MemOperand(fp, OFFSET_OF(T, y)) );
1029  __ pop(t1);
1030  __ nop();
1031  __ push(t1);
1032  __ lw(t2, MemOperand(fp, OFFSET_OF(T, y)) );
1033  __ pop(t2);
1034  __ nop();
1035  __ push(t2);
1036  __ lw(t2, MemOperand(fp, OFFSET_OF(T, y)) );
1037  __ pop(t1);
1038  __ nop();
1039  __ push(t1);
1040  __ lw(t2, MemOperand(fp, OFFSET_OF(T, y)) );
1041  __ pop(t3);
1042  __ nop();
1043 
1044  __ mov(fp, t6);
1045  __ jr(ra);
1046  __ nop();
1047 
1048  CodeDesc desc;
1049  assm.GetCode(&desc);
1050  Object* code = HEAP->CreateCode(
1051  desc,
1052  Code::ComputeFlags(Code::STUB),
1053  Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
1054  CHECK(code->IsCode());
1055  F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
1056  t.x = 1;
1057  t.y = 2;
1058  t.y1 = 3;
1059  t.y2 = 4;
1060  t.y3 = 0XBABA;
1061  t.y4 = 0xDEDA;
1062 
1063  Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
1064  USE(dummy);
1065 
1066  CHECK_EQ(3, t.y1);
1067 }
1068 
1069 
1070 TEST(MIPS13) {
1071  // Test Cvt_d_uw and Trunc_uw_d macros.
1072  InitializeVM();
1073  v8::HandleScope scope;
1074 
1075  typedef struct {
1076  double cvt_big_out;
1077  double cvt_small_out;
1078  uint32_t trunc_big_out;
1079  uint32_t trunc_small_out;
1080  uint32_t cvt_big_in;
1081  uint32_t cvt_small_in;
1082  } T;
1083  T t;
1084 
1085  MacroAssembler assm(Isolate::Current(), NULL, 0);
1086 
1088  CpuFeatures::Scope scope(FPU);
1089 
1090  __ sw(t0, MemOperand(a0, OFFSET_OF(T, cvt_small_in)));
1091  __ Cvt_d_uw(f10, t0, f22);
1092  __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, cvt_small_out)));
1093 
1094  __ Trunc_uw_d(f10, f10, f22);
1095  __ swc1(f10, MemOperand(a0, OFFSET_OF(T, trunc_small_out)));
1096 
1097  __ sw(t0, MemOperand(a0, OFFSET_OF(T, cvt_big_in)));
1098  __ Cvt_d_uw(f8, t0, f22);
1099  __ sdc1(f8, MemOperand(a0, OFFSET_OF(T, cvt_big_out)));
1100 
1101  __ Trunc_uw_d(f8, f8, f22);
1102  __ swc1(f8, MemOperand(a0, OFFSET_OF(T, trunc_big_out)));
1103 
1104  __ jr(ra);
1105  __ nop();
1106 
1107  CodeDesc desc;
1108  assm.GetCode(&desc);
1109  Object* code = HEAP->CreateCode(
1110  desc,
1111  Code::ComputeFlags(Code::STUB),
1112  Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
1113  CHECK(code->IsCode());
1114  F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
1115 
1116  t.cvt_big_in = 0xFFFFFFFF;
1117  t.cvt_small_in = 333;
1118 
1119  Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
1120  USE(dummy);
1121 
1122  CHECK_EQ(t.cvt_big_out, static_cast<double>(t.cvt_big_in));
1123  CHECK_EQ(t.cvt_small_out, static_cast<double>(t.cvt_small_in));
1124 
1125  CHECK_EQ(static_cast<int>(t.trunc_big_out), static_cast<int>(t.cvt_big_in));
1126  CHECK_EQ(static_cast<int>(t.trunc_small_out),
1127  static_cast<int>(t.cvt_small_in));
1128  }
1129 }
1130 
1131 
1132 TEST(MIPS14) {
1133  // Test round, floor, ceil, trunc, cvt.
1134  InitializeVM();
1135  v8::HandleScope scope;
1136 
1137 #define ROUND_STRUCT_ELEMENT(x) \
1138  int32_t x##_up_out; \
1139  int32_t x##_down_out; \
1140  int32_t neg_##x##_up_out; \
1141  int32_t neg_##x##_down_out; \
1142  uint32_t x##_err1_out; \
1143  uint32_t x##_err2_out; \
1144  uint32_t x##_err3_out; \
1145  uint32_t x##_err4_out; \
1146  int32_t x##_invalid_result;
1147 
1148  typedef struct {
1149  double round_up_in;
1150  double round_down_in;
1151  double neg_round_up_in;
1152  double neg_round_down_in;
1153  double err1_in;
1154  double err2_in;
1155  double err3_in;
1156  double err4_in;
1157 
1158  ROUND_STRUCT_ELEMENT(round)
1159  ROUND_STRUCT_ELEMENT(floor)
1160  ROUND_STRUCT_ELEMENT(ceil)
1161  ROUND_STRUCT_ELEMENT(trunc)
1163  } T;
1164  T t;
1165 
1166 #undef ROUND_STRUCT_ELEMENT
1167 
1168  MacroAssembler assm(Isolate::Current(), NULL, 0);
1169 
1171  CpuFeatures::Scope scope(FPU);
1172 
1173  // Save FCSR.
1174  __ cfc1(a1, FCSR);
1175  // Disable FPU exceptions.
1176  __ ctc1(zero_reg, FCSR);
1177 #define RUN_ROUND_TEST(x) \
1178  __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, round_up_in))); \
1179  __ x##_w_d(f0, f0); \
1180  __ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_up_out))); \
1181  \
1182  __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, round_down_in))); \
1183  __ x##_w_d(f0, f0); \
1184  __ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_down_out))); \
1185  \
1186  __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, neg_round_up_in))); \
1187  __ x##_w_d(f0, f0); \
1188  __ swc1(f0, MemOperand(a0, OFFSET_OF(T, neg_##x##_up_out))); \
1189  \
1190  __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, neg_round_down_in))); \
1191  __ x##_w_d(f0, f0); \
1192  __ swc1(f0, MemOperand(a0, OFFSET_OF(T, neg_##x##_down_out))); \
1193  \
1194  __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err1_in))); \
1195  __ ctc1(zero_reg, FCSR); \
1196  __ x##_w_d(f0, f0); \
1197  __ cfc1(a2, FCSR); \
1198  __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err1_out))); \
1199  \
1200  __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err2_in))); \
1201  __ ctc1(zero_reg, FCSR); \
1202  __ x##_w_d(f0, f0); \
1203  __ cfc1(a2, FCSR); \
1204  __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err2_out))); \
1205  \
1206  __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err3_in))); \
1207  __ ctc1(zero_reg, FCSR); \
1208  __ x##_w_d(f0, f0); \
1209  __ cfc1(a2, FCSR); \
1210  __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err3_out))); \
1211  \
1212  __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err4_in))); \
1213  __ ctc1(zero_reg, FCSR); \
1214  __ x##_w_d(f0, f0); \
1215  __ cfc1(a2, FCSR); \
1216  __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err4_out))); \
1217  __ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_invalid_result)));
1218 
1219  RUN_ROUND_TEST(round)
1220  RUN_ROUND_TEST(floor)
1221  RUN_ROUND_TEST(ceil)
1222  RUN_ROUND_TEST(trunc)
1223  RUN_ROUND_TEST(cvt)
1224 
1225  // Restore FCSR.
1226  __ ctc1(a1, FCSR);
1227 
1228  __ jr(ra);
1229  __ nop();
1230 
1231  CodeDesc desc;
1232  assm.GetCode(&desc);
1233  Object* code = HEAP->CreateCode(
1234  desc,
1235  Code::ComputeFlags(Code::STUB),
1236  Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
1237  CHECK(code->IsCode());
1238  F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
1239 
1240  t.round_up_in = 123.51;
1241  t.round_down_in = 123.49;
1242  t.neg_round_up_in = -123.5;
1243  t.neg_round_down_in = -123.49;
1244  t.err1_in = 123.51;
1245  t.err2_in = 1;
1246  t.err3_in = static_cast<double>(1) + 0xFFFFFFFF;
1247  t.err4_in = NAN;
1248 
1249  Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
1250  USE(dummy);
1251 
1252 #define GET_FPU_ERR(x) (static_cast<int>(x & kFCSRFlagMask))
1253 #define CHECK_ROUND_RESULT(type) \
1254  CHECK(GET_FPU_ERR(t.type##_err1_out) & kFCSRInexactFlagMask); \
1255  CHECK_EQ(0, GET_FPU_ERR(t.type##_err2_out)); \
1256  CHECK(GET_FPU_ERR(t.type##_err3_out) & kFCSRInvalidOpFlagMask); \
1257  CHECK(GET_FPU_ERR(t.type##_err4_out) & kFCSRInvalidOpFlagMask); \
1258  CHECK_EQ(kFPUInvalidResult, t.type##_invalid_result);
1259 
1260  CHECK_ROUND_RESULT(round);
1261  CHECK_ROUND_RESULT(floor);
1262  CHECK_ROUND_RESULT(ceil);
1263  CHECK_ROUND_RESULT(cvt);
1264  }
1265 }
1266 
1267 
1268 TEST(MIPS15) {
1269  // Test chaining of label usages within instructions (issue 1644).
1270  InitializeVM();
1271  v8::HandleScope scope;
1272  Assembler assm(Isolate::Current(), NULL, 0);
1273 
1274  Label target;
1275  __ beq(v0, v1, &target);
1276  __ nop();
1277  __ bne(v0, v1, &target);
1278  __ nop();
1279  __ bind(&target);
1280  __ nop();
1281 }
1282 
1283 #undef __
const FPURegister f4
#define CHECK_EQ(expected, value)
Definition: checks.h:219
#define RUN_ROUND_TEST(x)
const FPURegister f5
const Register r3
Object *(* F3)(void *p, int p1, int p2, int p3, int p4)
const FPURegister f0
const FPURegister f22
const FPURegister f10
const Register r6
int int32_t
Definition: unicode.cc:47
static bool IsSupported(CpuFeature f)
#define CHECK(condition)
Definition: checks.h:56
const Register r2
static Code * cast(Object *obj)
#define OFFSET_OF(type, field)
Definition: globals.h:273
#define CHECK_ROUND_RESULT(type)
const FPURegister f9
void GetCode(CodeDesc *desc)
Object *(* F2)(int x, int y, int p2, int p3, int p4)
static Flags ComputeFlags(Kind kind, InlineCacheState ic_state=UNINITIALIZED, ExtraICState extra_ic_state=kNoExtraICState, StubType type=NORMAL, int argc=-1, InlineCacheHolderFlag holder=OWN_MAP)
Definition: objects-inl.h:3491
#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4)
Definition: simulator-arm.h:48
const FPURegister f2
#define T(name, string, precedence)
Definition: token.cc:48
const Register r1
const FPUControlRegister FCSR
#define ROUND_STRUCT_ELEMENT(x)
Object *(* F1)(int x, int p1, int p2, int p3, int p4)
#define HEAP
Definition: isolate.h:1433
const FPURegister f1
const FPURegister f7
void USE(T)
Definition: globals.h:289
#define __
const FPURegister f12
const FPURegister f6
bool IsEmpty() const
Definition: v8.h:209
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 and VFP2 enable use of VFP2 instructions if available enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of MIPS FPU instructions if NULL
Definition: flags.cc:301
static Persistent< Context > New(ExtensionConfiguration *extensions=NULL, Handle< ObjectTemplate > global_template=Handle< ObjectTemplate >(), Handle< Value > global_object=Handle< Value >())
Definition: api.cc:4411
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra code(assertions) for debugging") DEFINE_bool(code_comments
const Register fp
const FPURegister f14
const Register r5
const FPURegister f8
const Register r4