test-run-native-calls.cc 40 KB
Newer Older
1
// Copyright 2015 the V8 project authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
#include <vector>

7
#include "src/base/overflowing-math.h"
8 9 10
#include "src/codegen/assembler.h"
#include "src/codegen/machine-type.h"
#include "src/codegen/register-configuration.h"
11 12
#include "src/compiler/linkage.h"
#include "src/compiler/raw-machine-assembler.h"
13
#include "src/objects/objects-inl.h"
14
#include "src/wasm/wasm-linkage.h"
15 16 17

#include "test/cctest/cctest.h"
#include "test/cctest/compiler/codegen-tester.h"
18
#include "test/cctest/compiler/graph-and-builders.h"
19 20
#include "test/cctest/compiler/value-helper.h"

21 22 23
namespace v8 {
namespace internal {
namespace compiler {
24
namespace test_run_native_calls {
25 26

namespace {
27 28
using float32 = float;
using float64 = double;
29 30 31

// Picks a representative pair of integers from the given range.
// 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
        max_pairs_(std::min(max_pairs, range_ * range_)),
39 40
        counter_(0) {}

41
  bool More() { return counter_ < max_pairs_; }
42 43 44 45 46

  void Next(int* r0, int* r1, bool same_is_ok) {
    do {
      // Find the next pair.
      if (exhaustive()) {
47 48
        *r0 = codes_[counter_ % range_];
        *r1 = codes_[counter_ / range_];
49
      } else {
50
        // Try each integer at least once for both r0 and r1.
51 52
        int index = counter_ / 2;
        if (counter_ & 1) {
53 54
          *r0 = codes_[index % range_];
          *r1 = codes_[index / range_];
55
        } else {
56 57
          *r1 = codes_[index % range_];
          *r0 = codes_[index / range_];
58 59 60
        }
      }
      counter_++;
61 62 63 64 65 66
      if ((same_is_ok) || (*r0 != *r1)) break;
      if (counter_ == max_pairs_) {
        // For the last hurrah, reg#0 with reg#n-1
        *r0 = codes_[0];
        *r1 = codes_[range_ - 1];
        break;
67 68 69 70 71
      }
    } while (true);
  }

 private:
72
  int range_;
73
  const int* codes_;
74
  int max_pairs_;
75
  int counter_;
76 77 78 79 80 81 82
  bool exhaustive() { return max_pairs_ == (range_ * range_); }
};


// Pairs of general purpose registers.
class RegisterPairs : public Pairs {
 public:
83
  RegisterPairs()
84 85
      : Pairs(100, GetRegConfig()->num_allocatable_general_registers(),
              GetRegConfig()->allocatable_general_codes()) {}
86 87
};

88
// Pairs of float registers.
89 90 91
class Float32RegisterPairs : public Pairs {
 public:
  Float32RegisterPairs()
92 93
      : Pairs(100, GetRegConfig()->num_allocatable_float_registers(),
              GetRegConfig()->allocatable_float_codes()) {}
94 95 96 97 98 99 100
};


// Pairs of double registers.
class Float64RegisterPairs : public Pairs {
 public:
  Float64RegisterPairs()
101 102
      : Pairs(100, GetRegConfig()->num_allocatable_double_registers(),
              GetRegConfig()->allocatable_double_codes()) {}
103 104 105 106
};


// Helper for allocating either an GP or FP reg, or the next stack slot.
107 108 109 110 111 112 113 114 115 116 117 118 119
class Allocator {
 public:
  Allocator(int* gp, int gpc, int* fp, int fpc) : stack_offset_(0) {
    for (int i = 0; i < gpc; ++i) {
      gp_.push_back(Register::from_code(gp[i]));
    }
    for (int i = 0; i < fpc; ++i) {
      fp_.push_back(DoubleRegister::from_code(fp[i]));
    }
    Reset();
  }

  int stack_offset() const { return stack_offset_; }
120 121

  LinkageLocation Next(MachineType type) {
122
    if (IsFloatingPoint(type.representation())) {
123
      // Allocate a floating point register/stack location.
124 125
      if (reg_allocator_->CanAllocateFP(type.representation())) {
        int code = reg_allocator_->NextFpReg(type.representation());
126
        return LinkageLocation::ForRegister(code, type);
127
      } else {
128 129
        int offset = -1 - stack_offset_;
        stack_offset_ += StackWords(type);
130
        return LinkageLocation::ForCallerFrameSlot(offset, type);
131 132 133
      }
    } else {
      // Allocate a general purpose register/stack location.
134 135 136
      if (reg_allocator_->CanAllocateGP()) {
        int code = reg_allocator_->NextGpReg();
        return LinkageLocation::ForRegister(code, type);
137
      } else {
138 139
        int offset = -1 - stack_offset_;
        stack_offset_ += StackWords(type);
140
        return LinkageLocation::ForCallerFrameSlot(offset, type);
141 142 143
      }
    }
  }
144
  int StackWords(MachineType type) {
145
    int size = 1 << ElementSizeLog2Of(type.representation());
146
    return size <= kSystemPointerSize ? 1 : size / kSystemPointerSize;
147 148
  }
  void Reset() {
149 150 151 152
    stack_offset_ = 0;
    reg_allocator_.reset(
        new wasm::LinkageAllocator(gp_.data(), static_cast<int>(gp_.size()),
                                   fp_.data(), static_cast<int>(fp_.size())));
153
  }
154 155 156 157 158 159

 private:
  std::vector<Register> gp_;
  std::vector<DoubleRegister> fp_;
  std::unique_ptr<wasm::LinkageAllocator> reg_allocator_;
  int stack_offset_;
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
};


class RegisterConfig {
 public:
  RegisterConfig(Allocator& p, Allocator& r) : params(p), rets(r) {}

