OLD | NEW |
---|---|
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/assembler.h" | 5 #include "src/assembler.h" |
6 #include "src/codegen.h" | 6 #include "src/codegen.h" |
7 #include "src/compiler/linkage.h" | 7 #include "src/compiler/linkage.h" |
8 #include "src/compiler/machine-type.h" | 8 #include "src/compiler/machine-type.h" |
9 #include "src/compiler/raw-machine-assembler.h" | 9 #include "src/compiler/raw-machine-assembler.h" |
10 | 10 |
11 #include "test/cctest/cctest.h" | 11 #include "test/cctest/cctest.h" |
12 #include "test/cctest/compiler/codegen-tester.h" | 12 #include "test/cctest/compiler/codegen-tester.h" |
13 #include "test/cctest/compiler/graph-builder-tester.h" | 13 #include "test/cctest/compiler/graph-builder-tester.h" |
14 #include "test/cctest/compiler/value-helper.h" | 14 #include "test/cctest/compiler/value-helper.h" |
15 | 15 |
16 using namespace v8::base; | 16 using namespace v8::base; |
17 using namespace v8::internal; | 17 using namespace v8::internal; |
18 using namespace v8::internal::compiler; | 18 using namespace v8::internal::compiler; |
19 | 19 |
20 typedef RawMachineAssembler::Label MLabel; | 20 typedef RawMachineAssembler::Label MLabel; |
21 | 21 |
22 #if !V8_TARGET_ARCH_ARM64 | 22 #if V8_TARGET_ARCH_ARM64 |
23 // TODO(titzer): fix native stack parameters on arm64 | 23 // TODO(titzer): fix native stack parameters on arm64 |
24 #define NATIVE_STACK_PARAMS_OK | 24 #define DISABLE_NATIVE_STACK_PARAMS true |
25 #else | |
26 #define DISABLE_NATIVE_STACK_PARAMS false | |
25 #endif | 27 #endif |
26 | 28 |
27 namespace { | 29 namespace { |
28 // Picks a representative set of registers from the allocatable set. | 30 typedef float float32; |
29 // If there are less than 100 possible pairs, do them all, otherwise try | 31 typedef double float64; |
32 | |
33 // Picks a representative set of integers from the gi | |
Michael Starzinger
2015/08/12 17:48:41
nit: comment looks incomplete.
| |
34 // If there are less than {max_pairs} possible pairs, do them all, otherwise try | |
30 // to select a representative set. | 35 // to select a representative set. |
31 class RegisterPairs { | 36 class Pairs { |
32 public: | 37 public: |
33 RegisterPairs() | 38 Pairs(int max_pairs, int range) |
34 : max_(std::min(100, Register::kMaxNumAllocatableRegisters * | 39 : range_(range), |
35 Register::kMaxNumAllocatableRegisters)), | 40 max_pairs_(std::min(max_pairs, range_ * range_)), |
36 counter_(0) {} | 41 counter_(0) {} |
37 | 42 |
38 bool More() { return counter_ < max_; } | 43 bool More() { return counter_ < max_pairs_; } |
39 | 44 |
40 void Next(int* r0, int* r1, bool same_is_ok) { | 45 void Next(int* r0, int* r1, bool same_is_ok) { |
41 do { | 46 do { |
42 // Find the next pair. | 47 // Find the next pair. |
43 if (exhaustive()) { | 48 if (exhaustive()) { |
44 *r0 = counter_ % Register::kMaxNumAllocatableRegisters; | 49 *r0 = counter_ % range_; |
45 *r1 = counter_ / Register::kMaxNumAllocatableRegisters; | 50 *r1 = counter_ / range_; |
46 } else { | 51 } else { |
47 // Try each register at least once for both r0 and r1. | 52 // Try each integer at least once for both r0 and r1. |
48 int index = counter_ / 2; | 53 int index = counter_ / 2; |
49 if (counter_ & 1) { | 54 if (counter_ & 1) { |
50 *r0 = index % Register::kMaxNumAllocatableRegisters; | 55 *r0 = index % range_; |
51 *r1 = index / Register::kMaxNumAllocatableRegisters; | 56 *r1 = index / range_; |
52 } else { | 57 } else { |
53 *r1 = index % Register::kMaxNumAllocatableRegisters; | 58 *r1 = index % range_; |
54 *r0 = index / Register::kMaxNumAllocatableRegisters; | 59 *r0 = index / range_; |
55 } | 60 } |
56 } | 61 } |
57 counter_++; | 62 counter_++; |
58 if (same_is_ok) break; | 63 if (same_is_ok) break; |
59 if (*r0 == *r1) { | 64 if (*r0 == *r1) { |
60 if (counter_ >= max_) { | 65 if (counter_ >= max_pairs_) { |
61 // For the last hurrah, reg#0 with reg#n-1 | 66 // For the last hurrah, reg#0 with reg#n-1 |
62 *r0 = 0; | 67 *r0 = 0; |
63 *r1 = Register::kMaxNumAllocatableRegisters - 1; | 68 *r1 = range_ - 1; |
64 break; | 69 break; |
65 } | 70 } |
66 } | 71 } |
67 } while (true); | 72 } while (true); |
68 | 73 |
69 DCHECK(*r0 >= 0 && *r0 < Register::kMaxNumAllocatableRegisters); | 74 DCHECK(*r0 >= 0 && *r0 < range_); |
70 DCHECK(*r1 >= 0 && *r1 < Register::kMaxNumAllocatableRegisters); | 75 DCHECK(*r1 >= 0 && *r1 < range_); |
71 printf("pair = %d, %d\n", *r0, *r1); | 76 // printf("pair = %d, %d\n", *r0, *r1); |
Michael Starzinger
2015/08/12 17:48:41
nit: Looks like a leftover.
| |
72 } | 77 } |
73 | 78 |
74 private: | 79 private: |
75 int max_; | 80 int range_; |
81 int max_pairs_; | |
76 int counter_; | 82 int counter_; |
77 bool exhaustive() { | 83 bool exhaustive() { return max_pairs_ == (range_ * range_); } |
78 return max_ == (Register::kMaxNumAllocatableRegisters * | |
79 Register::kMaxNumAllocatableRegisters); | |
80 } | |
81 }; | 84 }; |
82 | 85 |
83 | 86 |
87 // Pairs of general purpose registers. | |
88 class RegisterPairs : public Pairs { | |
89 public: | |
90 RegisterPairs() : Pairs(100, Register::kMaxNumAllocatableRegisters) {} | |
91 }; | |
92 | |
93 | |
94 // Pairs of double registers. | |
95 class Float32RegisterPairs : public Pairs { | |
96 public: | |
97 Float32RegisterPairs() | |
98 : Pairs(100, DoubleRegister::NumAllocatableAliasedRegisters()) {} | |
99 }; | |
100 | |
101 | |
102 // Pairs of double registers. | |
103 class Float64RegisterPairs : public Pairs { | |
104 public: | |
105 Float64RegisterPairs() | |
106 : Pairs(100, DoubleRegister::NumAllocatableAliasedRegisters()) {} | |
107 }; | |
108 | |
109 | |
84 // Helper for allocating either an GP or FP reg, or the next stack slot. | 110 // Helper for allocating either an GP or FP reg, or the next stack slot. |
85 struct Allocator { | 111 struct Allocator { |
86 Allocator(int* gp, int gpc, int* fp, int fpc) | 112 Allocator(int* gp, int gpc, int* fp, int fpc) |
87 : gp_count(gpc), | 113 : gp_count(gpc), |
88 gp_offset(0), | 114 gp_offset(0), |
89 gp_regs(gp), | 115 gp_regs(gp), |
90 fp_count(fpc), | 116 fp_count(fpc), |
91 fp_offset(0), | 117 fp_offset(0), |
92 fp_regs(fp), | 118 fp_regs(fp), |
93 stack_offset(0) {} | 119 stack_offset(0) {} |
(...skipping 164 matching lines...) Loading... | |
258 Node* ret = b.graph()->NewNode(b.common()->Return(), call, call, start); | 284 Node* ret = b.graph()->NewNode(b.common()->Return(), call, call, start); |
259 b.graph()->SetEnd(ret); | 285 b.graph()->SetEnd(ret); |
260 } | 286 } |
261 | 287 |
262 CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, msig); | 288 CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, msig); |
263 | 289 |
264 return CompileGraph("wrapper", cdesc, caller.graph()); | 290 return CompileGraph("wrapper", cdesc, caller.graph()); |
265 } | 291 } |
266 | 292 |
267 | 293 |
294 template <typename CType> | |
295 class ArgsBuffer { | |
296 public: | |
297 static const int kMaxParamCount = 64; | |
298 | |
299 explicit ArgsBuffer(int count, int seed = 1) : count_(count), seed_(seed) { | |
300 // initialize the buffer with "seed 0" | |
301 seed_ = 0; | |
302 Mutate(); | |
303 seed_ = seed; | |
304 } | |
305 | |
306 class Sig : public MachineSignature { | |
307 public: | |
308 explicit Sig(int param_count) | |
309 : MachineSignature(1, param_count, MachTypes()) { | |
310 CHECK(param_count <= kMaxParamCount); | |
311 } | |
312 }; | |
313 | |
314 static MachineType* MachTypes() { | |
315 MachineType t = MachineTypeForC<CType>(); | |
316 static MachineType kTypes[kMaxParamCount + 1] = { | |
317 t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, | |
318 t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, | |
319 t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t}; | |
320 return kTypes; | |
321 } | |
322 | |
323 Node* MakeConstant(RawMachineAssembler& raw, int32_t value) { | |
324 return raw.Int32Constant(value); | |
325 } | |
326 | |
327 Node* MakeConstant(RawMachineAssembler& raw, int64_t value) { | |
328 return raw.Int64Constant(value); | |
329 } | |
330 | |
331 Node* MakeConstant(RawMachineAssembler& raw, float32 value) { | |
332 return raw.Float32Constant(value); | |
333 } | |
334 | |
335 Node* MakeConstant(RawMachineAssembler& raw, float64 value) { | |
336 return raw.Float64Constant(value); | |
337 } | |
338 | |
339 Node* LoadInput(RawMachineAssembler& raw, Node* base, int index) { | |
340 Node* offset = raw.Int32Constant(index * sizeof(CType)); | |
341 return raw.Load(MachineTypeForC<CType>(), base, offset); | |
342 } | |
343 | |
344 Node* StoreOutput(RawMachineAssembler& raw, Node* value) { | |
345 Node* base = raw.PointerConstant(&output); | |
346 Node* offset = raw.Int32Constant(0); | |
347 return raw.Store(MachineTypeForC<CType>(), base, offset, value); | |
348 } | |
349 | |
350 void Mutate(); | |
351 | |
352 void Reset() { memset(input, 0, sizeof(input)); } | |
353 | |
354 int count_; | |
355 int seed_; | |
356 CType input[kMaxParamCount]; | |
357 CType output; | |
358 }; | |
359 | |
360 | |
361 template <> | |
362 void ArgsBuffer<int32_t>::Mutate() { | |
363 uint32_t base = 1111111111u * seed_; | |
364 for (int j = 0; j < count_; j++) { | |
365 input[j] = static_cast<int32_t>(256 + base + j + seed_ * 13); | |
366 } | |
367 output = -1; | |
368 seed_++; | |
369 } | |
370 | |
371 | |
372 template <> | |
373 void ArgsBuffer<int64_t>::Mutate() { | |
374 uint64_t base = 11111111111111111ull * seed_; | |
375 for (int j = 0; j < count_; j++) { | |
376 input[j] = static_cast<int64_t>(256 + base + j + seed_ * 13); | |
377 } | |
378 output = -1; | |
379 seed_++; | |
380 } | |
381 | |
382 | |
383 template <> | |
384 void ArgsBuffer<float32>::Mutate() { | |
385 float64 base = -33.25 * seed_; | |
386 for (int j = 0; j < count_; j++) { | |
387 input[j] = 256 + base + j + seed_ * 13; | |
388 } | |
389 output = std::numeric_limits<float32>::quiet_NaN(); | |
390 seed_++; | |
391 } | |
392 | |
393 | |
394 template <> | |
395 void ArgsBuffer<float64>::Mutate() { | |
396 float64 base = -111.25 * seed_; | |
397 for (int j = 0; j < count_; j++) { | |
398 input[j] = 256 + base + j + seed_ * 13; | |
399 } | |
400 output = std::numeric_limits<float64>::quiet_NaN(); | |
401 seed_++; | |
402 } | |
403 | |
404 | |
405 template <typename CType> | |
406 void ArgsBuffer<CType>::Mutate() { | |
Michael Starzinger
2015/08/12 17:48:41
Can we just skip the non-specialized implementatio
| |
407 UNIMPLEMENTED(); | |
408 } | |
409 | |
410 | |
411 int ParamCount(CallDescriptor* desc) { | |
412 return static_cast<int>(desc->GetMachineSignature()->parameter_count()); | |
413 } | |
414 | |
415 | |
416 template <typename CType> | |
417 class Computer { | |
418 public: | |
419 static void Run(CallDescriptor* desc, | |
420 void (*build)(CallDescriptor*, RawMachineAssembler&), | |
421 CType (*compute)(CallDescriptor*, CType* inputs), | |
422 int seed = 1) { | |
423 int num_params = ParamCount(desc); | |
424 CHECK_LE(num_params, kMaxParamCount); | |
425 Isolate* isolate = CcTest::InitIsolateOnce(); | |
426 HandleScope scope(isolate); | |
427 Handle<Code> inner = Handle<Code>::null(); | |
428 { | |
429 // Build the graph for the computation. | |
430 Zone zone; | |
431 Graph graph(&zone); | |
432 RawMachineAssembler raw(isolate, &graph, desc); | |
433 build(desc, raw); | |
434 inner = CompileGraph("Compute", desc, &graph, raw.Export()); | |
435 } | |
436 | |
437 CSignature0<int32_t> csig; | |
438 ArgsBuffer<CType> io(num_params, seed); | |
439 | |
440 { | |
441 // constant mode. | |
442 Handle<Code> wrapper = Handle<Code>::null(); | |
443 { | |
444 // Wrap the above code with a callable function that passes constants. | |
445 Zone zone; | |
446 Graph graph(&zone); | |
447 CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig); | |
448 RawMachineAssembler raw(isolate, &graph, cdesc); | |
449 Unique<HeapObject> unique = | |
450 Unique<HeapObject>::CreateUninitialized(inner); | |
451 Node* target = raw.HeapConstant(unique); | |
452 Node** args = zone.NewArray<Node*>(kMaxParamCount); | |
453 for (int i = 0; i < num_params; i++) { | |
454 args[i] = io.MakeConstant(raw, io.input[i]); | |
455 } | |
456 | |
457 Node* call = raw.CallN(desc, target, args); | |
458 Node* store = io.StoreOutput(raw, call); | |
459 USE(store); | |
460 raw.Return(raw.Int32Constant(seed)); | |
461 wrapper = | |
462 CompileGraph("Compute-wrapper-const", cdesc, &graph, raw.Export()); | |
463 } | |
464 | |
465 CodeRunner<int32_t> runnable(isolate, wrapper, &csig); | |
466 | |
467 // Run the code, checking it against the reference. | |
468 CType expected = compute(desc, io.input); | |
469 int32_t check_seed = runnable.Call(); | |
470 CHECK_EQ(seed, check_seed); | |
471 CHECK_EQ(expected, io.output); | |
472 } | |
473 | |
474 { | |
475 // buffer mode. | |
476 Handle<Code> wrapper = Handle<Code>::null(); | |
477 { | |
478 // Wrap the above code with a callable function that loads from {input}. | |
479 Zone zone; | |
480 Graph graph(&zone); | |
481 CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig); | |
482 RawMachineAssembler raw(isolate, &graph, cdesc); | |
483 Node* base = raw.PointerConstant(io.input); | |
484 Unique<HeapObject> unique = | |
485 Unique<HeapObject>::CreateUninitialized(inner); | |
486 Node* target = raw.HeapConstant(unique); | |
487 Node** args = zone.NewArray<Node*>(kMaxParamCount); | |
488 for (int i = 0; i < num_params; i++) { | |
489 args[i] = io.LoadInput(raw, base, i); | |
490 } | |
491 | |
492 Node* call = raw.CallN(desc, target, args); | |
493 Node* store = io.StoreOutput(raw, call); | |
494 USE(store); | |
495 raw.Return(raw.Int32Constant(seed)); | |
496 wrapper = CompileGraph("Compute-wrapper", cdesc, &graph, raw.Export()); | |
497 } | |
498 | |
499 CodeRunner<int32_t> runnable(isolate, wrapper, &csig); | |
500 | |
501 // Run the code, checking it against the reference. | |
502 for (int i = 0; i < 5; i++) { | |
503 CType expected = compute(desc, io.input); | |
504 int32_t check_seed = runnable.Call(); | |
505 CHECK_EQ(seed, check_seed); | |
506 CHECK_EQ(expected, io.output); | |
507 io.Mutate(); | |
508 } | |
509 } | |
510 } | |
511 }; | |
512 | |
268 } // namespace | 513 } // namespace |
269 | 514 |
270 | 515 |
271 static void TestInt32Sub(CallDescriptor* desc) { | 516 static void TestInt32Sub(CallDescriptor* desc) { |
272 Isolate* isolate = CcTest::InitIsolateOnce(); | 517 Isolate* isolate = CcTest::InitIsolateOnce(); |
273 HandleScope scope(isolate); | 518 HandleScope scope(isolate); |
274 Zone zone; | 519 Zone zone; |
275 GraphAndBuilders inner(&zone); | 520 GraphAndBuilders inner(&zone); |
276 { | 521 { |
277 // Build the add function. | 522 // Build the add function. |
(...skipping 18 matching lines...) Loading... | |
296 FOR_INT32_INPUTS(j) { | 541 FOR_INT32_INPUTS(j) { |
297 int32_t expected = static_cast<int32_t>(static_cast<uint32_t>(*i) - | 542 int32_t expected = static_cast<int32_t>(static_cast<uint32_t>(*i) - |
298 static_cast<uint32_t>(*j)); | 543 static_cast<uint32_t>(*j)); |
299 int32_t result = runnable.Call(*i, *j); | 544 int32_t result = runnable.Call(*i, *j); |
300 CHECK_EQ(expected, result); | 545 CHECK_EQ(expected, result); |
301 } | 546 } |
302 } | 547 } |
303 } | 548 } |
304 | 549 |
305 | 550 |
306 #ifdef NATIVE_STACK_PARAMS_OK | |
307 static void CopyTwentyInt32(CallDescriptor* desc) { | 551 static void CopyTwentyInt32(CallDescriptor* desc) { |
552 if (DISABLE_NATIVE_STACK_PARAMS) return; | |
553 | |
308 const int kNumParams = 20; | 554 const int kNumParams = 20; |
309 int32_t input[kNumParams]; | 555 int32_t input[kNumParams]; |
310 int32_t output[kNumParams]; | 556 int32_t output[kNumParams]; |
311 Isolate* isolate = CcTest::InitIsolateOnce(); | 557 Isolate* isolate = CcTest::InitIsolateOnce(); |
312 HandleScope scope(isolate); | 558 HandleScope scope(isolate); |
313 Handle<Code> inner = Handle<Code>::null(); | 559 Handle<Code> inner = Handle<Code>::null(); |
314 { | 560 { |
315 // Writes all parameters into the output buffer. | 561 // Writes all parameters into the output buffer. |
316 Zone zone; | 562 Zone zone; |
317 Graph graph(&zone); | 563 Graph graph(&zone); |
(...skipping 40 matching lines...) Loading... | |
358 } | 604 } |
359 | 605 |
360 memset(output, 0, sizeof(output)); | 606 memset(output, 0, sizeof(output)); |
361 CHECK_EQ(42, runnable.Call()); | 607 CHECK_EQ(42, runnable.Call()); |
362 | 608 |
363 for (int j = 0; j < kNumParams; j++) { | 609 for (int j = 0; j < kNumParams; j++) { |
364 CHECK_EQ(input[j], output[j]); | 610 CHECK_EQ(input[j], output[j]); |
365 } | 611 } |
366 } | 612 } |
367 } | 613 } |
368 #endif // NATIVE_STACK_PARAMS_OK | |
369 | 614 |
370 | 615 |
371 static void Test_RunInt32SubWithRet(int retreg) { | 616 static void Test_RunInt32SubWithRet(int retreg) { |
372 Int32Signature sig(2); | 617 Int32Signature sig(2); |
373 Zone zone; | 618 Zone zone; |
374 RegisterPairs pairs; | 619 RegisterPairs pairs; |
375 while (pairs.More()) { | 620 while (pairs.More()) { |
376 int parray[2]; | 621 int parray[2]; |
377 int rarray[] = {retreg}; | 622 int rarray[] = {retreg}; |
378 pairs.Next(&parray[0], &parray[1], false); | 623 pairs.Next(&parray[0], &parray[1], false); |
(...skipping 29 matching lines...) Loading... | |
408 TEST_INT32_SUB_WITH_RET(13) | 653 TEST_INT32_SUB_WITH_RET(13) |
409 TEST_INT32_SUB_WITH_RET(14) | 654 TEST_INT32_SUB_WITH_RET(14) |
410 TEST_INT32_SUB_WITH_RET(15) | 655 TEST_INT32_SUB_WITH_RET(15) |
411 TEST_INT32_SUB_WITH_RET(16) | 656 TEST_INT32_SUB_WITH_RET(16) |
412 TEST_INT32_SUB_WITH_RET(17) | 657 TEST_INT32_SUB_WITH_RET(17) |
413 TEST_INT32_SUB_WITH_RET(18) | 658 TEST_INT32_SUB_WITH_RET(18) |
414 TEST_INT32_SUB_WITH_RET(19) | 659 TEST_INT32_SUB_WITH_RET(19) |
415 | 660 |
416 | 661 |
417 TEST(Run_Int32Sub_all_allocatable_single) { | 662 TEST(Run_Int32Sub_all_allocatable_single) { |
418 #ifdef NATIVE_STACK_PARAMS_OK | 663 if (DISABLE_NATIVE_STACK_PARAMS) return; |
419 Int32Signature sig(2); | 664 Int32Signature sig(2); |
420 RegisterPairs pairs; | 665 RegisterPairs pairs; |
421 while (pairs.More()) { | 666 while (pairs.More()) { |
422 Zone zone; | 667 Zone zone; |
423 int parray[1]; | 668 int parray[1]; |
424 int rarray[1]; | 669 int rarray[1]; |
425 pairs.Next(&rarray[0], &parray[0], true); | 670 pairs.Next(&rarray[0], &parray[0], true); |
426 Allocator params(parray, 1, nullptr, 0); | 671 Allocator params(parray, 1, nullptr, 0); |
427 Allocator rets(rarray, 1, nullptr, 0); | 672 Allocator rets(rarray, 1, nullptr, 0); |
428 RegisterConfig config(params, rets); | 673 RegisterConfig config(params, rets); |
429 CallDescriptor* desc = config.Create(&zone, &sig); | 674 CallDescriptor* desc = config.Create(&zone, &sig); |
430 TestInt32Sub(desc); | 675 TestInt32Sub(desc); |
431 } | 676 } |
432 #endif // NATIVE_STACK_PARAMS_OK | |
433 } | 677 } |
434 | 678 |
435 | 679 |
436 TEST(Run_CopyTwentyInt32_all_allocatable_pairs) { | 680 TEST(Run_CopyTwentyInt32_all_allocatable_pairs) { |
437 #ifdef NATIVE_STACK_PARAMS_OK | 681 if (DISABLE_NATIVE_STACK_PARAMS) return; |
438 Int32Signature sig(20); | 682 Int32Signature sig(20); |
439 RegisterPairs pairs; | 683 RegisterPairs pairs; |
440 while (pairs.More()) { | 684 while (pairs.More()) { |
441 Zone zone; | 685 Zone zone; |
442 int parray[2]; | 686 int parray[2]; |
443 int rarray[] = {0}; | 687 int rarray[] = {0}; |
444 pairs.Next(&parray[0], &parray[1], false); | 688 pairs.Next(&parray[0], &parray[1], false); |
445 Allocator params(parray, 2, nullptr, 0); | 689 Allocator params(parray, 2, nullptr, 0); |
446 Allocator rets(rarray, 1, nullptr, 0); | 690 Allocator rets(rarray, 1, nullptr, 0); |
447 RegisterConfig config(params, rets); | 691 RegisterConfig config(params, rets); |
448 CallDescriptor* desc = config.Create(&zone, &sig); | 692 CallDescriptor* desc = config.Create(&zone, &sig); |
449 CopyTwentyInt32(desc); | 693 CopyTwentyInt32(desc); |
450 } | 694 } |
451 #endif // NATIVE_STACK_PARAMS_OK | |
452 } | |
453 | |
454 | |
455 #ifdef NATIVE_STACK_PARAMS_OK | |
456 int ParamCount(CallDescriptor* desc) { | |
457 return static_cast<int>(desc->GetMachineSignature()->parameter_count()); | |
458 } | |
459 | |
460 | |
461 // Super mega helper routine to generate a computation with a given | |
462 // call descriptor, compile the code, wrap the code, and pass various inputs, | |
463 // comparing against a reference implementation. | |
464 static void Run_Int32_Computation( | |
465 CallDescriptor* desc, void (*build)(CallDescriptor*, RawMachineAssembler&), | |
466 int32_t (*compute)(CallDescriptor*, int32_t* inputs), int seed = 1) { | |
467 int num_params = ParamCount(desc); | |
468 CHECK_LE(num_params, kMaxParamCount); | |
469 int32_t input[kMaxParamCount]; | |
470 Isolate* isolate = CcTest::InitIsolateOnce(); | |
471 HandleScope scope(isolate); | |
472 Handle<Code> inner = Handle<Code>::null(); | |
473 { | |
474 // Build the graph for the computation. | |
475 Zone zone; | |
476 Graph graph(&zone); | |
477 RawMachineAssembler raw(isolate, &graph, desc); | |
478 build(desc, raw); | |
479 inner = CompileGraph("Compute", desc, &graph, raw.Export()); | |
480 } | |
481 | |
482 CSignature0<int32_t> csig; | |
483 | |
484 if (false) { | |
485 // constant mode. | |
486 Handle<Code> wrapper = Handle<Code>::null(); | |
487 { | |
488 // Wrap the above code with a callable function that passes constants. | |
489 Zone zone; | |
490 Graph graph(&zone); | |
491 CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig); | |
492 RawMachineAssembler raw(isolate, &graph, cdesc); | |
493 Unique<HeapObject> unique = | |
494 Unique<HeapObject>::CreateUninitialized(inner); | |
495 Node* target = raw.HeapConstant(unique); | |
496 Node** args = zone.NewArray<Node*>(kMaxParamCount); | |
497 for (int i = 0; i < num_params; i++) { | |
498 args[i] = raw.Int32Constant(0x100 + i); | |
499 } | |
500 | |
501 Node* call = raw.CallN(desc, target, args); | |
502 raw.Return(call); | |
503 wrapper = CompileGraph("Compute-wrapper", cdesc, &graph, raw.Export()); | |
504 } | |
505 | |
506 CodeRunner<int32_t> runnable(isolate, wrapper, &csig); | |
507 | |
508 // Run the code, checking it against the reference. | |
509 for (int j = 0; j < kMaxParamCount; j++) { | |
510 input[j] = 0x100 + j; | |
511 } | |
512 int32_t expected = compute(desc, input); | |
513 int32_t result = runnable.Call(); | |
514 | |
515 CHECK_EQ(expected, result); | |
516 } | |
517 | |
518 { | |
519 // buffer mode. | |
520 Handle<Code> wrapper = Handle<Code>::null(); | |
521 { | |
522 // Wrap the above code with a callable function that loads from {input}. | |
523 Zone zone; | |
524 Graph graph(&zone); | |
525 CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig); | |
526 RawMachineAssembler raw(isolate, &graph, cdesc); | |
527 Node* base = raw.PointerConstant(input); | |
528 Unique<HeapObject> unique = | |
529 Unique<HeapObject>::CreateUninitialized(inner); | |
530 Node* target = raw.HeapConstant(unique); | |
531 Node** args = zone.NewArray<Node*>(kMaxParamCount); | |
532 for (int i = 0; i < num_params; i++) { | |
533 Node* offset = raw.Int32Constant(i * sizeof(int32_t)); | |
534 args[i] = raw.Load(kMachInt32, base, offset); | |
535 } | |
536 | |
537 Node* call = raw.CallN(desc, target, args); | |
538 raw.Return(call); | |
539 wrapper = CompileGraph("Compute-wrapper", cdesc, &graph, raw.Export()); | |
540 } | |
541 | |
542 CodeRunner<int32_t> runnable(isolate, wrapper, &csig); | |
543 | |
544 // Run the code, checking it against the reference. | |
545 for (int i = 0; i < 5; i++) { | |
546 // Use pseudo-random values for each run, but the first run gets args | |
547 // 100, 101, 102, 103... for easier diagnosis. | |
548 uint32_t base = 1111111111u * i * seed; | |
549 for (int j = 0; j < kMaxParamCount; j++) { | |
550 input[j] = static_cast<int32_t>(100 + base + j); | |
551 } | |
552 int32_t expected = compute(desc, input); | |
553 int32_t result = runnable.Call(); | |
554 | |
555 CHECK_EQ(expected, result); | |
556 } | |
557 } | |
558 } | 695 } |
559 | 696 |
560 | 697 |
698 template <typename CType> | |
699 static void Run_Computation( | |
700 CallDescriptor* desc, void (*build)(CallDescriptor*, RawMachineAssembler&), | |
701 CType (*compute)(CallDescriptor*, CType* inputs), int seed = 1) { | |
702 Computer<CType>::Run(desc, build, compute, seed); | |
703 } | |
704 | |
705 | |
561 static uint32_t coeff[] = {1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, | 706 static uint32_t coeff[] = {1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, |
562 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, | 707 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, |
563 79, 83, 89, 97, 101, 103, 107, 109, 113}; | 708 79, 83, 89, 97, 101, 103, 107, 109, 113}; |
564 | 709 |
565 | 710 |
566 static void Build_Int32_WeightedSum(CallDescriptor* desc, | 711 static void Build_Int32_WeightedSum(CallDescriptor* desc, |
567 RawMachineAssembler& raw) { | 712 RawMachineAssembler& raw) { |
568 Node* result = raw.Int32Constant(0); | 713 Node* result = raw.Int32Constant(0); |
569 for (int i = 0; i < ParamCount(desc); i++) { | 714 for (int i = 0; i < ParamCount(desc); i++) { |
570 Node* term = raw.Int32Mul(raw.Parameter(i), raw.Int32Constant(coeff[i])); | 715 Node* term = raw.Int32Mul(raw.Parameter(i), raw.Int32Constant(coeff[i])); |
571 result = raw.Int32Add(result, term); | 716 result = raw.Int32Add(result, term); |
572 } | 717 } |
573 raw.Return(result); | 718 raw.Return(result); |
574 } | 719 } |
575 | 720 |
576 | 721 |
577 static int32_t Compute_Int32_WeightedSum(CallDescriptor* desc, int32_t* input) { | 722 static int32_t Compute_Int32_WeightedSum(CallDescriptor* desc, int32_t* input) { |
578 uint32_t result = 0; | 723 uint32_t result = 0; |
579 for (int i = 0; i < ParamCount(desc); i++) { | 724 for (int i = 0; i < ParamCount(desc); i++) { |
580 result += static_cast<uint32_t>(input[i]) * coeff[i]; | 725 result += static_cast<uint32_t>(input[i]) * coeff[i]; |
581 } | 726 } |
582 return static_cast<int32_t>(result); | 727 return static_cast<int32_t>(result); |
583 } | 728 } |
584 | 729 |
585 | 730 |
586 static void Test_Int32_WeightedSum_of_size(int count) { | 731 static void Test_Int32_WeightedSum_of_size(int count) { |
732 if (DISABLE_NATIVE_STACK_PARAMS) return; | |
587 Int32Signature sig(count); | 733 Int32Signature sig(count); |
588 for (int p0 = 0; p0 < Register::kMaxNumAllocatableRegisters; p0++) { | 734 for (int p0 = 0; p0 < Register::kMaxNumAllocatableRegisters; p0++) { |
589 Zone zone; | 735 Zone zone; |
590 | 736 |
591 int parray[] = {p0}; | 737 int parray[] = {p0}; |
592 int rarray[] = {0}; | 738 int rarray[] = {0}; |
593 Allocator params(parray, 1, nullptr, 0); | 739 Allocator params(parray, 1, nullptr, 0); |
594 Allocator rets(rarray, 1, nullptr, 0); | 740 Allocator rets(rarray, 1, nullptr, 0); |
595 RegisterConfig config(params, rets); | 741 RegisterConfig config(params, rets); |
596 CallDescriptor* desc = config.Create(&zone, &sig); | 742 CallDescriptor* desc = config.Create(&zone, &sig); |
597 Run_Int32_Computation(desc, Build_Int32_WeightedSum, | 743 Run_Computation<int32_t>(desc, Build_Int32_WeightedSum, |
598 Compute_Int32_WeightedSum, 257 + count); | 744 Compute_Int32_WeightedSum, 257 + count); |
599 } | 745 } |
600 } | 746 } |
601 | 747 |
602 | 748 |
603 // Separate tests for parallelization. | 749 // Separate tests for parallelization. |
604 #define TEST_INT32_WEIGHTEDSUM(x) \ | 750 #define TEST_INT32_WEIGHTEDSUM(x) \ |
605 TEST(Run_Int32_WeightedSum_##x) { Test_Int32_WeightedSum_of_size(x); } | 751 TEST(Run_Int32_WeightedSum_##x) { Test_Int32_WeightedSum_of_size(x); } |
606 | 752 |
607 | 753 |
608 TEST_INT32_WEIGHTEDSUM(1) | 754 TEST_INT32_WEIGHTEDSUM(1) |
609 TEST_INT32_WEIGHTEDSUM(2) | 755 TEST_INT32_WEIGHTEDSUM(2) |
610 TEST_INT32_WEIGHTEDSUM(3) | 756 TEST_INT32_WEIGHTEDSUM(3) |
611 TEST_INT32_WEIGHTEDSUM(4) | 757 TEST_INT32_WEIGHTEDSUM(4) |
612 TEST_INT32_WEIGHTEDSUM(5) | 758 TEST_INT32_WEIGHTEDSUM(5) |
613 TEST_INT32_WEIGHTEDSUM(7) | 759 TEST_INT32_WEIGHTEDSUM(7) |
614 TEST_INT32_WEIGHTEDSUM(9) | 760 TEST_INT32_WEIGHTEDSUM(9) |
615 TEST_INT32_WEIGHTEDSUM(11) | 761 TEST_INT32_WEIGHTEDSUM(11) |
616 TEST_INT32_WEIGHTEDSUM(17) | 762 TEST_INT32_WEIGHTEDSUM(17) |
617 TEST_INT32_WEIGHTEDSUM(19) | 763 TEST_INT32_WEIGHTEDSUM(19) |
618 | 764 |
619 | 765 |
620 template <int which> | 766 template <int which> |
621 static void Build_Int32_Select(CallDescriptor* desc, RawMachineAssembler& raw) { | 767 static void Build_Select(CallDescriptor* desc, RawMachineAssembler& raw) { |
622 raw.Return(raw.Parameter(which)); | 768 raw.Return(raw.Parameter(which)); |
623 } | 769 } |
624 | 770 |
625 | 771 |
626 template <int which> | 772 template <typename CType, int which> |
627 static int32_t Compute_Int32_Select(CallDescriptor* desc, int32_t* inputs) { | 773 static CType Compute_Select(CallDescriptor* desc, CType* inputs) { |
628 return inputs[which]; | 774 return inputs[which]; |
629 } | 775 } |
630 | 776 |
631 | 777 |
632 template <int which> | 778 template <int which> |
633 void Test_Int32_Select() { | 779 void Test_Int32_Select() { |
780 if (DISABLE_NATIVE_STACK_PARAMS) return; | |
781 | |
634 int parray[] = {0}; | 782 int parray[] = {0}; |
635 int rarray[] = {0}; | 783 int rarray[] = {0}; |
636 Allocator params(parray, 1, nullptr, 0); | 784 Allocator params(parray, 1, nullptr, 0); |
637 Allocator rets(rarray, 1, nullptr, 0); | 785 Allocator rets(rarray, 1, nullptr, 0); |
638 RegisterConfig config(params, rets); | 786 RegisterConfig config(params, rets); |
639 | 787 |
640 Zone zone; | 788 Zone zone; |
641 | 789 |
642 for (int i = which + 1; i <= 64; i++) { | 790 for (int i = which + 1; i <= 64; i++) { |
643 Int32Signature sig(i); | 791 Int32Signature sig(i); |
644 CallDescriptor* desc = config.Create(&zone, &sig); | 792 CallDescriptor* desc = config.Create(&zone, &sig); |
645 Run_Int32_Computation(desc, Build_Int32_Select<which>, | 793 Run_Computation<int32_t>(desc, Build_Select<which>, |
646 Compute_Int32_Select<which>, 1025 + which); | 794 Compute_Select<int32_t, which>, 1025 + which); |
647 } | 795 } |
648 } | 796 } |
649 | 797 |
650 | 798 |
651 // Separate tests for parallelization. | 799 // Separate tests for parallelization. |
652 #define TEST_INT32_SELECT(x) \ | 800 #define TEST_INT32_SELECT(x) \ |
653 TEST(Run_Int32_Select_##x) { Test_Int32_Select<x>(); } | 801 TEST(Run_Int32_Select_##x) { Test_Int32_Select<x>(); } |
654 | 802 |
655 | 803 |
656 TEST_INT32_SELECT(0) | 804 TEST_INT32_SELECT(0) |
657 TEST_INT32_SELECT(1) | 805 TEST_INT32_SELECT(1) |
658 TEST_INT32_SELECT(2) | 806 TEST_INT32_SELECT(2) |
659 TEST_INT32_SELECT(3) | 807 TEST_INT32_SELECT(3) |
660 TEST_INT32_SELECT(4) | 808 TEST_INT32_SELECT(4) |
661 TEST_INT32_SELECT(5) | 809 TEST_INT32_SELECT(5) |
662 TEST_INT32_SELECT(6) | 810 TEST_INT32_SELECT(6) |
663 TEST_INT32_SELECT(11) | 811 TEST_INT32_SELECT(11) |
664 TEST_INT32_SELECT(15) | 812 TEST_INT32_SELECT(15) |
665 TEST_INT32_SELECT(19) | 813 TEST_INT32_SELECT(19) |
666 TEST_INT32_SELECT(45) | 814 TEST_INT32_SELECT(45) |
667 TEST_INT32_SELECT(62) | 815 TEST_INT32_SELECT(62) |
668 TEST_INT32_SELECT(63) | 816 TEST_INT32_SELECT(63) |
669 #endif // NATIVE_STACK_PARAMS_OK | |
670 | 817 |
671 | 818 |
672 TEST(TheLastTestForLint) { | 819 TEST(Int64Select_registers) { |
673 // Yes, thank you. | 820 if (Register::kMaxNumAllocatableRegisters < 2) return; |
821 if (kPointerSize < 8) return; // TODO(titzer): int64 on 32-bit platforms | |
822 | |
823 int rarray[] = {0}; | |
824 ArgsBuffer<int64_t>::Sig sig(2); | |
825 | |
826 RegisterPairs pairs; | |
827 Zone zone; | |
828 while (pairs.More()) { | |
829 int parray[2]; | |
830 pairs.Next(&parray[0], &parray[1], false); | |
831 Allocator params(parray, 2, nullptr, 0); | |
832 Allocator rets(rarray, 1, nullptr, 0); | |
833 RegisterConfig config(params, rets); | |
834 | |
835 CallDescriptor* desc = config.Create(&zone, &sig); | |
836 Run_Computation<int64_t>(desc, Build_Select<0>, Compute_Select<int64_t, 0>, | |
837 1021); | |
838 | |
839 Run_Computation<int64_t>(desc, Build_Select<1>, Compute_Select<int64_t, 1>, | |
840 1022); | |
841 } | |
674 } | 842 } |
843 | |
844 | |
845 TEST(Float32Select_registers) { | |
846 if (DoubleRegister::kMaxNumAllocatableRegisters < 2) return; | |
847 | |
848 int rarray[] = {0}; | |
849 ArgsBuffer<float32>::Sig sig(2); | |
850 | |
851 Float32RegisterPairs pairs; | |
852 Zone zone; | |
853 while (pairs.More()) { | |
854 int parray[2]; | |
855 pairs.Next(&parray[0], &parray[1], false); | |
856 Allocator params(nullptr, 0, parray, 2); | |
857 Allocator rets(nullptr, 0, rarray, 1); | |
858 RegisterConfig config(params, rets); | |
859 | |
860 CallDescriptor* desc = config.Create(&zone, &sig); | |
861 Run_Computation<float32>(desc, Build_Select<0>, Compute_Select<float32, 0>, | |
862 1019); | |
863 | |
864 Run_Computation<float32>(desc, Build_Select<1>, Compute_Select<float32, 1>, | |
865 1018); | |
866 } | |
867 } | |
868 | |
869 | |
870 TEST(Float64Select_registers) { | |
871 if (DoubleRegister::kMaxNumAllocatableRegisters < 2) return; | |
872 | |
873 int rarray[] = {0}; | |
874 ArgsBuffer<float64>::Sig sig(2); | |
875 | |
876 Float64RegisterPairs pairs; | |
877 Zone zone; | |
878 while (pairs.More()) { | |
879 int parray[2]; | |
880 pairs.Next(&parray[0], &parray[1], false); | |
881 Allocator params(nullptr, 0, parray, 2); | |
882 Allocator rets(nullptr, 0, rarray, 1); | |
883 RegisterConfig config(params, rets); | |
884 | |
885 CallDescriptor* desc = config.Create(&zone, &sig); | |
886 Run_Computation<float64>(desc, Build_Select<0>, Compute_Select<float64, 0>, | |
887 1033); | |
888 | |
889 Run_Computation<float64>(desc, Build_Select<1>, Compute_Select<float64, 1>, | |
890 1034); | |
891 } | |
892 } | |
OLD | NEW |