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 136 : max_pairs_(std::min(max_pairs, range_ * range_)),
39 204 : counter_(0) {}
40 :
41 : bool More() { return counter_ < max_pairs_; }
42 :
43 6288 : void Next(int* r0, int* r1, bool same_is_ok) {
44 : do {
45 : // Find the next pair.
46 6800 : 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 6800 : int index = counter_ / 2;
52 6800 : if (counter_ & 1) {
53 3400 : *r0 = codes_[index % range_];
54 3400 : *r1 = codes_[index / range_];
55 : } else {
56 3400 : *r1 = codes_[index % range_];
57 3400 : *r0 = codes_[index / range_];
58 : }
59 : }
60 6800 : counter_++;
61 6800 : if ((same_is_ok) || (*r0 != *r1)) break;
62 512 : 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 6288 : }
70 :
71 : private:
72 : int range_;
73 : const int* codes_;
74 : int max_pairs_;
75 : int counter_;
76 6800 : bool exhaustive() { return max_pairs_ == (range_ * range_); }
77 : };
78 :
79 :
80 : // Pairs of general purpose registers.
81 : class RegisterPairs : public Pairs {
82 : public:
83 60 : RegisterPairs()
84 : : Pairs(100, GetRegConfig()->num_allocatable_general_registers(),
85 120 : GetRegConfig()->allocatable_general_codes()) {}
86 : };
87 :
88 : // Pairs of float registers.
89 : class Float32RegisterPairs : public Pairs {
90 : public:
91 4 : Float32RegisterPairs()
92 : : Pairs(100, GetRegConfig()->num_allocatable_float_registers(),
93 12 : GetRegConfig()->allocatable_float_codes()) {}
94 : };
95 :
96 :
97 : // Pairs of double registers.
98 : class Float64RegisterPairs : public Pairs {
99 : public:
100 4 : Float64RegisterPairs()
101 : : Pairs(100, GetRegConfig()->num_allocatable_double_registers(),
102 8 : GetRegConfig()->allocatable_double_codes()) {}
103 : };
104 :
105 :
106 : // Helper for allocating either an GP or FP reg, or the next stack slot.
107 27456 : class Allocator {
108 : public:
109 27456 : Allocator(int* gp, int gpc, int* fp, int fpc) : stack_offset_(0) {
110 48560 : for (int i = 0; i < gpc; ++i) {
111 34832 : gp_.push_back(Register::from_code(gp[i]));
112 : }
113 18360 : for (int i = 0; i < fpc; ++i) {
114 4632 : fp_.push_back(DoubleRegister::from_code(fp[i]));
115 : }
116 13728 : Reset();
117 13728 : }
118 :
119 : int stack_offset() const { return stack_offset_; }
120 :
121 124092 : LinkageLocation Next(MachineType type) {
122 124092 : if (IsFloatingPoint(type.representation())) {
123 : // Allocate a floating point register/stack location.
124 5280 : if (reg_allocator_->CanAllocateFP(type.representation())) {
125 : int code = reg_allocator_->NextFpReg(type.representation());
126 : return LinkageLocation::ForRegister(code, type);
127 : } else {
128 2304 : int offset = -1 - stack_offset_;
129 2304 : stack_offset_ += StackWords(type);
130 : return LinkageLocation::ForCallerFrameSlot(offset, type);
131 : }
132 : } else {
133 : // Allocate a general purpose register/stack location.
134 118812 : if (reg_allocator_->CanAllocateGP()) {
135 : int code = reg_allocator_->NextGpReg();
136 : return LinkageLocation::ForRegister(code, type);
137 : } else {
138 96096 : int offset = -1 - stack_offset_;
139 96096 : stack_offset_ += StackWords(type);
140 : return LinkageLocation::ForCallerFrameSlot(offset, type);
141 : }
142 : }
143 : }
144 : int StackWords(MachineType type) {
145 98400 : int size = 1 << ElementSizeLog2Of(type.representation());
146 98400 : return size <= kSystemPointerSize ? 1 : size / kSystemPointerSize;
147 : }
148 32712 : void Reset() {
149 32712 : stack_offset_ = 0;
150 65424 : reg_allocator_.reset(
151 : new wasm::LinkageAllocator(gp_.data(), static_cast<int>(gp_.size()),
152 : fp_.data(), static_cast<int>(fp_.size())));
153 32712 : }
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 6864 : RegisterConfig(Allocator& p, Allocator& r) : params(p), rets(r) {}
166 :
167 9492 : CallDescriptor* Create(Zone* zone, MachineSignature* msig) {
168 9492 : rets.Reset();
169 9492 : params.Reset();
170 :
171 : LocationSignature::Builder locations(zone, msig->return_count(),
172 : msig->parameter_count());
173 : // Add return location(s).
174 9492 : const int return_count = static_cast<int>(locations.return_count_);
175 28476 : for (int i = 0; i < return_count; i++) {
176 18984 : locations.AddReturn(rets.Next(msig->GetReturn(i)));
177 : }
178 :
179 : // Add register and/or stack parameter(s).
180 9492 : const int parameter_count = static_cast<int>(msig->parameter_count());
181 238692 : for (int i = 0; i < parameter_count; i++) {
182 229200 : 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 9492 : 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 18984 : "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 : explicit Int32Signature(int param_count)
240 2424 : : MachineSignature(1, param_count, kIntTypes) {
241 2424 : CHECK_GE(kMaxParamCount, param_count);
242 : }
243 : };
244 :
245 26552 : Handle<Code> CompileGraph(const char* name, CallDescriptor* call_descriptor,
246 : Graph* graph, Schedule* schedule = nullptr) {
247 : Isolate* isolate = CcTest::InitIsolateOnce();
248 : OptimizedCompilationInfo info(ArrayVector("testing"), graph->zone(),
249 53104 : Code::STUB);
250 53104 : Handle<Code> code = Pipeline::GenerateCodeForTesting(
251 : &info, isolate, call_descriptor, graph,
252 53104 : AssemblerOptions::Default(isolate), schedule)
253 : .ToHandleChecked();
254 : #ifdef ENABLE_DISASSEMBLER
255 : if (FLAG_print_opt_code) {
256 : StdoutStream os;
257 : code->Disassemble(name, os);
258 : }
259 : #endif
260 53104 : return code;
261 : }
262 :
263 4816 : Handle<Code> WrapWithCFunction(Handle<Code> inner,
264 : CallDescriptor* call_descriptor) {
265 9632 : Zone zone(inner->GetIsolate()->allocator(), ZONE_NAME);
266 4816 : int param_count = static_cast<int>(call_descriptor->ParameterCount());
267 4816 : GraphAndBuilders caller(&zone);
268 : {
269 : GraphAndBuilders& b = caller;
270 4816 : Node* start = b.graph()->NewNode(b.common()->Start(param_count + 3));
271 : b.graph()->SetStart(start);
272 9632 : Node* target = b.graph()->NewNode(b.common()->HeapConstant(inner));
273 :
274 : // Add arguments to the call.
275 4816 : Node** args = zone.NewArray<Node*>(param_count + 3);
276 : int index = 0;
277 4816 : args[index++] = target;
278 24080 : for (int i = 0; i < param_count; i++) {
279 19264 : args[index] = b.graph()->NewNode(b.common()->Parameter(i), start);
280 9632 : index++;
281 : }
282 4816 : args[index++] = start; // effect.
283 4816 : args[index++] = start; // control.
284 :
285 : // Build the call and return nodes.
286 4816 : Node* call = b.graph()->NewNode(b.common()->Call(call_descriptor),
287 4816 : param_count + 3, args);
288 4816 : Node* zero = b.graph()->NewNode(b.common()->Int32Constant(0));
289 : Node* ret =
290 4816 : b.graph()->NewNode(b.common()->Return(), zero, call, call, start);
291 : b.graph()->SetEnd(ret);
292 : }
293 :
294 4816 : MachineSignature* msig = call_descriptor->GetMachineSignature(&zone);
295 4816 : CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, msig);
296 :
297 9632 : 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 5200 : explicit ArgsBuffer(int count, int seed = 1) : count_(count), seed_(seed) {
307 : // initialize the buffer with "seed 0"
308 5200 : seed_ = 0;
309 1600 : Mutate();
310 5200 : seed_ = seed;
311 : }
312 :
313 : class Sig : public MachineSignature {
314 : public:
315 56 : explicit Sig(int param_count)
316 56 : : MachineSignature(1, param_count, MachTypes()) {
317 56 : CHECK_GE(kMaxParamCount, param_count);
318 56 : }
319 : };
320 :
321 56 : 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 56 : t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t};
327 56 : return kTypes;
328 : }
329 :
330 : Node* MakeConstant(RawMachineAssembler& raw, int32_t value) {
331 90160 : return raw.Int32Constant(value);
332 : }
333 :
334 : Node* MakeConstant(RawMachineAssembler& raw, int64_t value) {
335 1472 : return raw.Int64Constant(value);
336 : }
337 :
338 : Node* MakeConstant(RawMachineAssembler& raw, float32 value) {
339 1692 : return raw.Float32Constant(value);
340 : }
341 :
342 : Node* MakeConstant(RawMachineAssembler& raw, float64 value) {
343 1708 : return raw.Float64Constant(value);
344 : }
345 :
346 95032 : Node* LoadInput(RawMachineAssembler& raw, Node* base, int index) {
347 95032 : Node* offset = raw.Int32Constant(index * sizeof(CType));
348 95032 : return raw.Load(MachineTypeForC<CType>(), base, offset);
349 : }
350 :
351 10400 : Node* StoreOutput(RawMachineAssembler& raw, Node* value) {
352 10400 : Node* base = raw.PointerConstant(&output);
353 10400 : Node* offset = raw.Int32Constant(0);
354 : return raw.Store(MachineTypeForC<CType>().representation(), base, offset,
355 10400 : 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 : void ArgsBuffer<int32_t>::Mutate() {
372 14320 : uint32_t base = 1111111111u * seed_;
373 1099104 : for (int j = 0; j < count_ && j < kMaxParamCount; j++) {
374 540960 : input[j] = static_cast<int32_t>(256 + base + j + seed_ * 13);
375 : }
376 17184 : output = -1;
377 17184 : seed_++;
378 : }
379 :
380 :
381 : template <>
382 : void ArgsBuffer<int64_t>::Mutate() {
383 3680 : uint64_t base = 11111111111111111ull * seed_;
384 22080 : for (int j = 0; j < count_ && j < kMaxParamCount; j++) {
385 8832 : input[j] = static_cast<int64_t>(256 + base + j + seed_ * 13);
386 : }
387 4416 : output = -1;
388 4416 : seed_++;
389 : }
390 :
391 :
392 : template <>
393 4776 : void ArgsBuffer<float32>::Mutate() {
394 4776 : float64 base = -33.25 * seed_;
395 25080 : for (int j = 0; j < count_ && j < kMaxParamCount; j++) {
396 10152 : input[j] = 256 + base + j + seed_ * 13;
397 : }
398 4776 : output = std::numeric_limits<float32>::quiet_NaN();
399 4776 : seed_++;
400 4776 : }
401 :
402 :
403 : template <>
404 4824 : void ArgsBuffer<float64>::Mutate() {
405 4824 : float64 base = -111.25 * seed_;
406 25320 : for (int j = 0; j < count_ && j < kMaxParamCount; j++) {
407 10248 : input[j] = 256 + base + j + seed_ * 13;
408 : }
409 4824 : output = std::numeric_limits<float64>::quiet_NaN();
410 4824 : seed_++;
411 4824 : }
412 :
413 : int ParamCount(CallDescriptor* call_descriptor) {
414 39608 : return static_cast<int>(call_descriptor->ParameterCount());
415 : }
416 :
417 :
418 : template <typename CType>
419 : class Computer {
420 : public:
421 5200 : 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 5200 : CHECK_LE(num_params, kMaxParamCount);
427 : Isolate* isolate = CcTest::InitIsolateOnce();
428 : HandleScope scope(isolate);
429 : Handle<Code> inner = Handle<Code>::null();
430 : {
431 : // Build the graph for the computation.
432 10400 : Zone zone(isolate->allocator(), ZONE_NAME);
433 5200 : Graph graph(&zone);
434 5200 : RawMachineAssembler raw(isolate, &graph, desc);
435 5200 : build(desc, raw);
436 5200 : inner = CompileGraph("Compute", desc, &graph, raw.Export());
437 : }
438 :
439 : 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 10400 : Zone zone(isolate->allocator(), ZONE_NAME);
448 5200 : Graph graph(&zone);
449 5200 : CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig);
450 5200 : RawMachineAssembler raw(isolate, &graph, cdesc);
451 5200 : Node* target = raw.HeapConstant(inner);
452 5200 : Node** inputs = zone.NewArray<Node*>(num_params + 1);
453 : int input_count = 0;
454 5200 : inputs[input_count++] = target;
455 195264 : for (int i = 0; i < num_params; i++) {
456 190064 : inputs[input_count++] = io.MakeConstant(raw, io.input[i]);
457 : }
458 :
459 5200 : Node* call = raw.CallN(desc, input_count, inputs);
460 5200 : Node* store = io.StoreOutput(raw, call);
461 : USE(store);
462 5200 : raw.Return(raw.Int32Constant(seed));
463 5200 : wrapper =
464 5200 : 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 5200 : CType expected = compute(desc, io.input);
471 : int32_t check_seed = runnable.Call();
472 5200 : CHECK_EQ(seed, check_seed);
473 5200 : 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 10400 : Zone zone(isolate->allocator(), ZONE_NAME);
482 5200 : Graph graph(&zone);
483 5200 : CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig);
484 5200 : RawMachineAssembler raw(isolate, &graph, cdesc);
485 : Node* base = raw.PointerConstant(io.input);
486 5200 : Node* target = raw.HeapConstant(inner);
487 : Node** inputs = zone.NewArray<Node*>(kMaxParamCount + 1);
488 : int input_count = 0;
489 5200 : inputs[input_count++] = target;
490 195264 : for (int i = 0; i < num_params; i++) {
491 95032 : inputs[input_count++] = io.LoadInput(raw, base, i);
492 : }
493 :
494 5200 : Node* call = raw.CallN(desc, input_count, inputs);
495 5200 : Node* store = io.StoreOutput(raw, call);
496 : USE(store);
497 5200 : raw.Return(raw.Int32Constant(seed));
498 5200 : 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 57200 : for (int i = 0; i < 5; i++) {
505 26000 : CType expected = compute(desc, io.input);
506 : int32_t check_seed = runnable.Call();
507 26000 : CHECK_EQ(seed, check_seed);
508 26000 : CHECK_EQ(expected, io.output);
509 8000 : io.Mutate();
510 : }
511 : }
512 5200 : }
513 : };
514 :
515 : } // namespace
516 :
517 :
518 4816 : static void TestInt32Sub(CallDescriptor* desc) {
519 : Isolate* isolate = CcTest::InitIsolateOnce();
520 : HandleScope scope(isolate);
521 9632 : Zone zone(isolate->allocator(), ZONE_NAME);
522 4816 : GraphAndBuilders inner(&zone);
523 : {
524 : // Build the add function.
525 : GraphAndBuilders& b = inner;
526 4816 : Node* start = b.graph()->NewNode(b.common()->Start(5));
527 : b.graph()->SetStart(start);
528 4816 : Node* p0 = b.graph()->NewNode(b.common()->Parameter(0), start);
529 4816 : Node* p1 = b.graph()->NewNode(b.common()->Parameter(1), start);
530 4816 : Node* add = b.graph()->NewNode(b.machine()->Int32Sub(), p0, p1);
531 4816 : Node* zero = b.graph()->NewNode(b.common()->Int32Constant(0));
532 : Node* ret =
533 4816 : b.graph()->NewNode(b.common()->Return(), zero, add, start, start);
534 : b.graph()->SetEnd(ret);
535 : }
536 :
537 4816 : Handle<Code> inner_code = CompileGraph("Int32Sub", desc, inner.graph());
538 4816 : Handle<Code> wrapper = WrapWithCFunction(inner_code, desc);
539 4816 : MachineSignature* msig = desc->GetMachineSignature(&zone);
540 : CodeRunner<int32_t> runnable(isolate, wrapper,
541 : CSignature::FromMachine(&zone, msig));
542 :
543 563472 : FOR_INT32_INPUTS(i) {
544 32681376 : FOR_INT32_INPUTS(j) {
545 16201024 : int32_t expected = static_cast<int32_t>(static_cast<uint32_t>(i) -
546 16201024 : static_cast<uint32_t>(j));
547 16201024 : int32_t result = runnable.Call(i, j);
548 16201024 : CHECK_EQ(expected, result);
549 : }
550 : }
551 4816 : }
552 :
553 :
554 368 : static void CopyTwentyInt32(CallDescriptor* desc) {
555 : const int kNumParams = 20;
556 : int32_t input[kNumParams];
557 : int32_t output[kNumParams];
558 : 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 736 : Zone zone(isolate->allocator(), ZONE_NAME);
564 368 : Graph graph(&zone);
565 368 : RawMachineAssembler raw(isolate, &graph, desc);
566 : Node* base = raw.PointerConstant(output);
567 15088 : for (int i = 0; i < kNumParams; i++) {
568 7360 : Node* offset = raw.Int32Constant(i * sizeof(int32_t));
569 7360 : raw.Store(MachineRepresentation::kWord32, base, offset, raw.Parameter(i),
570 7360 : kNoWriteBarrier);
571 : }
572 368 : raw.Return(raw.Int32Constant(42));
573 368 : inner = CompileGraph("CopyTwentyInt32", desc, &graph, raw.Export());
574 : }
575 :
576 : 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 736 : Zone zone(isolate->allocator(), ZONE_NAME);
581 368 : Graph graph(&zone);
582 368 : CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig);
583 368 : RawMachineAssembler raw(isolate, &graph, cdesc);
584 : Node* base = raw.PointerConstant(input);
585 368 : Node* target = raw.HeapConstant(inner);
586 : Node** inputs = zone.NewArray<Node*>(kNumParams + 1);
587 : int input_count = 0;
588 368 : inputs[input_count++] = target;
589 15088 : for (int i = 0; i < kNumParams; i++) {
590 7360 : Node* offset = raw.Int32Constant(i * sizeof(int32_t));
591 7360 : inputs[input_count++] = raw.Load(MachineType::Int32(), base, offset);
592 : }
593 :
594 368 : Node* call = raw.CallN(desc, input_count, inputs);
595 368 : raw.Return(call);
596 : wrapper =
597 368 : 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 4048 : for (int i = 0; i < 5; i++) {
604 1840 : uint32_t base = 1111111111u * i;
605 75440 : for (int j = 0; j < kNumParams; j++) {
606 36800 : input[j] = static_cast<int32_t>(base + 13 * j);
607 : }
608 :
609 : memset(output, 0, sizeof(output));
610 1840 : CHECK_EQ(42, runnable.Call());
611 :
612 75440 : for (int j = 0; j < kNumParams; j++) {
613 36800 : CHECK_EQ(input[j], output[j]);
614 : }
615 : }
616 368 : }
617 :
618 :
619 48 : static void Test_RunInt32SubWithRet(int retreg) {
620 : Int32Signature sig(2);
621 96 : v8::internal::AccountingAllocator allocator;
622 96 : Zone zone(&allocator, ZONE_NAME);
623 48 : RegisterPairs pairs;
624 8880 : while (pairs.More()) {
625 : int parray[2];
626 4416 : int rarray[] = {retreg};
627 4416 : pairs.Next(&parray[0], &parray[1], false);
628 8832 : Allocator params(parray, 2, nullptr, 0);
629 8832 : Allocator rets(rarray, 1, nullptr, 0);
630 : RegisterConfig config(params, rets);
631 4416 : TestInt32Sub(config.Create(&zone, &sig));
632 : }
633 48 : }
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 26664 : TEST_INT32_SUB_WITH_RET(0)
646 26664 : TEST_INT32_SUB_WITH_RET(1)
647 26664 : TEST_INT32_SUB_WITH_RET(2)
648 26664 : TEST_INT32_SUB_WITH_RET(3)
649 26664 : TEST_INT32_SUB_WITH_RET(4)
650 26664 : TEST_INT32_SUB_WITH_RET(5)
651 26664 : TEST_INT32_SUB_WITH_RET(6)
652 26664 : TEST_INT32_SUB_WITH_RET(7)
653 26664 : TEST_INT32_SUB_WITH_RET(8)
654 26664 : TEST_INT32_SUB_WITH_RET(9)
655 26664 : TEST_INT32_SUB_WITH_RET(10)
656 26664 : TEST_INT32_SUB_WITH_RET(11)
657 26664 : TEST_INT32_SUB_WITH_RET(12)
658 26664 : TEST_INT32_SUB_WITH_RET(13)
659 26664 : TEST_INT32_SUB_WITH_RET(14)
660 26664 : TEST_INT32_SUB_WITH_RET(15)
661 26660 : TEST_INT32_SUB_WITH_RET(16)
662 26660 : TEST_INT32_SUB_WITH_RET(17)
663 26660 : TEST_INT32_SUB_WITH_RET(18)
664 26660 : TEST_INT32_SUB_WITH_RET(19)
665 :
666 :
667 26660 : TEST(Run_Int32Sub_all_allocatable_single) {
668 : Int32Signature sig(2);
669 4 : RegisterPairs pairs;
670 804 : while (pairs.More()) {
671 800 : v8::internal::AccountingAllocator allocator;
672 800 : Zone zone(&allocator, ZONE_NAME);
673 : int parray[1];
674 : int rarray[1];
675 400 : pairs.Next(&rarray[0], &parray[0], true);
676 800 : Allocator params(parray, 1, nullptr, 0);
677 800 : Allocator rets(rarray, 1, nullptr, 0);
678 : RegisterConfig config(params, rets);
679 400 : TestInt32Sub(config.Create(&zone, &sig));
680 : }
681 4 : }
682 :
683 :
684 26660 : TEST(Run_CopyTwentyInt32_all_allocatable_pairs) {
685 : Int32Signature sig(20);
686 4 : RegisterPairs pairs;
687 740 : while (pairs.More()) {
688 736 : v8::internal::AccountingAllocator allocator;
689 736 : Zone zone(&allocator, ZONE_NAME);
690 : int parray[2];
691 736 : int rarray[] = {GetRegConfig()->GetAllocatableGeneralCode(0)};
692 368 : pairs.Next(&parray[0], &parray[1], false);
693 736 : Allocator params(parray, 2, nullptr, 0);
694 736 : Allocator rets(rarray, 1, nullptr, 0);
695 : RegisterConfig config(params, rets);
696 368 : CopyTwentyInt32(config.Create(&zone, &sig));
697 : }
698 4 : }
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 5196 : 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 480 : static void Build_Int32_WeightedSum(CallDescriptor* desc,
715 : RawMachineAssembler& raw) {
716 480 : Node* result = raw.Int32Constant(0);
717 7968 : for (int i = 0; i < ParamCount(desc); i++) {
718 3744 : Node* term = raw.Int32Mul(raw.Parameter(i), raw.Int32Constant(coeff[i]));
719 3744 : result = raw.Int32Add(result, term);
720 : }
721 480 : raw.Return(result);
722 480 : }
723 :
724 :
725 2880 : static int32_t Compute_Int32_WeightedSum(CallDescriptor* desc, int32_t* input) {
726 : uint32_t result = 0;
727 47808 : for (int i = 0; i < ParamCount(desc); i++) {
728 22464 : result += static_cast<uint32_t>(input[i]) * coeff[i];
729 : }
730 2880 : return static_cast<int32_t>(result);
731 : }
732 :
733 :
734 40 : static void Test_Int32_WeightedSum_of_size(int count) {
735 : Int32Signature sig(count);
736 1320 : for (int p0 = 0; p0 < Register::kNumRegisters; p0++) {
737 1280 : if (GetRegConfig()->IsAllocatableGeneralCode(p0)) {
738 960 : v8::internal::AccountingAllocator allocator;
739 960 : Zone zone(&allocator, ZONE_NAME);
740 :
741 480 : int parray[] = {p0};
742 960 : int rarray[] = {GetRegConfig()->GetAllocatableGeneralCode(0)};
743 960 : Allocator params(parray, 1, nullptr, 0);
744 960 : Allocator rets(rarray, 1, nullptr, 0);
745 : RegisterConfig config(params, rets);
746 480 : CallDescriptor* desc = config.Create(&zone, &sig);
747 480 : Run_Computation<int32_t>(desc, Build_Int32_WeightedSum,
748 : Compute_Int32_WeightedSum, 257 + count);
749 : }
750 : }
751 40 : }
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 26660 : TEST_INT32_WEIGHTEDSUM(1)
760 26660 : TEST_INT32_WEIGHTEDSUM(2)
761 26660 : TEST_INT32_WEIGHTEDSUM(3)
762 26660 : TEST_INT32_WEIGHTEDSUM(4)
763 26660 : TEST_INT32_WEIGHTEDSUM(5)
764 26660 : TEST_INT32_WEIGHTEDSUM(7)
765 26660 : TEST_INT32_WEIGHTEDSUM(9)
766 26660 : TEST_INT32_WEIGHTEDSUM(11)
767 26660 : TEST_INT32_WEIGHTEDSUM(17)
768 26660 : TEST_INT32_WEIGHTEDSUM(19)
769 :
770 :
771 : template <int which>
772 4712 : static void Build_Select(CallDescriptor* desc, RawMachineAssembler& raw) {
773 4712 : raw.Return(raw.Parameter(which));
774 4712 : }
775 :
776 :
777 : template <typename CType, int which>
778 28320 : static CType Compute_Select(CallDescriptor* desc, CType* inputs) {
779 28320 : return inputs[which];
780 : }
781 :
782 :
783 : template <typename CType, int which>
784 : static void RunSelect(CallDescriptor* desc) {
785 : int count = ParamCount(desc);
786 4832 : 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 52 : void Test_Int32_Select() {
795 104 : int parray[] = {GetRegConfig()->GetAllocatableGeneralCode(0)};
796 104 : int rarray[] = {GetRegConfig()->GetAllocatableGeneralCode(0)};
797 104 : Allocator params(parray, 1, nullptr, 0);
798 104 : Allocator rets(rarray, 1, nullptr, 0);
799 : RegisterConfig config(params, rets);
800 :
801 104 : v8::internal::AccountingAllocator allocator;
802 104 : Zone zone(&allocator, ZONE_NAME);
803 :
804 4820 : for (int i = which + 1; i <= 64; i++) {
805 : Int32Signature sig(i);
806 2384 : CallDescriptor* desc = config.Create(&zone, &sig);
807 : RunSelect<int32_t, which>(desc);
808 : }
809 52 : }
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 26660 : TEST_INT32_SELECT(0)
818 26660 : TEST_INT32_SELECT(1)
819 26660 : TEST_INT32_SELECT(2)
820 26660 : TEST_INT32_SELECT(3)
821 26660 : TEST_INT32_SELECT(4)
822 26660 : TEST_INT32_SELECT(5)
823 26660 : TEST_INT32_SELECT(6)
824 26660 : TEST_INT32_SELECT(11)
825 26660 : TEST_INT32_SELECT(15)
826 26660 : TEST_INT32_SELECT(19)
827 26660 : TEST_INT32_SELECT(45)
828 26660 : TEST_INT32_SELECT(62)
829 26660 : TEST_INT32_SELECT(63)
830 :
831 :
832 26660 : TEST(Int64Select_registers) {
833 4 : if (GetRegConfig()->num_allocatable_general_registers() < 2) return;
834 : // TODO(titzer): int64 on 32-bit platforms
835 : if (kSystemPointerSize < 8) return;
836 :
837 8 : int rarray[] = {GetRegConfig()->GetAllocatableGeneralCode(0)};
838 4 : ArgsBuffer<int64_t>::Sig sig(2);
839 :
840 4 : RegisterPairs pairs;
841 8 : v8::internal::AccountingAllocator allocator;
842 8 : Zone zone(&allocator, ZONE_NAME);
843 740 : while (pairs.More()) {
844 : int parray[2];
845 368 : pairs.Next(&parray[0], &parray[1], false);
846 736 : Allocator params(parray, 2, nullptr, 0);
847 736 : Allocator rets(rarray, 1, nullptr, 0);
848 : RegisterConfig config(params, rets);
849 :
850 368 : CallDescriptor* desc = config.Create(&zone, &sig);
851 : RunSelect<int64_t, 0>(desc);
852 : RunSelect<int64_t, 1>(desc);
853 : }
854 : }
855 :
856 :
857 26660 : TEST(Float32Select_registers) {
858 4 : if (GetRegConfig()->num_allocatable_double_registers() < 2) {
859 0 : return;
860 : }
861 :
862 8 : int rarray[] = {GetRegConfig()->GetAllocatableFloatCode(0)};
863 4 : ArgsBuffer<float32>::Sig sig(2);
864 :
865 4 : Float32RegisterPairs pairs;
866 8 : v8::internal::AccountingAllocator allocator;
867 8 : Zone zone(&allocator, ZONE_NAME);
868 740 : while (pairs.More()) {
869 : int parray[2];
870 368 : pairs.Next(&parray[0], &parray[1], false);
871 736 : Allocator params(nullptr, 0, parray, 2);
872 736 : Allocator rets(nullptr, 0, rarray, 1);
873 : RegisterConfig config(params, rets);
874 :
875 368 : CallDescriptor* desc = config.Create(&zone, &sig);
876 : RunSelect<float32, 0>(desc);
877 : RunSelect<float32, 1>(desc);
878 : }
879 : }
880 :
881 :
882 26660 : TEST(Float64Select_registers) {
883 4 : if (GetRegConfig()->num_allocatable_double_registers() < 2) return;
884 4 : if (GetRegConfig()->num_allocatable_general_registers() < 2) return;
885 8 : int rarray[] = {GetRegConfig()->GetAllocatableDoubleCode(0)};
886 4 : ArgsBuffer<float64>::Sig sig(2);
887 :
888 4 : Float64RegisterPairs pairs;
889 8 : v8::internal::AccountingAllocator allocator;
890 8 : Zone zone(&allocator, ZONE_NAME);
891 740 : while (pairs.More()) {
892 : int parray[2];
893 368 : pairs.Next(&parray[0], &parray[1], false);
894 736 : Allocator params(nullptr, 0, parray, 2);
895 736 : Allocator rets(nullptr, 0, rarray, 1);
896 : RegisterConfig config(params, rets);
897 :
898 368 : CallDescriptor* desc = config.Create(&zone, &sig);
899 : RunSelect<float64, 0>(desc);
900 : RunSelect<float64, 1>(desc);
901 : }
902 : }
903 :
904 :
905 26660 : TEST(Float32Select_stack_params_return_reg) {
906 8 : int rarray[] = {GetRegConfig()->GetAllocatableFloatCode(0)};
907 8 : Allocator params(nullptr, 0, nullptr, 0);
908 8 : Allocator rets(nullptr, 0, rarray, 1);
909 : RegisterConfig config(params, rets);
910 :
911 8 : v8::internal::AccountingAllocator allocator;
912 8 : Zone zone(&allocator, ZONE_NAME);
913 44 : for (int count = 1; count < 6; count++) {
914 20 : ArgsBuffer<float32>::Sig sig(count);
915 20 : CallDescriptor* desc = config.Create(&zone, &sig);
916 : RunSelect<float32, 0>(desc);
917 : RunSelect<float32, 1>(desc);
918 : RunSelect<float32, 2>(desc);
919 : RunSelect<float32, 3>(desc);
920 : RunSelect<float32, 4>(desc);
921 : RunSelect<float32, 5>(desc);
922 : }
923 4 : }
924 :
925 :
926 26660 : TEST(Float64Select_stack_params_return_reg) {
927 8 : int rarray[] = {GetRegConfig()->GetAllocatableDoubleCode(0)};
928 8 : Allocator params(nullptr, 0, nullptr, 0);
929 8 : Allocator rets(nullptr, 0, rarray, 1);
930 : RegisterConfig config(params, rets);
931 :
932 8 : v8::internal::AccountingAllocator allocator;
933 8 : Zone zone(&allocator, ZONE_NAME);
934 44 : for (int count = 1; count < 6; count++) {
935 20 : ArgsBuffer<float64>::Sig sig(count);
936 20 : CallDescriptor* desc = config.Create(&zone, &sig);
937 : RunSelect<float64, 0>(desc);
938 : RunSelect<float64, 1>(desc);
939 : RunSelect<float64, 2>(desc);
940 : RunSelect<float64, 3>(desc);
941 : RunSelect<float64, 4>(desc);
942 : RunSelect<float64, 5>(desc);
943 : }
944 4 : }
945 :
946 :
947 : template <typename CType, int which>
948 8 : static void Build_Select_With_Call(CallDescriptor* desc,
949 : RawMachineAssembler& raw) {
950 : Handle<Code> inner = Handle<Code>::null();
951 : int num_params = ParamCount(desc);
952 8 : CHECK_LE(num_params, kMaxParamCount);
953 : {
954 : Isolate* isolate = CcTest::InitIsolateOnce();
955 : // Build the actual select.
956 16 : Zone zone(isolate->allocator(), ZONE_NAME);
957 8 : Graph graph(&zone);
958 8 : RawMachineAssembler raw(isolate, &graph, desc);
959 8 : raw.Return(raw.Parameter(which));
960 8 : inner = CompileGraph("Select-indirection", desc, &graph, raw.Export());
961 8 : CHECK(!inner.is_null());
962 8 : CHECK(inner->IsCode());
963 : }
964 :
965 : {
966 : // Build a call to the function that does the select.
967 8 : Node* target = raw.HeapConstant(inner);
968 8 : Node** inputs = raw.zone()->NewArray<Node*>(num_params + 1);
969 : int input_count = 0;
970 8 : inputs[input_count++] = target;
971 40 : for (int i = 0; i < num_params; i++) {
972 16 : inputs[input_count++] = raw.Parameter(i);
973 : }
974 :
975 8 : Node* call = raw.CallN(desc, input_count, inputs);
976 8 : raw.Return(call);
977 : }
978 8 : }
979 :
980 :
981 26660 : TEST(Float64StackParamsToStackParams) {
982 8 : int rarray[] = {GetRegConfig()->GetAllocatableDoubleCode(0)};
983 8 : Allocator params(nullptr, 0, nullptr, 0);
984 8 : Allocator rets(nullptr, 0, rarray, 1);
985 :
986 8 : v8::internal::AccountingAllocator allocator;
987 8 : Zone zone(&allocator, ZONE_NAME);
988 4 : ArgsBuffer<float64>::Sig sig(2);
989 : RegisterConfig config(params, rets);
990 4 : CallDescriptor* desc = config.Create(&zone, &sig);
991 :
992 : Run_Computation<float64>(desc, Build_Select_With_Call<float64, 0>,
993 : Compute_Select<float64, 0>, 1098);
994 :
995 : Run_Computation<float64>(desc, Build_Select_With_Call<float64, 1>,
996 : Compute_Select<float64, 1>, 1099);
997 4 : }
998 :
999 :
1000 16 : void MixedParamTest(int start) {
1001 16 : if (GetRegConfig()->num_double_registers() < 2) return;
1002 :
1003 : // TODO(titzer): mix in 64-bit types on all platforms when supported.
1004 : #if V8_TARGET_ARCH_32_BIT
1005 : static MachineType types[] = {
1006 : MachineType::Int32(), MachineType::Float32(), MachineType::Float64(),
1007 : MachineType::Int32(), MachineType::Float64(), MachineType::Float32(),
1008 : MachineType::Float32(), MachineType::Float64(), MachineType::Int32(),
1009 : MachineType::Float32(), MachineType::Int32(), MachineType::Float64(),
1010 : MachineType::Float64(), MachineType::Float32(), MachineType::Int32(),
1011 : MachineType::Float64(), MachineType::Int32(), MachineType::Float32()};
1012 : #else
1013 : static MachineType types[] = {
1014 : MachineType::Int32(), MachineType::Int64(), MachineType::Float32(),
1015 : MachineType::Float64(), MachineType::Int32(), MachineType::Float64(),
1016 : MachineType::Float32(), MachineType::Int64(), MachineType::Int64(),
1017 : MachineType::Float32(), MachineType::Float32(), MachineType::Int32(),
1018 : MachineType::Float64(), MachineType::Float64(), MachineType::Int64(),
1019 : MachineType::Int32(), MachineType::Float64(), MachineType::Int32(),
1020 : MachineType::Float32()};
1021 : #endif
1022 :
1023 : Isolate* isolate = CcTest::InitIsolateOnce();
1024 :
1025 : // Build machine signature
1026 16 : MachineType* params = &types[start];
1027 16 : const int num_params = static_cast<int>(arraysize(types) - start);
1028 :
1029 : // Build call descriptor
1030 16 : int parray_gp[] = {GetRegConfig()->GetAllocatableGeneralCode(0),
1031 32 : GetRegConfig()->GetAllocatableGeneralCode(1)};
1032 32 : int rarray_gp[] = {GetRegConfig()->GetAllocatableGeneralCode(0)};
1033 16 : int parray_fp[] = {GetRegConfig()->GetAllocatableDoubleCode(0),
1034 32 : GetRegConfig()->GetAllocatableDoubleCode(1)};
1035 32 : int rarray_fp[] = {GetRegConfig()->GetAllocatableDoubleCode(0)};
1036 32 : Allocator palloc(parray_gp, 2, parray_fp, 2);
1037 32 : Allocator ralloc(rarray_gp, 1, rarray_fp, 1);
1038 : RegisterConfig config(palloc, ralloc);
1039 :
1040 576 : for (int which = 0; which < num_params; which++) {
1041 560 : v8::internal::AccountingAllocator allocator;
1042 560 : Zone zone(&allocator, ZONE_NAME);
1043 : HandleScope scope(isolate);
1044 280 : MachineSignature::Builder builder(&zone, 1, num_params);
1045 280 : builder.AddReturn(params[which]);
1046 10120 : for (int j = 0; j < num_params; j++) builder.AddParam(params[j]);
1047 : MachineSignature* sig = builder.Build();
1048 280 : CallDescriptor* desc = config.Create(&zone, sig);
1049 :
1050 : Handle<Code> select;
1051 : {
1052 : // build the select.
1053 560 : Zone zone(&allocator, ZONE_NAME);
1054 280 : Graph graph(&zone);
1055 280 : RawMachineAssembler raw(isolate, &graph, desc);
1056 280 : raw.Return(raw.Parameter(which));
1057 280 : select = CompileGraph("Compute", desc, &graph, raw.Export());
1058 : }
1059 :
1060 : {
1061 : // call the select.
1062 : Handle<Code> wrapper = Handle<Code>::null();
1063 : int32_t expected_ret;
1064 : char bytes[kDoubleSize];
1065 : alignas(8) char output[kDoubleSize];
1066 : int expected_size = 0;
1067 : CSignatureOf<int32_t> csig;
1068 : {
1069 : // Wrap the select code with a callable function that passes constants.
1070 560 : Zone zone(&allocator, ZONE_NAME);
1071 280 : Graph graph(&zone);
1072 280 : CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig);
1073 280 : RawMachineAssembler raw(isolate, &graph, cdesc);
1074 280 : Node* target = raw.HeapConstant(select);
1075 280 : Node** inputs = zone.NewArray<Node*>(num_params + 1);
1076 : int input_count = 0;
1077 280 : inputs[input_count++] = target;
1078 : int64_t constant = 0x0102030405060708;
1079 10120 : for (int i = 0; i < num_params; i++) {
1080 4920 : MachineType param_type = sig->GetParam(i);
1081 : Node* konst = nullptr;
1082 4920 : if (param_type == MachineType::Int32()) {
1083 1196 : int32_t value[] = {static_cast<int32_t>(constant)};
1084 1196 : konst = raw.Int32Constant(value[0]);
1085 1196 : if (i == which) memcpy(bytes, value, expected_size = 4);
1086 : }
1087 4920 : if (param_type == MachineType::Int64()) {
1088 : int64_t value[] = {static_cast<int64_t>(constant)};
1089 988 : konst = raw.Int64Constant(value[0]);
1090 988 : if (i == which) memcpy(bytes, value, expected_size = 8);
1091 : }
1092 4920 : if (param_type == MachineType::Float32()) {
1093 1336 : float32 value[] = {static_cast<float32>(constant)};
1094 1336 : konst = raw.Float32Constant(value[0]);
1095 1336 : if (i == which) memcpy(bytes, value, expected_size = 4);
1096 : }
1097 4920 : if (param_type == MachineType::Float64()) {
1098 1400 : float64 value[] = {static_cast<float64>(constant)};
1099 1400 : konst = raw.Float64Constant(value[0]);
1100 1400 : if (i == which) memcpy(bytes, value, expected_size = 8);
1101 : }
1102 4920 : CHECK_NOT_NULL(konst);
1103 :
1104 4920 : inputs[input_count++] = konst;
1105 : const int64_t kIncrement = 0x1010101010101010;
1106 : constant = base::AddWithWraparound(constant, kIncrement);
1107 : }
1108 :
1109 280 : Node* call = raw.CallN(desc, input_count, inputs);
1110 : Node* store =
1111 280 : raw.StoreToPointer(output, sig->GetReturn().representation(), call);
1112 : USE(store);
1113 280 : expected_ret = static_cast<int32_t>(constant);
1114 280 : raw.Return(raw.Int32Constant(expected_ret));
1115 : wrapper = CompileGraph("Select-mixed-wrapper-const", cdesc, &graph,
1116 280 : raw.Export());
1117 : }
1118 :
1119 : CodeRunner<int32_t> runnable(isolate, wrapper, &csig);
1120 280 : CHECK_EQ(expected_ret, runnable.Call());
1121 3608 : for (int i = 0; i < expected_size; i++) {
1122 1664 : CHECK_EQ(static_cast<int>(bytes[i]), static_cast<int>(output[i]));
1123 : }
1124 : }
1125 : }
1126 : }
1127 :
1128 :
1129 26660 : TEST(MixedParams_0) { MixedParamTest(0); }
1130 26660 : TEST(MixedParams_1) { MixedParamTest(1); }
1131 26660 : TEST(MixedParams_2) { MixedParamTest(2); }
1132 26660 : TEST(MixedParams_3) { MixedParamTest(3); }
1133 :
1134 : template <typename T>
1135 16 : void TestStackSlot(MachineType slot_type, T expected) {
1136 : // Test: Generate with a function f which reserves a stack slot, call an inner
1137 : // function g from f which writes into the stack slot of f.
1138 :
1139 16 : if (GetRegConfig()->num_allocatable_double_registers() < 2) return;
1140 :
1141 : Isolate* isolate = CcTest::InitIsolateOnce();
1142 :
1143 : // Lots of code to generate the build descriptor for the inner function.
1144 16 : int parray_gp[] = {GetRegConfig()->GetAllocatableGeneralCode(0),
1145 32 : GetRegConfig()->GetAllocatableGeneralCode(1)};
1146 32 : int rarray_gp[] = {GetRegConfig()->GetAllocatableGeneralCode(0)};
1147 16 : int parray_fp[] = {GetRegConfig()->GetAllocatableDoubleCode(0),
1148 32 : GetRegConfig()->GetAllocatableDoubleCode(1)};
1149 32 : int rarray_fp[] = {GetRegConfig()->GetAllocatableDoubleCode(0)};
1150 32 : Allocator palloc(parray_gp, 2, parray_fp, 2);
1151 32 : Allocator ralloc(rarray_gp, 1, rarray_fp, 1);
1152 : RegisterConfig config(palloc, ralloc);
1153 :
1154 32 : Zone zone(isolate->allocator(), ZONE_NAME);
1155 : HandleScope scope(isolate);
1156 : MachineSignature::Builder builder(&zone, 1, 12);
1157 : builder.AddReturn(MachineType::Int32());
1158 336 : for (int i = 0; i < 10; i++) {
1159 : builder.AddParam(MachineType::Int32());
1160 : }
1161 : builder.AddParam(slot_type);
1162 : builder.AddParam(MachineType::Pointer());
1163 : MachineSignature* sig = builder.Build();
1164 16 : CallDescriptor* desc = config.Create(&zone, sig);
1165 :
1166 : // Create inner function g. g has lots of parameters so that they are passed
1167 : // over the stack.
1168 : Handle<Code> inner;
1169 16 : Graph graph(&zone);
1170 16 : RawMachineAssembler g(isolate, &graph, desc);
1171 :
1172 16 : g.Store(slot_type.representation(), g.Parameter(11), g.Parameter(10),
1173 : WriteBarrierKind::kNoWriteBarrier);
1174 16 : g.Return(g.Parameter(9));
1175 16 : inner = CompileGraph("Compute", desc, &graph, g.Export());
1176 :
1177 : // Create function f with a stack slot which calls the inner function g.
1178 16 : BufferedRawMachineAssemblerTester<T> f(slot_type);
1179 16 : Node* target = f.HeapConstant(inner);
1180 16 : Node* stack_slot = f.StackSlot(slot_type.representation());
1181 : Node* nodes[14];
1182 : int input_count = 0;
1183 16 : nodes[input_count++] = target;
1184 336 : for (int i = 0; i < 10; i++) {
1185 160 : nodes[input_count++] = f.Int32Constant(i);
1186 : }
1187 32 : nodes[input_count++] = f.Parameter(0);
1188 16 : nodes[input_count++] = stack_slot;
1189 :
1190 16 : f.CallN(desc, input_count, nodes);
1191 16 : f.Return(f.Load(slot_type, stack_slot, f.IntPtrConstant(0)));
1192 :
1193 16 : CHECK_EQ(expected, f.Call(expected));
1194 : }
1195 :
1196 26660 : TEST(RunStackSlotInt32) {
1197 : int32_t magic = 0x12345678;
1198 4 : TestStackSlot(MachineType::Int32(), magic);
1199 4 : }
1200 :
1201 : #if !V8_TARGET_ARCH_32_BIT
1202 26660 : TEST(RunStackSlotInt64) {
1203 : int64_t magic = 0x123456789ABCDEF0;
1204 4 : TestStackSlot(MachineType::Int64(), magic);
1205 4 : }
1206 : #endif
1207 :
1208 26660 : TEST(RunStackSlotFloat32) {
1209 : float magic = 1234.125f;
1210 4 : TestStackSlot(MachineType::Float32(), magic);
1211 4 : }
1212 :
1213 26660 : TEST(RunStackSlotFloat64) {
1214 : double magic = 3456.375;
1215 4 : TestStackSlot(MachineType::Float64(), magic);
1216 4 : }
1217 :
1218 : } // namespace test_run_native_calls
1219 : } // namespace compiler
1220 : } // namespace internal
1221 79968 : } // namespace v8
|