  CallDescriptor* Create(Zone* zone, MachineSignature* msig) {
    rets.Reset();
    params.Reset();

    LocationSignature::Builder locations(zone, msig->return_count(),
                                         msig->parameter_count());
    // Add return location(s).
    const int return_count = static_cast<int>(locations.return_count_);
    for (int i = 0; i < return_count; i++) {
      locations.AddReturn(rets.Next(msig->GetReturn(i)));
    }

    // Add register and/or stack parameter(s).
    const int parameter_count = static_cast<int>(msig->parameter_count());
    for (int i = 0; i < parameter_count; i++) {
      locations.AddParam(params.Next(msig->GetParam(i)));
    }

    const RegList kCalleeSaveRegisters = 0;
    const RegList kCalleeSaveFPRegisters = 0;

188
    MachineType target_type = MachineType::AnyTagged();
189
    LinkageLocation target_loc = LinkageLocation::ForAnyRegister();
190
    int stack_param_count = params.stack_offset();
191 192 193 194 195 196 197 198 199
    return new (zone) CallDescriptor(       // --
        CallDescriptor::kCallCodeObject,    // kind
        target_type,                        // target MachineType
        target_loc,                         // target location
        locations.Build(),                  // location_sig
        stack_param_count,                  // stack_parameter_count
        compiler::Operator::kNoProperties,  // properties
        kCalleeSaveRegisters,               // callee-saved registers
        kCalleeSaveFPRegisters,             // callee-saved fp regs
200
        CallDescriptor::kNoFlags,           // flags
201 202 203 204 205 206 207 208 209 210 211
        "c-call");
  }

 private:
  Allocator& params;
  Allocator& rets;
};

const int kMaxParamCount = 64;

MachineType kIntTypes[kMaxParamCount + 1] = {
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
    MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
    MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
    MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
    MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
    MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
    MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
    MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
    MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
    MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
    MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
    MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
    MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
    MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
    MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
    MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
    MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
    MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
    MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
    MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
    MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
    MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
    MachineType::Int32(), MachineType::Int32()};
234 235 236 237 238 239 240


// For making uniform int32 signatures shorter.
class Int32Signature : public MachineSignature {
 public:
  explicit Int32Signature(int param_count)
      : MachineSignature(1, param_count, kIntTypes) {
241
    CHECK_GE(kMaxParamCount, param_count);
242 243 244
  }
};

245 246
Handle<Code> CompileGraph(const char* name, CallDescriptor* call_descriptor,
                          Graph* graph, Schedule* schedule = nullptr) {
247
  Isolate* isolate = CcTest::InitIsolateOnce();
248 249
  OptimizedCompilationInfo info(ArrayVector("testing"), graph->zone(),
                                Code::STUB);
250
  Handle<Code> code = Pipeline::GenerateCodeForTesting(
251 252
                          &info, isolate, call_descriptor, graph,
                          AssemblerOptions::Default(isolate), schedule)
253
                          .ToHandleChecked();
254 255
#ifdef ENABLE_DISASSEMBLER
  if (FLAG_print_opt_code) {
256
    StdoutStream os;
257
    code->Disassemble(name, os, isolate);
258 259 260 261 262
  }
#endif
  return code;
}

263 264
Handle<Code> WrapWithCFunction(Handle<Code> inner,
                               CallDescriptor* call_descriptor) {
265
  Zone zone(inner->GetIsolate()->allocator(), ZONE_NAME);
266
  int param_count = static_cast<int>(call_descriptor->ParameterCount());
267 268 269 270 271
  GraphAndBuilders caller(&zone);
  {
    GraphAndBuilders& b = caller;
    Node* start = b.graph()->NewNode(b.common()->Start(param_count + 3));
    b.graph()->SetStart(start);
272
    Node* target = b.graph()->NewNode(b.common()->HeapConstant(inner));
273 274 275 276 277 278 279 280 281 282 283 284 285

    // Add arguments to the call.
    Node** args = zone.NewArray<Node*>(param_count + 3);
    int index = 0;
    args[index++] = target;
    for (int i = 0; i < param_count; i++) {
      args[index] = b.graph()->NewNode(b.common()->Parameter(i), start);
      index++;
    }
    args[index++] = start;  // effect.
    args[index++] = start;  // control.

    // Build the call and return nodes.
286 287
    Node* call = b.graph()->NewNode(b.common()->Call(call_descriptor),
                                    param_count + 3, args);
288 289 290
    Node* zero = b.graph()->NewNode(b.common()->Int32Constant(0));
    Node* ret =
        b.graph()->NewNode(b.common()->Return(), zero, call, call, start);
291 292 293
    b.graph()->SetEnd(ret);
  }

294
  MachineSignature* msig = call_descriptor->GetMachineSignature(&zone);
295 296 297 298 299 300
  CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, msig);

  return CompileGraph("wrapper", cdesc, caller.graph());
}


301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
template <typename CType>
class ArgsBuffer {
 public:
  static const int kMaxParamCount = 64;

  explicit ArgsBuffer(int count, int seed = 1) : count_(count), seed_(seed) {
    // initialize the buffer with "seed 0"
    seed_ = 0;
    Mutate();
    seed_ = seed;
  }

  class Sig : public MachineSignature {
   public:
    explicit Sig(int param_count)
        : MachineSignature(1, param_count, MachTypes()) {
317
      CHECK_GE(kMaxParamCount, param_count);
318 319 320 321 322 323 324 325 326 327 328 329
    }
  };

  static MachineType* MachTypes() {
    MachineType t = MachineTypeForC<CType>();
    static MachineType kTypes[kMaxParamCount + 1] = {
        t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t,
        t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t,
        t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t};
    return kTypes;
  }

330 331
  Node* MakeConstant(RawMachineAssembler* raw, int32_t value) {
    return raw->Int32Constant(value);
332 333
  }

334 335
  Node* MakeConstant(RawMachineAssembler* raw, int64_t value) {
    return raw->Int64Constant(value);
336 337
  }

338 339
  Node* MakeConstant(RawMachineAssembler* raw, float32 value) {
    return raw->Float32Constant(value);
340 341
  }

342 343
  Node* MakeConstant(RawMachineAssembler* raw, float64 value) {
    return raw->Float64Constant(value);
344 345
  }

346 347 348
  Node* LoadInput(RawMachineAssembler* raw, Node* base, int index) {
    Node* offset = raw->Int32Constant(index * sizeof(CType));
    return raw->Load(MachineTypeForC<CType>(), base, offset);
349 350
  }

351 352 353 354 355
  Node* StoreOutput(RawMachineAssembler* raw, Node* value) {
    Node* base = raw->PointerConstant(&output);
    Node* offset = raw->Int32Constant(0);
    return raw->Store(MachineTypeForC<CType>().representation(), base, offset,
                      value, kNoWriteBarrier);
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
  }

