Revision f230a1cf deps/v8/test/cctest/test-assembler-x64.cc
deps/v8/test/cctest/test-assembler-x64.cc | ||
---|---|---|
35 | 35 |
#include "serialize.h" |
36 | 36 |
#include "cctest.h" |
37 | 37 |
|
38 |
using v8::internal::Assembler; |
|
39 |
using v8::internal::Code; |
|
40 |
using v8::internal::CodeDesc; |
|
41 |
using v8::internal::FUNCTION_CAST; |
|
42 |
using v8::internal::Immediate; |
|
43 |
using v8::internal::Isolate; |
|
44 |
using v8::internal::Label; |
|
45 |
using v8::internal::OS; |
|
46 |
using v8::internal::Operand; |
|
47 |
using v8::internal::byte; |
|
48 |
using v8::internal::greater; |
|
49 |
using v8::internal::less_equal; |
|
50 |
using v8::internal::equal; |
|
51 |
using v8::internal::not_equal; |
|
52 |
using v8::internal::r13; |
|
53 |
using v8::internal::r15; |
|
54 |
using v8::internal::r8; |
|
55 |
using v8::internal::r9; |
|
56 |
using v8::internal::rax; |
|
57 |
using v8::internal::rbx; |
|
58 |
using v8::internal::rbp; |
|
59 |
using v8::internal::rcx; |
|
60 |
using v8::internal::rdi; |
|
61 |
using v8::internal::rdx; |
|
62 |
using v8::internal::rsi; |
|
63 |
using v8::internal::rsp; |
|
64 |
using v8::internal::times_1; |
|
65 |
using v8::internal::xmm0; |
|
38 |
using namespace v8::internal; |
|
66 | 39 |
|
67 | 40 |
// Test the x64 assembler by compiling some simple functions into |
68 | 41 |
// a buffer and executing them. These tests do not initialize the |
... | ... | |
77 | 50 |
typedef int (*F0)(); |
78 | 51 |
typedef int (*F1)(int64_t x); |
79 | 52 |
typedef int (*F2)(int64_t x, int64_t y); |
53 |
typedef int (*F3)(double x); |
|
54 |
typedef int64_t (*F4)(int64_t* x, int64_t* y); |
|
55 |
typedef int64_t (*F5)(int64_t x); |
|
80 | 56 |
|
81 | 57 |
#ifdef _WIN64 |
82 |
static const v8::internal::Register arg1 = rcx;
|
|
83 |
static const v8::internal::Register arg2 = rdx;
|
|
58 |
static const Register arg1 = rcx; |
|
59 |
static const Register arg2 = rdx; |
|
84 | 60 |
#else |
85 |
static const v8::internal::Register arg1 = rdi;
|
|
86 |
static const v8::internal::Register arg2 = rsi;
|
|
61 |
static const Register arg1 = rdi; |
|
62 |
static const Register arg2 = rsi; |
|
87 | 63 |
#endif |
88 | 64 |
|
89 | 65 |
#define __ assm. |
... | ... | |
96 | 72 |
&actual_size, |
97 | 73 |
true)); |
98 | 74 |
CHECK(buffer); |
99 |
Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size));
|
|
75 |
Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
|
|
100 | 76 |
|
101 | 77 |
// Assemble a simple function that copies argument 2 and returns it. |
102 | 78 |
__ movq(rax, arg2); |
... | ... | |
118 | 94 |
&actual_size, |
119 | 95 |
true)); |
120 | 96 |
CHECK(buffer); |
121 |
Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size));
|
|
97 |
Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
|
|
122 | 98 |
|
123 | 99 |
// Assemble a simple function that copies argument 2 and returns it. |
124 | 100 |
// We compile without stack frame pointers, so the gdb debugger shows |
... | ... | |
150 | 126 |
&actual_size, |
151 | 127 |
true)); |
152 | 128 |
CHECK(buffer); |
153 |
Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size));
|
|
129 |
Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
|
|
154 | 130 |
|
155 | 131 |
// Assemble a simple function that adds arguments returning the sum. |
156 | 132 |
__ movq(rax, arg2); |
... | ... | |
172 | 148 |
&actual_size, |
173 | 149 |
true)); |
174 | 150 |
CHECK(buffer); |
175 |
Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size));
|
|
151 |
Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
|
|
176 | 152 |
|
177 | 153 |
// Assemble a simple function that multiplies arguments returning the high |
178 | 154 |
// word. |
... | ... | |
193 | 169 |
} |
194 | 170 |
|
195 | 171 |
|
172 |
TEST(AssemblerX64XchglOperations) { |
|
173 |
// Allocate an executable page of memory. |
|
174 |
size_t actual_size; |
|
175 |
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, |
|
176 |
&actual_size, |
|
177 |
true)); |
|
178 |
CHECK(buffer); |
|
179 |
Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size)); |
|
180 |
|
|
181 |
__ movq(rax, Operand(arg1, 0)); |
|
182 |
__ movq(rbx, Operand(arg2, 0)); |
|
183 |
__ xchgl(rax, rbx); |
|
184 |
__ movq(Operand(arg1, 0), rax); |
|
185 |
__ movq(Operand(arg2, 0), rbx); |
|
186 |
__ ret(0); |
|
187 |
|
|
188 |
CodeDesc desc; |
|
189 |
assm.GetCode(&desc); |
|
190 |
// Call the function from C++. |
|
191 |
int64_t left = V8_2PART_UINT64_C(0x10000000, 20000000); |
|
192 |
int64_t right = V8_2PART_UINT64_C(0x30000000, 40000000); |
|
193 |
int64_t result = FUNCTION_CAST<F4>(buffer)(&left, &right); |
|
194 |
CHECK_EQ(V8_2PART_UINT64_C(0x00000000, 40000000), left); |
|
195 |
CHECK_EQ(V8_2PART_UINT64_C(0x00000000, 20000000), right); |
|
196 |
USE(result); |
|
197 |
} |
|
198 |
|
|
199 |
|
|
200 |
TEST(AssemblerX64OrlOperations) { |
|
201 |
// Allocate an executable page of memory. |
|
202 |
size_t actual_size; |
|
203 |
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, |
|
204 |
&actual_size, |
|
205 |
true)); |
|
206 |
CHECK(buffer); |
|
207 |
Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size)); |
|
208 |
|
|
209 |
__ movq(rax, Operand(arg2, 0)); |
|
210 |
__ orl(Operand(arg1, 0), rax); |
|
211 |
__ ret(0); |
|
212 |
|
|
213 |
CodeDesc desc; |
|
214 |
assm.GetCode(&desc); |
|
215 |
// Call the function from C++. |
|
216 |
int64_t left = V8_2PART_UINT64_C(0x10000000, 20000000); |
|
217 |
int64_t right = V8_2PART_UINT64_C(0x30000000, 40000000); |
|
218 |
int64_t result = FUNCTION_CAST<F4>(buffer)(&left, &right); |
|
219 |
CHECK_EQ(V8_2PART_UINT64_C(0x10000000, 60000000), left); |
|
220 |
USE(result); |
|
221 |
} |
|
222 |
|
|
223 |
|
|
224 |
TEST(AssemblerX64RollOperations) { |
|
225 |
// Allocate an executable page of memory. |
|
226 |
size_t actual_size; |
|
227 |
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, |
|
228 |
&actual_size, |
|
229 |
true)); |
|
230 |
CHECK(buffer); |
|
231 |
Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size)); |
|
232 |
|
|
233 |
__ movq(rax, arg1); |
|
234 |
__ roll(rax, Immediate(1)); |
|
235 |
__ ret(0); |
|
236 |
|
|
237 |
CodeDesc desc; |
|
238 |
assm.GetCode(&desc); |
|
239 |
// Call the function from C++. |
|
240 |
int64_t src = V8_2PART_UINT64_C(0x10000000, C0000000); |
|
241 |
int64_t result = FUNCTION_CAST<F5>(buffer)(src); |
|
242 |
CHECK_EQ(V8_2PART_UINT64_C(0x00000000, 80000001), result); |
|
243 |
} |
|
244 |
|
|
245 |
|
|
246 |
TEST(AssemblerX64SublOperations) { |
|
247 |
// Allocate an executable page of memory. |
|
248 |
size_t actual_size; |
|
249 |
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, |
|
250 |
&actual_size, |
|
251 |
true)); |
|
252 |
CHECK(buffer); |
|
253 |
Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size)); |
|
254 |
|
|
255 |
__ movq(rax, Operand(arg2, 0)); |
|
256 |
__ subl(Operand(arg1, 0), rax); |
|
257 |
__ ret(0); |
|
258 |
|
|
259 |
CodeDesc desc; |
|
260 |
assm.GetCode(&desc); |
|
261 |
// Call the function from C++. |
|
262 |
int64_t left = V8_2PART_UINT64_C(0x10000000, 20000000); |
|
263 |
int64_t right = V8_2PART_UINT64_C(0x30000000, 40000000); |
|
264 |
int64_t result = FUNCTION_CAST<F4>(buffer)(&left, &right); |
|
265 |
CHECK_EQ(V8_2PART_UINT64_C(0x10000000, e0000000), left); |
|
266 |
USE(result); |
|
267 |
} |
|
268 |
|
|
269 |
|
|
270 |
TEST(AssemblerX64TestlOperations) { |
|
271 |
// Allocate an executable page of memory. |
|
272 |
size_t actual_size; |
|
273 |
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, |
|
274 |
&actual_size, |
|
275 |
true)); |
|
276 |
CHECK(buffer); |
|
277 |
Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size)); |
|
278 |
|
|
279 |
// Set rax with the ZF flag of the testl instruction. |
|
280 |
Label done; |
|
281 |
__ movq(rax, Immediate(1)); |
|
282 |
__ movq(rbx, Operand(arg2, 0)); |
|
283 |
__ testl(Operand(arg1, 0), rbx); |
|
284 |
__ j(zero, &done, Label::kNear); |
|
285 |
__ movq(rax, Immediate(0)); |
|
286 |
__ bind(&done); |
|
287 |
__ ret(0); |
|
288 |
|
|
289 |
CodeDesc desc; |
|
290 |
assm.GetCode(&desc); |
|
291 |
// Call the function from C++. |
|
292 |
int64_t left = V8_2PART_UINT64_C(0x10000000, 20000000); |
|
293 |
int64_t right = V8_2PART_UINT64_C(0x30000000, 00000000); |
|
294 |
int64_t result = FUNCTION_CAST<F4>(buffer)(&left, &right); |
|
295 |
CHECK_EQ(static_cast<int64_t>(1), result); |
|
296 |
} |
|
297 |
|
|
298 |
|
|
299 |
TEST(AssemblerX64XorlOperations) { |
|
300 |
// Allocate an executable page of memory. |
|
301 |
size_t actual_size; |
|
302 |
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, |
|
303 |
&actual_size, |
|
304 |
true)); |
|
305 |
CHECK(buffer); |
|
306 |
Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size)); |
|
307 |
|
|
308 |
__ movq(rax, Operand(arg2, 0)); |
|
309 |
__ xorl(Operand(arg1, 0), rax); |
|
310 |
__ ret(0); |
|
311 |
|
|
312 |
CodeDesc desc; |
|
313 |
assm.GetCode(&desc); |
|
314 |
// Call the function from C++. |
|
315 |
int64_t left = V8_2PART_UINT64_C(0x10000000, 20000000); |
|
316 |
int64_t right = V8_2PART_UINT64_C(0x30000000, 60000000); |
|
317 |
int64_t result = FUNCTION_CAST<F4>(buffer)(&left, &right); |
|
318 |
CHECK_EQ(V8_2PART_UINT64_C(0x10000000, 40000000), left); |
|
319 |
USE(result); |
|
320 |
} |
|
321 |
|
|
322 |
|
|
196 | 323 |
TEST(AssemblerX64MemoryOperands) { |
197 | 324 |
// Allocate an executable page of memory. |
198 | 325 |
size_t actual_size; |
... | ... | |
200 | 327 |
&actual_size, |
201 | 328 |
true)); |
202 | 329 |
CHECK(buffer); |
203 |
Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size));
|
|
330 |
Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
|
|
204 | 331 |
|
205 | 332 |
// Assemble a simple function that copies argument 2 and returns it. |
206 | 333 |
__ push(rbp); |
... | ... | |
234 | 361 |
&actual_size, |
235 | 362 |
true)); |
236 | 363 |
CHECK(buffer); |
237 |
Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size));
|
|
364 |
Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
|
|
238 | 365 |
|
239 | 366 |
// Assemble a simple function that copies argument 1 and returns it. |
240 | 367 |
__ push(rbp); |
... | ... | |
263 | 390 |
&actual_size, |
264 | 391 |
true)); |
265 | 392 |
CHECK(buffer); |
266 |
Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size));
|
|
393 |
Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
|
|
267 | 394 |
// Assemble two loops using rax as counter, and verify the ending counts. |
268 | 395 |
Label Fail; |
269 | 396 |
__ movq(rax, Immediate(-3)); |
... | ... | |
353 | 480 |
// Test chaining of label usages within instructions (issue 1644). |
354 | 481 |
CcTest::InitializeVM(); |
355 | 482 |
v8::HandleScope scope(CcTest::isolate()); |
356 |
Assembler assm(Isolate::Current(), NULL, 0);
|
|
483 |
Assembler assm(CcTest::i_isolate(), NULL, 0);
|
|
357 | 484 |
|
358 | 485 |
Label target; |
359 | 486 |
__ j(equal, &target); |
... | ... | |
366 | 493 |
TEST(AssemblerMultiByteNop) { |
367 | 494 |
CcTest::InitializeVM(); |
368 | 495 |
v8::HandleScope scope(CcTest::isolate()); |
369 |
v8::internal::byte buffer[1024];
|
|
370 |
Isolate* isolate = Isolate::Current();
|
|
496 |
byte buffer[1024]; |
|
497 |
Isolate* isolate = CcTest::i_isolate();
|
|
371 | 498 |
Assembler assm(isolate, buffer, sizeof(buffer)); |
372 | 499 |
__ push(rbx); |
373 | 500 |
__ push(rcx); |
... | ... | |
420 | 547 |
Code* code = Code::cast(isolate->heap()->CreateCode( |
421 | 548 |
desc, |
422 | 549 |
Code::ComputeFlags(Code::STUB), |
423 |
v8::internal::Handle<Code>())->ToObjectChecked());
|
|
550 |
Handle<Code>())->ToObjectChecked()); |
|
424 | 551 |
CHECK(code->IsCode()); |
425 | 552 |
|
426 | 553 |
F0 f = FUNCTION_CAST<F0>(code->entry()); |
... | ... | |
433 | 560 |
#define ELEMENT_COUNT 4 |
434 | 561 |
|
435 | 562 |
void DoSSE2(const v8::FunctionCallbackInfo<v8::Value>& args) { |
436 |
CcTest::InitializeVM(); |
|
437 | 563 |
v8::HandleScope scope(CcTest::isolate()); |
438 |
v8::internal::byte buffer[1024];
|
|
564 |
byte buffer[1024]; |
|
439 | 565 |
|
440 | 566 |
CHECK(args[0]->IsArray()); |
441 | 567 |
v8::Local<v8::Array> vec = v8::Local<v8::Array>::Cast(args[0]); |
442 | 568 |
CHECK_EQ(ELEMENT_COUNT, vec->Length()); |
443 | 569 |
|
444 |
Isolate* isolate = Isolate::Current();
|
|
570 |
Isolate* isolate = CcTest::i_isolate();
|
|
445 | 571 |
Assembler assm(isolate, buffer, sizeof(buffer)); |
446 | 572 |
|
447 | 573 |
// Remove return address from the stack for fix stack frame alignment. |
... | ... | |
473 | 599 |
Code* code = Code::cast(isolate->heap()->CreateCode( |
474 | 600 |
desc, |
475 | 601 |
Code::ComputeFlags(Code::STUB), |
476 |
v8::internal::Handle<Code>())->ToObjectChecked());
|
|
602 |
Handle<Code>())->ToObjectChecked()); |
|
477 | 603 |
CHECK(code->IsCode()); |
478 | 604 |
|
479 | 605 |
F0 f = FUNCTION_CAST<F0>(code->entry()); |
... | ... | |
483 | 609 |
|
484 | 610 |
|
485 | 611 |
TEST(StackAlignmentForSSE2) { |
612 |
CcTest::InitializeVM(); |
|
486 | 613 |
CHECK_EQ(0, OS::ActivationFrameAlignment() % 16); |
487 | 614 |
|
488 |
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
|
615 |
v8::Isolate* isolate = CcTest::isolate();
|
|
489 | 616 |
v8::HandleScope handle_scope(isolate); |
490 | 617 |
v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); |
491 | 618 |
global_template->Set(v8_str("do_sse2"), v8::FunctionTemplate::New(DoSSE2)); |
... | ... | |
517 | 644 |
#endif // __GNUC__ |
518 | 645 |
|
519 | 646 |
|
647 |
TEST(AssemblerX64Extractps) { |
|
648 |
CcTest::InitializeVM(); |
|
649 |
if (!CpuFeatures::IsSupported(SSE4_1)) return; |
|
650 |
|
|
651 |
v8::HandleScope scope(CcTest::isolate()); |
|
652 |
byte buffer[256]; |
|
653 |
Isolate* isolate = CcTest::i_isolate(); |
|
654 |
Assembler assm(isolate, buffer, sizeof(buffer)); |
|
655 |
{ CpuFeatureScope fscope2(&assm, SSE4_1); |
|
656 |
__ extractps(rax, xmm0, 0x1); |
|
657 |
__ ret(0); |
|
658 |
} |
|
659 |
|
|
660 |
CodeDesc desc; |
|
661 |
assm.GetCode(&desc); |
|
662 |
Code* code = Code::cast(isolate->heap()->CreateCode( |
|
663 |
desc, |
|
664 |
Code::ComputeFlags(Code::STUB), |
|
665 |
Handle<Code>())->ToObjectChecked()); |
|
666 |
CHECK(code->IsCode()); |
|
667 |
#ifdef OBJECT_PRINT |
|
668 |
Code::cast(code)->Print(); |
|
669 |
#endif |
|
670 |
|
|
671 |
F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry()); |
|
672 |
uint64_t value1 = V8_2PART_UINT64_C(0x12345678, 87654321); |
|
673 |
CHECK_EQ(0x12345678, f(uint64_to_double(value1))); |
|
674 |
uint64_t value2 = V8_2PART_UINT64_C(0x87654321, 12345678); |
|
675 |
CHECK_EQ(0x87654321, f(uint64_to_double(value2))); |
|
676 |
} |
|
677 |
|
|
678 |
|
|
520 | 679 |
#undef __ |
Also available in: Unified diff