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"
33#include "mips/macro-assembler-mips.h"
34#include "mips/simulator-mips.h"
35
36#include "cctest.h"
37
38using namespace v8::internal;
39
40
41// Define these function prototypes to match JSEntryFunction in execution.cc.
42typedef Object* (*F1)(int x, int p1, int p2, int p3, int p4);
43typedef Object* (*F2)(int x, int y, int p2, int p3, int p4);
44typedef Object* (*F3)(void* p, int p1, int p2, int p3, int p4);
45
46
47static v8::Persistent<v8::Context> env;
48
49
50static 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
63TEST(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
88TEST(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
126TEST(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
266TEST(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
287  if (CpuFeatures::IsSupported(FPU)) {
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
345TEST(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
360  if (CpuFeatures::IsSupported(FPU)) {
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
405TEST(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
421  if (CpuFeatures::IsSupported(FPU)) {
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
476TEST(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
548TEST(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
569  if (CpuFeatures::IsSupported(FPU)) {
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
629TEST(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
733TEST(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
761TEST(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
836TEST(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
980TEST(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
1070TEST(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
1087  if (CpuFeatures::IsSupported(FPU)) {
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
1132TEST(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)
1162    ROUND_STRUCT_ELEMENT(cvt)
1163  } T;
1164  T t;
1165
1166#undef ROUND_STRUCT_ELEMENT
1167
1168  MacroAssembler assm(Isolate::Current(), NULL, 0);
1169
1170  if (CpuFeatures::IsSupported(FPU)) {
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
1268TEST(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 __
1284