  // Computes the next set of inputs by updating the {input} array.
  void Mutate();

  void Reset() { memset(input, 0, sizeof(input)); }

  int count_;
  int seed_;
  CType input[kMaxParamCount];
  CType output;
};


template <>
void ArgsBuffer<int32_t>::Mutate() {
  uint32_t base = 1111111111u * seed_;
373
  for (int j = 0; j < count_ && j < kMaxParamCount; j++) {
374 375 376 377 378 379 380 381 382 383
    input[j] = static_cast<int32_t>(256 + base + j + seed_ * 13);
  }
  output = -1;
  seed_++;
}


template <>
void ArgsBuffer<int64_t>::Mutate() {
  uint64_t base = 11111111111111111ull * seed_;
384
  for (int j = 0; j < count_ && j < kMaxParamCount; j++) {
385 386 387 388 389 390 391 392 393 394
    input[j] = static_cast<int64_t>(256 + base + j + seed_ * 13);
  }
  output = -1;
  seed_++;
}


template <>
void ArgsBuffer<float32>::Mutate() {
  float64 base = -33.25 * seed_;
395
  for (int j = 0; j < count_ && j < kMaxParamCount; j++) {
396 397 398 399 400 401 402 403 404 405
    input[j] = 256 + base + j + seed_ * 13;
  }
  output = std::numeric_limits<float32>::quiet_NaN();
  seed_++;
}


template <>
void ArgsBuffer<float64>::Mutate() {
  float64 base = -111.25 * seed_;
406
  for (int j = 0; j < count_ && j < kMaxParamCount; j++) {
407 408 409 410 411 412
    input[j] = 256 + base + j + seed_ * 13;
  }
  output = std::numeric_limits<float64>::quiet_NaN();
  seed_++;
}

413 414
int ParamCount(CallDescriptor* call_descriptor) {
  return static_cast<int>(call_descriptor->ParameterCount());
415 416 417 418 419 420 421
}


template <typename CType>
class Computer {
 public:
  static void Run(CallDescriptor* desc,
422
                  void (*build)(CallDescriptor*, RawMachineAssembler*),
423 424 425 426 427 428 429 430 431
                  CType (*compute)(CallDescriptor*, CType* inputs),
                  int seed = 1) {
    int num_params = ParamCount(desc);
    CHECK_LE(num_params, kMaxParamCount);
    Isolate* isolate = CcTest::InitIsolateOnce();
    HandleScope scope(isolate);
    Handle<Code> inner = Handle<Code>::null();
    {
      // Build the graph for the computation.
432
      Zone zone(isolate->allocator(), ZONE_NAME);
433 434
      Graph graph(&zone);
      RawMachineAssembler raw(isolate, &graph, desc);
435
      build(desc, &raw);
436
      inner = CompileGraph("Compute", desc, &graph, raw.ExportForTest());
437 438
    }

439
    CSignatureOf<int32_t> csig;
440 441 442 443 444 445 446
    ArgsBuffer<CType> io(num_params, seed);

    {
      // constant mode.
      Handle<Code> wrapper = Handle<Code>::null();
      {
        // Wrap the above code with a callable function that passes constants.
447
        Zone zone(isolate->allocator(), ZONE_NAME);
448 449 450
        Graph graph(&zone);
        CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig);
        RawMachineAssembler raw(isolate, &graph, cdesc);
451
        Node* target = raw.HeapConstant(inner);
452 453 454
        Node** inputs = zone.NewArray<Node*>(num_params + 1);
        int input_count = 0;
        inputs[input_count++] = target;
455
        for (int i = 0; i < num_params; i++) {
456
          inputs[input_count++] = io.MakeConstant(&raw, io.input[i]);
457 458
        }

459
        Node* call = raw.CallN(desc, input_count, inputs);
460
        Node* store = io.StoreOutput(&raw, call);
461 462
        USE(store);
        raw.Return(raw.Int32Constant(seed));
463 464
        wrapper = CompileGraph("Compute-wrapper-const", cdesc, &graph,
                               raw.ExportForTest());
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480
      }

      CodeRunner<int32_t> runnable(isolate, wrapper, &csig);

      // Run the code, checking it against the reference.
      CType expected = compute(desc, io.input);
      int32_t check_seed = runnable.Call();
      CHECK_EQ(seed, check_seed);
      CHECK_EQ(expected, io.output);
    }

    {
      // buffer mode.
      Handle<Code> wrapper = Handle<Code>::null();
      {
        // Wrap the above code with a callable function that loads from {input}.
481
        Zone zone(isolate->allocator(), ZONE_NAME);
482 483 484 485
        Graph graph(&zone);
        CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig);
        RawMachineAssembler raw(isolate, &graph, cdesc);
        Node* base = raw.PointerConstant(io.input);
486
        Node* target = raw.HeapConstant(inner);
487 488 489
        Node** inputs = zone.NewArray<Node*>(kMaxParamCount + 1);
        int input_count = 0;
        inputs[input_count++] = target;
490
        for (int i = 0; i < num_params; i++) {
491
          inputs[input_count++] = io.LoadInput(&raw, base, i);
492 493
        }

494
        Node* call = raw.CallN(desc, input_count, inputs);
495
        Node* store = io.StoreOutput(&raw, call);
496 497
        USE(store);
        raw.Return(raw.Int32Constant(seed));
498 499
        wrapper =
            CompileGraph("Compute-wrapper", cdesc, &graph, raw.ExportForTest());
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
      }

      CodeRunner<int32_t> runnable(isolate, wrapper, &csig);

      // Run the code, checking it against the reference.
      for (int i = 0; i < 5; i++) {
        CType expected = compute(desc, io.input);
        int32_t check_seed = runnable.Call();
        CHECK_EQ(seed, check_seed);
        CHECK_EQ(expected, io.output);
        io.Mutate();
      }
    }
  }
};

516 517 518 519 520 521
}  // namespace


