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

Generated by: LCOV version 1.10