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