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