static void TestInt32Sub(CallDescriptor* desc) {
  Isolate* isolate = CcTest::InitIsolateOnce();
  HandleScope scope(isolate);
522
  Zone zone(isolate->allocator(), ZONE_NAME);
523 524 525 526 527 528 529 530 531
  GraphAndBuilders inner(&zone);
  {
    // Build the add function.
    GraphAndBuilders& b = inner;
    Node* start = b.graph()->NewNode(b.common()->Start(5));
    b.graph()->SetStart(start);
    Node* p0 = b.graph()->NewNode(b.common()->Parameter(0), start);
    Node* p1 = b.graph()->NewNode(b.common()->Parameter(1), start);
    Node* add = b.graph()->NewNode(b.machine()->Int32Sub(), p0, p1);
532 533 534
    Node* zero = b.graph()->NewNode(b.common()->Int32Constant(0));
    Node* ret =
        b.graph()->NewNode(b.common()->Return(), zero, add, start, start);
535 536 537 538 539
    b.graph()->SetEnd(ret);
  }

  Handle<Code> inner_code = CompileGraph("Int32Sub", desc, inner.graph());
  Handle<Code> wrapper = WrapWithCFunction(inner_code, desc);
540
  MachineSignature* msig = desc->GetMachineSignature(&zone);
541 542 543 544 545
  CodeRunner<int32_t> runnable(isolate, wrapper,
                               CSignature::FromMachine(&zone, msig));

  FOR_INT32_INPUTS(i) {
    FOR_INT32_INPUTS(j) {
546 547 548
      int32_t expected = static_cast<int32_t>(static_cast<uint32_t>(i) -
                                              static_cast<uint32_t>(j));
      int32_t result = runnable.Call(i, j);
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
      CHECK_EQ(expected, result);
    }
  }
}


static void CopyTwentyInt32(CallDescriptor* desc) {
  const int kNumParams = 20;
  int32_t input[kNumParams];
  int32_t output[kNumParams];
  Isolate* isolate = CcTest::InitIsolateOnce();
  HandleScope scope(isolate);
  Handle<Code> inner = Handle<Code>::null();
  {
    // Writes all parameters into the output buffer.
564
    Zone zone(isolate->allocator(), ZONE_NAME);
565 566 567 568 569
    Graph graph(&zone);
    RawMachineAssembler raw(isolate, &graph, desc);
    Node* base = raw.PointerConstant(output);
    for (int i = 0; i < kNumParams; i++) {
      Node* offset = raw.Int32Constant(i * sizeof(int32_t));
570
      raw.Store(MachineRepresentation::kWord32, base, offset, raw.Parameter(i),
571
                kNoWriteBarrier);
572 573
    }
    raw.Return(raw.Int32Constant(42));
574
    inner = CompileGraph("CopyTwentyInt32", desc, &graph, raw.ExportForTest());
575 576
  }

577
  CSignatureOf<int32_t> csig;
578 579 580
  Handle<Code> wrapper = Handle<Code>::null();
  {
    // Loads parameters from the input buffer and calls the above code.
581
    Zone zone(isolate->allocator(), ZONE_NAME);
582 583 584 585
    Graph graph(&zone);
    CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig);
    RawMachineAssembler raw(isolate, &graph, cdesc);
    Node* base = raw.PointerConstant(input);
586
    Node* target = raw.HeapConstant(inner);
587 588 589
    Node** inputs = zone.NewArray<Node*>(kNumParams + 1);
    int input_count = 0;
    inputs[input_count++] = target;
590 591
    for (int i = 0; i < kNumParams; i++) {
      Node* offset = raw.Int32Constant(i * sizeof(int32_t));
592
      inputs[input_count++] = raw.Load(MachineType::Int32(), base, offset);
593 594
    }

595
    Node* call = raw.CallN(desc, input_count, inputs);
596
    raw.Return(call);
597 598
    wrapper = CompileGraph("CopyTwentyInt32-wrapper", cdesc, &graph,
                           raw.ExportForTest());
599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
  }

  CodeRunner<int32_t> runnable(isolate, wrapper, &csig);

  // Run the code, checking it correctly implements the memcpy.
  for (int i = 0; i < 5; i++) {
    uint32_t base = 1111111111u * i;
    for (int j = 0; j < kNumParams; j++) {
      input[j] = static_cast<int32_t>(base + 13 * j);
    }

    memset(output, 0, sizeof(output));
    CHECK_EQ(42, runnable.Call());

    for (int j = 0; j < kNumParams; j++) {
      CHECK_EQ(input[j], output[j]);
    }
  }
}


static void Test_RunInt32SubWithRet(int retreg) {
  Int32Signature sig(2);
622
  v8::internal::AccountingAllocator allocator;
623
  Zone zone(&allocator, ZONE_NAME);
624 625 626 627 628 629 630 631
  RegisterPairs pairs;
  while (pairs.More()) {
    int parray[2];
    int rarray[] = {retreg};
    pairs.Next(&parray[0], &parray[1], false);
    Allocator params(parray, 2, nullptr, 0);
    Allocator rets(rarray, 1, nullptr, 0);
    RegisterConfig config(params, rets);
632
    TestInt32Sub(config.Create(&zone, &sig));
633 634 635 636 637
  }
}


// Separate tests for parallelization.
638 639 640 641 642 643
#define TEST_INT32_SUB_WITH_RET(x)                     \
  TEST(Run_Int32Sub_all_allocatable_pairs_##x) {       \
    if (x < Register::kNumRegisters &&                 \
        GetRegConfig()->IsAllocatableGeneralCode(x)) { \
      Test_RunInt32SubWithRet(x);                      \
    }                                                  \
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671
  }

TEST_INT32_SUB_WITH_RET(0)
TEST_INT32_SUB_WITH_RET(1)
TEST_INT32_SUB_WITH_RET(2)
TEST_INT32_SUB_WITH_RET(3)
TEST_INT32_SUB_WITH_RET(4)
TEST_INT32_SUB_WITH_RET(5)
TEST_INT32_SUB_WITH_RET(6)
TEST_INT32_SUB_WITH_RET(7)
TEST_INT32_SUB_WITH_RET(8)
TEST_INT32_SUB_WITH_RET(9)
TEST_INT32_SUB_WITH_RET(10)
TEST_INT32_SUB_WITH_RET(11)
TEST_INT32_SUB_WITH_RET(12)
TEST_INT32_SUB_WITH_RET(13)
TEST_INT32_SUB_WITH_RET(14)
TEST_INT32_SUB_WITH_RET(15)
TEST_INT32_SUB_WITH_RET(16)
TEST_INT32_SUB_WITH_RET(17)
TEST_INT32_SUB_WITH_RET(18)
TEST_INT32_SUB_WITH_RET(19)


