LCOV - code coverage report
Current view: top level - test/cctest/compiler - test-run-native-calls.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 550 556 98.9 %
Date: 2017-10-20 Functions: 183 185 98.9 %

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

Generated by: LCOV version 1.10