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