TEST(Run_Int32Sub_all_allocatable_single) {
  Int32Signature sig(2);
  RegisterPairs pairs;
  while (pairs.More()) {
672
    v8::internal::AccountingAllocator allocator;
673
    Zone zone(&allocator, ZONE_NAME);
674 675 676 677 678 679
    int parray[1];
    int rarray[1];
    pairs.Next(&rarray[0], &parray[0], true);
    Allocator params(parray, 1, nullptr, 0);
    Allocator rets(rarray, 1, nullptr, 0);
    RegisterConfig config(params, rets);
680
    TestInt32Sub(config.Create(&zone, &sig));
681 682 683 684 685 686 687 688
  }
}


TEST(Run_CopyTwentyInt32_all_allocatable_pairs) {
  Int32Signature sig(20);
  RegisterPairs pairs;
  while (pairs.More()) {
689
    v8::internal::AccountingAllocator allocator;
690
    Zone zone(&allocator, ZONE_NAME);
691
    int parray[2];
692
    int rarray[] = {GetRegConfig()->GetAllocatableGeneralCode(0)};
693 694 695 696
    pairs.Next(&parray[0], &parray[1], false);
    Allocator params(parray, 2, nullptr, 0);
    Allocator rets(rarray, 1, nullptr, 0);
    RegisterConfig config(params, rets);
697
    CopyTwentyInt32(config.Create(&zone, &sig));
698 699 700
  }
}

701 702
template <typename CType>
static void Run_Computation(
703
    CallDescriptor* desc, void (*build)(CallDescriptor*, RawMachineAssembler*),
704 705
    CType (*compute)(CallDescriptor*, CType* inputs), int seed = 1) {
  Computer<CType>::Run(desc, build, compute, seed);
706 707 708 709 710 711
}

static uint32_t coeff[] = {1,  2,  3,  5,  7,   11,  13,  17,  19, 23, 29,
                           31, 37, 41, 43, 47,  53,  59,  61,  67, 71, 73,
                           79, 83, 89, 97, 101, 103, 107, 109, 113};

712 713 714
static void Build_Int32_WeightedSum(CallDescriptor* desc,
                                    RawMachineAssembler* raw) {
  Node* result = raw->Int32Constant(0);
715
  for (int i = 0; i < ParamCount(desc); i++) {
716 717
    Node* term = raw->Int32Mul(raw->Parameter(i), raw->Int32Constant(coeff[i]));
    result = raw->Int32Add(result, term);
718
  }
719
  raw->Return(result);
720 721 722 723 724 725 726 727 728 729 730 731 732
}

static int32_t Compute_Int32_WeightedSum(CallDescriptor* desc, int32_t* input) {
  uint32_t result = 0;
  for (int i = 0; i < ParamCount(desc); i++) {
    result += static_cast<uint32_t>(input[i]) * coeff[i];
  }
  return static_cast<int32_t>(result);
}


static void Test_Int32_WeightedSum_of_size(int count) {
  Int32Signature sig(count);
733
  for (int p0 = 0; p0 < Register::kNumRegisters; p0++) {
734
    if (GetRegConfig()->IsAllocatableGeneralCode(p0)) {
735
      v8::internal::AccountingAllocator allocator;
736
      Zone zone(&allocator, ZONE_NAME);
737

738
      int parray[] = {p0};
739
      int rarray[] = {GetRegConfig()->GetAllocatableGeneralCode(0)};
740 741 742 743 744 745 746
      Allocator params(parray, 1, nullptr, 0);
      Allocator rets(rarray, 1, nullptr, 0);
      RegisterConfig config(params, rets);
      CallDescriptor* desc = config.Create(&zone, &sig);
      Run_Computation<int32_t>(desc, Build_Int32_WeightedSum,
                               Compute_Int32_WeightedSum, 257 + count);
    }
747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
  }
}


