Upstream version 8.37.180.0
[platform/framework/web/crosswalk.git] / src / v8 / test / cctest / test-assembler-ia32.cc
1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include <stdlib.h>
29
30 #include "src/v8.h"
31
32 #include "src/disassembler.h"
33 #include "src/factory.h"
34 #include "src/macro-assembler.h"
35 #include "src/platform.h"
36 #include "src/serialize.h"
37 #include "test/cctest/cctest.h"
38
39 using namespace v8::internal;
40
41
42 typedef int (*F0)();
43 typedef int (*F1)(int x);
44 typedef int (*F2)(int x, int y);
45
46
47 #define __ assm.
48
49 TEST(AssemblerIa320) {
50   CcTest::InitializeVM();
51   Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
52   HandleScope scope(isolate);
53
54   v8::internal::byte buffer[256];
55   Assembler assm(isolate, buffer, sizeof buffer);
56
57   __ mov(eax, Operand(esp, 4));
58   __ add(eax, Operand(esp, 8));
59   __ ret(0);
60
61   CodeDesc desc;
62   assm.GetCode(&desc);
63   Handle<Code> code = isolate->factory()->NewCode(
64       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
65 #ifdef OBJECT_PRINT
66   code->Print();
67 #endif
68   F2 f = FUNCTION_CAST<F2>(code->entry());
69   int res = f(3, 4);
70   ::printf("f() = %d\n", res);
71   CHECK_EQ(7, res);
72 }
73
74
75 TEST(AssemblerIa321) {
76   CcTest::InitializeVM();
77   Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
78   HandleScope scope(isolate);
79
80   v8::internal::byte buffer[256];
81   Assembler assm(isolate, buffer, sizeof buffer);
82   Label L, C;
83
84   __ mov(edx, Operand(esp, 4));
85   __ xor_(eax, eax);  // clear eax
86   __ jmp(&C);
87
88   __ bind(&L);
89   __ add(eax, edx);
90   __ sub(edx, Immediate(1));
91
92   __ bind(&C);
93   __ test(edx, edx);
94   __ j(not_zero, &L);
95   __ ret(0);
96
97   CodeDesc desc;
98   assm.GetCode(&desc);
99   Handle<Code> code = isolate->factory()->NewCode(
100       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
101 #ifdef OBJECT_PRINT
102   code->Print();
103 #endif
104   F1 f = FUNCTION_CAST<F1>(code->entry());
105   int res = f(100);
106   ::printf("f() = %d\n", res);
107   CHECK_EQ(5050, res);
108 }
109
110
111 TEST(AssemblerIa322) {
112   CcTest::InitializeVM();
113   Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
114   HandleScope scope(isolate);
115
116   v8::internal::byte buffer[256];
117   Assembler assm(isolate, buffer, sizeof buffer);
118   Label L, C;
119
120   __ mov(edx, Operand(esp, 4));
121   __ mov(eax, 1);
122   __ jmp(&C);
123
124   __ bind(&L);
125   __ imul(eax, edx);
126   __ sub(edx, Immediate(1));
127
128   __ bind(&C);
129   __ test(edx, edx);
130   __ j(not_zero, &L);
131   __ ret(0);
132
133   // some relocated stuff here, not executed
134   __ mov(eax, isolate->factory()->true_value());
135   __ jmp(NULL, RelocInfo::RUNTIME_ENTRY);
136
137   CodeDesc desc;
138   assm.GetCode(&desc);
139   Handle<Code> code = isolate->factory()->NewCode(
140       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
141 #ifdef OBJECT_PRINT
142   code->Print();
143 #endif
144   F1 f = FUNCTION_CAST<F1>(code->entry());
145   int res = f(10);
146   ::printf("f() = %d\n", res);
147   CHECK_EQ(3628800, res);
148 }
149
150
151 typedef int (*F3)(float x);
152
153 TEST(AssemblerIa323) {
154   CcTest::InitializeVM();
155
156   Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
157   HandleScope scope(isolate);
158
159   v8::internal::byte buffer[256];
160   Assembler assm(isolate, buffer, sizeof buffer);
161
162   __ cvttss2si(eax, Operand(esp, 4));
163   __ ret(0);
164
165   CodeDesc desc;
166   assm.GetCode(&desc);
167   Handle<Code> code = isolate->factory()->NewCode(
168       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
169   // don't print the code - our disassembler can't handle cvttss2si
170   // instead print bytes
171   Disassembler::Dump(stdout,
172                      code->instruction_start(),
173                      code->instruction_start() + code->instruction_size());
174   F3 f = FUNCTION_CAST<F3>(code->entry());
175   int res = f(static_cast<float>(-3.1415));
176   ::printf("f() = %d\n", res);
177   CHECK_EQ(-3, res);
178 }
179
180
181 typedef int (*F4)(double x);
182
183 TEST(AssemblerIa324) {
184   CcTest::InitializeVM();
185
186   Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
187   HandleScope scope(isolate);
188
189   v8::internal::byte buffer[256];
190   Assembler assm(isolate, buffer, sizeof buffer);
191
192   __ cvttsd2si(eax, Operand(esp, 4));
193   __ ret(0);
194
195   CodeDesc desc;
196   assm.GetCode(&desc);
197   Handle<Code> code = isolate->factory()->NewCode(
198       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
199   // don't print the code - our disassembler can't handle cvttsd2si
200   // instead print bytes
201   Disassembler::Dump(stdout,
202                      code->instruction_start(),
203                      code->instruction_start() + code->instruction_size());
204   F4 f = FUNCTION_CAST<F4>(code->entry());
205   int res = f(2.718281828);
206   ::printf("f() = %d\n", res);
207   CHECK_EQ(2, res);
208 }
209
210
211 static int baz = 42;
212 TEST(AssemblerIa325) {
213   CcTest::InitializeVM();
214   Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
215   HandleScope scope(isolate);
216
217   v8::internal::byte buffer[256];
218   Assembler assm(isolate, buffer, sizeof buffer);
219
220   __ mov(eax, Operand(reinterpret_cast<intptr_t>(&baz), RelocInfo::NONE32));
221   __ ret(0);
222
223   CodeDesc desc;
224   assm.GetCode(&desc);
225   Handle<Code> code = isolate->factory()->NewCode(
226       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
227   F0 f = FUNCTION_CAST<F0>(code->entry());
228   int res = f();
229   CHECK_EQ(42, res);
230 }
231
232
233 typedef double (*F5)(double x, double y);
234
235 TEST(AssemblerIa326) {
236   CcTest::InitializeVM();
237
238   Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
239   HandleScope scope(isolate);
240   v8::internal::byte buffer[256];
241   Assembler assm(isolate, buffer, sizeof buffer);
242
243   __ movsd(xmm0, Operand(esp, 1 * kPointerSize));
244   __ movsd(xmm1, Operand(esp, 3 * kPointerSize));
245   __ addsd(xmm0, xmm1);
246   __ mulsd(xmm0, xmm1);
247   __ subsd(xmm0, xmm1);
248   __ divsd(xmm0, xmm1);
249   // Copy xmm0 to st(0) using eight bytes of stack.
250   __ sub(esp, Immediate(8));
251   __ movsd(Operand(esp, 0), xmm0);
252   __ fld_d(Operand(esp, 0));
253   __ add(esp, Immediate(8));
254   __ ret(0);
255
256   CodeDesc desc;
257   assm.GetCode(&desc);
258   Handle<Code> code = isolate->factory()->NewCode(
259       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
260 #ifdef DEBUG
261   ::printf("\n---\n");
262   // don't print the code - our disassembler can't handle SSE instructions
263   // instead print bytes
264   Disassembler::Dump(stdout,
265                      code->instruction_start(),
266                      code->instruction_start() + code->instruction_size());
267 #endif
268   F5 f = FUNCTION_CAST<F5>(code->entry());
269   double res = f(2.2, 1.1);
270   ::printf("f() = %f\n", res);
271   CHECK(2.29 < res && res < 2.31);
272 }
273
274
275 typedef double (*F6)(int x);
276
277 TEST(AssemblerIa328) {
278   CcTest::InitializeVM();
279
280   Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
281   HandleScope scope(isolate);
282   v8::internal::byte buffer[256];
283   Assembler assm(isolate, buffer, sizeof buffer);
284   __ mov(eax, Operand(esp, 4));
285   __ cvtsi2sd(xmm0, eax);
286   // Copy xmm0 to st(0) using eight bytes of stack.
287   __ sub(esp, Immediate(8));
288   __ movsd(Operand(esp, 0), xmm0);
289   __ fld_d(Operand(esp, 0));
290   __ add(esp, Immediate(8));
291   __ ret(0);
292   CodeDesc desc;
293   assm.GetCode(&desc);
294   Handle<Code> code = isolate->factory()->NewCode(
295       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
296 #ifdef OBJECT_PRINT
297   code->Print();
298 #endif
299   F6 f = FUNCTION_CAST<F6>(code->entry());
300   double res = f(12);
301
302   ::printf("f() = %f\n", res);
303   CHECK(11.99 < res && res < 12.001);
304 }
305
306
307 typedef int (*F7)(double x, double y);
308
309 TEST(AssemblerIa329) {
310   CcTest::InitializeVM();
311   Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
312   HandleScope scope(isolate);
313   v8::internal::byte buffer[256];
314   MacroAssembler assm(isolate, buffer, sizeof buffer);
315   enum { kEqual = 0, kGreater = 1, kLess = 2, kNaN = 3, kUndefined = 4 };
316   Label equal_l, less_l, greater_l, nan_l;
317   __ fld_d(Operand(esp, 3 * kPointerSize));
318   __ fld_d(Operand(esp, 1 * kPointerSize));
319   __ FCmp();
320   __ j(parity_even, &nan_l);
321   __ j(equal, &equal_l);
322   __ j(below, &less_l);
323   __ j(above, &greater_l);
324
325   __ mov(eax, kUndefined);
326   __ ret(0);
327
328   __ bind(&equal_l);
329   __ mov(eax, kEqual);
330   __ ret(0);
331
332   __ bind(&greater_l);
333   __ mov(eax, kGreater);
334   __ ret(0);
335
336   __ bind(&less_l);
337   __ mov(eax, kLess);
338   __ ret(0);
339
340   __ bind(&nan_l);
341   __ mov(eax, kNaN);
342   __ ret(0);
343
344
345   CodeDesc desc;
346   assm.GetCode(&desc);
347   Handle<Code> code = isolate->factory()->NewCode(
348       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
349 #ifdef OBJECT_PRINT
350   code->Print();
351 #endif
352
353   F7 f = FUNCTION_CAST<F7>(code->entry());
354   CHECK_EQ(kLess, f(1.1, 2.2));
355   CHECK_EQ(kEqual, f(2.2, 2.2));
356   CHECK_EQ(kGreater, f(3.3, 2.2));
357   CHECK_EQ(kNaN, f(OS::nan_value(), 1.1));
358 }
359
360
361 TEST(AssemblerIa3210) {
362   // Test chaining of label usages within instructions (issue 1644).
363   CcTest::InitializeVM();
364   Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
365   HandleScope scope(isolate);
366   Assembler assm(isolate, NULL, 0);
367
368   Label target;
369   __ j(equal, &target);
370   __ j(not_equal, &target);
371   __ bind(&target);
372   __ nop();
373 }
374
375
376 TEST(AssemblerMultiByteNop) {
377   CcTest::InitializeVM();
378   Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
379   HandleScope scope(isolate);
380   v8::internal::byte buffer[1024];
381   Assembler assm(isolate, buffer, sizeof(buffer));
382   __ push(ebx);
383   __ push(ecx);
384   __ push(edx);
385   __ push(edi);
386   __ push(esi);
387   __ mov(eax, 1);
388   __ mov(ebx, 2);
389   __ mov(ecx, 3);
390   __ mov(edx, 4);
391   __ mov(edi, 5);
392   __ mov(esi, 6);
393   for (int i = 0; i < 16; i++) {
394     int before = assm.pc_offset();
395     __ Nop(i);
396     CHECK_EQ(assm.pc_offset() - before, i);
397   }
398
399   Label fail;
400   __ cmp(eax, 1);
401   __ j(not_equal, &fail);
402   __ cmp(ebx, 2);
403   __ j(not_equal, &fail);
404   __ cmp(ecx, 3);
405   __ j(not_equal, &fail);
406   __ cmp(edx, 4);
407   __ j(not_equal, &fail);
408   __ cmp(edi, 5);
409   __ j(not_equal, &fail);
410   __ cmp(esi, 6);
411   __ j(not_equal, &fail);
412   __ mov(eax, 42);
413   __ pop(esi);
414   __ pop(edi);
415   __ pop(edx);
416   __ pop(ecx);
417   __ pop(ebx);
418   __ ret(0);
419   __ bind(&fail);
420   __ mov(eax, 13);
421   __ pop(esi);
422   __ pop(edi);
423   __ pop(edx);
424   __ pop(ecx);
425   __ pop(ebx);
426   __ ret(0);
427
428   CodeDesc desc;
429   assm.GetCode(&desc);
430   Handle<Code> code = isolate->factory()->NewCode(
431       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
432   CHECK(code->IsCode());
433
434   F0 f = FUNCTION_CAST<F0>(code->entry());
435   int res = f();
436   CHECK_EQ(42, res);
437 }
438
439
440 #ifdef __GNUC__
441 #define ELEMENT_COUNT 4
442
443 void DoSSE2(const v8::FunctionCallbackInfo<v8::Value>& args) {
444   Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
445   HandleScope scope(isolate);
446
447   CHECK(args[0]->IsArray());
448   v8::Local<v8::Array> vec = v8::Local<v8::Array>::Cast(args[0]);
449   CHECK_EQ(ELEMENT_COUNT, vec->Length());
450
451   v8::internal::byte buffer[256];
452   Assembler assm(isolate, buffer, sizeof buffer);
453
454   // Remove return address from the stack for fix stack frame alignment.
455   __ pop(ecx);
456
457   // Store input vector on the stack.
458   for (int i = 0; i < ELEMENT_COUNT; ++i) {
459     __ push(Immediate(vec->Get(i)->Int32Value()));
460   }
461
462   // Read vector into a xmm register.
463   __ pxor(xmm0, xmm0);
464   __ movdqa(xmm0, Operand(esp, 0));
465   // Create mask and store it in the return register.
466   __ movmskps(eax, xmm0);
467
468   // Remove unused data from the stack.
469   __ add(esp, Immediate(ELEMENT_COUNT * sizeof(int32_t)));
470   // Restore return address.
471   __ push(ecx);
472
473   __ ret(0);
474
475   CodeDesc desc;
476   assm.GetCode(&desc);
477
478   Handle<Code> code = isolate->factory()->NewCode(
479       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
480
481   F0 f = FUNCTION_CAST<F0>(code->entry());
482   int res = f();
483   args.GetReturnValue().Set(v8::Integer::New(CcTest::isolate(), res));
484 }
485
486
487 TEST(StackAlignmentForSSE2) {
488   CcTest::InitializeVM();
489   CHECK_EQ(0, OS::ActivationFrameAlignment() % 16);
490
491   v8::Isolate* isolate = CcTest::isolate();
492   v8::HandleScope handle_scope(isolate);
493   v8::Handle<v8::ObjectTemplate> global_template =
494       v8::ObjectTemplate::New(isolate);
495   global_template->Set(v8_str("do_sse2"),
496                        v8::FunctionTemplate::New(isolate, DoSSE2));
497
498   LocalContext env(NULL, global_template);
499   CompileRun(
500       "function foo(vec) {"
501       "  return do_sse2(vec);"
502       "}");
503
504   v8::Local<v8::Object> global_object = env->Global();
505   v8::Local<v8::Function> foo =
506       v8::Local<v8::Function>::Cast(global_object->Get(v8_str("foo")));
507
508   int32_t vec[ELEMENT_COUNT] = { -1, 1, 1, 1 };
509   v8::Local<v8::Array> v8_vec = v8::Array::New(isolate, ELEMENT_COUNT);
510   for (int i = 0; i < ELEMENT_COUNT; i++) {
511       v8_vec->Set(i, v8_num(vec[i]));
512   }
513
514   v8::Local<v8::Value> args[] = { v8_vec };
515   v8::Local<v8::Value> result = foo->Call(global_object, 1, args);
516
517   // The mask should be 0b1000.
518   CHECK_EQ(8, result->Int32Value());
519 }
520
521 #undef ELEMENT_COUNT
522 #endif  // __GNUC__
523
524
525 TEST(AssemblerIa32Extractps) {
526   CcTest::InitializeVM();
527   if (!CpuFeatures::IsSupported(SSE4_1)) return;
528
529   Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
530   HandleScope scope(isolate);
531   v8::internal::byte buffer[256];
532   MacroAssembler assm(isolate, buffer, sizeof buffer);
533   { CpuFeatureScope fscope41(&assm, SSE4_1);
534     __ movsd(xmm1, Operand(esp, 4));
535     __ extractps(eax, xmm1, 0x1);
536     __ ret(0);
537   }
538
539   CodeDesc desc;
540   assm.GetCode(&desc);
541   Handle<Code> code = isolate->factory()->NewCode(
542       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
543 #ifdef OBJECT_PRINT
544   code->Print();
545 #endif
546
547   F4 f = FUNCTION_CAST<F4>(code->entry());
548   uint64_t value1 = V8_2PART_UINT64_C(0x12345678, 87654321);
549   CHECK_EQ(0x12345678, f(uint64_to_double(value1)));
550   uint64_t value2 = V8_2PART_UINT64_C(0x87654321, 12345678);
551   CHECK_EQ(0x87654321, f(uint64_to_double(value2)));
552 }
553
554
555 typedef int (*F8)(float x, float y);
556 TEST(AssemblerIa32SSE) {
557   CcTest::InitializeVM();
558
559   Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
560   HandleScope scope(isolate);
561   v8::internal::byte buffer[256];
562   MacroAssembler assm(isolate, buffer, sizeof buffer);
563   {
564     __ movss(xmm0, Operand(esp, kPointerSize));
565     __ movss(xmm1, Operand(esp, 2 * kPointerSize));
566     __ shufps(xmm0, xmm0, 0x0);
567     __ shufps(xmm1, xmm1, 0x0);
568     __ movaps(xmm2, xmm1);
569     __ addps(xmm2, xmm0);
570     __ mulps(xmm2, xmm1);
571     __ subps(xmm2, xmm0);
572     __ divps(xmm2, xmm1);
573     __ cvttss2si(eax, xmm2);
574     __ ret(0);
575   }
576
577   CodeDesc desc;
578   assm.GetCode(&desc);
579   Handle<Code> code = isolate->factory()->NewCode(
580       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
581 #ifdef OBJECT_PRINT
582   code->Print();
583 #endif
584
585   F8 f = FUNCTION_CAST<F8>(code->entry());
586   CHECK_EQ(2, f(1.0, 2.0));
587 }
588
589
590 #undef __