blob: bfdcc0e8cacd8da74c8da76584b4b83a2d806355 [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) {
Ben Murdochda12d292016-06-02 14:46:10 +0100273 Zone zone(inner->GetIsolate()->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000274 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.
Ben Murdochda12d292016-06-02 14:46:10 +0100440 Zone zone(isolate->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000441 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.
Ben Murdochda12d292016-06-02 14:46:10 +0100455 Zone zone(isolate->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000456 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}.
Ben Murdochda12d292016-06-02 14:46:10 +0100487 Zone zone(isolate->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000488 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);
Ben Murdochda12d292016-06-02 14:46:10 +0100525 Zone zone(isolate->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000526 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.
Ben Murdochda12d292016-06-02 14:46:10 +0100566 Zone zone(isolate->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000567 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.
Ben Murdochda12d292016-06-02 14:46:10 +0100583 Zone zone(isolate->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000584 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);
Ben Murdochda12d292016-06-02 14:46:10 +0100622 base::AccountingAllocator allocator;
623 Zone zone(&allocator);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000624 RegisterPairs pairs;
625 while (pairs.More()) {
626 int parray[2];
627 int rarray[] = {retreg};
628 pairs.Next(&parray[0], &parray[1], false);
629 Allocator params(parray, 2, nullptr, 0);
630 Allocator rets(rarray, 1, nullptr, 0);
631 RegisterConfig config(params, rets);
632 CallDescriptor* desc = config.Create(&zone, &sig);
633 TestInt32Sub(desc);
634 }
635}
636
637
638// Separate tests for parallelization.
639#define TEST_INT32_SUB_WITH_RET(x) \
640 TEST(Run_Int32Sub_all_allocatable_pairs_##x) { \
641 if (x < Register::kNumRegisters && \
642 Register::from_code(x).IsAllocatable()) { \
643 Test_RunInt32SubWithRet(x); \
644 } \
645 }
646
647
648TEST_INT32_SUB_WITH_RET(0)
649TEST_INT32_SUB_WITH_RET(1)
650TEST_INT32_SUB_WITH_RET(2)
651TEST_INT32_SUB_WITH_RET(3)
652TEST_INT32_SUB_WITH_RET(4)
653TEST_INT32_SUB_WITH_RET(5)
654TEST_INT32_SUB_WITH_RET(6)
655TEST_INT32_SUB_WITH_RET(7)
656TEST_INT32_SUB_WITH_RET(8)
657TEST_INT32_SUB_WITH_RET(9)
658TEST_INT32_SUB_WITH_RET(10)
659TEST_INT32_SUB_WITH_RET(11)
660TEST_INT32_SUB_WITH_RET(12)
661TEST_INT32_SUB_WITH_RET(13)
662TEST_INT32_SUB_WITH_RET(14)
663TEST_INT32_SUB_WITH_RET(15)
664TEST_INT32_SUB_WITH_RET(16)
665TEST_INT32_SUB_WITH_RET(17)
666TEST_INT32_SUB_WITH_RET(18)
667TEST_INT32_SUB_WITH_RET(19)
668
669
670TEST(Run_Int32Sub_all_allocatable_single) {
671 Int32Signature sig(2);
672 RegisterPairs pairs;
673 while (pairs.More()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100674 base::AccountingAllocator allocator;
675 Zone zone(&allocator);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000676 int parray[1];
677 int rarray[1];
678 pairs.Next(&rarray[0], &parray[0], true);
679 Allocator params(parray, 1, nullptr, 0);
680 Allocator rets(rarray, 1, nullptr, 0);
681 RegisterConfig config(params, rets);
682 CallDescriptor* desc = config.Create(&zone, &sig);
683 TestInt32Sub(desc);
684 }
685}
686
687
688TEST(Run_CopyTwentyInt32_all_allocatable_pairs) {
689 Int32Signature sig(20);
690 RegisterPairs pairs;
691 while (pairs.More()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100692 base::AccountingAllocator allocator;
693 Zone zone(&allocator);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000694 int parray[2];
695 int rarray[] = {
696 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
697 ->GetAllocatableGeneralCode(0)};
698 pairs.Next(&parray[0], &parray[1], false);
699 Allocator params(parray, 2, nullptr, 0);
700 Allocator rets(rarray, 1, nullptr, 0);
701 RegisterConfig config(params, rets);
702 CallDescriptor* desc = config.Create(&zone, &sig);
703 CopyTwentyInt32(desc);
704 }
705}
706
707
708template <typename CType>
709static void Run_Computation(
710 CallDescriptor* desc, void (*build)(CallDescriptor*, RawMachineAssembler&),
711 CType (*compute)(CallDescriptor*, CType* inputs), int seed = 1) {
712 Computer<CType>::Run(desc, build, compute, seed);
713}
714
715
716static uint32_t coeff[] = {1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
717 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73,
718 79, 83, 89, 97, 101, 103, 107, 109, 113};
719
720
721static void Build_Int32_WeightedSum(CallDescriptor* desc,
722 RawMachineAssembler& raw) {
723 Node* result = raw.Int32Constant(0);
724 for (int i = 0; i < ParamCount(desc); i++) {
725 Node* term = raw.Int32Mul(raw.Parameter(i), raw.Int32Constant(coeff[i]));
726 result = raw.Int32Add(result, term);
727 }
728 raw.Return(result);
729}
730
731
732static int32_t Compute_Int32_WeightedSum(CallDescriptor* desc, int32_t* input) {
733 uint32_t result = 0;
734 for (int i = 0; i < ParamCount(desc); i++) {
735 result += static_cast<uint32_t>(input[i]) * coeff[i];
736 }
737 return static_cast<int32_t>(result);
738}
739
740
741static void Test_Int32_WeightedSum_of_size(int count) {
742 Int32Signature sig(count);
743 for (int p0 = 0; p0 < Register::kNumRegisters; p0++) {
744 if (Register::from_code(p0).IsAllocatable()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100745 base::AccountingAllocator allocator;
746 Zone zone(&allocator);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000747
748 int parray[] = {p0};
749 int rarray[] = {
750 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
751 ->GetAllocatableGeneralCode(0)};
752 Allocator params(parray, 1, nullptr, 0);
753 Allocator rets(rarray, 1, nullptr, 0);
754 RegisterConfig config(params, rets);
755 CallDescriptor* desc = config.Create(&zone, &sig);
756 Run_Computation<int32_t>(desc, Build_Int32_WeightedSum,
757 Compute_Int32_WeightedSum, 257 + count);
758 }
759 }
760}
761
762
763// Separate tests for parallelization.
764#define TEST_INT32_WEIGHTEDSUM(x) \
765 TEST(Run_Int32_WeightedSum_##x) { Test_Int32_WeightedSum_of_size(x); }
766
767
768TEST_INT32_WEIGHTEDSUM(1)
769TEST_INT32_WEIGHTEDSUM(2)
770TEST_INT32_WEIGHTEDSUM(3)
771TEST_INT32_WEIGHTEDSUM(4)
772TEST_INT32_WEIGHTEDSUM(5)
773TEST_INT32_WEIGHTEDSUM(7)
774TEST_INT32_WEIGHTEDSUM(9)
775TEST_INT32_WEIGHTEDSUM(11)
776TEST_INT32_WEIGHTEDSUM(17)
777TEST_INT32_WEIGHTEDSUM(19)
778
779
780template <int which>
781static void Build_Select(CallDescriptor* desc, RawMachineAssembler& raw) {
782 raw.Return(raw.Parameter(which));
783}
784
785
786template <typename CType, int which>
787static CType Compute_Select(CallDescriptor* desc, CType* inputs) {
788 return inputs[which];
789}
790
791
792template <typename CType, int which>
793static void RunSelect(CallDescriptor* desc) {
794 int count = ParamCount(desc);
795 if (count <= which) return;
796 Run_Computation<CType>(desc, Build_Select<which>,
797 Compute_Select<CType, which>,
798 1044 + which + 3 * sizeof(CType));
799}
800
801
802template <int which>
803void Test_Int32_Select() {
804 int parray[] = {
805 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
806 ->GetAllocatableGeneralCode(0)};
807 int rarray[] = {
808 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
809 ->GetAllocatableGeneralCode(0)};
810 Allocator params(parray, 1, nullptr, 0);
811 Allocator rets(rarray, 1, nullptr, 0);
812 RegisterConfig config(params, rets);
813
Ben Murdochda12d292016-06-02 14:46:10 +0100814 base::AccountingAllocator allocator;
815 Zone zone(&allocator);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000816
817 for (int i = which + 1; i <= 64; i++) {
818 Int32Signature sig(i);
819 CallDescriptor* desc = config.Create(&zone, &sig);
820 RunSelect<int32_t, which>(desc);
821 }
822}
823
824
825// Separate tests for parallelization.
826#define TEST_INT32_SELECT(x) \
827 TEST(Run_Int32_Select_##x) { Test_Int32_Select<x>(); }
828
829
830TEST_INT32_SELECT(0)
831TEST_INT32_SELECT(1)
832TEST_INT32_SELECT(2)
833TEST_INT32_SELECT(3)
834TEST_INT32_SELECT(4)
835TEST_INT32_SELECT(5)
836TEST_INT32_SELECT(6)
837TEST_INT32_SELECT(11)
838TEST_INT32_SELECT(15)
839TEST_INT32_SELECT(19)
840TEST_INT32_SELECT(45)
841TEST_INT32_SELECT(62)
842TEST_INT32_SELECT(63)
843
844
845TEST(Int64Select_registers) {
846 if (RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
847 ->num_allocatable_general_registers() < 2)
848 return;
849 if (kPointerSize < 8) return; // TODO(titzer): int64 on 32-bit platforms
850
851 int rarray[] = {
852 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
853 ->GetAllocatableGeneralCode(0)};
854 ArgsBuffer<int64_t>::Sig sig(2);
855
856 RegisterPairs pairs;
Ben Murdochda12d292016-06-02 14:46:10 +0100857 base::AccountingAllocator allocator;
858 Zone zone(&allocator);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000859 while (pairs.More()) {
860 int parray[2];
861 pairs.Next(&parray[0], &parray[1], false);
862 Allocator params(parray, 2, nullptr, 0);
863 Allocator rets(rarray, 1, nullptr, 0);
864 RegisterConfig config(params, rets);
865
866 CallDescriptor* desc = config.Create(&zone, &sig);
867 RunSelect<int64_t, 0>(desc);
868 RunSelect<int64_t, 1>(desc);
869 }
870}
871
872
873TEST(Float32Select_registers) {
874 if (RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
875 ->num_allocatable_double_registers() < 2) {
876 return;
877 }
878
879 int rarray[] = {
880 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
881 ->GetAllocatableDoubleCode(0)};
882 ArgsBuffer<float32>::Sig sig(2);
883
884 Float32RegisterPairs pairs;
Ben Murdochda12d292016-06-02 14:46:10 +0100885 base::AccountingAllocator allocator;
886 Zone zone(&allocator);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000887 while (pairs.More()) {
888 int parray[2];
889 pairs.Next(&parray[0], &parray[1], false);
890 Allocator params(nullptr, 0, parray, 2);
891 Allocator rets(nullptr, 0, rarray, 1);
892 RegisterConfig config(params, rets);
893
894 CallDescriptor* desc = config.Create(&zone, &sig);
895 RunSelect<float32, 0>(desc);
896 RunSelect<float32, 1>(desc);
897 }
898}
899
900
901TEST(Float64Select_registers) {
902 if (RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
903 ->num_allocatable_double_registers() < 2)
904 return;
905 if (RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
906 ->num_allocatable_general_registers() < 2)
907 return;
908 int rarray[] = {
909 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
910 ->GetAllocatableDoubleCode(0)};
911 ArgsBuffer<float64>::Sig sig(2);
912
913 Float64RegisterPairs pairs;
Ben Murdochda12d292016-06-02 14:46:10 +0100914 base::AccountingAllocator allocator;
915 Zone zone(&allocator);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000916 while (pairs.More()) {
917 int parray[2];
918 pairs.Next(&parray[0], &parray[1], false);
919 Allocator params(nullptr, 0, parray, 2);
920 Allocator rets(nullptr, 0, rarray, 1);
921 RegisterConfig config(params, rets);
922
923 CallDescriptor* desc = config.Create(&zone, &sig);
924 RunSelect<float64, 0>(desc);
925 RunSelect<float64, 1>(desc);
926 }
927}
928
929
930TEST(Float32Select_stack_params_return_reg) {
931 int rarray[] = {
932 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
933 ->GetAllocatableDoubleCode(0)};
934 Allocator params(nullptr, 0, nullptr, 0);
935 Allocator rets(nullptr, 0, rarray, 1);
936 RegisterConfig config(params, rets);
937
Ben Murdochda12d292016-06-02 14:46:10 +0100938 base::AccountingAllocator allocator;
939 Zone zone(&allocator);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000940 for (int count = 1; count < 6; count++) {
941 ArgsBuffer<float32>::Sig sig(count);
942 CallDescriptor* desc = config.Create(&zone, &sig);
943 RunSelect<float32, 0>(desc);
944 RunSelect<float32, 1>(desc);
945 RunSelect<float32, 2>(desc);
946 RunSelect<float32, 3>(desc);
947 RunSelect<float32, 4>(desc);
948 RunSelect<float32, 5>(desc);
949 }
950}
951
952
953TEST(Float64Select_stack_params_return_reg) {
954 int rarray[] = {
955 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
956 ->GetAllocatableDoubleCode(0)};
957 Allocator params(nullptr, 0, nullptr, 0);
958 Allocator rets(nullptr, 0, rarray, 1);
959 RegisterConfig config(params, rets);
960
Ben Murdochda12d292016-06-02 14:46:10 +0100961 base::AccountingAllocator allocator;
962 Zone zone(&allocator);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000963 for (int count = 1; count < 6; count++) {
964 ArgsBuffer<float64>::Sig sig(count);
965 CallDescriptor* desc = config.Create(&zone, &sig);
966 RunSelect<float64, 0>(desc);
967 RunSelect<float64, 1>(desc);
968 RunSelect<float64, 2>(desc);
969 RunSelect<float64, 3>(desc);
970 RunSelect<float64, 4>(desc);
971 RunSelect<float64, 5>(desc);
972 }
973}
974
975
976template <typename CType, int which>
977static void Build_Select_With_Call(CallDescriptor* desc,
978 RawMachineAssembler& raw) {
979 Handle<Code> inner = Handle<Code>::null();
980 int num_params = ParamCount(desc);
981 CHECK_LE(num_params, kMaxParamCount);
982 {
983 Isolate* isolate = CcTest::InitIsolateOnce();
984 // Build the actual select.
Ben Murdochda12d292016-06-02 14:46:10 +0100985 Zone zone(isolate->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000986 Graph graph(&zone);
987 RawMachineAssembler raw(isolate, &graph, desc);
988 raw.Return(raw.Parameter(which));
989 inner = CompileGraph("Select-indirection", desc, &graph, raw.Export());
990 CHECK(!inner.is_null());
991 CHECK(inner->IsCode());
992 }
993
994 {
995 // Build a call to the function that does the select.
996 Node* target = raw.HeapConstant(inner);
997 Node** args = raw.zone()->NewArray<Node*>(num_params);
998 for (int i = 0; i < num_params; i++) {
999 args[i] = raw.Parameter(i);
1000 }
1001
1002 Node* call = raw.CallN(desc, target, args);
1003 raw.Return(call);
1004 }
1005}
1006
1007
1008TEST(Float64StackParamsToStackParams) {
1009 int rarray[] = {
1010 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1011 ->GetAllocatableDoubleCode(0)};
1012 Allocator params(nullptr, 0, nullptr, 0);
1013 Allocator rets(nullptr, 0, rarray, 1);
1014
Ben Murdochda12d292016-06-02 14:46:10 +01001015 base::AccountingAllocator allocator;
1016 Zone zone(&allocator);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001017 ArgsBuffer<float64>::Sig sig(2);
1018 RegisterConfig config(params, rets);
1019 CallDescriptor* desc = config.Create(&zone, &sig);
1020
1021 Run_Computation<float64>(desc, Build_Select_With_Call<float64, 0>,
1022 Compute_Select<float64, 0>, 1098);
1023
1024 Run_Computation<float64>(desc, Build_Select_With_Call<float64, 1>,
1025 Compute_Select<float64, 1>, 1099);
1026}
1027
1028
1029void MixedParamTest(int start) {
1030 if (RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1031 ->num_double_registers() < 2)
1032 return;
1033
1034// TODO(titzer): mix in 64-bit types on all platforms when supported.
1035#if V8_TARGET_ARCH_32_BIT
1036 static MachineType types[] = {
1037 MachineType::Int32(), MachineType::Float32(), MachineType::Float64(),
1038 MachineType::Int32(), MachineType::Float64(), MachineType::Float32(),
1039 MachineType::Float32(), MachineType::Float64(), MachineType::Int32(),
1040 MachineType::Float32(), MachineType::Int32(), MachineType::Float64(),
1041 MachineType::Float64(), MachineType::Float32(), MachineType::Int32(),
1042 MachineType::Float64(), MachineType::Int32(), MachineType::Float32()};
1043#else
1044 static MachineType types[] = {
1045 MachineType::Int32(), MachineType::Int64(), MachineType::Float32(),
1046 MachineType::Float64(), MachineType::Int32(), MachineType::Float64(),
1047 MachineType::Float32(), MachineType::Int64(), MachineType::Int64(),
1048 MachineType::Float32(), MachineType::Float32(), MachineType::Int32(),
1049 MachineType::Float64(), MachineType::Float64(), MachineType::Int64(),
1050 MachineType::Int32(), MachineType::Float64(), MachineType::Int32(),
1051 MachineType::Float32()};
1052#endif
1053
1054 Isolate* isolate = CcTest::InitIsolateOnce();
1055
1056 // Build machine signature
1057 MachineType* params = &types[start];
1058 const int num_params = static_cast<int>(arraysize(types) - start);
1059
1060 // Build call descriptor
1061 int parray_gp[] = {
1062 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1063 ->GetAllocatableGeneralCode(0),
1064 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1065 ->GetAllocatableGeneralCode(1)};
1066 int rarray_gp[] = {
1067 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1068 ->GetAllocatableGeneralCode(0)};
1069 int parray_fp[] = {
1070 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1071 ->GetAllocatableDoubleCode(0),
1072 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1073 ->GetAllocatableDoubleCode(1)};
1074 int rarray_fp[] = {
1075 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1076 ->GetAllocatableDoubleCode(0)};
1077 Allocator palloc(parray_gp, 2, parray_fp, 2);
1078 Allocator ralloc(rarray_gp, 1, rarray_fp, 1);
1079 RegisterConfig config(palloc, ralloc);
1080
1081 for (int which = 0; which < num_params; which++) {
Ben Murdochda12d292016-06-02 14:46:10 +01001082 base::AccountingAllocator allocator;
1083 Zone zone(&allocator);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001084 HandleScope scope(isolate);
1085 MachineSignature::Builder builder(&zone, 1, num_params);
1086 builder.AddReturn(params[which]);
1087 for (int j = 0; j < num_params; j++) builder.AddParam(params[j]);
1088 MachineSignature* sig = builder.Build();
1089 CallDescriptor* desc = config.Create(&zone, sig);
1090
1091 Handle<Code> select;
1092 {
1093 // build the select.
Ben Murdochda12d292016-06-02 14:46:10 +01001094 Zone zone(&allocator);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001095 Graph graph(&zone);
1096 RawMachineAssembler raw(isolate, &graph, desc);
1097 raw.Return(raw.Parameter(which));
1098 select = CompileGraph("Compute", desc, &graph, raw.Export());
1099 }
1100
1101 {
1102 // call the select.
1103 Handle<Code> wrapper = Handle<Code>::null();
1104 int32_t expected_ret;
1105 char bytes[kDoubleSize];
1106 V8_ALIGNED(8) char output[kDoubleSize];
1107 int expected_size = 0;
1108 CSignature0<int32_t> csig;
1109 {
1110 // Wrap the select code with a callable function that passes constants.
Ben Murdochda12d292016-06-02 14:46:10 +01001111 Zone zone(&allocator);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001112 Graph graph(&zone);
1113 CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig);
1114 RawMachineAssembler raw(isolate, &graph, cdesc);
1115 Node* target = raw.HeapConstant(select);
1116 Node** args = zone.NewArray<Node*>(num_params);
1117 int64_t constant = 0x0102030405060708;
1118 for (int i = 0; i < num_params; i++) {
1119 MachineType param_type = sig->GetParam(i);
1120 Node* konst = nullptr;
1121 if (param_type == MachineType::Int32()) {
1122 int32_t value[] = {static_cast<int32_t>(constant)};
1123 konst = raw.Int32Constant(value[0]);
1124 if (i == which) memcpy(bytes, value, expected_size = 4);
1125 }
1126 if (param_type == MachineType::Int64()) {
1127 int64_t value[] = {static_cast<int64_t>(constant)};
1128 konst = raw.Int64Constant(value[0]);
1129 if (i == which) memcpy(bytes, value, expected_size = 8);
1130 }
1131 if (param_type == MachineType::Float32()) {
1132 float32 value[] = {static_cast<float32>(constant)};
1133 konst = raw.Float32Constant(value[0]);
1134 if (i == which) memcpy(bytes, value, expected_size = 4);
1135 }
1136 if (param_type == MachineType::Float64()) {
1137 float64 value[] = {static_cast<float64>(constant)};
1138 konst = raw.Float64Constant(value[0]);
1139 if (i == which) memcpy(bytes, value, expected_size = 8);
1140 }
1141 CHECK_NOT_NULL(konst);
1142
1143 args[i] = konst;
1144 constant += 0x1010101010101010;
1145 }
1146
1147 Node* call = raw.CallN(desc, target, args);
1148 Node* store =
1149 raw.StoreToPointer(output, sig->GetReturn().representation(), call);
1150 USE(store);
1151 expected_ret = static_cast<int32_t>(constant);
1152 raw.Return(raw.Int32Constant(expected_ret));
1153 wrapper = CompileGraph("Select-mixed-wrapper-const", cdesc, &graph,
1154 raw.Export());
1155 }
1156
1157 CodeRunner<int32_t> runnable(isolate, wrapper, &csig);
1158 CHECK_EQ(expected_ret, runnable.Call());
1159 for (int i = 0; i < expected_size; i++) {
1160 CHECK_EQ(static_cast<int>(bytes[i]), static_cast<int>(output[i]));
1161 }
1162 }
1163 }
1164}
1165
1166
1167TEST(MixedParams_0) { MixedParamTest(0); }
1168TEST(MixedParams_1) { MixedParamTest(1); }
1169TEST(MixedParams_2) { MixedParamTest(2); }
1170TEST(MixedParams_3) { MixedParamTest(3); }
1171
Ben Murdoch097c5b22016-05-18 11:27:45 +01001172template <typename T>
1173void TestStackSlot(MachineType slot_type, T expected) {
1174 // Test: Generate with a function f which reserves a stack slot, call an inner
1175 // function g from f which writes into the stack slot of f.
1176
1177 if (RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1178 ->num_allocatable_double_registers() < 2)
1179 return;
1180
1181 Isolate* isolate = CcTest::InitIsolateOnce();
1182
1183 // Lots of code to generate the build descriptor for the inner function.
1184 int parray_gp[] = {
1185 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1186 ->GetAllocatableGeneralCode(0),
1187 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1188 ->GetAllocatableGeneralCode(1)};
1189 int rarray_gp[] = {
1190 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1191 ->GetAllocatableGeneralCode(0)};
1192 int parray_fp[] = {
1193 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1194 ->GetAllocatableDoubleCode(0),
1195 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1196 ->GetAllocatableDoubleCode(1)};
1197 int rarray_fp[] = {
1198 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN)
1199 ->GetAllocatableDoubleCode(0)};
1200 Allocator palloc(parray_gp, 2, parray_fp, 2);
1201 Allocator ralloc(rarray_gp, 1, rarray_fp, 1);
1202 RegisterConfig config(palloc, ralloc);
1203
Ben Murdochda12d292016-06-02 14:46:10 +01001204 Zone zone(isolate->allocator());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001205 HandleScope scope(isolate);
1206 MachineSignature::Builder builder(&zone, 1, 12);
1207 builder.AddReturn(MachineType::Int32());
1208 for (int i = 0; i < 10; i++) {
1209 builder.AddParam(MachineType::Int32());
1210 }
1211 builder.AddParam(slot_type);
1212 builder.AddParam(MachineType::Pointer());
1213 MachineSignature* sig = builder.Build();
1214 CallDescriptor* desc = config.Create(&zone, sig);
1215
1216 // Create inner function g. g has lots of parameters so that they are passed
1217 // over the stack.
1218 Handle<Code> inner;
1219 Graph graph(&zone);
1220 RawMachineAssembler g(isolate, &graph, desc);
1221
1222 g.Store(slot_type.representation(), g.Parameter(11), g.Parameter(10),
1223 WriteBarrierKind::kNoWriteBarrier);
1224 g.Return(g.Parameter(9));
1225 inner = CompileGraph("Compute", desc, &graph, g.Export());
1226
1227 // Create function f with a stack slot which calls the inner function g.
1228 BufferedRawMachineAssemblerTester<T> f(slot_type);
1229 Node* target = f.HeapConstant(inner);
1230 Node* stack_slot = f.StackSlot(slot_type.representation());
1231 Node* args[12];
1232 for (int i = 0; i < 10; i++) {
1233 args[i] = f.Int32Constant(i);
1234 }
1235 args[10] = f.Parameter(0);
1236 args[11] = stack_slot;
1237
1238 f.CallN(desc, target, args);
1239 f.Return(f.Load(slot_type, stack_slot, f.IntPtrConstant(0)));
1240
1241 CHECK_EQ(expected, f.Call(expected));
1242}
1243
1244TEST(RunStackSlotInt32) {
1245 int32_t magic = 0x12345678;
1246 TestStackSlot(MachineType::Int32(), magic);
1247}
1248
1249#if !V8_TARGET_ARCH_32_BIT
1250TEST(RunStackSlotInt64) {
1251 int64_t magic = 0x123456789abcdef0;
1252 TestStackSlot(MachineType::Int64(), magic);
1253}
1254#endif
1255
1256TEST(RunStackSlotFloat32) {
1257 float magic = 1234.125f;
1258 TestStackSlot(MachineType::Float32(), magic);
1259}
1260
1261TEST(RunStackSlotFloat64) {
1262 double magic = 3456.375;
1263 TestStackSlot(MachineType::Float64(), magic);
1264}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001265} // namespace compiler
1266} // namespace internal
1267} // namespace v8