// Separate tests for parallelization.
#define TEST_INT32_WEIGHTEDSUM(x) \
  TEST(Run_Int32_WeightedSum_##x) { Test_Int32_WeightedSum_of_size(x); }


TEST_INT32_WEIGHTEDSUM(1)
TEST_INT32_WEIGHTEDSUM(2)
TEST_INT32_WEIGHTEDSUM(3)
TEST_INT32_WEIGHTEDSUM(4)
TEST_INT32_WEIGHTEDSUM(5)
TEST_INT32_WEIGHTEDSUM(7)
TEST_INT32_WEIGHTEDSUM(9)
TEST_INT32_WEIGHTEDSUM(11)
TEST_INT32_WEIGHTEDSUM(17)
TEST_INT32_WEIGHTEDSUM(19)

template <int which>
768 769
static void Build_Select(CallDescriptor* desc, RawMachineAssembler* raw) {
  raw->Return(raw->Parameter(which));
770 771
}

772 773
template <typename CType, int which>
static CType Compute_Select(CallDescriptor* desc, CType* inputs) {
774 775 776 777
  return inputs[which];
}


778 779 780 781 782 783 784 785 786 787
template <typename CType, int which>
static void RunSelect(CallDescriptor* desc) {
  int count = ParamCount(desc);
  if (count <= which) return;
  Run_Computation<CType>(desc, Build_Select<which>,
                         Compute_Select<CType, which>,
                         1044 + which + 3 * sizeof(CType));
}


788 789
template <int which>
void Test_Int32_Select() {
790 791
  int parray[] = {GetRegConfig()->GetAllocatableGeneralCode(0)};
  int rarray[] = {GetRegConfig()->GetAllocatableGeneralCode(0)};
792 793 794 795
  Allocator params(parray, 1, nullptr, 0);
  Allocator rets(rarray, 1, nullptr, 0);
  RegisterConfig config(params, rets);

796
  v8::internal::AccountingAllocator allocator;
797
  Zone zone(&allocator, ZONE_NAME);
798 799 800 801

  for (int i = which + 1; i <= 64; i++) {
    Int32Signature sig(i);
    CallDescriptor* desc = config.Create(&zone, &sig);
802
    RunSelect<int32_t, which>(desc);
803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
  }
}


// Separate tests for parallelization.
#define TEST_INT32_SELECT(x) \
  TEST(Run_Int32_Select_##x) { Test_Int32_Select<x>(); }


TEST_INT32_SELECT(0)
TEST_INT32_SELECT(1)
TEST_INT32_SELECT(2)
TEST_INT32_SELECT(3)
TEST_INT32_SELECT(4)
TEST_INT32_SELECT(5)
TEST_INT32_SELECT(6)
TEST_INT32_SELECT(11)
TEST_INT32_SELECT(15)
TEST_INT32_SELECT(19)
TEST_INT32_SELECT(45)
TEST_INT32_SELECT(62)
TEST_INT32_SELECT(63)


827
TEST(Int64Select_registers) {
828
  if (GetRegConfig()->num_allocatable_general_registers() < 2) return;
829 830
  // TODO(titzer): int64 on 32-bit platforms
  if (kSystemPointerSize < 8) return;
831

832
  int rarray[] = {GetRegConfig()->GetAllocatableGeneralCode(0)};
833 834 835
  ArgsBuffer<int64_t>::Sig sig(2);

  RegisterPairs pairs;
836
  v8::internal::AccountingAllocator allocator;
837
  Zone zone(&allocator, ZONE_NAME);
838 839 840 841 842 843 844 845
  while (pairs.More()) {
    int parray[2];
    pairs.Next(&parray[0], &parray[1], false);
    Allocator params(parray, 2, nullptr, 0);
    Allocator rets(rarray, 1, nullptr, 0);
    RegisterConfig config(params, rets);

    CallDescriptor* desc = config.Create(&zone, &sig);
846 847
    RunSelect<int64_t, 0>(desc);
    RunSelect<int64_t, 1>(desc);
848 849 850 851 852
  }
}


TEST(Float32Select_registers) {
853
  if (GetRegConfig()->num_allocatable_double_registers() < 2) {
854 855
    return;
  }
856

857
  int rarray[] = {GetRegConfig()->GetAllocatableFloatCode(0)};
858 859 860
  ArgsBuffer<float32>::Sig sig(2);

  Float32RegisterPairs pairs;
861
  v8::internal::AccountingAllocator allocator;
862
  Zone zone(&allocator, ZONE_NAME);
863 864 865 866 867 868 869 870
  while (pairs.More()) {
    int parray[2];
    pairs.Next(&parray[0], &parray[1], false);
    Allocator params(nullptr, 0, parray, 2);
    Allocator rets(nullptr, 0, rarray, 1);
    RegisterConfig config(params, rets);

    CallDescriptor* desc = config.Create(&zone, &sig);
871 872
    RunSelect<float32, 0>(desc);
    RunSelect<float32, 1>(desc);
873 874 875 876 877
  }
}


TEST(Float64Select_registers) {
878 879 880
  if (GetRegConfig()->num_allocatable_double_registers() < 2) return;
  if (GetRegConfig()->num_allocatable_general_registers() < 2) return;
  int rarray[] = {GetRegConfig()->GetAllocatableDoubleCode(0)};
881 882 883
  ArgsBuffer<float64>::Sig sig(2);

  Float64RegisterPairs pairs;
884
  v8::internal::AccountingAllocator allocator;
885
  Zone zone(&allocator, ZONE_NAME);
886 887 888 889 890 891 892 893
  while (pairs.More()) {
    int parray[2];
    pairs.Next(&parray[0], &parray[1], false);
    Allocator params(nullptr, 0, parray, 2);
    Allocator rets(nullptr, 0, rarray, 1);
    RegisterConfig config(params, rets);

    CallDescriptor* desc = config.Create(&zone, &sig);
894 895 896 897 898 899 900
    RunSelect<float64, 0>(desc);
    RunSelect<float64, 1>(desc);
  }
}


TEST(Float32Select_stack_params_return_reg) {
901
  int rarray[] = {GetRegConfig()->GetAllocatableFloatCode(0)};
902 903 904
  Allocator params(nullptr, 0, nullptr, 0);
  Allocator rets(nullptr, 0, rarray, 1);
  RegisterConfig config(params, rets);
905

906
  v8::internal::AccountingAllocator allocator;
907
  Zone zone(&allocator, ZONE_NAME);
908 909 910 911 912 913 914 915 916 917 918 919 920 921
  for (int count = 1; count < 6; count++) {
    ArgsBuffer<float32>::Sig sig(count);
    CallDescriptor* desc = config.Create(&zone, &sig);
    RunSelect<float32, 0>(desc);
    RunSelect<float32, 1>(desc);
    RunSelect<float32, 2>(desc);
    RunSelect<float32, 3>(desc);
    RunSelect<float32, 4>(desc);
    RunSelect<float32, 5>(desc);
  }
}


TEST(Float64Select_stack_params_return_reg) {
922
  int rarray[] = {GetRegConfig()->GetAllocatableDoubleCode(0)};
923 924 925 926
  Allocator params(nullptr, 0, nullptr, 0);
  Allocator rets(nullptr, 0, rarray, 1);
  RegisterConfig config(params, rets);

927
  v8::internal::AccountingAllocator allocator;
928
  Zone zone(&allocator, ZONE_NAME);
929 930 931 932 933 934 935 936 937
  for (int count = 1; count < 6; count++) {
    ArgsBuffer<float64>::Sig sig(count);
    CallDescriptor* desc = config.Create(&zone, &sig);
    RunSelect<float64, 0>(desc);
    RunSelect<float64, 1>(desc);
    RunSelect<float64, 2>(desc);
    RunSelect<float64, 3>(desc);
    RunSelect<float64, 4>(desc);
    RunSelect<float64, 5>(desc);
938
  }
939
}
940 941

template <typename CType, int which>
942 943
static void Build_Select_With_Call(CallDescriptor* desc,
                                   RawMachineAssembler* raw) {
944 945 946 947 948 949
  Handle<Code> inner = Handle<Code>::null();
  int num_params = ParamCount(desc);
  CHECK_LE(num_params, kMaxParamCount);
  {
    Isolate* isolate = CcTest::InitIsolateOnce();
    // Build the actual select.
950
    Zone zone(isolate->allocator(), ZONE_NAME);
951 952 953
    Graph graph(&zone);
    RawMachineAssembler raw(isolate, &graph, desc);
    raw.Return(raw.Parameter(which));
954 955
    inner =
        CompileGraph("Select-indirection", desc, &graph, raw.ExportForTest());
956 957 958 959 960 961
    CHECK(!inner.is_null());
    CHECK(inner->IsCode());
  }

  {
    // Build a call to the function that does the select.
962 963
    Node* target = raw->HeapConstant(inner);
    Node** inputs = raw->zone()->NewArray<Node*>(num_params + 1);
964 965
    int input_count = 0;
    inputs[input_count++] = target;
966
    for (int i = 0; i < num_params; i++) {
967
      inputs[input_count++] = raw->Parameter(i);
968 969
    }

970 971
    Node* call = raw->CallN(desc, input_count, inputs);
    raw->Return(call);
972 973 974 975
  }
}

TEST(Float64StackParamsToStackParams) {
976
  int rarray[] = {GetRegConfig()->GetAllocatableDoubleCode(0)};
977 978 979
  Allocator params(nullptr, 0, nullptr, 0);
  Allocator rets(nullptr, 0, rarray, 1);

980
  v8::internal::AccountingAllocator allocator;
981
  Zone zone(&allocator, ZONE_NAME);
982 983 984 985 986 987 988 989 990 991
  ArgsBuffer<float64>::Sig sig(2);
  RegisterConfig config(params, rets);
  CallDescriptor* desc = config.Create(&zone, &sig);

  Run_Computation<float64>(desc, Build_Select_With_Call<float64, 0>,
                           Compute_Select<float64, 0>, 1098);

  Run_Computation<float64>(desc, Build_Select_With_Call<float64, 1>,
                           Compute_Select<float64, 1>, 1099);
}
992 993 994


void MixedParamTest(int start) {
995
  if (GetRegConfig()->num_double_registers() < 2) return;
996 997 998 999

// TODO(titzer): mix in 64-bit types on all platforms when supported.
#if V8_TARGET_ARCH_32_BIT
  static MachineType types[] = {
1000 1001 1002 1003 1004 1005
      MachineType::Int32(),   MachineType::Float32(), MachineType::Float64(),
      MachineType::Int32(),   MachineType::Float64(), MachineType::Float32(),
      MachineType::Float32(), MachineType::Float64(), MachineType::Int32(),
      MachineType::Float32(), MachineType::Int32(),   MachineType::Float64(),
      MachineType::Float64(), MachineType::Float32(), MachineType::Int32(),
      MachineType::Float64(), MachineType::Int32(),   MachineType::Float32()};
1006 1007
#else
  static MachineType types[] = {
1008 1009 1010 1011 1012 1013 1014
      MachineType::Int32(),   MachineType::Int64(),   MachineType::Float32(),
      MachineType::Float64(), MachineType::Int32(),   MachineType::Float64(),
      MachineType::Float32(), MachineType::Int64(),   MachineType::Int64(),
      MachineType::Float32(), MachineType::Float32(), MachineType::Int32(),
      MachineType::Float64(), MachineType::Float64(), MachineType::Int64(),
      MachineType::Int32(),   MachineType::Float64(), MachineType::Int32(),
      MachineType::Float32()};
1015 1016 1017 1018 1019 1020 1021 1022 1023
#endif

  Isolate* isolate = CcTest::InitIsolateOnce();

  // Build machine signature
  MachineType* params = &types[start];
  const int num_params = static_cast<int>(arraysize(types) - start);

  // Build call descriptor
1024 1025 1026 1027 1028 1029
  int parray_gp[] = {GetRegConfig()->GetAllocatableGeneralCode(0),
                     GetRegConfig()->GetAllocatableGeneralCode(1)};
  int rarray_gp[] = {GetRegConfig()->GetAllocatableGeneralCode(0)};
  int parray_fp[] = {GetRegConfig()->GetAllocatableDoubleCode(0),
                     GetRegConfig()->GetAllocatableDoubleCode(1)};
  int rarray_fp[] = {GetRegConfig()->GetAllocatableDoubleCode(0)};
1030 1031
  Allocator palloc(parray_gp, 2, parray_fp, 2);
  Allocator ralloc(rarray_gp, 1, rarray_fp, 1);
1032 1033 1034
  RegisterConfig config(palloc, ralloc);

  for (int which = 0; which < num_params; which++) {
1035
    v8::internal::AccountingAllocator allocator;
1036
    Zone zone(&allocator, ZONE_NAME);
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
    HandleScope scope(isolate);
    MachineSignature::Builder builder(&zone, 1, num_params);
    builder.AddReturn(params[which]);
    for (int j = 0; j < num_params; j++) builder.AddParam(params[j]);
    MachineSignature* sig = builder.Build();
    CallDescriptor* desc = config.Create(&zone, sig);

    Handle<Code> select;
    {
      // build the select.
1047
      Zone zone(&allocator, ZONE_NAME);
1048 1049 1050
      Graph graph(&zone);
      RawMachineAssembler raw(isolate, &graph, desc);
      raw.Return(raw.Parameter(which));
1051
      select = CompileGraph("Compute", desc, &graph, raw.ExportForTest());
1052 1053 1054 1055 1056 1057 1058
    }

    {
      // call the select.
      Handle<Code> wrapper = Handle<Code>::null();
      int32_t expected_ret;
      char bytes[kDoubleSize];
1059
      alignas(8) char output[kDoubleSize];
1060
      int expected_size = 0;
1061
      CSignatureOf<int32_t> csig;
1062 1063
      {
        // Wrap the select code with a callable function that passes constants.
1064
        Zone zone(&allocator, ZONE_NAME);
1065 1066 1067
        Graph graph(&zone);
        CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig);
        RawMachineAssembler raw(isolate, &graph, cdesc);
1068
        Node* target = raw.HeapConstant(select);
1069 1070 1071
        Node** inputs = zone.NewArray<Node*>(num_params + 1);
        int input_count = 0;
        inputs[input_count++] = target;
1072 1073 1074 1075
        int64_t constant = 0x0102030405060708;
        for (int i = 0; i < num_params; i++) {
          MachineType param_type = sig->GetParam(i);
          Node* konst = nullptr;
1076
          if (param_type == MachineType::Int32()) {
1077 1078 1079 1080
            int32_t value[] = {static_cast<int32_t>(constant)};
            konst = raw.Int32Constant(value[0]);
            if (i == which) memcpy(bytes, value, expected_size = 4);
          }
1081
          if (param_type == MachineType::Int64()) {
1082 1083 1084 1085
            int64_t value[] = {static_cast<int64_t>(constant)};
            konst = raw.Int64Constant(value[0]);
            if (i == which) memcpy(bytes, value, expected_size = 8);
          }
1086
          if (param_type == MachineType::Float32()) {
1087 1088 1089 1090
            float32 value[] = {static_cast<float32>(constant)};
            konst = raw.Float32Constant(value[0]);
            if (i == which) memcpy(bytes, value, expected_size = 4);
          }
1091
          if (param_type == MachineType::Float64()) {
1092 1093 1094 1095 1096 1097
            float64 value[] = {static_cast<float64>(constant)};
            konst = raw.Float64Constant(value[0]);
            if (i == which) memcpy(bytes, value, expected_size = 8);
          }
          CHECK_NOT_NULL(konst);

1098
          inputs[input_count++] = konst;
1099 1100
          const int64_t kIncrement = 0x1010101010101010;
          constant = base::AddWithWraparound(constant, kIncrement);
1101 1102
        }

1103
        Node* call = raw.CallN(desc, input_count, inputs);
1104 1105
        Node* store =
            raw.StoreToPointer(output, sig->GetReturn().representation(), call);
1106 1107 1108 1109
        USE(store);
        expected_ret = static_cast<int32_t>(constant);
        raw.Return(raw.Int32Constant(expected_ret));
        wrapper = CompileGraph("Select-mixed-wrapper-const", cdesc, &graph,
1110
                               raw.ExportForTest());
1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126
      }

      CodeRunner<int32_t> runnable(isolate, wrapper, &csig);
      CHECK_EQ(expected_ret, runnable.Call());
      for (int i = 0; i < expected_size; i++) {
        CHECK_EQ(static_cast<int>(bytes[i]), static_cast<int>(output[i]));
      }
    }
  }
}


TEST(MixedParams_0) { MixedParamTest(0); }
TEST(MixedParams_1) { MixedParamTest(1); }
TEST(MixedParams_2) { MixedParamTest(2); }
TEST(MixedParams_3) { MixedParamTest(3); }
1127

1128 1129 1130 1131 1132
template <typename T>
void TestStackSlot(MachineType slot_type, T expected) {
  // Test: Generate with a function f which reserves a stack slot, call an inner
  // function g from f which writes into the stack slot of f.

1133
  if (GetRegConfig()->num_allocatable_double_registers() < 2) return;
1134 1135 1136 1137

  Isolate* isolate = CcTest::InitIsolateOnce();

  // Lots of code to generate the build descriptor for the inner function.
1138 1139 1140 1141 1142 1143
  int parray_gp[] = {GetRegConfig()->GetAllocatableGeneralCode(0),
                     GetRegConfig()->GetAllocatableGeneralCode(1)};
  int rarray_gp[] = {GetRegConfig()->GetAllocatableGeneralCode(0)};
  int parray_fp[] = {GetRegConfig()->GetAllocatableDoubleCode(0),
                     GetRegConfig()->GetAllocatableDoubleCode(1)};
  int rarray_fp[] = {GetRegConfig()->GetAllocatableDoubleCode(0)};
1144 1145 1146 1147
  Allocator palloc(parray_gp, 2, parray_fp, 2);
  Allocator ralloc(rarray_gp, 1, rarray_fp, 1);
  RegisterConfig config(palloc, ralloc);

1148
  Zone zone(isolate->allocator(), ZONE_NAME);
1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168
  HandleScope scope(isolate);
  MachineSignature::Builder builder(&zone, 1, 12);
  builder.AddReturn(MachineType::Int32());
  for (int i = 0; i < 10; i++) {
    builder.AddParam(MachineType::Int32());
  }
  builder.AddParam(slot_type);
  builder.AddParam(MachineType::Pointer());
  MachineSignature* sig = builder.Build();
  CallDescriptor* desc = config.Create(&zone, sig);

  // Create inner function g. g has lots of parameters so that they are passed
  // over the stack.
  Handle<Code> inner;
  Graph graph(&zone);
  RawMachineAssembler g(isolate, &graph, desc);

  g.Store(slot_type.representation(), g.Parameter(11), g.Parameter(10),
          WriteBarrierKind::kNoWriteBarrier);
  g.Return(g.Parameter(9));
1169
  inner = CompileGraph("Compute", desc, &graph, g.ExportForTest());
1170 1171 1172 1173 1174

  // Create function f with a stack slot which calls the inner function g.
  BufferedRawMachineAssemblerTester<T> f(slot_type);
  Node* target = f.HeapConstant(inner);
  Node* stack_slot = f.StackSlot(slot_type.representation());
1175 1176 1177
  Node* nodes[14];
  int input_count = 0;
  nodes[input_count++] = target;
1178
  for (int i = 0; i < 10; i++) {
1179
    nodes[input_count++] = f.Int32Constant(i);
1180
  }
1181 1182
  nodes[input_count++] = f.Parameter(0);
  nodes[input_count++] = stack_slot;
1183

1184
  f.CallN(desc, input_count, nodes);
1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196
  f.Return(f.Load(slot_type, stack_slot, f.IntPtrConstant(0)));

  CHECK_EQ(expected, f.Call(expected));
}

TEST(RunStackSlotInt32) {
  int32_t magic = 0x12345678;
  TestStackSlot(MachineType::Int32(), magic);
}

#if !V8_TARGET_ARCH_32_BIT
TEST(RunStackSlotInt64) {
1197
  int64_t magic = 0x123456789ABCDEF0;
1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210
  TestStackSlot(MachineType::Int64(), magic);
}
#endif

TEST(RunStackSlotFloat32) {
  float magic = 1234.125f;
  TestStackSlot(MachineType::Float32(), magic);
}

TEST(RunStackSlotFloat64) {
  double magic = 3456.375;
  TestStackSlot(MachineType::Float64(), magic);
}
1211 1212

}  // namespace test_run_native_calls
1213 1214 1215
}  // namespace compiler
}  // namespace internal
}  // namespace v8