blob: 791b0d7ae5868e82534b0ba60af91e9621906ebe [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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
3// found in the LICENSE file.
4
5#include "src/assembler.h"
6#include "src/codegen.h"
7#include "src/compiler/linkage.h"
8#include "src/compiler/raw-machine-assembler.h"
9#include "src/machine-type.h"
10#include "src/register-configuration.h"
11
12#include "test/cctest/cctest.h"
13#include "test/cctest/compiler/codegen-tester.h"
14#include "test/cctest/compiler/graph-builder-tester.h"
15#include "test/cctest/compiler/value-helper.h"
16
17namespace v8 {
18namespace internal {
19namespace compiler {
20
21namespace {
22typedef float float32;
23typedef double float64;
24
25// Picks a representative pair of integers from the given range.
26// If there are less than {max_pairs} possible pairs, do them all, otherwise try
27// to select a representative set.
28class Pairs {
29 public:
30 Pairs(int max_pairs, int range, const int* codes)
31 : range_(range),
32 codes_(codes),
33 max_pairs_(std::min(max_pairs, range_ * range_)),
34 counter_(0) {}
35
36 bool More() { return counter_ < max_pairs_; }
37
38 void Next(int* r0, int* r1, bool same_is_ok) {
39 do {
40 // Find the next pair.
41 if (exhaustive()) {
42 *r0 = codes_[counter_ % range_];
43 *r1 = codes_[counter_ / range_];
44 } else {
45 // Try each integer at least once for both r0 and r1.
46 int index = counter_ / 2;
47 if (counter_ & 1) {
48 *r0 = codes_[index % range_];
49 *r1 = codes_[index / range_];
50 } else {
51 *r1 = codes_[index % range_];
52 *r0 = codes_[index / range_];
53 }
54 }
55 counter_++;
56 if ((same_is_ok) || (*r0 != *r1)) break;
57 if (counter_ == max_pairs_) {
58 // For the last hurrah, reg#0 with reg#n-1
59 *r0 = codes_[0];
60 *r1 = codes_[range_ - 1];
61 break;
62 }
63 } while (true);
64 }
65
66 private:
67 int range_;
68 const int* codes_;
69 int max_pairs_;
70 int counter_;
71 bool exhaustive() { return max_pairs_ == (range_ * range_); }
72};
73
74
75// Pairs of general purpose registers.
76class RegisterPairs : public Pairs {
77 public:
78 RegisterPairs()
79 : Pairs(
80 100,
81 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
82 ->num_allocatable_general_registers(),
83 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
84 ->allocatable_general_codes()) {}
85};
86
87
88// Pairs of double registers.
89class Float32RegisterPairs : public Pairs {
90 public:
91 Float32RegisterPairs()
92 : Pairs(
93 100,
94 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
95 ->num_allocatable_aliased_double_registers(),
96 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
97 ->allocatable_double_codes()) {}
98};
99
100
101// Pairs of double registers.
102class Float64RegisterPairs : public Pairs {
103 public:
104 Float64RegisterPairs()
105 : Pairs(
106 100,
107 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
108 ->num_allocatable_aliased_double_registers(),
109 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
110 ->allocatable_double_codes()) {}
111};
112
113
114// Helper for allocating either an GP or FP reg, or the next stack slot.
115struct Allocator {
116 Allocator(int* gp, int gpc, int* fp, int fpc)
117 : gp_count(gpc),
118 gp_offset(0),
119 gp_regs(gp),
120 fp_count(fpc),
121 fp_offset(0),
122 fp_regs(fp),
123 stack_offset(0) {}
124
125 int gp_count;
126 int gp_offset;
127 int* gp_regs;
128
129 int fp_count;
130 int fp_offset;
131 int* fp_regs;
132
133 int stack_offset;
134
135 LinkageLocation Next(MachineType type) {
136 if (IsFloatingPoint(type.representation())) {
137 // Allocate a floating point register/stack location.
138 if (fp_offset < fp_count) {
139 return LinkageLocation::ForRegister(fp_regs[fp_offset++]);
140 } else {
141 int offset = -1 - stack_offset;
142 stack_offset += StackWords(type);
143 return LinkageLocation::ForCallerFrameSlot(offset);
144 }
145 } else {
146 // Allocate a general purpose register/stack location.
147 if (gp_offset < gp_count) {
148 return LinkageLocation::ForRegister(gp_regs[gp_offset++]);
149 } else {
150 int offset = -1 - stack_offset;
151 stack_offset += StackWords(type);
152 return LinkageLocation::ForCallerFrameSlot(offset);
153 }
154 }
155 }
156 int StackWords(MachineType type) {
157 // TODO(titzer): hack. float32 occupies 8 bytes on stack.
158 int size = IsFloatingPoint(type.representation())
159 ? kDoubleSize
160 : (1 << ElementSizeLog2Of(type.representation()));
161 return size <= kPointerSize ? 1 : size / kPointerSize;
162 }
163 void Reset() {
164 fp_offset = 0;
165 gp_offset = 0;
166 stack_offset = 0;
167 }
168};
169
170
171class RegisterConfig {
172 public:
173 RegisterConfig(Allocator& p, Allocator& r) : params(p), rets(r) {}
174
175 CallDescriptor* Create(Zone* zone, MachineSignature* msig) {
176 rets.Reset();
177 params.Reset();
178
179 LocationSignature::Builder locations(zone, msig->return_count(),
180 msig->parameter_count());
181 // Add return location(s).
182 const int return_count = static_cast<int>(locations.return_count_);
183 for (int i = 0; i < return_count; i++) {
184 locations.AddReturn(rets.Next(msig->GetReturn(i)));
185 }
186
187 // Add register and/or stack parameter(s).
188 const int parameter_count = static_cast<int>(msig->parameter_count());
189 for (int i = 0; i < parameter_count; i++) {
190 locations.AddParam(params.Next(msig->GetParam(i)));
191 }
192
193 const RegList kCalleeSaveRegisters = 0;
194 const RegList kCalleeSaveFPRegisters = 0;
195
196 MachineType target_type = MachineType::AnyTagged();
197 LinkageLocation target_loc = LinkageLocation::ForAnyRegister();
198 int stack_param_count = params.stack_offset;
199 return new (zone) CallDescriptor( // --
200 CallDescriptor::kCallCodeObject, // kind
201 target_type, // target MachineType
202 target_loc, // target location
203 msig, // machine_sig
204 locations.Build(), // location_sig
205 stack_param_count, // stack_parameter_count
206 compiler::Operator::kNoProperties, // properties
207 kCalleeSaveRegisters, // callee-saved registers
208 kCalleeSaveFPRegisters, // callee-saved fp regs
209 CallDescriptor::kUseNativeStack, // flags
210 "c-call");
211 }
212
213 private:
214 Allocator& params;
215 Allocator& rets;
216};
217
218const int kMaxParamCount = 64;
219
220MachineType kIntTypes[kMaxParamCount + 1] = {
221 MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
222 MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
223 MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
224 MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
225 MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
226 MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
227 MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
228 MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
229 MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
230 MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
231 MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
232 MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
233 MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
234 MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
235 MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
236 MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
237 MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
238 MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
239 MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
240 MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
241 MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
242 MachineType::Int32(), MachineType::Int32()};
243
244
245// For making uniform int32 signatures shorter.
246class Int32Signature : public MachineSignature {
247 public:
248 explicit Int32Signature(int param_count)
249 : MachineSignature(1, param_count, kIntTypes) {
250 CHECK(param_count <= kMaxParamCount);
251 }
252};
253
254
255Handle<Code> CompileGraph(const char* name, CallDescriptor* desc, Graph* graph,
256 Schedule* schedule = nullptr) {
257 Isolate* isolate = CcTest::InitIsolateOnce();
258 CompilationInfo info("testing", isolate, graph->zone());
259 Handle<Code> code =
260 Pipeline::GenerateCodeForTesting(&info, desc, graph, schedule);
261 CHECK(!code.is_null());
262#ifdef ENABLE_DISASSEMBLER
263 if (FLAG_print_opt_code) {
264 OFStream os(stdout);
265 code->Disassemble(name, os);
266 }
267#endif
268 return code;
269}
270
271
272Handle<Code> WrapWithCFunction(Handle<Code> inner, CallDescriptor* desc) {
273 Zone zone;
274 MachineSignature* msig =
275 const_cast<MachineSignature*>(desc->GetMachineSignature());
276 int param_count = static_cast<int>(msig->parameter_count());
277 GraphAndBuilders caller(&zone);
278 {
279 GraphAndBuilders& b = caller;
280 Node* start = b.graph()->NewNode(b.common()->Start(param_count + 3));
281 b.graph()->SetStart(start);
282 Node* target = b.graph()->NewNode(b.common()->HeapConstant(inner));
283
284 // Add arguments to the call.
285 Node** args = zone.NewArray<Node*>(param_count + 3);
286 int index = 0;
287 args[index++] = target;
288 for (int i = 0; i < param_count; i++) {
289 args[index] = b.graph()->NewNode(b.common()->Parameter(i), start);
290 index++;
291 }
292 args[index++] = start; // effect.
293 args[index++] = start; // control.
294
295 // Build the call and return nodes.
296 Node* call =
297 b.graph()->NewNode(b.common()->Call(desc), param_count + 3, args);
298 Node* ret = b.graph()->NewNode(b.common()->Return(), call, call, start);
299 b.graph()->SetEnd(ret);
300 }
301
302 CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, msig);
303
304 return CompileGraph("wrapper", cdesc, caller.graph());
305}
306
307
308template <typename CType>
309class ArgsBuffer {
310 public:
311 static const int kMaxParamCount = 64;
312
313 explicit ArgsBuffer(int count, int seed = 1) : count_(count), seed_(seed) {
314 // initialize the buffer with "seed 0"
315 seed_ = 0;
316 Mutate();
317 seed_ = seed;
318 }
319
320 class Sig : public MachineSignature {
321 public:
322 explicit Sig(int param_count)
323 : MachineSignature(1, param_count, MachTypes()) {
324 CHECK(param_count <= kMaxParamCount);
325 }
326 };
327
328 static MachineType* MachTypes() {
329 MachineType t = MachineTypeForC<CType>();
330 static MachineType kTypes[kMaxParamCount + 1] = {
331 t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t,
332 t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t,
333 t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t};
334 return kTypes;
335 }
336
337 Node* MakeConstant(RawMachineAssembler& raw, int32_t value) {
338 return raw.Int32Constant(value);
339 }
340
341 Node* MakeConstant(RawMachineAssembler& raw, int64_t value) {
342 return raw.Int64Constant(value);
343 }
344
345 Node* MakeConstant(RawMachineAssembler& raw, float32 value) {
346 return raw.Float32Constant(value);
347 }
348
349 Node* MakeConstant(RawMachineAssembler& raw, float64 value) {
350 return raw.Float64Constant(value);
351 }
352
353 Node* LoadInput(RawMachineAssembler& raw, Node* base, int index) {
354 Node* offset = raw.Int32Constant(index * sizeof(CType));
355 return raw.Load(MachineTypeForC<CType>(), base, offset);
356 }
357
358 Node* StoreOutput(RawMachineAssembler& raw, Node* value) {
359 Node* base = raw.PointerConstant(&output);
360 Node* offset = raw.Int32Constant(0);
361 return raw.Store(MachineTypeForC<CType>().representation(), base, offset,
362 value, kNoWriteBarrier);
363 }
364
365 // Computes the next set of inputs by updating the {input} array.
366 void Mutate();
367
368 void Reset() { memset(input, 0, sizeof(input)); }
369
370 int count_;
371 int seed_;
372 CType input[kMaxParamCount];
373 CType output;
374};
375
376
377template <>
378void ArgsBuffer<int32_t>::Mutate() {
379 uint32_t base = 1111111111u * seed_;
380 for (int j = 0; j < count_ && j < kMaxParamCount; j++) {
381 input[j] = static_cast<int32_t>(256 + base + j + seed_ * 13);
382 }
383 output = -1;
384 seed_++;
385}
386
387
388template <>
389void ArgsBuffer<int64_t>::Mutate() {
390 uint64_t base = 11111111111111111ull * seed_;
391 for (int j = 0; j < count_ && j < kMaxParamCount; j++) {
392 input[j] = static_cast<int64_t>(256 + base + j + seed_ * 13);
393 }
394 output = -1;
395 seed_++;
396}
397
398
399template <>
400void ArgsBuffer<float32>::Mutate() {
401 float64 base = -33.25 * seed_;
402 for (int j = 0; j < count_ && j < kMaxParamCount; j++) {
403 input[j] = 256 + base + j + seed_ * 13;
404 }
405 output = std::numeric_limits<float32>::quiet_NaN();
406 seed_++;
407}
408
409
410template <>
411void ArgsBuffer<float64>::Mutate() {
412 float64 base = -111.25 * seed_;
413 for (int j = 0; j < count_ && j < kMaxParamCount; j++) {
414 input[j] = 256 + base + j + seed_ * 13;
415 }
416 output = std::numeric_limits<float64>::quiet_NaN();
417 seed_++;
418}
419
420
421int ParamCount(CallDescriptor* desc) {
422 return static_cast<int>(desc->GetMachineSignature()->parameter_count());
423}
424
425
426template <typename CType>
427class Computer {
428 public:
429 static void Run(CallDescriptor* desc,
430 void (*build)(CallDescriptor*, RawMachineAssembler&),
431 CType (*compute)(CallDescriptor*, CType* inputs),
432 int seed = 1) {
433 int num_params = ParamCount(desc);
434 CHECK_LE(num_params, kMaxParamCount);
435 Isolate* isolate = CcTest::InitIsolateOnce();
436 HandleScope scope(isolate);
437 Handle<Code> inner = Handle<Code>::null();
438 {
439 // Build the graph for the computation.
440 Zone zone;
441 Graph graph(&zone);
442 RawMachineAssembler raw(isolate, &graph, desc);
443 build(desc, raw);
444 inner = CompileGraph("Compute", desc, &graph, raw.Export());
445 }
446
447 CSignature0<int32_t> csig;
448 ArgsBuffer<CType> io(num_params, seed);
449
450 {
451 // constant mode.
452 Handle<Code> wrapper = Handle<Code>::null();
453 {
454 // Wrap the above code with a callable function that passes constants.
455 Zone zone;
456 Graph graph(&zone);
457 CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig);
458 RawMachineAssembler raw(isolate, &graph, cdesc);
459 Node* target = raw.HeapConstant(inner);
460 Node** args = zone.NewArray<Node*>(num_params);
461 for (int i = 0; i < num_params; i++) {
462 args[i] = io.MakeConstant(raw, io.input[i]);
463 }
464
465 Node* call = raw.CallN(desc, target, args);
466 Node* store = io.StoreOutput(raw, call);
467 USE(store);
468 raw.Return(raw.Int32Constant(seed));
469 wrapper =
470 CompileGraph("Compute-wrapper-const", cdesc, &graph, raw.Export());
471 }
472
473 CodeRunner<int32_t> runnable(isolate, wrapper, &csig);
474
475 // Run the code, checking it against the reference.
476 CType expected = compute(desc, io.input);
477 int32_t check_seed = runnable.Call();
478 CHECK_EQ(seed, check_seed);
479 CHECK_EQ(expected, io.output);
480 }
481
482 {
483 // buffer mode.
484 Handle<Code> wrapper = Handle<Code>::null();
485 {
486 // Wrap the above code with a callable function that loads from {input}.
487 Zone zone;
488 Graph graph(&zone);
489 CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig);
490 RawMachineAssembler raw(isolate, &graph, cdesc);
491 Node* base = raw.PointerConstant(io.input);
492 Node* target = raw.HeapConstant(inner);
493 Node** args = zone.NewArray<Node*>(kMaxParamCount);
494 for (int i = 0; i < num_params; i++) {
495 args[i] = io.LoadInput(raw, base, i);
496 }
497
498 Node* call = raw.CallN(desc, target, args);
499 Node* store = io.StoreOutput(raw, call);
500 USE(store);
501 raw.Return(raw.Int32Constant(seed));
502 wrapper = CompileGraph("Compute-wrapper", cdesc, &graph, raw.Export());
503 }
504
505 CodeRunner<int32_t> runnable(isolate, wrapper, &csig);
506
507 // Run the code, checking it against the reference.
508 for (int i = 0; i < 5; i++) {
509 CType expected = compute(desc, io.input);
510 int32_t check_seed = runnable.Call();
511 CHECK_EQ(seed, check_seed);
512 CHECK_EQ(expected, io.output);
513 io.Mutate();
514 }
515 }
516 }
517};
518
519} // namespace
520
521
522static void TestInt32Sub(CallDescriptor* desc) {
523 Isolate* isolate = CcTest::InitIsolateOnce();
524 HandleScope scope(isolate);
525 Zone zone;
526 GraphAndBuilders inner(&zone);
527 {
528 // Build the add function.
529 GraphAndBuilders& b = inner;
530 Node* start = b.graph()->NewNode(b.common()->Start(5));
531 b.graph()->SetStart(start);
532 Node* p0 = b.graph()->NewNode(b.common()->Parameter(0), start);
533 Node* p1 = b.graph()->NewNode(b.common()->Parameter(1), start);
534 Node* add = b.graph()->NewNode(b.machine()->Int32Sub(), p0, p1);
535 Node* ret = b.graph()->NewNode(b.common()->Return(), add, start, start);
536 b.graph()->SetEnd(ret);
537 }
538
539 Handle<Code> inner_code = CompileGraph("Int32Sub", desc, inner.graph());
540 Handle<Code> wrapper = WrapWithCFunction(inner_code, desc);
541 MachineSignature* msig =
542 const_cast<MachineSignature*>(desc->GetMachineSignature());
543 CodeRunner<int32_t> runnable(isolate, wrapper,
544 CSignature::FromMachine(&zone, msig));
545
546 FOR_INT32_INPUTS(i) {
547 FOR_INT32_INPUTS(j) {
548 int32_t expected = static_cast<int32_t>(static_cast<uint32_t>(*i) -
549 static_cast<uint32_t>(*j));
550 int32_t result = runnable.Call(*i, *j);
551 CHECK_EQ(expected, result);
552 }
553 }
554}
555
556
557static void CopyTwentyInt32(CallDescriptor* desc) {
558 const int kNumParams = 20;
559 int32_t input[kNumParams];
560 int32_t output[kNumParams];
561 Isolate* isolate = CcTest::InitIsolateOnce();
562 HandleScope scope(isolate);
563 Handle<Code> inner = Handle<Code>::null();
564 {
565 // Writes all parameters into the output buffer.
566 Zone zone;
567 Graph graph(&zone);
568 RawMachineAssembler raw(isolate, &graph, desc);
569 Node* base = raw.PointerConstant(output);
570 for (int i = 0; i < kNumParams; i++) {
571 Node* offset = raw.Int32Constant(i * sizeof(int32_t));
572 raw.Store(MachineRepresentation::kWord32, base, offset, raw.Parameter(i),
573 kNoWriteBarrier);
574 }
575 raw.Return(raw.Int32Constant(42));
576 inner = CompileGraph("CopyTwentyInt32", desc, &graph, raw.Export());
577 }
578
579 CSignature0<int32_t> csig;
580 Handle<Code> wrapper = Handle<Code>::null();
581 {
582 // Loads parameters from the input buffer and calls the above code.
583 Zone zone;
584 Graph graph(&zone);
585 CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig);
586 RawMachineAssembler raw(isolate, &graph, cdesc);
587 Node* base = raw.PointerConstant(input);
588 Node* target = raw.HeapConstant(inner);
589 Node** args = zone.NewArray<Node*>(kNumParams);
590 for (int i = 0; i < kNumParams; i++) {
591 Node* offset = raw.Int32Constant(i * sizeof(int32_t));
592 args[i] = raw.Load(MachineType::Int32(), base, offset);
593 }
594
595 Node* call = raw.CallN(desc, target, args);
596 raw.Return(call);
597 wrapper =
598 CompileGraph("CopyTwentyInt32-wrapper", cdesc, &graph, raw.Export());
599 }
600
601 CodeRunner<int32_t> runnable(isolate, wrapper, &csig);
602
603 // Run the code, checking it correctly implements the memcpy.
604 for (int i = 0; i < 5; i++) {
605 uint32_t base = 1111111111u * i;
606 for (int j = 0; j < kNumParams; j++) {
607 input[j] = static_cast<int32_t>(base + 13 * j);
608 }
609
610 memset(output, 0, sizeof(output));
611 CHECK_EQ(42, runnable.Call());
612
613 for (int j = 0; j < kNumParams; j++) {
614 CHECK_EQ(input[j], output[j]);
615 }
616 }
617}
618
619
620static void Test_RunInt32SubWithRet(int retreg) {
621 Int32Signature sig(2);
622 Zone zone;
623 RegisterPairs pairs;
624 while (pairs.More()) {
625 int parray[2];
626 int rarray[] = {retreg};
627 pairs.Next(&parray[0], &parray[1], false);
628 Allocator params(parray, 2, nullptr, 0);
629 Allocator rets(rarray, 1, nullptr, 0);
630 RegisterConfig config(params, rets);
631 CallDescriptor* desc = config.Create(&zone, &sig);
632 TestInt32Sub(desc);
633 }
634}
635
636
637// Separate tests for parallelization.
638#define TEST_INT32_SUB_WITH_RET(x) \
639 TEST(Run_Int32Sub_all_allocatable_pairs_##x) { \
640 if (x < Register::kNumRegisters && \
641 Register::from_code(x).IsAllocatable()) { \
642 Test_RunInt32SubWithRet(x); \
643 } \
644 }
645
646
647TEST_INT32_SUB_WITH_RET(0)
648TEST_INT32_SUB_WITH_RET(1)
649TEST_INT32_SUB_WITH_RET(2)
650TEST_INT32_SUB_WITH_RET(3)
651TEST_INT32_SUB_WITH_RET(4)
652TEST_INT32_SUB_WITH_RET(5)
653TEST_INT32_SUB_WITH_RET(6)
654TEST_INT32_SUB_WITH_RET(7)
655TEST_INT32_SUB_WITH_RET(8)
656TEST_INT32_SUB_WITH_RET(9)
657TEST_INT32_SUB_WITH_RET(10)
658TEST_INT32_SUB_WITH_RET(11)
659TEST_INT32_SUB_WITH_RET(12)
660TEST_INT32_SUB_WITH_RET(13)
661TEST_INT32_SUB_WITH_RET(14)
662TEST_INT32_SUB_WITH_RET(15)
663TEST_INT32_SUB_WITH_RET(16)
664TEST_INT32_SUB_WITH_RET(17)
665TEST_INT32_SUB_WITH_RET(18)
666TEST_INT32_SUB_WITH_RET(19)
667
668
669TEST(Run_Int32Sub_all_allocatable_single) {
670 Int32Signature sig(2);
671 RegisterPairs pairs;
672 while (pairs.More()) {
673 Zone zone;
674 int parray[1];
675 int rarray[1];
676 pairs.Next(&rarray[0], &parray[0], true);
677 Allocator params(parray, 1, nullptr, 0);
678 Allocator rets(rarray, 1, nullptr, 0);
679 RegisterConfig config(params, rets);
680 CallDescriptor* desc = config.Create(&zone, &sig);
681 TestInt32Sub(desc);
682 }
683}
684
685
686TEST(Run_CopyTwentyInt32_all_allocatable_pairs) {
687 Int32Signature sig(20);
688 RegisterPairs pairs;
689 while (pairs.More()) {
690 Zone zone;
691 int parray[2];
692 int rarray[] = {
693 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
694 ->GetAllocatableGeneralCode(0)};
695 pairs.Next(&parray[0], &parray[1], false);
696 Allocator params(parray, 2, nullptr, 0);
697 Allocator rets(rarray, 1, nullptr, 0);
698 RegisterConfig config(params, rets);
699 CallDescriptor* desc = config.Create(&zone, &sig);
700 CopyTwentyInt32(desc);
701 }
702}
703
704
705template <typename CType>
706static void Run_Computation(
707 CallDescriptor* desc, void (*build)(CallDescriptor*, RawMachineAssembler&),
708 CType (*compute)(CallDescriptor*, CType* inputs), int seed = 1) {
709 Computer<CType>::Run(desc, build, compute, seed);
710}
711
712
713static uint32_t coeff[] = {1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
714 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73,
715 79, 83, 89, 97, 101, 103, 107, 109, 113};
716
717
718static void Build_Int32_WeightedSum(CallDescriptor* desc,
719 RawMachineAssembler& raw) {
720 Node* result = raw.Int32Constant(0);
721 for (int i = 0; i < ParamCount(desc); i++) {
722 Node* term = raw.Int32Mul(raw.Parameter(i), raw.Int32Constant(coeff[i]));
723 result = raw.Int32Add(result, term);
724 }
725 raw.Return(result);
726}
727
728
729static int32_t Compute_Int32_WeightedSum(CallDescriptor* desc, int32_t* input) {
730 uint32_t result = 0;
731 for (int i = 0; i < ParamCount(desc); i++) {
732 result += static_cast<uint32_t>(input[i]) * coeff[i];
733 }
734 return static_cast<int32_t>(result);
735}
736
737
738static void Test_Int32_WeightedSum_of_size(int count) {
739 Int32Signature sig(count);
740 for (int p0 = 0; p0 < Register::kNumRegisters; p0++) {
741 if (Register::from_code(p0).IsAllocatable()) {
742 Zone zone;
743
744 int parray[] = {p0};
745 int rarray[] = {
746 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
747 ->GetAllocatableGeneralCode(0)};
748 Allocator params(parray, 1, nullptr, 0);
749 Allocator rets(rarray, 1, nullptr, 0);
750 RegisterConfig config(params, rets);
751 CallDescriptor* desc = config.Create(&zone, &sig);
752 Run_Computation<int32_t>(desc, Build_Int32_WeightedSum,
753 Compute_Int32_WeightedSum, 257 + count);
754 }
755 }
756}
757
758
759// Separate tests for parallelization.
760#define TEST_INT32_WEIGHTEDSUM(x) \
761 TEST(Run_Int32_WeightedSum_##x) { Test_Int32_WeightedSum_of_size(x); }
762
763
764TEST_INT32_WEIGHTEDSUM(1)
765TEST_INT32_WEIGHTEDSUM(2)
766TEST_INT32_WEIGHTEDSUM(3)
767TEST_INT32_WEIGHTEDSUM(4)
768TEST_INT32_WEIGHTEDSUM(5)
769TEST_INT32_WEIGHTEDSUM(7)
770TEST_INT32_WEIGHTEDSUM(9)
771TEST_INT32_WEIGHTEDSUM(11)
772TEST_INT32_WEIGHTEDSUM(17)
773TEST_INT32_WEIGHTEDSUM(19)
774
775
776template <int which>
777static void Build_Select(CallDescriptor* desc, RawMachineAssembler& raw) {
778 raw.Return(raw.Parameter(which));
779}
780
781
782template <typename CType, int which>
783static CType Compute_Select(CallDescriptor* desc, CType* inputs) {
784 return inputs[which];
785}
786
787
788template <typename CType, int which>
789static void RunSelect(CallDescriptor* desc) {
790 int count = ParamCount(desc);
791 if (count <= which) return;
792 Run_Computation<CType>(desc, Build_Select<which>,
793 Compute_Select<CType, which>,
794 1044 + which + 3 * sizeof(CType));
795}
796
797
798template <int which>
799void Test_Int32_Select() {
800 int parray[] = {
801 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
802 ->GetAllocatableGeneralCode(0)};
803 int rarray[] = {
804 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
805 ->GetAllocatableGeneralCode(0)};
806 Allocator params(parray, 1, nullptr, 0);
807 Allocator rets(rarray, 1, nullptr, 0);
808 RegisterConfig config(params, rets);
809
810 Zone zone;
811
812 for (int i = which + 1; i <= 64; i++) {
813 Int32Signature sig(i);
814 CallDescriptor* desc = config.Create(&zone, &sig);
815 RunSelect<int32_t, which>(desc);
816 }
817}
818
819
820// Separate tests for parallelization.
821#define TEST_INT32_SELECT(x) \
822 TEST(Run_Int32_Select_##x) { Test_Int32_Select<x>(); }
823
824
825TEST_INT32_SELECT(0)
826TEST_INT32_SELECT(1)
827TEST_INT32_SELECT(2)
828TEST_INT32_SELECT(3)
829TEST_INT32_SELECT(4)
830TEST_INT32_SELECT(5)
831TEST_INT32_SELECT(6)
832TEST_INT32_SELECT(11)
833TEST_INT32_SELECT(15)
834TEST_INT32_SELECT(19)
835TEST_INT32_SELECT(45)
836TEST_INT32_SELECT(62)
837TEST_INT32_SELECT(63)
838
839
840TEST(Int64Select_registers) {
841 if (RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
842 ->num_allocatable_general_registers() < 2)
843 return;
844 if (kPointerSize < 8) return; // TODO(titzer): int64 on 32-bit platforms
845
846 int rarray[] = {
847 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
848 ->GetAllocatableGeneralCode(0)};
849 ArgsBuffer<int64_t>::Sig sig(2);
850
851 RegisterPairs pairs;
852 Zone zone;
853 while (pairs.More()) {
854 int parray[2];
855 pairs.Next(&parray[0], &parray[1], false);
856 Allocator params(parray, 2, nullptr, 0);
857 Allocator rets(rarray, 1, nullptr, 0);
858 RegisterConfig config(params, rets);
859
860 CallDescriptor* desc = config.Create(&zone, &sig);
861 RunSelect<int64_t, 0>(desc);
862 RunSelect<int64_t, 1>(desc);
863 }
864}
865
866
867TEST(Float32Select_registers) {
868 if (RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
869 ->num_allocatable_double_registers() < 2) {
870 return;
871 }
872
873 int rarray[] = {
874 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
875 ->GetAllocatableDoubleCode(0)};
876 ArgsBuffer<float32>::Sig sig(2);
877
878 Float32RegisterPairs pairs;
879 Zone zone;
880 while (pairs.More()) {
881 int parray[2];
882 pairs.Next(&parray[0], &parray[1], false);
883 Allocator params(nullptr, 0, parray, 2);
884 Allocator rets(nullptr, 0, rarray, 1);
885 RegisterConfig config(params, rets);
886
887 CallDescriptor* desc = config.Create(&zone, &sig);
888 RunSelect<float32, 0>(desc);
889 RunSelect<float32, 1>(desc);
890 }
891}
892
893
894TEST(Float64Select_registers) {
895 if (RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
896 ->num_allocatable_double_registers() < 2)
897 return;
898 if (RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
899 ->num_allocatable_general_registers() < 2)
900 return;
901 int rarray[] = {
902 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
903 ->GetAllocatableDoubleCode(0)};
904 ArgsBuffer<float64>::Sig sig(2);
905
906 Float64RegisterPairs pairs;
907 Zone zone;
908 while (pairs.More()) {
909 int parray[2];
910 pairs.Next(&parray[0], &parray[1], false);
911 Allocator params(nullptr, 0, parray, 2);
912 Allocator rets(nullptr, 0, rarray, 1);
913 RegisterConfig config(params, rets);
914
915 CallDescriptor* desc = config.Create(&zone, &sig);
916 RunSelect<float64, 0>(desc);
917 RunSelect<float64, 1>(desc);
918 }
919}
920
921
922TEST(Float32Select_stack_params_return_reg) {
923 int rarray[] = {
924 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
925 ->GetAllocatableDoubleCode(0)};
926 Allocator params(nullptr, 0, nullptr, 0);
927 Allocator rets(nullptr, 0, rarray, 1);
928 RegisterConfig config(params, rets);
929
930 Zone zone;
931 for (int count = 1; count < 6; count++) {
932 ArgsBuffer<float32>::Sig sig(count);
933 CallDescriptor* desc = config.Create(&zone, &sig);
934 RunSelect<float32, 0>(desc);
935 RunSelect<float32, 1>(desc);
936 RunSelect<float32, 2>(desc);
937 RunSelect<float32, 3>(desc);
938 RunSelect<float32, 4>(desc);
939 RunSelect<float32, 5>(desc);
940 }
941}
942
943
944TEST(Float64Select_stack_params_return_reg) {
945 int rarray[] = {
946 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
947 ->GetAllocatableDoubleCode(0)};
948 Allocator params(nullptr, 0, nullptr, 0);
949 Allocator rets(nullptr, 0, rarray, 1);
950 RegisterConfig config(params, rets);
951
952 Zone zone;
953 for (int count = 1; count < 6; count++) {
954 ArgsBuffer<float64>::Sig sig(count);
955 CallDescriptor* desc = config.Create(&zone, &sig);
956 RunSelect<float64, 0>(desc);
957 RunSelect<float64, 1>(desc);
958 RunSelect<float64, 2>(desc);
959 RunSelect<float64, 3>(desc);
960 RunSelect<float64, 4>(desc);
961 RunSelect<float64, 5>(desc);
962 }
963}
964
965
966template <typename CType, int which>
967static void Build_Select_With_Call(CallDescriptor* desc,
968 RawMachineAssembler& raw) {
969 Handle<Code> inner = Handle<Code>::null();
970 int num_params = ParamCount(desc);
971 CHECK_LE(num_params, kMaxParamCount);
972 {
973 Isolate* isolate = CcTest::InitIsolateOnce();
974 // Build the actual select.
975 Zone zone;
976 Graph graph(&zone);
977 RawMachineAssembler raw(isolate, &graph, desc);
978 raw.Return(raw.Parameter(which));
979 inner = CompileGraph("Select-indirection", desc, &graph, raw.Export());
980 CHECK(!inner.is_null());
981 CHECK(inner->IsCode());
982 }
983
984 {
985 // Build a call to the function that does the select.
986 Node* target = raw.HeapConstant(inner);
987 Node** args = raw.zone()->NewArray<Node*>(num_params);
988 for (int i = 0; i < num_params; i++) {
989 args[i] = raw.Parameter(i);
990 }
991
992 Node* call = raw.CallN(desc, target, args);
993 raw.Return(call);
994 }
995}
996
997
998TEST(Float64StackParamsToStackParams) {
999 int rarray[] = {
1000 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1001 ->GetAllocatableDoubleCode(0)};
1002 Allocator params(nullptr, 0, nullptr, 0);
1003 Allocator rets(nullptr, 0, rarray, 1);
1004
1005 Zone zone;
1006 ArgsBuffer<float64>::Sig sig(2);
1007 RegisterConfig config(params, rets);
1008 CallDescriptor* desc = config.Create(&zone, &sig);
1009
1010 Run_Computation<float64>(desc, Build_Select_With_Call<float64, 0>,
1011 Compute_Select<float64, 0>, 1098);
1012
1013 Run_Computation<float64>(desc, Build_Select_With_Call<float64, 1>,
1014 Compute_Select<float64, 1>, 1099);
1015}
1016
1017
1018void MixedParamTest(int start) {
1019 if (RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1020 ->num_double_registers() < 2)
1021 return;
1022
1023// TODO(titzer): mix in 64-bit types on all platforms when supported.
1024#if V8_TARGET_ARCH_32_BIT
1025 static MachineType types[] = {
1026 MachineType::Int32(), MachineType::Float32(), MachineType::Float64(),
1027 MachineType::Int32(), MachineType::Float64(), MachineType::Float32(),
1028 MachineType::Float32(), MachineType::Float64(), MachineType::Int32(),
1029 MachineType::Float32(), MachineType::Int32(), MachineType::Float64(),
1030 MachineType::Float64(), MachineType::Float32(), MachineType::Int32(),
1031 MachineType::Float64(), MachineType::Int32(), MachineType::Float32()};
1032#else
1033 static MachineType types[] = {
1034 MachineType::Int32(), MachineType::Int64(), MachineType::Float32(),
1035 MachineType::Float64(), MachineType::Int32(), MachineType::Float64(),
1036 MachineType::Float32(), MachineType::Int64(), MachineType::Int64(),
1037 MachineType::Float32(), MachineType::Float32(), MachineType::Int32(),
1038 MachineType::Float64(), MachineType::Float64(), MachineType::Int64(),
1039 MachineType::Int32(), MachineType::Float64(), MachineType::Int32(),
1040 MachineType::Float32()};
1041#endif
1042
1043 Isolate* isolate = CcTest::InitIsolateOnce();
1044
1045 // Build machine signature
1046 MachineType* params = &types[start];
1047 const int num_params = static_cast<int>(arraysize(types) - start);
1048
1049 // Build call descriptor
1050 int parray_gp[] = {
1051 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1052 ->GetAllocatableGeneralCode(0),
1053 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1054 ->GetAllocatableGeneralCode(1)};
1055 int rarray_gp[] = {
1056 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1057 ->GetAllocatableGeneralCode(0)};
1058 int parray_fp[] = {
1059 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1060 ->GetAllocatableDoubleCode(0),
1061 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1062 ->GetAllocatableDoubleCode(1)};
1063 int rarray_fp[] = {
1064 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1065 ->GetAllocatableDoubleCode(0)};
1066 Allocator palloc(parray_gp, 2, parray_fp, 2);
1067 Allocator ralloc(rarray_gp, 1, rarray_fp, 1);
1068 RegisterConfig config(palloc, ralloc);
1069
1070 for (int which = 0; which < num_params; which++) {
1071 Zone zone;
1072 HandleScope scope(isolate);
1073 MachineSignature::Builder builder(&zone, 1, num_params);
1074 builder.AddReturn(params[which]);
1075 for (int j = 0; j < num_params; j++) builder.AddParam(params[j]);
1076 MachineSignature* sig = builder.Build();
1077 CallDescriptor* desc = config.Create(&zone, sig);
1078
1079 Handle<Code> select;
1080 {
1081 // build the select.
1082 Zone zone;
1083 Graph graph(&zone);
1084 RawMachineAssembler raw(isolate, &graph, desc);
1085 raw.Return(raw.Parameter(which));
1086 select = CompileGraph("Compute", desc, &graph, raw.Export());
1087 }
1088
1089 {
1090 // call the select.
1091 Handle<Code> wrapper = Handle<Code>::null();
1092 int32_t expected_ret;
1093 char bytes[kDoubleSize];
1094 V8_ALIGNED(8) char output[kDoubleSize];
1095 int expected_size = 0;
1096 CSignature0<int32_t> csig;
1097 {
1098 // Wrap the select code with a callable function that passes constants.
1099 Zone zone;
1100 Graph graph(&zone);
1101 CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig);
1102 RawMachineAssembler raw(isolate, &graph, cdesc);
1103 Node* target = raw.HeapConstant(select);
1104 Node** args = zone.NewArray<Node*>(num_params);
1105 int64_t constant = 0x0102030405060708;
1106 for (int i = 0; i < num_params; i++) {
1107 MachineType param_type = sig->GetParam(i);
1108 Node* konst = nullptr;
1109 if (param_type == MachineType::Int32()) {
1110 int32_t value[] = {static_cast<int32_t>(constant)};
1111 konst = raw.Int32Constant(value[0]);
1112 if (i == which) memcpy(bytes, value, expected_size = 4);
1113 }
1114 if (param_type == MachineType::Int64()) {
1115 int64_t value[] = {static_cast<int64_t>(constant)};
1116 konst = raw.Int64Constant(value[0]);
1117 if (i == which) memcpy(bytes, value, expected_size = 8);
1118 }
1119 if (param_type == MachineType::Float32()) {
1120 float32 value[] = {static_cast<float32>(constant)};
1121 konst = raw.Float32Constant(value[0]);
1122 if (i == which) memcpy(bytes, value, expected_size = 4);
1123 }
1124 if (param_type == MachineType::Float64()) {
1125 float64 value[] = {static_cast<float64>(constant)};
1126 konst = raw.Float64Constant(value[0]);
1127 if (i == which) memcpy(bytes, value, expected_size = 8);
1128 }
1129 CHECK_NOT_NULL(konst);
1130
1131 args[i] = konst;
1132 constant += 0x1010101010101010;
1133 }
1134
1135 Node* call = raw.CallN(desc, target, args);
1136 Node* store =
1137 raw.StoreToPointer(output, sig->GetReturn().representation(), call);
1138 USE(store);
1139 expected_ret = static_cast<int32_t>(constant);
1140 raw.Return(raw.Int32Constant(expected_ret));
1141 wrapper = CompileGraph("Select-mixed-wrapper-const", cdesc, &graph,
1142 raw.Export());
1143 }
1144
1145 CodeRunner<int32_t> runnable(isolate, wrapper, &csig);
1146 CHECK_EQ(expected_ret, runnable.Call());
1147 for (int i = 0; i < expected_size; i++) {
1148 CHECK_EQ(static_cast<int>(bytes[i]), static_cast<int>(output[i]));
1149 }
1150 }
1151 }
1152}
1153
1154
1155TEST(MixedParams_0) { MixedParamTest(0); }
1156TEST(MixedParams_1) { MixedParamTest(1); }
1157TEST(MixedParams_2) { MixedParamTest(2); }
1158TEST(MixedParams_3) { MixedParamTest(3); }
1159
1160} // namespace compiler
1161} // namespace internal
1162} // namespace v8