1// Copyright 2009 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/base/platform/platform.h"
33#include "src/factory.h"
34#include "src/macro-assembler.h"
35#include "src/serialize.h"
36#include "test/cctest/cctest.h"
37
38namespace i = v8::internal;
39using i::Address;
40using i::Assembler;
41using i::CodeDesc;
42using i::Condition;
43using i::FUNCTION_CAST;
44using i::HandleScope;
45using i::Immediate;
46using i::Isolate;
47using i::Label;
48using i::MacroAssembler;
49using i::Operand;
50using i::RelocInfo;
51using i::Representation;
52using i::Smi;
53using i::SmiIndex;
54using i::byte;
55using i::carry;
56using i::greater;
57using i::greater_equal;
58using i::kIntSize;
59using i::kPointerSize;
60using i::kSmiTagMask;
61using i::kSmiValueSize;
62using i::less_equal;
63using i::negative;
64using i::not_carry;
65using i::not_equal;
66using i::equal;
67using i::not_zero;
68using i::positive;
69using i::r11;
70using i::r13;
71using i::r14;
72using i::r15;
73using i::r8;
74using i::r9;
75using i::rax;
76using i::rbp;
77using i::rbx;
78using i::rcx;
79using i::rdi;
80using i::rdx;
81using i::rsi;
82using i::rsp;
83using i::times_pointer_size;
84
85// Test the x64 assembler by compiling some simple functions into
86// a buffer and executing them.  These tests do not initialize the
87// V8 library, create a context, or use any V8 objects.
88// The AMD64 calling convention is used, with the first five arguments
89// in RSI, RDI, RDX, RCX, R8, and R9, and floating point arguments in
90// the XMM registers.  The return value is in RAX.
91// This calling convention is used on Linux, with GCC, and on Mac OS,
92// with GCC.  A different convention is used on 64-bit windows.
93
94typedef int (*F0)();
95
96#define __ masm->
97
98
99static void EntryCode(MacroAssembler* masm) {
100  // Smi constant register is callee save.
101  __ pushq(i::kSmiConstantRegister);
102  __ pushq(i::kRootRegister);
103  __ InitializeSmiConstantRegister();
104  __ InitializeRootRegister();
105}
106
107
108static void ExitCode(MacroAssembler* masm) {
109  // Return -1 if kSmiConstantRegister was clobbered during the test.
110  __ Move(rdx, Smi::FromInt(1));
111  __ cmpq(rdx, i::kSmiConstantRegister);
112  __ movq(rdx, Immediate(-1));
113  __ cmovq(not_equal, rax, rdx);
114  __ popq(i::kRootRegister);
115  __ popq(i::kSmiConstantRegister);
116}
117
118
119TEST(Smi) {
120  // Check that C++ Smi operations work as expected.
121  int64_t test_numbers[] = {
122      0, 1, -1, 127, 128, -128, -129, 255, 256, -256, -257,
123      Smi::kMaxValue, static_cast<int64_t>(Smi::kMaxValue) + 1,
124      Smi::kMinValue, static_cast<int64_t>(Smi::kMinValue) - 1
125  };
126  int test_number_count = 15;
127  for (int i = 0; i < test_number_count; i++) {
128    int64_t number = test_numbers[i];
129    bool is_valid = Smi::IsValid(number);
130    bool is_in_range = number >= Smi::kMinValue && number <= Smi::kMaxValue;
131    CHECK_EQ(is_in_range, is_valid);
132    if (is_valid) {
133      Smi* smi_from_intptr = Smi::FromIntptr(number);
134      if (static_cast<int>(number) == number) {  // Is a 32-bit int.
135        Smi* smi_from_int = Smi::FromInt(static_cast<int32_t>(number));
136        CHECK_EQ(smi_from_int, smi_from_intptr);
137      }
138      int64_t smi_value = smi_from_intptr->value();
139      CHECK_EQ(number, smi_value);
140    }
141  }
142}
143
144
145static void TestMoveSmi(MacroAssembler* masm, Label* exit, int id, Smi* value) {
146  __ movl(rax, Immediate(id));
147  __ Move(rcx, value);
148  __ Set(rdx, reinterpret_cast<intptr_t>(value));
149  __ cmpq(rcx, rdx);
150  __ j(not_equal, exit);
151}
152
153
154// Test that we can move a Smi value literally into a register.
155TEST(SmiMove) {
156  // Allocate an executable page of memory.
157  size_t actual_size;
158  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
159      Assembler::kMinimalBufferSize, &actual_size, true));
160  CHECK(buffer);
161  Isolate* isolate = CcTest::i_isolate();
162  HandleScope handles(isolate);
163  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
164  MacroAssembler* masm = &assembler;  // Create a pointer for the __ macro.
165  EntryCode(masm);
166  Label exit;
167
168  TestMoveSmi(masm, &exit, 1, Smi::FromInt(0));
169  TestMoveSmi(masm, &exit, 2, Smi::FromInt(127));
170  TestMoveSmi(masm, &exit, 3, Smi::FromInt(128));
171  TestMoveSmi(masm, &exit, 4, Smi::FromInt(255));
172  TestMoveSmi(masm, &exit, 5, Smi::FromInt(256));
173  TestMoveSmi(masm, &exit, 6, Smi::FromInt(Smi::kMaxValue));
174  TestMoveSmi(masm, &exit, 7, Smi::FromInt(-1));
175  TestMoveSmi(masm, &exit, 8, Smi::FromInt(-128));
176  TestMoveSmi(masm, &exit, 9, Smi::FromInt(-129));
177  TestMoveSmi(masm, &exit, 10, Smi::FromInt(-256));
178  TestMoveSmi(masm, &exit, 11, Smi::FromInt(-257));
179  TestMoveSmi(masm, &exit, 12, Smi::FromInt(Smi::kMinValue));
180
181  __ xorq(rax, rax);  // Success.
182  __ bind(&exit);
183  ExitCode(masm);
184  __ ret(0);
185
186  CodeDesc desc;
187  masm->GetCode(&desc);
188  // Call the function from C++.
189  int result = FUNCTION_CAST<F0>(buffer)();
190  CHECK_EQ(0, result);
191}
192
193
194void TestSmiCompare(MacroAssembler* masm, Label* exit, int id, int x, int y) {
195  __ Move(rcx, Smi::FromInt(x));
196  __ movq(r8, rcx);
197  __ Move(rdx, Smi::FromInt(y));
198  __ movq(r9, rdx);
199  __ SmiCompare(rcx, rdx);
200  if (x < y) {
201    __ movl(rax, Immediate(id + 1));
202    __ j(greater_equal, exit);
203  } else if (x > y) {
204    __ movl(rax, Immediate(id + 2));
205    __ j(less_equal, exit);
206  } else {
207    DCHECK_EQ(x, y);
208    __ movl(rax, Immediate(id + 3));
209    __ j(not_equal, exit);
210  }
211  __ movl(rax, Immediate(id + 4));
212  __ cmpq(rcx, r8);
213  __ j(not_equal, exit);
214  __ incq(rax);
215  __ cmpq(rdx, r9);
216  __ j(not_equal, exit);
217
218  if (x != y) {
219    __ SmiCompare(rdx, rcx);
220    if (y < x) {
221      __ movl(rax, Immediate(id + 9));
222      __ j(greater_equal, exit);
223    } else {
224      DCHECK(y > x);
225      __ movl(rax, Immediate(id + 10));
226      __ j(less_equal, exit);
227    }
228  } else {
229    __ cmpq(rcx, rcx);
230    __ movl(rax, Immediate(id + 11));
231    __ j(not_equal, exit);
232    __ incq(rax);
233    __ cmpq(rcx, r8);
234    __ j(not_equal, exit);
235  }
236}
237
238
239// Test that we can compare smis for equality (and more).
240TEST(SmiCompare) {
241  // Allocate an executable page of memory.
242  size_t actual_size;
243  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
244      Assembler::kMinimalBufferSize * 2, &actual_size, true));
245  CHECK(buffer);
246  Isolate* isolate = CcTest::i_isolate();
247  HandleScope handles(isolate);
248  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
249
250  MacroAssembler* masm = &assembler;
251  EntryCode(masm);
252  Label exit;
253
254  TestSmiCompare(masm, &exit, 0x10, 0, 0);
255  TestSmiCompare(masm, &exit, 0x20, 0, 1);
256  TestSmiCompare(masm, &exit, 0x30, 1, 0);
257  TestSmiCompare(masm, &exit, 0x40, 1, 1);
258  TestSmiCompare(masm, &exit, 0x50, 0, -1);
259  TestSmiCompare(masm, &exit, 0x60, -1, 0);
260  TestSmiCompare(masm, &exit, 0x70, -1, -1);
261  TestSmiCompare(masm, &exit, 0x80, 0, Smi::kMinValue);
262  TestSmiCompare(masm, &exit, 0x90, Smi::kMinValue, 0);
263  TestSmiCompare(masm, &exit, 0xA0, 0, Smi::kMaxValue);
264  TestSmiCompare(masm, &exit, 0xB0, Smi::kMaxValue, 0);
265  TestSmiCompare(masm, &exit, 0xC0, -1, Smi::kMinValue);
266  TestSmiCompare(masm, &exit, 0xD0, Smi::kMinValue, -1);
267  TestSmiCompare(masm, &exit, 0xE0, -1, Smi::kMaxValue);
268  TestSmiCompare(masm, &exit, 0xF0, Smi::kMaxValue, -1);
269  TestSmiCompare(masm, &exit, 0x100, Smi::kMinValue, Smi::kMinValue);
270  TestSmiCompare(masm, &exit, 0x110, Smi::kMinValue, Smi::kMaxValue);
271  TestSmiCompare(masm, &exit, 0x120, Smi::kMaxValue, Smi::kMinValue);
272  TestSmiCompare(masm, &exit, 0x130, Smi::kMaxValue, Smi::kMaxValue);
273
274  __ xorq(rax, rax);  // Success.
275  __ bind(&exit);
276  ExitCode(masm);
277  __ ret(0);
278
279  CodeDesc desc;
280  masm->GetCode(&desc);
281  // Call the function from C++.
282  int result = FUNCTION_CAST<F0>(buffer)();
283  CHECK_EQ(0, result);
284}
285
286
287
288TEST(Integer32ToSmi) {
289  // Allocate an executable page of memory.
290  size_t actual_size;
291  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
292      Assembler::kMinimalBufferSize, &actual_size, true));
293  CHECK(buffer);
294  Isolate* isolate = CcTest::i_isolate();
295  HandleScope handles(isolate);
296  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
297
298  MacroAssembler* masm = &assembler;
299  EntryCode(masm);
300  Label exit;
301
302  __ movq(rax, Immediate(1));  // Test number.
303  __ movl(rcx, Immediate(0));
304  __ Integer32ToSmi(rcx, rcx);
305  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(0)));
306  __ cmpq(rcx, rdx);
307  __ j(not_equal, &exit);
308
309  __ movq(rax, Immediate(2));  // Test number.
310  __ movl(rcx, Immediate(1024));
311  __ Integer32ToSmi(rcx, rcx);
312  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(1024)));
313  __ cmpq(rcx, rdx);
314  __ j(not_equal, &exit);
315
316  __ movq(rax, Immediate(3));  // Test number.
317  __ movl(rcx, Immediate(-1));
318  __ Integer32ToSmi(rcx, rcx);
319  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(-1)));
320  __ cmpq(rcx, rdx);
321  __ j(not_equal, &exit);
322
323  __ movq(rax, Immediate(4));  // Test number.
324  __ movl(rcx, Immediate(Smi::kMaxValue));
325  __ Integer32ToSmi(rcx, rcx);
326  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMaxValue)));
327  __ cmpq(rcx, rdx);
328  __ j(not_equal, &exit);
329
330  __ movq(rax, Immediate(5));  // Test number.
331  __ movl(rcx, Immediate(Smi::kMinValue));
332  __ Integer32ToSmi(rcx, rcx);
333  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMinValue)));
334  __ cmpq(rcx, rdx);
335  __ j(not_equal, &exit);
336
337  // Different target register.
338
339  __ movq(rax, Immediate(6));  // Test number.
340  __ movl(rcx, Immediate(0));
341  __ Integer32ToSmi(r8, rcx);
342  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(0)));
343  __ cmpq(r8, rdx);
344  __ j(not_equal, &exit);
345
346  __ movq(rax, Immediate(7));  // Test number.
347  __ movl(rcx, Immediate(1024));
348  __ Integer32ToSmi(r8, rcx);
349  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(1024)));
350  __ cmpq(r8, rdx);
351  __ j(not_equal, &exit);
352
353  __ movq(rax, Immediate(8));  // Test number.
354  __ movl(rcx, Immediate(-1));
355  __ Integer32ToSmi(r8, rcx);
356  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(-1)));
357  __ cmpq(r8, rdx);
358  __ j(not_equal, &exit);
359
360  __ movq(rax, Immediate(9));  // Test number.
361  __ movl(rcx, Immediate(Smi::kMaxValue));
362  __ Integer32ToSmi(r8, rcx);
363  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMaxValue)));
364  __ cmpq(r8, rdx);
365  __ j(not_equal, &exit);
366
367  __ movq(rax, Immediate(10));  // Test number.
368  __ movl(rcx, Immediate(Smi::kMinValue));
369  __ Integer32ToSmi(r8, rcx);
370  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMinValue)));
371  __ cmpq(r8, rdx);
372  __ j(not_equal, &exit);
373
374
375  __ xorq(rax, rax);  // Success.
376  __ bind(&exit);
377  ExitCode(masm);
378  __ ret(0);
379
380  CodeDesc desc;
381  masm->GetCode(&desc);
382  // Call the function from C++.
383  int result = FUNCTION_CAST<F0>(buffer)();
384  CHECK_EQ(0, result);
385}
386
387
388void TestI64PlusConstantToSmi(MacroAssembler* masm,
389                              Label* exit,
390                              int id,
391                              int64_t x,
392                              int y) {
393  int64_t result = x + y;
394  DCHECK(Smi::IsValid(result));
395  __ movl(rax, Immediate(id));
396  __ Move(r8, Smi::FromInt(static_cast<int>(result)));
397  __ movq(rcx, x);
398  __ movq(r11, rcx);
399  __ Integer64PlusConstantToSmi(rdx, rcx, y);
400  __ cmpq(rdx, r8);
401  __ j(not_equal, exit);
402
403  __ incq(rax);
404  __ cmpq(r11, rcx);
405  __ j(not_equal, exit);
406
407  __ incq(rax);
408  __ Integer64PlusConstantToSmi(rcx, rcx, y);
409  __ cmpq(rcx, r8);
410  __ j(not_equal, exit);
411}
412
413
414TEST(Integer64PlusConstantToSmi) {
415  // Allocate an executable page of memory.
416  size_t actual_size;
417  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
418      Assembler::kMinimalBufferSize, &actual_size, true));
419  CHECK(buffer);
420  Isolate* isolate = CcTest::i_isolate();
421  HandleScope handles(isolate);
422  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
423
424  MacroAssembler* masm = &assembler;
425  EntryCode(masm);
426  Label exit;
427
428  int64_t twice_max = static_cast<int64_t>(Smi::kMaxValue) * 2;
429
430  TestI64PlusConstantToSmi(masm, &exit, 0x10, 0, 0);
431  TestI64PlusConstantToSmi(masm, &exit, 0x20, 0, 1);
432  TestI64PlusConstantToSmi(masm, &exit, 0x30, 1, 0);
433  TestI64PlusConstantToSmi(masm, &exit, 0x40, Smi::kMaxValue - 5, 5);
434  TestI64PlusConstantToSmi(masm, &exit, 0x50, Smi::kMinValue + 5, 5);
435  TestI64PlusConstantToSmi(masm, &exit, 0x60, twice_max, -Smi::kMaxValue);
436  TestI64PlusConstantToSmi(masm, &exit, 0x70, -twice_max, Smi::kMaxValue);
437  TestI64PlusConstantToSmi(masm, &exit, 0x80, 0, Smi::kMinValue);
438  TestI64PlusConstantToSmi(masm, &exit, 0x90, 0, Smi::kMaxValue);
439  TestI64PlusConstantToSmi(masm, &exit, 0xA0, Smi::kMinValue, 0);
440  TestI64PlusConstantToSmi(masm, &exit, 0xB0, Smi::kMaxValue, 0);
441  TestI64PlusConstantToSmi(masm, &exit, 0xC0, twice_max, Smi::kMinValue);
442
443  __ xorq(rax, rax);  // Success.
444  __ bind(&exit);
445  ExitCode(masm);
446  __ ret(0);
447
448  CodeDesc desc;
449  masm->GetCode(&desc);
450  // Call the function from C++.
451  int result = FUNCTION_CAST<F0>(buffer)();
452  CHECK_EQ(0, result);
453}
454
455
456TEST(SmiCheck) {
457  // Allocate an executable page of memory.
458  size_t actual_size;
459  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
460      Assembler::kMinimalBufferSize, &actual_size, true));
461  CHECK(buffer);
462  Isolate* isolate = CcTest::i_isolate();
463  HandleScope handles(isolate);
464  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
465
466  MacroAssembler* masm = &assembler;
467  EntryCode(masm);
468  Label exit;
469  Condition cond;
470
471  __ movl(rax, Immediate(1));  // Test number.
472
473  // CheckSmi
474
475  __ movl(rcx, Immediate(0));
476  __ Integer32ToSmi(rcx, rcx);
477  cond = masm->CheckSmi(rcx);
478  __ j(NegateCondition(cond), &exit);
479
480  __ incq(rax);
481  __ xorq(rcx, Immediate(kSmiTagMask));
482  cond = masm->CheckSmi(rcx);
483  __ j(cond, &exit);
484
485  __ incq(rax);
486  __ movl(rcx, Immediate(-1));
487  __ Integer32ToSmi(rcx, rcx);
488  cond = masm->CheckSmi(rcx);
489  __ j(NegateCondition(cond), &exit);
490
491  __ incq(rax);
492  __ xorq(rcx, Immediate(kSmiTagMask));
493  cond = masm->CheckSmi(rcx);
494  __ j(cond, &exit);
495
496  __ incq(rax);
497  __ movl(rcx, Immediate(Smi::kMaxValue));
498  __ Integer32ToSmi(rcx, rcx);
499  cond = masm->CheckSmi(rcx);
500  __ j(NegateCondition(cond), &exit);
501
502  __ incq(rax);
503  __ xorq(rcx, Immediate(kSmiTagMask));
504  cond = masm->CheckSmi(rcx);
505  __ j(cond, &exit);
506
507  __ incq(rax);
508  __ movl(rcx, Immediate(Smi::kMinValue));
509  __ Integer32ToSmi(rcx, rcx);
510  cond = masm->CheckSmi(rcx);
511  __ j(NegateCondition(cond), &exit);
512
513  __ incq(rax);
514  __ xorq(rcx, Immediate(kSmiTagMask));
515  cond = masm->CheckSmi(rcx);
516  __ j(cond, &exit);
517
518  // CheckPositiveSmi
519
520  __ incq(rax);
521  __ movl(rcx, Immediate(0));
522  __ Integer32ToSmi(rcx, rcx);
523  cond = masm->CheckNonNegativeSmi(rcx);
524  __ j(NegateCondition(cond), &exit);
525
526  __ incq(rax);
527  __ xorq(rcx, Immediate(kSmiTagMask));
528  cond = masm->CheckNonNegativeSmi(rcx);  // "zero" non-smi.
529  __ j(cond, &exit);
530
531  __ incq(rax);
532  __ movq(rcx, Immediate(-1));
533  __ Integer32ToSmi(rcx, rcx);
534  cond = masm->CheckNonNegativeSmi(rcx);  // Negative smis are not positive.
535  __ j(cond, &exit);
536
537  __ incq(rax);
538  __ movq(rcx, Immediate(Smi::kMinValue));
539  __ Integer32ToSmi(rcx, rcx);
540  cond = masm->CheckNonNegativeSmi(rcx);  // Most negative smi is not positive.
541  __ j(cond, &exit);
542
543  __ incq(rax);
544  __ xorq(rcx, Immediate(kSmiTagMask));
545  cond = masm->CheckNonNegativeSmi(rcx);  // "Negative" non-smi.
546  __ j(cond, &exit);
547
548  __ incq(rax);
549  __ movq(rcx, Immediate(Smi::kMaxValue));
550  __ Integer32ToSmi(rcx, rcx);
551  cond = masm->CheckNonNegativeSmi(rcx);  // Most positive smi is positive.
552  __ j(NegateCondition(cond), &exit);
553
554  __ incq(rax);
555  __ xorq(rcx, Immediate(kSmiTagMask));
556  cond = masm->CheckNonNegativeSmi(rcx);  // "Positive" non-smi.
557  __ j(cond, &exit);
558
559  // CheckIsMinSmi
560
561  __ incq(rax);
562  __ movq(rcx, Immediate(Smi::kMaxValue));
563  __ Integer32ToSmi(rcx, rcx);
564  cond = masm->CheckIsMinSmi(rcx);
565  __ j(cond, &exit);
566
567  __ incq(rax);
568  __ movq(rcx, Immediate(0));
569  __ Integer32ToSmi(rcx, rcx);
570  cond = masm->CheckIsMinSmi(rcx);
571  __ j(cond, &exit);
572
573  __ incq(rax);
574  __ movq(rcx, Immediate(Smi::kMinValue));
575  __ Integer32ToSmi(rcx, rcx);
576  cond = masm->CheckIsMinSmi(rcx);
577  __ j(NegateCondition(cond), &exit);
578
579  __ incq(rax);
580  __ movq(rcx, Immediate(Smi::kMinValue + 1));
581  __ Integer32ToSmi(rcx, rcx);
582  cond = masm->CheckIsMinSmi(rcx);
583  __ j(cond, &exit);
584
585  // CheckBothSmi
586
587  __ incq(rax);
588  __ movq(rcx, Immediate(Smi::kMaxValue));
589  __ Integer32ToSmi(rcx, rcx);
590  __ movq(rdx, Immediate(Smi::kMinValue));
591  __ Integer32ToSmi(rdx, rdx);
592  cond = masm->CheckBothSmi(rcx, rdx);
593  __ j(NegateCondition(cond), &exit);
594
595  __ incq(rax);
596  __ xorq(rcx, Immediate(kSmiTagMask));
597  cond = masm->CheckBothSmi(rcx, rdx);
598  __ j(cond, &exit);
599
600  __ incq(rax);
601  __ xorq(rdx, Immediate(kSmiTagMask));
602  cond = masm->CheckBothSmi(rcx, rdx);
603  __ j(cond, &exit);
604
605  __ incq(rax);
606  __ xorq(rcx, Immediate(kSmiTagMask));
607  cond = masm->CheckBothSmi(rcx, rdx);
608  __ j(cond, &exit);
609
610  __ incq(rax);
611  cond = masm->CheckBothSmi(rcx, rcx);
612  __ j(NegateCondition(cond), &exit);
613
614  __ incq(rax);
615  cond = masm->CheckBothSmi(rdx, rdx);
616  __ j(cond, &exit);
617
618  // CheckInteger32ValidSmiValue
619  __ incq(rax);
620  __ movq(rcx, Immediate(0));
621  cond = masm->CheckInteger32ValidSmiValue(rax);
622  __ j(NegateCondition(cond), &exit);
623
624  __ incq(rax);
625  __ movq(rcx, Immediate(-1));
626  cond = masm->CheckInteger32ValidSmiValue(rax);
627  __ j(NegateCondition(cond), &exit);
628
629  __ incq(rax);
630  __ movq(rcx, Immediate(Smi::kMaxValue));
631  cond = masm->CheckInteger32ValidSmiValue(rax);
632  __ j(NegateCondition(cond), &exit);
633
634  __ incq(rax);
635  __ movq(rcx, Immediate(Smi::kMinValue));
636  cond = masm->CheckInteger32ValidSmiValue(rax);
637  __ j(NegateCondition(cond), &exit);
638
639  // Success
640  __ xorq(rax, rax);
641
642  __ bind(&exit);
643  ExitCode(masm);
644  __ ret(0);
645
646  CodeDesc desc;
647  masm->GetCode(&desc);
648  // Call the function from C++.
649  int result = FUNCTION_CAST<F0>(buffer)();
650  CHECK_EQ(0, result);
651}
652
653
654
655void TestSmiNeg(MacroAssembler* masm, Label* exit, int id, int x) {
656  __ Move(rcx, Smi::FromInt(x));
657  __ movq(r11, rcx);
658  if (x == Smi::kMinValue || x == 0) {
659    // Negation fails.
660    __ movl(rax, Immediate(id + 8));
661    __ SmiNeg(r9, rcx, exit);
662
663    __ incq(rax);
664    __ cmpq(r11, rcx);
665    __ j(not_equal, exit);
666
667    __ incq(rax);
668    __ SmiNeg(rcx, rcx, exit);
669
670    __ incq(rax);
671    __ cmpq(r11, rcx);
672    __ j(not_equal, exit);
673  } else {
674    Label smi_ok, smi_ok2;
675    int result = -x;
676    __ movl(rax, Immediate(id));
677    __ Move(r8, Smi::FromInt(result));
678
679    __ SmiNeg(r9, rcx, &smi_ok);
680    __ jmp(exit);
681    __ bind(&smi_ok);
682    __ incq(rax);
683    __ cmpq(r9, r8);
684    __ j(not_equal, exit);
685
686    __ incq(rax);
687    __ cmpq(r11, rcx);
688    __ j(not_equal, exit);
689
690    __ incq(rax);
691    __ SmiNeg(rcx, rcx, &smi_ok2);
692    __ jmp(exit);
693    __ bind(&smi_ok2);
694    __ incq(rax);
695    __ cmpq(rcx, r8);
696    __ j(not_equal, exit);
697  }
698}
699
700
701TEST(SmiNeg) {
702  // Allocate an executable page of memory.
703  size_t actual_size;
704  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
705      Assembler::kMinimalBufferSize, &actual_size, true));
706  CHECK(buffer);
707  Isolate* isolate = CcTest::i_isolate();
708  HandleScope handles(isolate);
709  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
710
711  MacroAssembler* masm = &assembler;
712  EntryCode(masm);
713  Label exit;
714
715  TestSmiNeg(masm, &exit, 0x10, 0);
716  TestSmiNeg(masm, &exit, 0x20, 1);
717  TestSmiNeg(masm, &exit, 0x30, -1);
718  TestSmiNeg(masm, &exit, 0x40, 127);
719  TestSmiNeg(masm, &exit, 0x50, 65535);
720  TestSmiNeg(masm, &exit, 0x60, Smi::kMinValue);
721  TestSmiNeg(masm, &exit, 0x70, Smi::kMaxValue);
722  TestSmiNeg(masm, &exit, 0x80, -Smi::kMaxValue);
723
724  __ xorq(rax, rax);  // Success.
725  __ bind(&exit);
726  ExitCode(masm);
727  __ ret(0);
728
729  CodeDesc desc;
730  masm->GetCode(&desc);
731  // Call the function from C++.
732  int result = FUNCTION_CAST<F0>(buffer)();
733  CHECK_EQ(0, result);
734}
735
736
737static void SmiAddTest(MacroAssembler* masm,
738                       Label* exit,
739                       int id,
740                       int first,
741                       int second) {
742  __ movl(rcx, Immediate(first));
743  __ Integer32ToSmi(rcx, rcx);
744  __ movl(rdx, Immediate(second));
745  __ Integer32ToSmi(rdx, rdx);
746  __ movl(r8, Immediate(first + second));
747  __ Integer32ToSmi(r8, r8);
748
749  __ movl(rax, Immediate(id));  // Test number.
750  __ SmiAdd(r9, rcx, rdx, exit);
751  __ cmpq(r9, r8);
752  __ j(not_equal, exit);
753
754  __ incq(rax);
755  __ SmiAdd(rcx, rcx, rdx, exit);
756  __ cmpq(rcx, r8);
757  __ j(not_equal, exit);
758
759  __ movl(rcx, Immediate(first));
760  __ Integer32ToSmi(rcx, rcx);
761
762  __ incq(rax);
763  __ SmiAddConstant(r9, rcx, Smi::FromInt(second));
764  __ cmpq(r9, r8);
765  __ j(not_equal, exit);
766
767  __ SmiAddConstant(rcx, rcx, Smi::FromInt(second));
768  __ cmpq(rcx, r8);
769  __ j(not_equal, exit);
770
771  __ movl(rcx, Immediate(first));
772  __ Integer32ToSmi(rcx, rcx);
773
774  i::SmiOperationExecutionMode mode;
775  mode.Add(i::PRESERVE_SOURCE_REGISTER);
776  mode.Add(i::BAILOUT_ON_OVERFLOW);
777  __ incq(rax);
778  __ SmiAddConstant(r9, rcx, Smi::FromInt(second), mode, exit);
779  __ cmpq(r9, r8);
780  __ j(not_equal, exit);
781
782  __ incq(rax);
783  __ SmiAddConstant(rcx, rcx, Smi::FromInt(second), mode, exit);
784  __ cmpq(rcx, r8);
785  __ j(not_equal, exit);
786
787  __ movl(rcx, Immediate(first));
788  __ Integer32ToSmi(rcx, rcx);
789
790  mode.RemoveAll();
791  mode.Add(i::PRESERVE_SOURCE_REGISTER);
792  mode.Add(i::BAILOUT_ON_NO_OVERFLOW);
793  Label done;
794  __ incq(rax);
795  __ SmiAddConstant(rcx, rcx, Smi::FromInt(second), mode, &done);
796  __ jmp(exit);
797  __ bind(&done);
798  __ cmpq(rcx, r8);
799  __ j(not_equal, exit);
800}
801
802
803static void SmiAddOverflowTest(MacroAssembler* masm,
804                               Label* exit,
805                               int id,
806                               int x) {
807  // Adds a Smi to x so that the addition overflows.
808  DCHECK(x != 0);  // Can't overflow by adding a Smi.
809  int y_max = (x > 0) ? (Smi::kMaxValue + 0) : (Smi::kMinValue - x - 1);
810  int y_min = (x > 0) ? (Smi::kMaxValue - x + 1) : (Smi::kMinValue + 0);
811
812  __ movl(rax, Immediate(id));
813  __ Move(rcx, Smi::FromInt(x));
814  __ movq(r11, rcx);  // Store original Smi value of x in r11.
815  __ Move(rdx, Smi::FromInt(y_min));
816  {
817    Label overflow_ok;
818    __ SmiAdd(r9, rcx, rdx, &overflow_ok);
819    __ jmp(exit);
820    __ bind(&overflow_ok);
821    __ incq(rax);
822    __ cmpq(rcx, r11);
823    __ j(not_equal, exit);
824  }
825
826  {
827    Label overflow_ok;
828    __ incq(rax);
829    __ SmiAdd(rcx, rcx, rdx, &overflow_ok);
830    __ jmp(exit);
831    __ bind(&overflow_ok);
832    __ incq(rax);
833    __ cmpq(rcx, r11);
834    __ j(not_equal, exit);
835  }
836
837  i::SmiOperationExecutionMode mode;
838  mode.Add(i::PRESERVE_SOURCE_REGISTER);
839  mode.Add(i::BAILOUT_ON_OVERFLOW);
840  __ movq(rcx, r11);
841  {
842    Label overflow_ok;
843    __ incq(rax);
844    __ SmiAddConstant(r9, rcx, Smi::FromInt(y_min), mode, &overflow_ok);
845    __ jmp(exit);
846    __ bind(&overflow_ok);
847    __ incq(rax);
848    __ cmpq(rcx, r11);
849    __ j(not_equal, exit);
850  }
851
852  {
853    Label overflow_ok;
854    __ incq(rax);
855    __ SmiAddConstant(rcx, rcx, Smi::FromInt(y_min), mode, &overflow_ok);
856    __ jmp(exit);
857    __ bind(&overflow_ok);
858    __ incq(rax);
859    __ cmpq(rcx, r11);
860    __ j(not_equal, exit);
861  }
862
863  __ Move(rdx, Smi::FromInt(y_max));
864
865  {
866    Label overflow_ok;
867    __ incq(rax);
868    __ SmiAdd(r9, rcx, rdx, &overflow_ok);
869    __ jmp(exit);
870    __ bind(&overflow_ok);
871    __ incq(rax);
872    __ cmpq(rcx, r11);
873    __ j(not_equal, exit);
874  }
875
876  {
877    Label overflow_ok;
878    __ incq(rax);
879    __ SmiAdd(rcx, rcx, rdx, &overflow_ok);
880    __ jmp(exit);
881    __ bind(&overflow_ok);
882    __ incq(rax);
883    __ cmpq(rcx, r11);
884    __ j(not_equal, exit);
885  }
886
887  __ movq(rcx, r11);
888  {
889    Label overflow_ok;
890    __ incq(rax);
891    __ SmiAddConstant(r9, rcx, Smi::FromInt(y_max), mode, &overflow_ok);
892    __ jmp(exit);
893    __ bind(&overflow_ok);
894    __ incq(rax);
895    __ cmpq(rcx, r11);
896    __ j(not_equal, exit);
897  }
898
899  mode.RemoveAll();
900  mode.Add(i::BAILOUT_ON_OVERFLOW);
901  {
902    Label overflow_ok;
903    __ incq(rax);
904    __ SmiAddConstant(rcx, rcx, Smi::FromInt(y_max), mode, &overflow_ok);
905    __ jmp(exit);
906    __ bind(&overflow_ok);
907    __ incq(rax);
908    __ cmpq(rcx, r11);
909    __ j(equal, exit);
910  }
911}
912
913
914TEST(SmiAdd) {
915  // Allocate an executable page of memory.
916  size_t actual_size;
917  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
918      Assembler::kMinimalBufferSize * 3, &actual_size, true));
919  CHECK(buffer);
920  Isolate* isolate = CcTest::i_isolate();
921  HandleScope handles(isolate);
922  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
923
924  MacroAssembler* masm = &assembler;
925  EntryCode(masm);
926  Label exit;
927
928  // No-overflow tests.
929  SmiAddTest(masm, &exit, 0x10, 1, 2);
930  SmiAddTest(masm, &exit, 0x20, 1, -2);
931  SmiAddTest(masm, &exit, 0x30, -1, 2);
932  SmiAddTest(masm, &exit, 0x40, -1, -2);
933  SmiAddTest(masm, &exit, 0x50, 0x1000, 0x2000);
934  SmiAddTest(masm, &exit, 0x60, Smi::kMinValue, 5);
935  SmiAddTest(masm, &exit, 0x70, Smi::kMaxValue, -5);
936  SmiAddTest(masm, &exit, 0x80, Smi::kMaxValue, Smi::kMinValue);
937
938  SmiAddOverflowTest(masm, &exit, 0x90, -1);
939  SmiAddOverflowTest(masm, &exit, 0xA0, 1);
940  SmiAddOverflowTest(masm, &exit, 0xB0, 1024);
941  SmiAddOverflowTest(masm, &exit, 0xC0, Smi::kMaxValue);
942  SmiAddOverflowTest(masm, &exit, 0xD0, -2);
943  SmiAddOverflowTest(masm, &exit, 0xE0, -42000);
944  SmiAddOverflowTest(masm, &exit, 0xF0, Smi::kMinValue);
945
946  __ xorq(rax, rax);  // Success.
947  __ bind(&exit);
948  ExitCode(masm);
949  __ ret(0);
950
951  CodeDesc desc;
952  masm->GetCode(&desc);
953  // Call the function from C++.
954  int result = FUNCTION_CAST<F0>(buffer)();
955  CHECK_EQ(0, result);
956}
957
958
959static void SmiSubTest(MacroAssembler* masm,
960                      Label* exit,
961                      int id,
962                      int first,
963                      int second) {
964  __ Move(rcx, Smi::FromInt(first));
965  __ Move(rdx, Smi::FromInt(second));
966  __ Move(r8, Smi::FromInt(first - second));
967
968  __ movl(rax, Immediate(id));  // Test 0.
969  __ SmiSub(r9, rcx, rdx, exit);
970  __ cmpq(r9, r8);
971  __ j(not_equal, exit);
972
973  __ incq(rax);  // Test 1.
974  __ SmiSub(rcx, rcx, rdx, exit);
975  __ cmpq(rcx, r8);
976  __ j(not_equal, exit);
977
978  __ Move(rcx, Smi::FromInt(first));
979
980  __ incq(rax);  // Test 2.
981  __ SmiSubConstant(r9, rcx, Smi::FromInt(second));
982  __ cmpq(r9, r8);
983  __ j(not_equal, exit);
984
985  __ incq(rax);  // Test 3.
986  __ SmiSubConstant(rcx, rcx, Smi::FromInt(second));
987  __ cmpq(rcx, r8);
988  __ j(not_equal, exit);
989
990  i::SmiOperationExecutionMode mode;
991  mode.Add(i::PRESERVE_SOURCE_REGISTER);
992  mode.Add(i::BAILOUT_ON_OVERFLOW);
993  __ Move(rcx, Smi::FromInt(first));
994  __ incq(rax);  // Test 4.
995  __ SmiSubConstant(rcx, rcx, Smi::FromInt(second), mode, exit);
996  __ cmpq(rcx, r8);
997  __ j(not_equal, exit);
998
999  __ Move(rcx, Smi::FromInt(first));
1000  __ incq(rax);  // Test 5.
1001  __ SmiSubConstant(r9, rcx, Smi::FromInt(second), mode, exit);
1002  __ cmpq(r9, r8);
1003  __ j(not_equal, exit);
1004
1005  mode.RemoveAll();
1006  mode.Add(i::PRESERVE_SOURCE_REGISTER);
1007  mode.Add(i::BAILOUT_ON_NO_OVERFLOW);
1008  __ Move(rcx, Smi::FromInt(first));
1009  Label done;
1010  __ incq(rax);  // Test 6.
1011  __ SmiSubConstant(rcx, rcx, Smi::FromInt(second), mode, &done);
1012  __ jmp(exit);
1013  __ bind(&done);
1014  __ cmpq(rcx, r8);
1015  __ j(not_equal, exit);
1016}
1017
1018
1019static void SmiSubOverflowTest(MacroAssembler* masm,
1020                               Label* exit,
1021                               int id,
1022                               int x) {
1023  // Subtracts a Smi from x so that the subtraction overflows.
1024  DCHECK(x != -1);  // Can't overflow by subtracting a Smi.
1025  int y_max = (x < 0) ? (Smi::kMaxValue + 0) : (Smi::kMinValue + 0);
1026  int y_min = (x < 0) ? (Smi::kMaxValue + x + 2) : (Smi::kMinValue + x);
1027
1028  __ movl(rax, Immediate(id));
1029  __ Move(rcx, Smi::FromInt(x));
1030  __ movq(r11, rcx);  // Store original Smi value of x in r11.
1031  __ Move(rdx, Smi::FromInt(y_min));
1032  {
1033    Label overflow_ok;
1034    __ SmiSub(r9, rcx, rdx, &overflow_ok);
1035    __ jmp(exit);
1036    __ bind(&overflow_ok);
1037    __ incq(rax);
1038    __ cmpq(rcx, r11);
1039    __ j(not_equal, exit);
1040  }
1041
1042  {
1043    Label overflow_ok;
1044    __ incq(rax);
1045    __ SmiSub(rcx, rcx, rdx, &overflow_ok);
1046    __ jmp(exit);
1047    __ bind(&overflow_ok);
1048    __ incq(rax);
1049    __ cmpq(rcx, r11);
1050    __ j(not_equal, exit);
1051  }
1052
1053  i::SmiOperationExecutionMode mode;
1054  mode.Add(i::PRESERVE_SOURCE_REGISTER);
1055  mode.Add(i::BAILOUT_ON_OVERFLOW);
1056
1057  __ movq(rcx, r11);
1058  {
1059    Label overflow_ok;
1060    __ incq(rax);
1061    __ SmiSubConstant(r9, rcx, Smi::FromInt(y_min), mode, &overflow_ok);
1062    __ jmp(exit);
1063    __ bind(&overflow_ok);
1064    __ incq(rax);
1065    __ cmpq(rcx, r11);
1066    __ j(not_equal, exit);
1067  }
1068
1069  {
1070    Label overflow_ok;
1071    __ incq(rax);
1072    __ SmiSubConstant(rcx, rcx, Smi::FromInt(y_min), mode, &overflow_ok);
1073    __ jmp(exit);
1074    __ bind(&overflow_ok);
1075    __ incq(rax);
1076    __ cmpq(rcx, r11);
1077    __ j(not_equal, exit);
1078  }
1079
1080  __ Move(rdx, Smi::FromInt(y_max));
1081
1082  {
1083    Label overflow_ok;
1084    __ incq(rax);
1085    __ SmiSub(r9, rcx, rdx, &overflow_ok);
1086    __ jmp(exit);
1087    __ bind(&overflow_ok);
1088    __ incq(rax);
1089    __ cmpq(rcx, r11);
1090    __ j(not_equal, exit);
1091  }
1092
1093  {
1094    Label overflow_ok;
1095    __ incq(rax);
1096    __ SmiSub(rcx, rcx, rdx, &overflow_ok);
1097    __ jmp(exit);
1098    __ bind(&overflow_ok);
1099    __ incq(rax);
1100    __ cmpq(rcx, r11);
1101    __ j(not_equal, exit);
1102  }
1103
1104  __ movq(rcx, r11);
1105  {
1106    Label overflow_ok;
1107    __ incq(rax);
1108    __ SmiSubConstant(rcx, rcx, Smi::FromInt(y_max), mode, &overflow_ok);
1109    __ jmp(exit);
1110    __ bind(&overflow_ok);
1111    __ incq(rax);
1112    __ cmpq(rcx, r11);
1113    __ j(not_equal, exit);
1114  }
1115
1116  mode.RemoveAll();
1117  mode.Add(i::BAILOUT_ON_OVERFLOW);
1118  __ movq(rcx, r11);
1119  {
1120    Label overflow_ok;
1121    __ incq(rax);
1122    __ SmiSubConstant(rcx, rcx, Smi::FromInt(y_max), mode, &overflow_ok);
1123    __ jmp(exit);
1124    __ bind(&overflow_ok);
1125    __ incq(rax);
1126    __ cmpq(rcx, r11);
1127    __ j(equal, exit);
1128  }
1129}
1130
1131
1132TEST(SmiSub) {
1133  // Allocate an executable page of memory.
1134  size_t actual_size;
1135  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
1136      Assembler::kMinimalBufferSize * 4, &actual_size, true));
1137  CHECK(buffer);
1138  Isolate* isolate = CcTest::i_isolate();
1139  HandleScope handles(isolate);
1140  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1141
1142  MacroAssembler* masm = &assembler;
1143  EntryCode(masm);
1144  Label exit;
1145
1146  SmiSubTest(masm, &exit, 0x10, 1, 2);
1147  SmiSubTest(masm, &exit, 0x20, 1, -2);
1148  SmiSubTest(masm, &exit, 0x30, -1, 2);
1149  SmiSubTest(masm, &exit, 0x40, -1, -2);
1150  SmiSubTest(masm, &exit, 0x50, 0x1000, 0x2000);
1151  SmiSubTest(masm, &exit, 0x60, Smi::kMinValue, -5);
1152  SmiSubTest(masm, &exit, 0x70, Smi::kMaxValue, 5);
1153  SmiSubTest(masm, &exit, 0x80, -Smi::kMaxValue, Smi::kMinValue);
1154  SmiSubTest(masm, &exit, 0x90, 0, Smi::kMaxValue);
1155
1156  SmiSubOverflowTest(masm, &exit, 0xA0, 1);
1157  SmiSubOverflowTest(masm, &exit, 0xB0, 1024);
1158  SmiSubOverflowTest(masm, &exit, 0xC0, Smi::kMaxValue);
1159  SmiSubOverflowTest(masm, &exit, 0xD0, -2);
1160  SmiSubOverflowTest(masm, &exit, 0xE0, -42000);
1161  SmiSubOverflowTest(masm, &exit, 0xF0, Smi::kMinValue);
1162  SmiSubOverflowTest(masm, &exit, 0x100, 0);
1163
1164  __ xorq(rax, rax);  // Success.
1165  __ bind(&exit);
1166  ExitCode(masm);
1167  __ ret(0);
1168
1169  CodeDesc desc;
1170  masm->GetCode(&desc);
1171  // Call the function from C++.
1172  int result = FUNCTION_CAST<F0>(buffer)();
1173  CHECK_EQ(0, result);
1174}
1175
1176
1177
1178void TestSmiMul(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1179  int64_t result = static_cast<int64_t>(x) * static_cast<int64_t>(y);
1180  bool negative_zero = (result == 0) && (x < 0 || y < 0);
1181  __ Move(rcx, Smi::FromInt(x));
1182  __ movq(r11, rcx);
1183  __ Move(rdx, Smi::FromInt(y));
1184  if (Smi::IsValid(result) && !negative_zero) {
1185    __ movl(rax, Immediate(id));
1186    __ Move(r8, Smi::FromIntptr(result));
1187    __ SmiMul(r9, rcx, rdx, exit);
1188    __ incq(rax);
1189    __ cmpq(r11, rcx);
1190    __ j(not_equal, exit);
1191    __ incq(rax);
1192    __ cmpq(r9, r8);
1193    __ j(not_equal, exit);
1194
1195    __ incq(rax);
1196    __ SmiMul(rcx, rcx, rdx, exit);
1197    __ cmpq(rcx, r8);
1198    __ j(not_equal, exit);
1199  } else {
1200    __ movl(rax, Immediate(id + 8));
1201    Label overflow_ok, overflow_ok2;
1202    __ SmiMul(r9, rcx, rdx, &overflow_ok);
1203    __ jmp(exit);
1204    __ bind(&overflow_ok);
1205    __ incq(rax);
1206    __ cmpq(r11, rcx);
1207    __ j(not_equal, exit);
1208    __ incq(rax);
1209    __ SmiMul(rcx, rcx, rdx, &overflow_ok2);
1210    __ jmp(exit);
1211    __ bind(&overflow_ok2);
1212    // 31-bit version doesn't preserve rcx on failure.
1213    // __ incq(rax);
1214    // __ cmpq(r11, rcx);
1215    // __ j(not_equal, exit);
1216  }
1217}
1218
1219
1220TEST(SmiMul) {
1221  // Allocate an executable page of memory.
1222  size_t actual_size;
1223  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
1224      Assembler::kMinimalBufferSize, &actual_size, true));
1225  CHECK(buffer);
1226  Isolate* isolate = CcTest::i_isolate();
1227  HandleScope handles(isolate);
1228  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1229
1230  MacroAssembler* masm = &assembler;
1231  EntryCode(masm);
1232  Label exit;
1233
1234  TestSmiMul(masm, &exit, 0x10, 0, 0);
1235  TestSmiMul(masm, &exit, 0x20, -1, 0);
1236  TestSmiMul(masm, &exit, 0x30, 0, -1);
1237  TestSmiMul(masm, &exit, 0x40, -1, -1);
1238  TestSmiMul(masm, &exit, 0x50, 0x10000, 0x10000);
1239  TestSmiMul(masm, &exit, 0x60, 0x10000, 0xffff);
1240  TestSmiMul(masm, &exit, 0x70, 0x10000, 0xffff);
1241  TestSmiMul(masm, &exit, 0x80, Smi::kMaxValue, -1);
1242  TestSmiMul(masm, &exit, 0x90, Smi::kMaxValue, -2);
1243  TestSmiMul(masm, &exit, 0xa0, Smi::kMaxValue, 2);
1244  TestSmiMul(masm, &exit, 0xb0, (Smi::kMaxValue / 2), 2);
1245  TestSmiMul(masm, &exit, 0xc0, (Smi::kMaxValue / 2) + 1, 2);
1246  TestSmiMul(masm, &exit, 0xd0, (Smi::kMinValue / 2), 2);
1247  TestSmiMul(masm, &exit, 0xe0, (Smi::kMinValue / 2) - 1, 2);
1248
1249  __ xorq(rax, rax);  // Success.
1250  __ bind(&exit);
1251  ExitCode(masm);
1252  __ ret(0);
1253
1254  CodeDesc desc;
1255  masm->GetCode(&desc);
1256  // Call the function from C++.
1257  int result = FUNCTION_CAST<F0>(buffer)();
1258  CHECK_EQ(0, result);
1259}
1260
1261
1262void TestSmiDiv(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1263  bool division_by_zero = (y == 0);
1264  bool negative_zero = (x == 0 && y < 0);
1265#if V8_TARGET_ARCH_X64
1266  bool overflow = (x == Smi::kMinValue && y < 0);  // Safe approx. used.
1267#else
1268  bool overflow = (x == Smi::kMinValue && y == -1);
1269#endif
1270  bool fraction = !division_by_zero && !overflow && (x % y != 0);
1271  __ Move(r11, Smi::FromInt(x));
1272  __ Move(r14, Smi::FromInt(y));
1273  if (!fraction && !overflow && !negative_zero && !division_by_zero) {
1274    // Division succeeds
1275    __ movq(rcx, r11);
1276    __ movq(r15, Immediate(id));
1277    int result = x / y;
1278    __ Move(r8, Smi::FromInt(result));
1279    __ SmiDiv(r9, rcx, r14, exit);
1280    // Might have destroyed rcx and r14.
1281    __ incq(r15);
1282    __ cmpq(r9, r8);
1283    __ j(not_equal, exit);
1284
1285    __ incq(r15);
1286    __ movq(rcx, r11);
1287    __ Move(r14, Smi::FromInt(y));
1288    __ cmpq(rcx, r11);
1289    __ j(not_equal, exit);
1290
1291    __ incq(r15);
1292    __ SmiDiv(rcx, rcx, r14, exit);
1293
1294    __ incq(r15);
1295    __ cmpq(rcx, r8);
1296    __ j(not_equal, exit);
1297  } else {
1298    // Division fails.
1299    __ movq(r15, Immediate(id + 8));
1300
1301    Label fail_ok, fail_ok2;
1302    __ movq(rcx, r11);
1303    __ SmiDiv(r9, rcx, r14, &fail_ok);
1304    __ jmp(exit);
1305    __ bind(&fail_ok);
1306
1307    __ incq(r15);
1308    __ cmpq(rcx, r11);
1309    __ j(not_equal, exit);
1310
1311    __ incq(r15);
1312    __ SmiDiv(rcx, rcx, r14, &fail_ok2);
1313    __ jmp(exit);
1314    __ bind(&fail_ok2);
1315
1316    __ incq(r15);
1317    __ cmpq(rcx, r11);
1318    __ j(not_equal, exit);
1319  }
1320}
1321
1322
1323TEST(SmiDiv) {
1324  // Allocate an executable page of memory.
1325  size_t actual_size;
1326  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
1327      Assembler::kMinimalBufferSize * 2, &actual_size, true));
1328  CHECK(buffer);
1329  Isolate* isolate = CcTest::i_isolate();
1330  HandleScope handles(isolate);
1331  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1332
1333  MacroAssembler* masm = &assembler;
1334  EntryCode(masm);
1335  Label exit;
1336
1337  __ pushq(r14);
1338  __ pushq(r15);
1339  TestSmiDiv(masm, &exit, 0x10, 1, 1);
1340  TestSmiDiv(masm, &exit, 0x20, 1, 0);
1341  TestSmiDiv(masm, &exit, 0x30, -1, 0);
1342  TestSmiDiv(masm, &exit, 0x40, 0, 1);
1343  TestSmiDiv(masm, &exit, 0x50, 0, -1);
1344  TestSmiDiv(masm, &exit, 0x60, 4, 2);
1345  TestSmiDiv(masm, &exit, 0x70, -4, 2);
1346  TestSmiDiv(masm, &exit, 0x80, 4, -2);
1347  TestSmiDiv(masm, &exit, 0x90, -4, -2);
1348  TestSmiDiv(masm, &exit, 0xa0, 3, 2);
1349  TestSmiDiv(masm, &exit, 0xb0, 3, 4);
1350  TestSmiDiv(masm, &exit, 0xc0, 1, Smi::kMaxValue);
1351  TestSmiDiv(masm, &exit, 0xd0, -1, Smi::kMaxValue);
1352  TestSmiDiv(masm, &exit, 0xe0, Smi::kMaxValue, 1);
1353  TestSmiDiv(masm, &exit, 0xf0, Smi::kMaxValue, Smi::kMaxValue);
1354  TestSmiDiv(masm, &exit, 0x100, Smi::kMaxValue, -Smi::kMaxValue);
1355  TestSmiDiv(masm, &exit, 0x110, Smi::kMaxValue, -1);
1356  TestSmiDiv(masm, &exit, 0x120, Smi::kMinValue, 1);
1357  TestSmiDiv(masm, &exit, 0x130, Smi::kMinValue, Smi::kMinValue);
1358  TestSmiDiv(masm, &exit, 0x140, Smi::kMinValue, -1);
1359
1360  __ xorq(r15, r15);  // Success.
1361  __ bind(&exit);
1362  __ movq(rax, r15);
1363  __ popq(r15);
1364  __ popq(r14);
1365  ExitCode(masm);
1366  __ ret(0);
1367
1368  CodeDesc desc;
1369  masm->GetCode(&desc);
1370  // Call the function from C++.
1371  int result = FUNCTION_CAST<F0>(buffer)();
1372  CHECK_EQ(0, result);
1373}
1374
1375
1376void TestSmiMod(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1377  bool division_by_zero = (y == 0);
1378  bool division_overflow = (x == Smi::kMinValue) && (y == -1);
1379  bool fraction = !division_by_zero && !division_overflow && ((x % y) != 0);
1380  bool negative_zero = (!fraction && x < 0);
1381  __ Move(rcx, Smi::FromInt(x));
1382  __ movq(r11, rcx);
1383  __ Move(r14, Smi::FromInt(y));
1384  if (!division_overflow && !negative_zero && !division_by_zero) {
1385    // Modulo succeeds
1386    __ movq(r15, Immediate(id));
1387    int result = x % y;
1388    __ Move(r8, Smi::FromInt(result));
1389    __ SmiMod(r9, rcx, r14, exit);
1390
1391    __ incq(r15);
1392    __ cmpq(r9, r8);
1393    __ j(not_equal, exit);
1394
1395    __ incq(r15);
1396    __ cmpq(rcx, r11);
1397    __ j(not_equal, exit);
1398
1399    __ incq(r15);
1400    __ SmiMod(rcx, rcx, r14, exit);
1401
1402    __ incq(r15);
1403    __ cmpq(rcx, r8);
1404    __ j(not_equal, exit);
1405  } else {
1406    // Modulo fails.
1407    __ movq(r15, Immediate(id + 8));
1408
1409    Label fail_ok, fail_ok2;
1410    __ SmiMod(r9, rcx, r14, &fail_ok);
1411    __ jmp(exit);
1412    __ bind(&fail_ok);
1413
1414    __ incq(r15);
1415    __ cmpq(rcx, r11);
1416    __ j(not_equal, exit);
1417
1418    __ incq(r15);
1419    __ SmiMod(rcx, rcx, r14, &fail_ok2);
1420    __ jmp(exit);
1421    __ bind(&fail_ok2);
1422
1423    __ incq(r15);
1424    __ cmpq(rcx, r11);
1425    __ j(not_equal, exit);
1426  }
1427}
1428
1429
1430TEST(SmiMod) {
1431  // Allocate an executable page of memory.
1432  size_t actual_size;
1433  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
1434      Assembler::kMinimalBufferSize * 2, &actual_size, true));
1435  CHECK(buffer);
1436  Isolate* isolate = CcTest::i_isolate();
1437  HandleScope handles(isolate);
1438  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1439
1440  MacroAssembler* masm = &assembler;
1441  EntryCode(masm);
1442  Label exit;
1443
1444  __ pushq(r14);
1445  __ pushq(r15);
1446  TestSmiMod(masm, &exit, 0x10, 1, 1);
1447  TestSmiMod(masm, &exit, 0x20, 1, 0);
1448  TestSmiMod(masm, &exit, 0x30, -1, 0);
1449  TestSmiMod(masm, &exit, 0x40, 0, 1);
1450  TestSmiMod(masm, &exit, 0x50, 0, -1);
1451  TestSmiMod(masm, &exit, 0x60, 4, 2);
1452  TestSmiMod(masm, &exit, 0x70, -4, 2);
1453  TestSmiMod(masm, &exit, 0x80, 4, -2);
1454  TestSmiMod(masm, &exit, 0x90, -4, -2);
1455  TestSmiMod(masm, &exit, 0xa0, 3, 2);
1456  TestSmiMod(masm, &exit, 0xb0, 3, 4);
1457  TestSmiMod(masm, &exit, 0xc0, 1, Smi::kMaxValue);
1458  TestSmiMod(masm, &exit, 0xd0, -1, Smi::kMaxValue);
1459  TestSmiMod(masm, &exit, 0xe0, Smi::kMaxValue, 1);
1460  TestSmiMod(masm, &exit, 0xf0, Smi::kMaxValue, Smi::kMaxValue);
1461  TestSmiMod(masm, &exit, 0x100, Smi::kMaxValue, -Smi::kMaxValue);
1462  TestSmiMod(masm, &exit, 0x110, Smi::kMaxValue, -1);
1463  TestSmiMod(masm, &exit, 0x120, Smi::kMinValue, 1);
1464  TestSmiMod(masm, &exit, 0x130, Smi::kMinValue, Smi::kMinValue);
1465  TestSmiMod(masm, &exit, 0x140, Smi::kMinValue, -1);
1466
1467  __ xorq(r15, r15);  // Success.
1468  __ bind(&exit);
1469  __ movq(rax, r15);
1470  __ popq(r15);
1471  __ popq(r14);
1472  ExitCode(masm);
1473  __ ret(0);
1474
1475  CodeDesc desc;
1476  masm->GetCode(&desc);
1477  // Call the function from C++.
1478  int result = FUNCTION_CAST<F0>(buffer)();
1479  CHECK_EQ(0, result);
1480}
1481
1482
1483void TestSmiIndex(MacroAssembler* masm, Label* exit, int id, int x) {
1484  __ movl(rax, Immediate(id));
1485
1486  for (int i = 0; i < 8; i++) {
1487    __ Move(rcx, Smi::FromInt(x));
1488    SmiIndex index = masm->SmiToIndex(rdx, rcx, i);
1489    DCHECK(index.reg.is(rcx) || index.reg.is(rdx));
1490    __ shlq(index.reg, Immediate(index.scale));
1491    __ Set(r8, static_cast<intptr_t>(x) << i);
1492    __ cmpq(index.reg, r8);
1493    __ j(not_equal, exit);
1494    __ incq(rax);
1495    __ Move(rcx, Smi::FromInt(x));
1496    index = masm->SmiToIndex(rcx, rcx, i);
1497    DCHECK(index.reg.is(rcx));
1498    __ shlq(rcx, Immediate(index.scale));
1499    __ Set(r8, static_cast<intptr_t>(x) << i);
1500    __ cmpq(rcx, r8);
1501    __ j(not_equal, exit);
1502    __ incq(rax);
1503
1504    __ Move(rcx, Smi::FromInt(x));
1505    index = masm->SmiToNegativeIndex(rdx, rcx, i);
1506    DCHECK(index.reg.is(rcx) || index.reg.is(rdx));
1507    __ shlq(index.reg, Immediate(index.scale));
1508    __ Set(r8, static_cast<intptr_t>(-x) << i);
1509    __ cmpq(index.reg, r8);
1510    __ j(not_equal, exit);
1511    __ incq(rax);
1512    __ Move(rcx, Smi::FromInt(x));
1513    index = masm->SmiToNegativeIndex(rcx, rcx, i);
1514    DCHECK(index.reg.is(rcx));
1515    __ shlq(rcx, Immediate(index.scale));
1516    __ Set(r8, static_cast<intptr_t>(-x) << i);
1517    __ cmpq(rcx, r8);
1518    __ j(not_equal, exit);
1519    __ incq(rax);
1520  }
1521}
1522
1523
1524TEST(SmiIndex) {
1525  // Allocate an executable page of memory.
1526  size_t actual_size;
1527  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
1528      Assembler::kMinimalBufferSize * 5, &actual_size, true));
1529  CHECK(buffer);
1530  Isolate* isolate = CcTest::i_isolate();
1531  HandleScope handles(isolate);
1532  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1533
1534  MacroAssembler* masm = &assembler;
1535  EntryCode(masm);
1536  Label exit;
1537
1538  TestSmiIndex(masm, &exit, 0x10, 0);
1539  TestSmiIndex(masm, &exit, 0x20, 1);
1540  TestSmiIndex(masm, &exit, 0x30, 100);
1541  TestSmiIndex(masm, &exit, 0x40, 1000);
1542  TestSmiIndex(masm, &exit, 0x50, Smi::kMaxValue);
1543
1544  __ xorq(rax, rax);  // Success.
1545  __ bind(&exit);
1546  ExitCode(masm);
1547  __ ret(0);
1548
1549  CodeDesc desc;
1550  masm->GetCode(&desc);
1551  // Call the function from C++.
1552  int result = FUNCTION_CAST<F0>(buffer)();
1553  CHECK_EQ(0, result);
1554}
1555
1556
1557void TestSelectNonSmi(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1558  __ movl(rax, Immediate(id));
1559  __ Move(rcx, Smi::FromInt(x));
1560  __ Move(rdx, Smi::FromInt(y));
1561  __ xorq(rdx, Immediate(kSmiTagMask));
1562  __ SelectNonSmi(r9, rcx, rdx, exit);
1563
1564  __ incq(rax);
1565  __ cmpq(r9, rdx);
1566  __ j(not_equal, exit);
1567
1568  __ incq(rax);
1569  __ Move(rcx, Smi::FromInt(x));
1570  __ Move(rdx, Smi::FromInt(y));
1571  __ xorq(rcx, Immediate(kSmiTagMask));
1572  __ SelectNonSmi(r9, rcx, rdx, exit);
1573
1574  __ incq(rax);
1575  __ cmpq(r9, rcx);
1576  __ j(not_equal, exit);
1577
1578  __ incq(rax);
1579  Label fail_ok;
1580  __ Move(rcx, Smi::FromInt(x));
1581  __ Move(rdx, Smi::FromInt(y));
1582  __ xorq(rcx, Immediate(kSmiTagMask));
1583  __ xorq(rdx, Immediate(kSmiTagMask));
1584  __ SelectNonSmi(r9, rcx, rdx, &fail_ok);
1585  __ jmp(exit);
1586  __ bind(&fail_ok);
1587}
1588
1589
1590TEST(SmiSelectNonSmi) {
1591  // Allocate an executable page of memory.
1592  size_t actual_size;
1593  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
1594      Assembler::kMinimalBufferSize * 2, &actual_size, true));
1595  CHECK(buffer);
1596  Isolate* isolate = CcTest::i_isolate();
1597  HandleScope handles(isolate);
1598  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1599
1600  MacroAssembler* masm = &assembler;
1601  EntryCode(masm);
1602  Label exit;
1603
1604  TestSelectNonSmi(masm, &exit, 0x10, 0, 0);
1605  TestSelectNonSmi(masm, &exit, 0x20, 0, 1);
1606  TestSelectNonSmi(masm, &exit, 0x30, 1, 0);
1607  TestSelectNonSmi(masm, &exit, 0x40, 0, -1);
1608  TestSelectNonSmi(masm, &exit, 0x50, -1, 0);
1609  TestSelectNonSmi(masm, &exit, 0x60, -1, -1);
1610  TestSelectNonSmi(masm, &exit, 0x70, 1, 1);
1611  TestSelectNonSmi(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue);
1612  TestSelectNonSmi(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue);
1613
1614  __ xorq(rax, rax);  // Success.
1615  __ bind(&exit);
1616  ExitCode(masm);
1617  __ ret(0);
1618
1619  CodeDesc desc;
1620  masm->GetCode(&desc);
1621  // Call the function from C++.
1622  int result = FUNCTION_CAST<F0>(buffer)();
1623  CHECK_EQ(0, result);
1624}
1625
1626
1627void TestSmiAnd(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1628  int result = x & y;
1629
1630  __ movl(rax, Immediate(id));
1631
1632  __ Move(rcx, Smi::FromInt(x));
1633  __ movq(r11, rcx);
1634  __ Move(rdx, Smi::FromInt(y));
1635  __ Move(r8, Smi::FromInt(result));
1636  __ SmiAnd(r9, rcx, rdx);
1637  __ cmpq(r8, r9);
1638  __ j(not_equal, exit);
1639
1640  __ incq(rax);
1641  __ cmpq(r11, rcx);
1642  __ j(not_equal, exit);
1643
1644  __ incq(rax);
1645  __ SmiAnd(rcx, rcx, rdx);
1646  __ cmpq(r8, rcx);
1647  __ j(not_equal, exit);
1648
1649  __ movq(rcx, r11);
1650  __ incq(rax);
1651  __ SmiAndConstant(r9, rcx, Smi::FromInt(y));
1652  __ cmpq(r8, r9);
1653  __ j(not_equal, exit);
1654
1655  __ incq(rax);
1656  __ cmpq(r11, rcx);
1657  __ j(not_equal, exit);
1658
1659  __ incq(rax);
1660  __ SmiAndConstant(rcx, rcx, Smi::FromInt(y));
1661  __ cmpq(r8, rcx);
1662  __ j(not_equal, exit);
1663}
1664
1665
1666TEST(SmiAnd) {
1667  // Allocate an executable page of memory.
1668  size_t actual_size;
1669  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
1670      Assembler::kMinimalBufferSize * 2, &actual_size, true));
1671  CHECK(buffer);
1672  Isolate* isolate = CcTest::i_isolate();
1673  HandleScope handles(isolate);
1674  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1675
1676  MacroAssembler* masm = &assembler;
1677  EntryCode(masm);
1678  Label exit;
1679
1680  TestSmiAnd(masm, &exit, 0x10, 0, 0);
1681  TestSmiAnd(masm, &exit, 0x20, 0, 1);
1682  TestSmiAnd(masm, &exit, 0x30, 1, 0);
1683  TestSmiAnd(masm, &exit, 0x40, 0, -1);
1684  TestSmiAnd(masm, &exit, 0x50, -1, 0);
1685  TestSmiAnd(masm, &exit, 0x60, -1, -1);
1686  TestSmiAnd(masm, &exit, 0x70, 1, 1);
1687  TestSmiAnd(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue);
1688  TestSmiAnd(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue);
1689  TestSmiAnd(masm, &exit, 0xA0, Smi::kMinValue, -1);
1690  TestSmiAnd(masm, &exit, 0xB0, Smi::kMinValue, -1);
1691
1692  __ xorq(rax, rax);  // Success.
1693  __ bind(&exit);
1694  ExitCode(masm);
1695  __ ret(0);
1696
1697  CodeDesc desc;
1698  masm->GetCode(&desc);
1699  // Call the function from C++.
1700  int result = FUNCTION_CAST<F0>(buffer)();
1701  CHECK_EQ(0, result);
1702}
1703
1704
1705void TestSmiOr(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1706  int result = x | y;
1707
1708  __ movl(rax, Immediate(id));
1709
1710  __ Move(rcx, Smi::FromInt(x));
1711  __ movq(r11, rcx);
1712  __ Move(rdx, Smi::FromInt(y));
1713  __ Move(r8, Smi::FromInt(result));
1714  __ SmiOr(r9, rcx, rdx);
1715  __ cmpq(r8, r9);
1716  __ j(not_equal, exit);
1717
1718  __ incq(rax);
1719  __ cmpq(r11, rcx);
1720  __ j(not_equal, exit);
1721
1722  __ incq(rax);
1723  __ SmiOr(rcx, rcx, rdx);
1724  __ cmpq(r8, rcx);
1725  __ j(not_equal, exit);
1726
1727  __ movq(rcx, r11);
1728  __ incq(rax);
1729  __ SmiOrConstant(r9, rcx, Smi::FromInt(y));
1730  __ cmpq(r8, r9);
1731  __ j(not_equal, exit);
1732
1733  __ incq(rax);
1734  __ cmpq(r11, rcx);
1735  __ j(not_equal, exit);
1736
1737  __ incq(rax);
1738  __ SmiOrConstant(rcx, rcx, Smi::FromInt(y));
1739  __ cmpq(r8, rcx);
1740  __ j(not_equal, exit);
1741}
1742
1743
1744TEST(SmiOr) {
1745  // Allocate an executable page of memory.
1746  size_t actual_size;
1747  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
1748      Assembler::kMinimalBufferSize * 2, &actual_size, true));
1749  CHECK(buffer);
1750  Isolate* isolate = CcTest::i_isolate();
1751  HandleScope handles(isolate);
1752  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1753
1754  MacroAssembler* masm = &assembler;
1755  EntryCode(masm);
1756  Label exit;
1757
1758  TestSmiOr(masm, &exit, 0x10, 0, 0);
1759  TestSmiOr(masm, &exit, 0x20, 0, 1);
1760  TestSmiOr(masm, &exit, 0x30, 1, 0);
1761  TestSmiOr(masm, &exit, 0x40, 0, -1);
1762  TestSmiOr(masm, &exit, 0x50, -1, 0);
1763  TestSmiOr(masm, &exit, 0x60, -1, -1);
1764  TestSmiOr(masm, &exit, 0x70, 1, 1);
1765  TestSmiOr(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue);
1766  TestSmiOr(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue);
1767  TestSmiOr(masm, &exit, 0xA0, Smi::kMinValue, -1);
1768  TestSmiOr(masm, &exit, 0xB0, 0x05555555, 0x01234567);
1769  TestSmiOr(masm, &exit, 0xC0, 0x05555555, 0x0fedcba9);
1770  TestSmiOr(masm, &exit, 0xD0, Smi::kMinValue, -1);
1771
1772  __ xorq(rax, rax);  // Success.
1773  __ bind(&exit);
1774  ExitCode(masm);
1775  __ ret(0);
1776
1777  CodeDesc desc;
1778  masm->GetCode(&desc);
1779  // Call the function from C++.
1780  int result = FUNCTION_CAST<F0>(buffer)();
1781  CHECK_EQ(0, result);
1782}
1783
1784
1785void TestSmiXor(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1786  int result = x ^ y;
1787
1788  __ movl(rax, Immediate(id));
1789
1790  __ Move(rcx, Smi::FromInt(x));
1791  __ movq(r11, rcx);
1792  __ Move(rdx, Smi::FromInt(y));
1793  __ Move(r8, Smi::FromInt(result));
1794  __ SmiXor(r9, rcx, rdx);
1795  __ cmpq(r8, r9);
1796  __ j(not_equal, exit);
1797
1798  __ incq(rax);
1799  __ cmpq(r11, rcx);
1800  __ j(not_equal, exit);
1801
1802  __ incq(rax);
1803  __ SmiXor(rcx, rcx, rdx);
1804  __ cmpq(r8, rcx);
1805  __ j(not_equal, exit);
1806
1807  __ movq(rcx, r11);
1808  __ incq(rax);
1809  __ SmiXorConstant(r9, rcx, Smi::FromInt(y));
1810  __ cmpq(r8, r9);
1811  __ j(not_equal, exit);
1812
1813  __ incq(rax);
1814  __ cmpq(r11, rcx);
1815  __ j(not_equal, exit);
1816
1817  __ incq(rax);
1818  __ SmiXorConstant(rcx, rcx, Smi::FromInt(y));
1819  __ cmpq(r8, rcx);
1820  __ j(not_equal, exit);
1821}
1822
1823
1824TEST(SmiXor) {
1825  // Allocate an executable page of memory.
1826  size_t actual_size;
1827  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
1828      Assembler::kMinimalBufferSize * 2, &actual_size, true));
1829  CHECK(buffer);
1830  Isolate* isolate = CcTest::i_isolate();
1831  HandleScope handles(isolate);
1832  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1833
1834  MacroAssembler* masm = &assembler;
1835  EntryCode(masm);
1836  Label exit;
1837
1838  TestSmiXor(masm, &exit, 0x10, 0, 0);
1839  TestSmiXor(masm, &exit, 0x20, 0, 1);
1840  TestSmiXor(masm, &exit, 0x30, 1, 0);
1841  TestSmiXor(masm, &exit, 0x40, 0, -1);
1842  TestSmiXor(masm, &exit, 0x50, -1, 0);
1843  TestSmiXor(masm, &exit, 0x60, -1, -1);
1844  TestSmiXor(masm, &exit, 0x70, 1, 1);
1845  TestSmiXor(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue);
1846  TestSmiXor(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue);
1847  TestSmiXor(masm, &exit, 0xA0, Smi::kMinValue, -1);
1848  TestSmiXor(masm, &exit, 0xB0, 0x5555555, 0x01234567);
1849  TestSmiXor(masm, &exit, 0xC0, 0x5555555, 0x0fedcba9);
1850  TestSmiXor(masm, &exit, 0xD0, Smi::kMinValue, -1);
1851
1852  __ xorq(rax, rax);  // Success.
1853  __ bind(&exit);
1854  ExitCode(masm);
1855  __ ret(0);
1856
1857  CodeDesc desc;
1858  masm->GetCode(&desc);
1859  // Call the function from C++.
1860  int result = FUNCTION_CAST<F0>(buffer)();
1861  CHECK_EQ(0, result);
1862}
1863
1864
1865void TestSmiNot(MacroAssembler* masm, Label* exit, int id, int x) {
1866  int result = ~x;
1867  __ movl(rax, Immediate(id));
1868
1869  __ Move(r8, Smi::FromInt(result));
1870  __ Move(rcx, Smi::FromInt(x));
1871  __ movq(r11, rcx);
1872
1873  __ SmiNot(r9, rcx);
1874  __ cmpq(r9, r8);
1875  __ j(not_equal, exit);
1876
1877  __ incq(rax);
1878  __ cmpq(r11, rcx);
1879  __ j(not_equal, exit);
1880
1881  __ incq(rax);
1882  __ SmiNot(rcx, rcx);
1883  __ cmpq(rcx, r8);
1884  __ j(not_equal, exit);
1885}
1886
1887
1888TEST(SmiNot) {
1889  // Allocate an executable page of memory.
1890  size_t actual_size;
1891  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
1892      Assembler::kMinimalBufferSize, &actual_size, true));
1893  CHECK(buffer);
1894  Isolate* isolate = CcTest::i_isolate();
1895  HandleScope handles(isolate);
1896  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1897
1898  MacroAssembler* masm = &assembler;
1899  EntryCode(masm);
1900  Label exit;
1901
1902  TestSmiNot(masm, &exit, 0x10, 0);
1903  TestSmiNot(masm, &exit, 0x20, 1);
1904  TestSmiNot(masm, &exit, 0x30, -1);
1905  TestSmiNot(masm, &exit, 0x40, 127);
1906  TestSmiNot(masm, &exit, 0x50, 65535);
1907  TestSmiNot(masm, &exit, 0x60, Smi::kMinValue);
1908  TestSmiNot(masm, &exit, 0x70, Smi::kMaxValue);
1909  TestSmiNot(masm, &exit, 0x80, 0x05555555);
1910
1911  __ xorq(rax, rax);  // Success.
1912  __ bind(&exit);
1913  ExitCode(masm);
1914  __ ret(0);
1915
1916  CodeDesc desc;
1917  masm->GetCode(&desc);
1918  // Call the function from C++.
1919  int result = FUNCTION_CAST<F0>(buffer)();
1920  CHECK_EQ(0, result);
1921}
1922
1923
1924void TestSmiShiftLeft(MacroAssembler* masm, Label* exit, int id, int x) {
1925  const int shifts[] = { 0, 1, 7, 24, kSmiValueSize - 1};
1926  const int kNumShifts = 5;
1927  __ movl(rax, Immediate(id));
1928  for (int i = 0; i < kNumShifts; i++) {
1929    // rax == id + i * 10.
1930    int shift = shifts[i];
1931    int result = x << shift;
1932    CHECK(Smi::IsValid(result));
1933    __ Move(r8, Smi::FromInt(result));
1934    __ Move(rcx, Smi::FromInt(x));
1935    __ SmiShiftLeftConstant(r9, rcx, shift);
1936
1937    __ incq(rax);
1938    __ cmpq(r9, r8);
1939    __ j(not_equal, exit);
1940
1941    __ incq(rax);
1942    __ Move(rcx, Smi::FromInt(x));
1943    __ SmiShiftLeftConstant(rcx, rcx, shift);
1944
1945    __ incq(rax);
1946    __ cmpq(rcx, r8);
1947    __ j(not_equal, exit);
1948
1949    __ incq(rax);
1950    __ Move(rdx, Smi::FromInt(x));
1951    __ Move(rcx, Smi::FromInt(shift));
1952    __ SmiShiftLeft(r9, rdx, rcx);
1953
1954    __ incq(rax);
1955    __ cmpq(r9, r8);
1956    __ j(not_equal, exit);
1957
1958    __ incq(rax);
1959    __ Move(rdx, Smi::FromInt(x));
1960    __ Move(r11, Smi::FromInt(shift));
1961    __ SmiShiftLeft(r9, rdx, r11);
1962
1963    __ incq(rax);
1964    __ cmpq(r9, r8);
1965    __ j(not_equal, exit);
1966
1967    __ incq(rax);
1968    __ Move(rdx, Smi::FromInt(x));
1969    __ Move(r11, Smi::FromInt(shift));
1970    __ SmiShiftLeft(rdx, rdx, r11);
1971
1972    __ incq(rax);
1973    __ cmpq(rdx, r8);
1974    __ j(not_equal, exit);
1975
1976    __ incq(rax);
1977  }
1978}
1979
1980
1981TEST(SmiShiftLeft) {
1982  // Allocate an executable page of memory.
1983  size_t actual_size;
1984  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
1985      Assembler::kMinimalBufferSize * 7, &actual_size, true));
1986  CHECK(buffer);
1987  Isolate* isolate = CcTest::i_isolate();
1988  HandleScope handles(isolate);
1989  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1990
1991  MacroAssembler* masm = &assembler;
1992  EntryCode(masm);
1993  Label exit;
1994
1995  TestSmiShiftLeft(masm, &exit, 0x10, 0);
1996  TestSmiShiftLeft(masm, &exit, 0x50, 1);
1997  TestSmiShiftLeft(masm, &exit, 0x90, 127);
1998  TestSmiShiftLeft(masm, &exit, 0xD0, 65535);
1999  TestSmiShiftLeft(masm, &exit, 0x110, Smi::kMaxValue);
2000  TestSmiShiftLeft(masm, &exit, 0x150, Smi::kMinValue);
2001  TestSmiShiftLeft(masm, &exit, 0x190, -1);
2002
2003  __ xorq(rax, rax);  // Success.
2004  __ bind(&exit);
2005  ExitCode(masm);
2006  __ ret(0);
2007
2008  CodeDesc desc;
2009  masm->GetCode(&desc);
2010  // Call the function from C++.
2011  int result = FUNCTION_CAST<F0>(buffer)();
2012  CHECK_EQ(0, result);
2013}
2014
2015
2016void TestSmiShiftLogicalRight(MacroAssembler* masm,
2017                              Label* exit,
2018                              int id,
2019                              int x) {
2020  const int shifts[] = { 0, 1, 7, 24, kSmiValueSize - 1};
2021  const int kNumShifts = 5;
2022  __ movl(rax, Immediate(id));
2023  for (int i = 0; i < kNumShifts; i++) {
2024    int shift = shifts[i];
2025    intptr_t result = static_cast<unsigned int>(x) >> shift;
2026    if (Smi::IsValid(result)) {
2027      __ Move(r8, Smi::FromInt(static_cast<int>(result)));
2028      __ Move(rcx, Smi::FromInt(x));
2029      __ SmiShiftLogicalRightConstant(r9, rcx, shift, exit);
2030
2031      __ incq(rax);
2032      __ cmpq(r9, r8);
2033      __ j(not_equal, exit);
2034
2035      __ incq(rax);
2036      __ Move(rdx, Smi::FromInt(x));
2037      __ Move(rcx, Smi::FromInt(shift));
2038      __ SmiShiftLogicalRight(r9, rdx, rcx, exit);
2039
2040      __ incq(rax);
2041      __ cmpq(r9, r8);
2042      __ j(not_equal, exit);
2043
2044      __ incq(rax);
2045      __ Move(rdx, Smi::FromInt(x));
2046      __ Move(r11, Smi::FromInt(shift));
2047      __ SmiShiftLogicalRight(r9, rdx, r11, exit);
2048
2049      __ incq(rax);
2050      __ cmpq(r9, r8);
2051      __ j(not_equal, exit);
2052
2053      __ incq(rax);
2054    } else {
2055      // Cannot happen with long smis.
2056      Label fail_ok;
2057      __ Move(rcx, Smi::FromInt(x));
2058      __ movq(r11, rcx);
2059      __ SmiShiftLogicalRightConstant(r9, rcx, shift, &fail_ok);
2060      __ jmp(exit);
2061      __ bind(&fail_ok);
2062
2063      __ incq(rax);
2064      __ cmpq(rcx, r11);
2065      __ j(not_equal, exit);
2066
2067      __ incq(rax);
2068      __ Move(r8, Smi::FromInt(shift));
2069      Label fail_ok3;
2070      __ SmiShiftLogicalRight(r9, rcx, r8, &fail_ok3);
2071      __ jmp(exit);
2072      __ bind(&fail_ok3);
2073
2074      __ incq(rax);
2075      __ cmpq(rcx, r11);
2076      __ j(not_equal, exit);
2077
2078      __ addq(rax, Immediate(3));
2079    }
2080  }
2081}
2082
2083
2084TEST(SmiShiftLogicalRight) {
2085  // Allocate an executable page of memory.
2086  size_t actual_size;
2087  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
2088      Assembler::kMinimalBufferSize * 5, &actual_size, true));
2089  CHECK(buffer);
2090  Isolate* isolate = CcTest::i_isolate();
2091  HandleScope handles(isolate);
2092  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
2093
2094  MacroAssembler* masm = &assembler;
2095  EntryCode(masm);
2096  Label exit;
2097
2098  TestSmiShiftLogicalRight(masm, &exit, 0x10, 0);
2099  TestSmiShiftLogicalRight(masm, &exit, 0x30, 1);
2100  TestSmiShiftLogicalRight(masm, &exit, 0x50, 127);
2101  TestSmiShiftLogicalRight(masm, &exit, 0x70, 65535);
2102  TestSmiShiftLogicalRight(masm, &exit, 0x90, Smi::kMaxValue);
2103  TestSmiShiftLogicalRight(masm, &exit, 0xB0, Smi::kMinValue);
2104  TestSmiShiftLogicalRight(masm, &exit, 0xD0, -1);
2105
2106  __ xorq(rax, rax);  // Success.
2107  __ bind(&exit);
2108  ExitCode(masm);
2109  __ ret(0);
2110
2111  CodeDesc desc;
2112  masm->GetCode(&desc);
2113  // Call the function from C++.
2114  int result = FUNCTION_CAST<F0>(buffer)();
2115  CHECK_EQ(0, result);
2116}
2117
2118
2119void TestSmiShiftArithmeticRight(MacroAssembler* masm,
2120                                 Label* exit,
2121                                 int id,
2122                                 int x) {
2123  const int shifts[] = { 0, 1, 7, 24, kSmiValueSize - 1};
2124  const int kNumShifts = 5;
2125  __ movl(rax, Immediate(id));
2126  for (int i = 0; i < kNumShifts; i++) {
2127    int shift = shifts[i];
2128    // Guaranteed arithmetic shift.
2129    int result = (x < 0) ? ~((~x) >> shift) : (x >> shift);
2130    __ Move(r8, Smi::FromInt(result));
2131    __ Move(rcx, Smi::FromInt(x));
2132    __ SmiShiftArithmeticRightConstant(rcx, rcx, shift);
2133
2134    __ cmpq(rcx, r8);
2135    __ j(not_equal, exit);
2136
2137    __ incq(rax);
2138    __ Move(rdx, Smi::FromInt(x));
2139    __ Move(r11, Smi::FromInt(shift));
2140    __ SmiShiftArithmeticRight(rdx, rdx, r11);
2141
2142    __ cmpq(rdx, r8);
2143    __ j(not_equal, exit);
2144
2145    __ incq(rax);
2146  }
2147}
2148
2149
2150TEST(SmiShiftArithmeticRight) {
2151  // Allocate an executable page of memory.
2152  size_t actual_size;
2153  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
2154      Assembler::kMinimalBufferSize * 3, &actual_size, true));
2155  CHECK(buffer);
2156  Isolate* isolate = CcTest::i_isolate();
2157  HandleScope handles(isolate);
2158  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
2159
2160  MacroAssembler* masm = &assembler;
2161  EntryCode(masm);
2162  Label exit;
2163
2164  TestSmiShiftArithmeticRight(masm, &exit, 0x10, 0);
2165  TestSmiShiftArithmeticRight(masm, &exit, 0x20, 1);
2166  TestSmiShiftArithmeticRight(masm, &exit, 0x30, 127);
2167  TestSmiShiftArithmeticRight(masm, &exit, 0x40, 65535);
2168  TestSmiShiftArithmeticRight(masm, &exit, 0x50, Smi::kMaxValue);
2169  TestSmiShiftArithmeticRight(masm, &exit, 0x60, Smi::kMinValue);
2170  TestSmiShiftArithmeticRight(masm, &exit, 0x70, -1);
2171
2172  __ xorq(rax, rax);  // Success.
2173  __ bind(&exit);
2174  ExitCode(masm);
2175  __ ret(0);
2176
2177  CodeDesc desc;
2178  masm->GetCode(&desc);
2179  // Call the function from C++.
2180  int result = FUNCTION_CAST<F0>(buffer)();
2181  CHECK_EQ(0, result);
2182}
2183
2184
2185void TestPositiveSmiPowerUp(MacroAssembler* masm, Label* exit, int id, int x) {
2186  DCHECK(x >= 0);
2187  int powers[] = { 0, 1, 2, 3, 8, 16, 24, 31 };
2188  int power_count = 8;
2189  __ movl(rax, Immediate(id));
2190  for (int i = 0; i  < power_count; i++) {
2191    int power = powers[i];
2192    intptr_t result = static_cast<intptr_t>(x) << power;
2193    __ Set(r8, result);
2194    __ Move(rcx, Smi::FromInt(x));
2195    __ movq(r11, rcx);
2196    __ PositiveSmiTimesPowerOfTwoToInteger64(rdx, rcx, power);
2197    __ cmpq(rdx, r8);
2198    __ j(not_equal, exit);
2199    __ incq(rax);
2200    __ cmpq(r11, rcx);  // rcx unchanged.
2201    __ j(not_equal, exit);
2202    __ incq(rax);
2203    __ PositiveSmiTimesPowerOfTwoToInteger64(rcx, rcx, power);
2204    __ cmpq(rdx, r8);
2205    __ j(not_equal, exit);
2206    __ incq(rax);
2207  }
2208}
2209
2210
2211TEST(PositiveSmiTimesPowerOfTwoToInteger64) {
2212  // Allocate an executable page of memory.
2213  size_t actual_size;
2214  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
2215      Assembler::kMinimalBufferSize * 4, &actual_size, true));
2216  CHECK(buffer);
2217  Isolate* isolate = CcTest::i_isolate();
2218  HandleScope handles(isolate);
2219  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
2220
2221  MacroAssembler* masm = &assembler;
2222  EntryCode(masm);
2223  Label exit;
2224
2225  TestPositiveSmiPowerUp(masm, &exit, 0x20, 0);
2226  TestPositiveSmiPowerUp(masm, &exit, 0x40, 1);
2227  TestPositiveSmiPowerUp(masm, &exit, 0x60, 127);
2228  TestPositiveSmiPowerUp(masm, &exit, 0x80, 128);
2229  TestPositiveSmiPowerUp(masm, &exit, 0xA0, 255);
2230  TestPositiveSmiPowerUp(masm, &exit, 0xC0, 256);
2231  TestPositiveSmiPowerUp(masm, &exit, 0x100, 65535);
2232  TestPositiveSmiPowerUp(masm, &exit, 0x120, 65536);
2233  TestPositiveSmiPowerUp(masm, &exit, 0x140, Smi::kMaxValue);
2234
2235  __ xorq(rax, rax);  // Success.
2236  __ bind(&exit);
2237  ExitCode(masm);
2238  __ ret(0);
2239
2240  CodeDesc desc;
2241  masm->GetCode(&desc);
2242  // Call the function from C++.
2243  int result = FUNCTION_CAST<F0>(buffer)();
2244  CHECK_EQ(0, result);
2245}
2246
2247
2248TEST(OperandOffset) {
2249  uint32_t data[256];
2250  for (uint32_t i = 0; i < 256; i++) { data[i] = i * 0x01010101; }
2251
2252  // Allocate an executable page of memory.
2253  size_t actual_size;
2254  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
2255      Assembler::kMinimalBufferSize * 2, &actual_size, true));
2256  CHECK(buffer);
2257  Isolate* isolate = CcTest::i_isolate();
2258  HandleScope handles(isolate);
2259  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
2260
2261  MacroAssembler* masm = &assembler;
2262  Label exit;
2263
2264  EntryCode(masm);
2265  __ pushq(r13);
2266  __ pushq(r14);
2267  __ pushq(rbx);
2268  __ pushq(rbp);
2269  __ pushq(Immediate(0x100));  // <-- rbp
2270  __ movq(rbp, rsp);
2271  __ pushq(Immediate(0x101));
2272  __ pushq(Immediate(0x102));
2273  __ pushq(Immediate(0x103));
2274  __ pushq(Immediate(0x104));
2275  __ pushq(Immediate(0x105));  // <-- rbx
2276  __ pushq(Immediate(0x106));
2277  __ pushq(Immediate(0x107));
2278  __ pushq(Immediate(0x108));
2279  __ pushq(Immediate(0x109));  // <-- rsp
2280  // rbp = rsp[9]
2281  // r15 = rsp[3]
2282  // rbx = rsp[5]
2283  // r13 = rsp[7]
2284  __ leaq(r14, Operand(rsp, 3 * kPointerSize));
2285  __ leaq(r13, Operand(rbp, -3 * kPointerSize));
2286  __ leaq(rbx, Operand(rbp, -5 * kPointerSize));
2287  __ movl(rcx, Immediate(2));
2288  __ Move(r8, reinterpret_cast<Address>(&data[128]), RelocInfo::NONE64);
2289  __ movl(rax, Immediate(1));
2290
2291  Operand sp0 = Operand(rsp, 0);
2292
2293  // Test 1.
2294  __ movl(rdx, sp0);  // Sanity check.
2295  __ cmpl(rdx, Immediate(0x109));
2296  __ j(not_equal, &exit);
2297  __ incq(rax);
2298
2299  // Test 2.
2300  // Zero to non-zero displacement.
2301  __ movl(rdx, Operand(sp0, 2 * kPointerSize));
2302  __ cmpl(rdx, Immediate(0x107));
2303  __ j(not_equal, &exit);
2304  __ incq(rax);
2305
2306  Operand sp2 = Operand(rsp, 2 * kPointerSize);
2307
2308  // Test 3.
2309  __ movl(rdx, sp2);  // Sanity check.
2310  __ cmpl(rdx, Immediate(0x107));
2311  __ j(not_equal, &exit);
2312  __ incq(rax);
2313
2314  __ movl(rdx, Operand(sp2, 2 * kPointerSize));
2315  __ cmpl(rdx, Immediate(0x105));
2316  __ j(not_equal, &exit);
2317  __ incq(rax);
2318
2319  // Non-zero to zero displacement.
2320  __ movl(rdx, Operand(sp2, -2 * kPointerSize));
2321  __ cmpl(rdx, Immediate(0x109));
2322  __ j(not_equal, &exit);
2323  __ incq(rax);
2324
2325  Operand sp2c2 = Operand(rsp, rcx, times_pointer_size, 2 * kPointerSize);
2326
2327  // Test 6.
2328  __ movl(rdx, sp2c2);  // Sanity check.
2329  __ cmpl(rdx, Immediate(0x105));
2330  __ j(not_equal, &exit);
2331  __ incq(rax);
2332
2333  __ movl(rdx, Operand(sp2c2, 2 * kPointerSize));
2334  __ cmpl(rdx, Immediate(0x103));
2335  __ j(not_equal, &exit);
2336  __ incq(rax);
2337
2338  // Non-zero to zero displacement.
2339  __ movl(rdx, Operand(sp2c2, -2 * kPointerSize));
2340  __ cmpl(rdx, Immediate(0x107));
2341  __ j(not_equal, &exit);
2342  __ incq(rax);
2343
2344
2345  Operand bp0 = Operand(rbp, 0);
2346
2347  // Test 9.
2348  __ movl(rdx, bp0);  // Sanity check.
2349  __ cmpl(rdx, Immediate(0x100));
2350  __ j(not_equal, &exit);
2351  __ incq(rax);
2352
2353  // Zero to non-zero displacement.
2354  __ movl(rdx, Operand(bp0, -2 * kPointerSize));
2355  __ cmpl(rdx, Immediate(0x102));
2356  __ j(not_equal, &exit);
2357  __ incq(rax);
2358
2359  Operand bp2 = Operand(rbp, -2 * kPointerSize);
2360
2361  // Test 11.
2362  __ movl(rdx, bp2);  // Sanity check.
2363  __ cmpl(rdx, Immediate(0x102));
2364  __ j(not_equal, &exit);
2365  __ incq(rax);
2366
2367  // Non-zero to zero displacement.
2368  __ movl(rdx, Operand(bp2, 2 * kPointerSize));
2369  __ cmpl(rdx, Immediate(0x100));
2370  __ j(not_equal, &exit);
2371  __ incq(rax);
2372
2373  __ movl(rdx, Operand(bp2, -2 * kPointerSize));
2374  __ cmpl(rdx, Immediate(0x104));
2375  __ j(not_equal, &exit);
2376  __ incq(rax);
2377
2378  Operand bp2c4 = Operand(rbp, rcx, times_pointer_size, -4 * kPointerSize);
2379
2380  // Test 14:
2381  __ movl(rdx, bp2c4);  // Sanity check.
2382  __ cmpl(rdx, Immediate(0x102));
2383  __ j(not_equal, &exit);
2384  __ incq(rax);
2385
2386  __ movl(rdx, Operand(bp2c4, 2 * kPointerSize));
2387  __ cmpl(rdx, Immediate(0x100));
2388  __ j(not_equal, &exit);
2389  __ incq(rax);
2390
2391  __ movl(rdx, Operand(bp2c4, -2 * kPointerSize));
2392  __ cmpl(rdx, Immediate(0x104));
2393  __ j(not_equal, &exit);
2394  __ incq(rax);
2395
2396  Operand bx0 = Operand(rbx, 0);
2397
2398  // Test 17.
2399  __ movl(rdx, bx0);  // Sanity check.
2400  __ cmpl(rdx, Immediate(0x105));
2401  __ j(not_equal, &exit);
2402  __ incq(rax);
2403
2404  __ movl(rdx, Operand(bx0, 5 * kPointerSize));
2405  __ cmpl(rdx, Immediate(0x100));
2406  __ j(not_equal, &exit);
2407  __ incq(rax);
2408
2409  __ movl(rdx, Operand(bx0, -4 * kPointerSize));
2410  __ cmpl(rdx, Immediate(0x109));
2411  __ j(not_equal, &exit);
2412  __ incq(rax);
2413
2414  Operand bx2 = Operand(rbx, 2 * kPointerSize);
2415
2416  // Test 20.
2417  __ movl(rdx, bx2);  // Sanity check.
2418  __ cmpl(rdx, Immediate(0x103));
2419  __ j(not_equal, &exit);
2420  __ incq(rax);
2421
2422  __ movl(rdx, Operand(bx2, 2 * kPointerSize));
2423  __ cmpl(rdx, Immediate(0x101));
2424  __ j(not_equal, &exit);
2425  __ incq(rax);
2426
2427  // Non-zero to zero displacement.
2428  __ movl(rdx, Operand(bx2, -2 * kPointerSize));
2429  __ cmpl(rdx, Immediate(0x105));
2430  __ j(not_equal, &exit);
2431  __ incq(rax);
2432
2433  Operand bx2c2 = Operand(rbx, rcx, times_pointer_size, -2 * kPointerSize);
2434
2435  // Test 23.
2436  __ movl(rdx, bx2c2);  // Sanity check.
2437  __ cmpl(rdx, Immediate(0x105));
2438  __ j(not_equal, &exit);
2439  __ incq(rax);
2440
2441  __ movl(rdx, Operand(bx2c2, 2 * kPointerSize));
2442  __ cmpl(rdx, Immediate(0x103));
2443  __ j(not_equal, &exit);
2444  __ incq(rax);
2445
2446  __ movl(rdx, Operand(bx2c2, -2 * kPointerSize));
2447  __ cmpl(rdx, Immediate(0x107));
2448  __ j(not_equal, &exit);
2449  __ incq(rax);
2450
2451  Operand r80 = Operand(r8, 0);
2452
2453  // Test 26.
2454  __ movl(rdx, r80);  // Sanity check.
2455  __ cmpl(rdx, Immediate(0x80808080));
2456  __ j(not_equal, &exit);
2457  __ incq(rax);
2458
2459  __ movl(rdx, Operand(r80, -8 * kIntSize));
2460  __ cmpl(rdx, Immediate(0x78787878));
2461  __ j(not_equal, &exit);
2462  __ incq(rax);
2463
2464  __ movl(rdx, Operand(r80, 8 * kIntSize));
2465  __ cmpl(rdx, Immediate(0x88888888));
2466  __ j(not_equal, &exit);
2467  __ incq(rax);
2468
2469  __ movl(rdx, Operand(r80, -64 * kIntSize));
2470  __ cmpl(rdx, Immediate(0x40404040));
2471  __ j(not_equal, &exit);
2472  __ incq(rax);
2473
2474  __ movl(rdx, Operand(r80, 64 * kIntSize));
2475  __ cmpl(rdx, Immediate(0xC0C0C0C0));
2476  __ j(not_equal, &exit);
2477  __ incq(rax);
2478
2479  Operand r88 = Operand(r8, 8 * kIntSize);
2480
2481  // Test 31.
2482  __ movl(rdx, r88);  // Sanity check.
2483  __ cmpl(rdx, Immediate(0x88888888));
2484  __ j(not_equal, &exit);
2485  __ incq(rax);
2486
2487  __ movl(rdx, Operand(r88, -8 * kIntSize));
2488  __ cmpl(rdx, Immediate(0x80808080));
2489  __ j(not_equal, &exit);
2490  __ incq(rax);
2491
2492  __ movl(rdx, Operand(r88, 8 * kIntSize));
2493  __ cmpl(rdx, Immediate(0x90909090));
2494  __ j(not_equal, &exit);
2495  __ incq(rax);
2496
2497  __ movl(rdx, Operand(r88, -64 * kIntSize));
2498  __ cmpl(rdx, Immediate(0x48484848));
2499  __ j(not_equal, &exit);
2500  __ incq(rax);
2501
2502  __ movl(rdx, Operand(r88, 64 * kIntSize));
2503  __ cmpl(rdx, Immediate(0xC8C8C8C8));
2504  __ j(not_equal, &exit);
2505  __ incq(rax);
2506
2507
2508  Operand r864 = Operand(r8, 64 * kIntSize);
2509
2510  // Test 36.
2511  __ movl(rdx, r864);  // Sanity check.
2512  __ cmpl(rdx, Immediate(0xC0C0C0C0));
2513  __ j(not_equal, &exit);
2514  __ incq(rax);
2515
2516  __ movl(rdx, Operand(r864, -8 * kIntSize));
2517  __ cmpl(rdx, Immediate(0xB8B8B8B8));
2518  __ j(not_equal, &exit);
2519  __ incq(rax);
2520
2521  __ movl(rdx, Operand(r864, 8 * kIntSize));
2522  __ cmpl(rdx, Immediate(0xC8C8C8C8));
2523  __ j(not_equal, &exit);
2524  __ incq(rax);
2525
2526  __ movl(rdx, Operand(r864, -64 * kIntSize));
2527  __ cmpl(rdx, Immediate(0x80808080));
2528  __ j(not_equal, &exit);
2529  __ incq(rax);
2530
2531  __ movl(rdx, Operand(r864, 32 * kIntSize));
2532  __ cmpl(rdx, Immediate(0xE0E0E0E0));
2533  __ j(not_equal, &exit);
2534  __ incq(rax);
2535
2536  // 32-bit offset to 8-bit offset.
2537  __ movl(rdx, Operand(r864, -60 * kIntSize));
2538  __ cmpl(rdx, Immediate(0x84848484));
2539  __ j(not_equal, &exit);
2540  __ incq(rax);
2541
2542  __ movl(rdx, Operand(r864, 60 * kIntSize));
2543  __ cmpl(rdx, Immediate(0xFCFCFCFC));
2544  __ j(not_equal, &exit);
2545  __ incq(rax);
2546
2547  // Test unaligned offsets.
2548
2549  // Test 43.
2550  __ movl(rdx, Operand(r80, 2));
2551  __ cmpl(rdx, Immediate(0x81818080));
2552  __ j(not_equal, &exit);
2553  __ incq(rax);
2554
2555  __ movl(rdx, Operand(r80, -2));
2556  __ cmpl(rdx, Immediate(0x80807F7F));
2557  __ j(not_equal, &exit);
2558  __ incq(rax);
2559
2560  __ movl(rdx, Operand(r80, 126));
2561  __ cmpl(rdx, Immediate(0xA0A09F9F));
2562  __ j(not_equal, &exit);
2563  __ incq(rax);
2564
2565  __ movl(rdx, Operand(r80, -126));
2566  __ cmpl(rdx, Immediate(0x61616060));
2567  __ j(not_equal, &exit);
2568  __ incq(rax);
2569
2570  __ movl(rdx, Operand(r80, 254));
2571  __ cmpl(rdx, Immediate(0xC0C0BFBF));
2572  __ j(not_equal, &exit);
2573  __ incq(rax);
2574
2575  __ movl(rdx, Operand(r80, -254));
2576  __ cmpl(rdx, Immediate(0x41414040));
2577  __ j(not_equal, &exit);
2578  __ incq(rax);
2579
2580  // Success.
2581
2582  __ movl(rax, Immediate(0));
2583  __ bind(&exit);
2584  __ leaq(rsp, Operand(rbp, kPointerSize));
2585  __ popq(rbp);
2586  __ popq(rbx);
2587  __ popq(r14);
2588  __ popq(r13);
2589  ExitCode(masm);
2590  __ ret(0);
2591
2592
2593  CodeDesc desc;
2594  masm->GetCode(&desc);
2595  // Call the function from C++.
2596  int result = FUNCTION_CAST<F0>(buffer)();
2597  CHECK_EQ(0, result);
2598}
2599
2600
2601TEST(LoadAndStoreWithRepresentation) {
2602  // Allocate an executable page of memory.
2603  size_t actual_size;
2604  byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
2605      Assembler::kMinimalBufferSize, &actual_size, true));
2606  CHECK(buffer);
2607  Isolate* isolate = CcTest::i_isolate();
2608  HandleScope handles(isolate);
2609  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
2610  MacroAssembler* masm = &assembler;  // Create a pointer for the __ macro.
2611  EntryCode(masm);
2612  __ subq(rsp, Immediate(1 * kPointerSize));
2613  Label exit;
2614
2615  // Test 1.
2616  __ movq(rax, Immediate(1));  // Test number.
2617  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2618  __ movq(rcx, Immediate(-1));
2619  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::UInteger8());
2620  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2621  __ movl(rdx, Immediate(255));
2622  __ cmpq(rcx, rdx);
2623  __ j(not_equal, &exit);
2624  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::UInteger8());
2625  __ cmpq(rcx, rdx);
2626  __ j(not_equal, &exit);
2627
2628  // Test 2.
2629  __ movq(rax, Immediate(2));  // Test number.
2630  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2631  __ Set(rcx, V8_2PART_UINT64_C(0xdeadbeaf, 12345678));
2632  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::Smi());
2633  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2634  __ Set(rdx, V8_2PART_UINT64_C(0xdeadbeaf, 12345678));
2635  __ cmpq(rcx, rdx);
2636  __ j(not_equal, &exit);
2637  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::Smi());
2638  __ cmpq(rcx, rdx);
2639  __ j(not_equal, &exit);
2640
2641  // Test 3.
2642  __ movq(rax, Immediate(3));  // Test number.
2643  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2644  __ movq(rcx, Immediate(-1));
2645  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::Integer32());
2646  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2647  __ movl(rdx, Immediate(-1));
2648  __ cmpq(rcx, rdx);
2649  __ j(not_equal, &exit);
2650  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::Integer32());
2651  __ cmpq(rcx, rdx);
2652  __ j(not_equal, &exit);
2653
2654  // Test 4.
2655  __ movq(rax, Immediate(4));  // Test number.
2656  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2657  __ movl(rcx, Immediate(0x44332211));
2658  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::HeapObject());
2659  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2660  __ movl(rdx, Immediate(0x44332211));
2661  __ cmpq(rcx, rdx);
2662  __ j(not_equal, &exit);
2663  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::HeapObject());
2664  __ cmpq(rcx, rdx);
2665  __ j(not_equal, &exit);
2666
2667  // Test 5.
2668  __ movq(rax, Immediate(5));  // Test number.
2669  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2670  __ Set(rcx, V8_2PART_UINT64_C(0x12345678, deadbeaf));
2671  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::Tagged());
2672  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2673  __ Set(rdx, V8_2PART_UINT64_C(0x12345678, deadbeaf));
2674  __ cmpq(rcx, rdx);
2675  __ j(not_equal, &exit);
2676  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::Tagged());
2677  __ cmpq(rcx, rdx);
2678  __ j(not_equal, &exit);
2679
2680  // Test 6.
2681  __ movq(rax, Immediate(6));  // Test number.
2682  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2683  __ Set(rcx, V8_2PART_UINT64_C(0x11223344, 55667788));
2684  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::External());
2685  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2686  __ Set(rdx, V8_2PART_UINT64_C(0x11223344, 55667788));
2687  __ cmpq(rcx, rdx);
2688  __ j(not_equal, &exit);
2689  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::External());
2690  __ cmpq(rcx, rdx);
2691  __ j(not_equal, &exit);
2692
2693  // Test 7.
2694  __ movq(rax, Immediate(7));  // Test number.
2695  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2696  __ movq(rcx, Immediate(-1));
2697  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::Integer8());
2698  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2699  __ movl(rdx, Immediate(255));
2700  __ cmpq(rcx, rdx);
2701  __ j(not_equal, &exit);
2702  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::Integer8());
2703  __ movq(rcx, Immediate(-1));
2704  __ cmpq(rcx, rdx);
2705  __ j(not_equal, &exit);
2706
2707  // Test 8.
2708  __ movq(rax, Immediate(8));  // Test number.
2709  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2710  __ movq(rcx, Immediate(-1));
2711  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::Integer16());
2712  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2713  __ movl(rdx, Immediate(65535));
2714  __ cmpq(rcx, rdx);
2715  __ j(not_equal, &exit);
2716  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::Integer16());
2717  __ movq(rcx, Immediate(-1));
2718  __ cmpq(rcx, rdx);
2719  __ j(not_equal, &exit);
2720
2721  // Test 9.
2722  __ movq(rax, Immediate(9));  // Test number.
2723  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2724  __ movq(rcx, Immediate(-1));
2725  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::UInteger16());
2726  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2727  __ movl(rdx, Immediate(65535));
2728  __ cmpq(rcx, rdx);
2729  __ j(not_equal, &exit);
2730  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::UInteger16());
2731  __ cmpq(rcx, rdx);
2732  __ j(not_equal, &exit);
2733
2734  __ xorq(rax, rax);  // Success.
2735  __ bind(&exit);
2736  __ addq(rsp, Immediate(1 * kPointerSize));
2737  ExitCode(masm);
2738  __ ret(0);
2739
2740  CodeDesc desc;
2741  masm->GetCode(&desc);
2742  // Call the function from C++.
2743  int result = FUNCTION_CAST<F0>(buffer)();
2744  CHECK_EQ(0, result);
2745}
2746
2747
2748#undef __
2749