• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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 
47 static v8::Persistent<v8::Context> env;
48 
49 
InitializeVM()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 
TEST(MIPS0)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 
TEST(MIPS1)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 
TEST(MIPS2)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 
TEST(MIPS3)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 
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 
TEST(MIPS4)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 
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 
TEST(MIPS5)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 
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 
TEST(MIPS6)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 
TEST(MIPS7)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 
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 
TEST(MIPS8)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 
TEST(MIPS9)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 
TEST(MIPS10)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 
TEST(MIPS11)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 
TEST(MIPS12)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 
TEST(MIPS13)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 
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 
TEST(MIPS14)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)
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 
TEST(MIPS15)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 __
1284