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