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: 522 528 98.9 %
Date: 2019-04-19 Functions: 156 158 98.7 %

          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         136 :         max_pairs_(std::min(max_pairs, range_ * range_)),
      39         204 :         counter_(0) {}
      40             : 
      41             :   bool More() { return counter_ < max_pairs_; }
      42             : 
      43        6288 :   void Next(int* r0, int* r1, bool same_is_ok) {
      44             :     do {
      45             :       // Find the next pair.
      46        6800 :       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        6800 :         int index = counter_ / 2;
      52        6800 :         if (counter_ & 1) {
      53        3400 :           *r0 = codes_[index % range_];
      54        3400 :           *r1 = codes_[index / range_];
      55             :         } else {
      56        3400 :           *r1 = codes_[index % range_];
      57        3400 :           *r0 = codes_[index / range_];
      58             :         }
      59             :       }
      60        6800 :       counter_++;
      61        6800 :       if ((same_is_ok) || (*r0 != *r1)) break;
      62         512 :       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        6288 :   }
      70             : 
      71             :  private:
      72             :   int range_;
      73             :   const int* codes_;
      74             :   int max_pairs_;
      75             :   int counter_;
      76        6800 :   bool exhaustive() { return max_pairs_ == (range_ * range_); }
      77             : };
      78             : 
      79             : 
      80             : // Pairs of general purpose registers.
      81             : class RegisterPairs : public Pairs {
      82             :  public:
      83          60 :   RegisterPairs()
      84             :       : Pairs(100, GetRegConfig()->num_allocatable_general_registers(),
      85         120 :               GetRegConfig()->allocatable_general_codes()) {}
      86             : };
      87             : 
      88             : // Pairs of float registers.
      89             : class Float32RegisterPairs : public Pairs {
      90             :  public:
      91           4 :   Float32RegisterPairs()
      92             :       : Pairs(100, GetRegConfig()->num_allocatable_float_registers(),
      93          12 :               GetRegConfig()->allocatable_float_codes()) {}
      94             : };
      95             : 
      96             : 
      97             : // Pairs of double registers.
      98             : class Float64RegisterPairs : public Pairs {
      99             :  public:
     100           4 :   Float64RegisterPairs()
     101             :       : Pairs(100, GetRegConfig()->num_allocatable_double_registers(),
     102           8 :               GetRegConfig()->allocatable_double_codes()) {}
     103             : };
     104             : 
     105             : 
     106             : // Helper for allocating either an GP or FP reg, or the next stack slot.
     107       27456 : class Allocator {
     108             :  public:
     109       27456 :   Allocator(int* gp, int gpc, int* fp, int fpc) : stack_offset_(0) {
     110       48560 :     for (int i = 0; i < gpc; ++i) {
     111       34832 :       gp_.push_back(Register::from_code(gp[i]));
     112             :     }
     113       18360 :     for (int i = 0; i < fpc; ++i) {
     114        4632 :       fp_.push_back(DoubleRegister::from_code(fp[i]));
     115             :     }
     116       13728 :     Reset();
     117       13728 :   }
     118             : 
     119             :   int stack_offset() const { return stack_offset_; }
     120             : 
     121      124092 :   LinkageLocation Next(MachineType type) {
     122      124092 :     if (IsFloatingPoint(type.representation())) {
     123             :       // Allocate a floating point register/stack location.
     124        5280 :       if (reg_allocator_->CanAllocateFP(type.representation())) {
     125             :         int code = reg_allocator_->NextFpReg(type.representation());
     126             :         return LinkageLocation::ForRegister(code, type);
     127             :       } else {
     128        2304 :         int offset = -1 - stack_offset_;
     129        2304 :         stack_offset_ += StackWords(type);
     130             :         return LinkageLocation::ForCallerFrameSlot(offset, type);
     131             :       }
     132             :     } else {
     133             :       // Allocate a general purpose register/stack location.
     134      118812 :       if (reg_allocator_->CanAllocateGP()) {
     135             :         int code = reg_allocator_->NextGpReg();
     136             :         return LinkageLocation::ForRegister(code, type);
     137             :       } else {
     138       96096 :         int offset = -1 - stack_offset_;
     139       96096 :         stack_offset_ += StackWords(type);
     140             :         return LinkageLocation::ForCallerFrameSlot(offset, type);
     141             :       }
     142             :     }
     143             :   }
     144             :   int StackWords(MachineType type) {
     145       98400 :     int size = 1 << ElementSizeLog2Of(type.representation());
     146       98400 :     return size <= kSystemPointerSize ? 1 : size / kSystemPointerSize;
     147             :   }
     148       32712 :   void Reset() {
     149       32712 :     stack_offset_ = 0;
     150       65424 :     reg_allocator_.reset(
     151             :         new wasm::LinkageAllocator(gp_.data(), static_cast<int>(gp_.size()),
     152             :                                    fp_.data(), static_cast<int>(fp_.size())));
     153       32712 :   }
     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        6864 :   RegisterConfig(Allocator& p, Allocator& r) : params(p), rets(r) {}
     166             : 
     167        9492 :   CallDescriptor* Create(Zone* zone, MachineSignature* msig) {
     168        9492 :     rets.Reset();
     169        9492 :     params.Reset();
     170             : 
     171             :     LocationSignature::Builder locations(zone, msig->return_count(),
     172             :                                          msig->parameter_count());
     173             :     // Add return location(s).
     174        9492 :     const int return_count = static_cast<int>(locations.return_count_);
     175       28476 :     for (int i = 0; i < return_count; i++) {
     176       18984 :       locations.AddReturn(rets.Next(msig->GetReturn(i)));
     177             :     }
     178             : 
     179             :     // Add register and/or stack parameter(s).
     180        9492 :     const int parameter_count = static_cast<int>(msig->parameter_count());
     181      238692 :     for (int i = 0; i < parameter_count; i++) {
     182      229200 :       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        9492 :     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       18984 :         "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             :   explicit Int32Signature(int param_count)
     240        2424 :       : MachineSignature(1, param_count, kIntTypes) {
     241        2424 :     CHECK_GE(kMaxParamCount, param_count);
     242             :   }
     243             : };
     244             : 
     245       26552 : Handle<Code> CompileGraph(const char* name, CallDescriptor* call_descriptor,
     246             :                           Graph* graph, Schedule* schedule = nullptr) {
     247             :   Isolate* isolate = CcTest::InitIsolateOnce();
     248             :   OptimizedCompilationInfo info(ArrayVector("testing"), graph->zone(),
     249       53104 :                                 Code::STUB);
     250       53104 :   Handle<Code> code = Pipeline::GenerateCodeForTesting(
     251             :                           &info, isolate, call_descriptor, graph,
     252       53104 :                           AssemblerOptions::Default(isolate), schedule)
     253             :                           .ToHandleChecked();
     254             : #ifdef ENABLE_DISASSEMBLER
     255             :   if (FLAG_print_opt_code) {
     256             :     StdoutStream os;
     257             :     code->Disassemble(name, os);
     258             :   }
     259             : #endif
     260       53104 :   return code;
     261             : }
     262             : 
     263        4816 : Handle<Code> WrapWithCFunction(Handle<Code> inner,
     264             :                                CallDescriptor* call_descriptor) {
     265        9632 :   Zone zone(inner->GetIsolate()->allocator(), ZONE_NAME);
     266        4816 :   int param_count = static_cast<int>(call_descriptor->ParameterCount());
     267        4816 :   GraphAndBuilders caller(&zone);
     268             :   {
     269             :     GraphAndBuilders& b = caller;
     270        4816 :     Node* start = b.graph()->NewNode(b.common()->Start(param_count + 3));
     271             :     b.graph()->SetStart(start);
     272        9632 :     Node* target = b.graph()->NewNode(b.common()->HeapConstant(inner));
     273             : 
     274             :     // Add arguments to the call.
     275        4816 :     Node** args = zone.NewArray<Node*>(param_count + 3);
     276             :     int index = 0;
     277        4816 :     args[index++] = target;
     278       24080 :     for (int i = 0; i < param_count; i++) {
     279       19264 :       args[index] = b.graph()->NewNode(b.common()->Parameter(i), start);
     280        9632 :       index++;
     281             :     }
     282        4816 :     args[index++] = start;  // effect.
     283        4816 :     args[index++] = start;  // control.
     284             : 
     285             :     // Build the call and return nodes.
     286        4816 :     Node* call = b.graph()->NewNode(b.common()->Call(call_descriptor),
     287        4816 :                                     param_count + 3, args);
     288        4816 :     Node* zero = b.graph()->NewNode(b.common()->Int32Constant(0));
     289             :     Node* ret =
     290        4816 :         b.graph()->NewNode(b.common()->Return(), zero, call, call, start);
     291             :     b.graph()->SetEnd(ret);
     292             :   }
     293             : 
     294        4816 :   MachineSignature* msig = call_descriptor->GetMachineSignature(&zone);
     295        4816 :   CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, msig);
     296             : 
     297        9632 :   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        5200 :   explicit ArgsBuffer(int count, int seed = 1) : count_(count), seed_(seed) {
     307             :     // initialize the buffer with "seed 0"
     308        5200 :     seed_ = 0;
     309        1600 :     Mutate();
     310        5200 :     seed_ = seed;
     311             :   }
     312             : 
     313             :   class Sig : public MachineSignature {
     314             :    public:
     315          56 :     explicit Sig(int param_count)
     316          56 :         : MachineSignature(1, param_count, MachTypes()) {
     317          56 :       CHECK_GE(kMaxParamCount, param_count);
     318          56 :     }
     319             :   };
     320             : 
     321          56 :   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          56 :         t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t};
     327          56 :     return kTypes;
     328             :   }
     329             : 
     330             :   Node* MakeConstant(RawMachineAssembler& raw, int32_t value) {
     331       90160 :     return raw.Int32Constant(value);
     332             :   }
     333             : 
     334             :   Node* MakeConstant(RawMachineAssembler& raw, int64_t value) {
     335        1472 :     return raw.Int64Constant(value);
     336             :   }
     337             : 
     338             :   Node* MakeConstant(RawMachineAssembler& raw, float32 value) {
     339        1692 :     return raw.Float32Constant(value);
     340             :   }
     341             : 
     342             :   Node* MakeConstant(RawMachineAssembler& raw, float64 value) {
     343        1708 :     return raw.Float64Constant(value);
     344             :   }
     345             : 
     346       95032 :   Node* LoadInput(RawMachineAssembler& raw, Node* base, int index) {
     347       95032 :     Node* offset = raw.Int32Constant(index * sizeof(CType));
     348       95032 :     return raw.Load(MachineTypeForC<CType>(), base, offset);
     349             :   }
     350             : 
     351       10400 :   Node* StoreOutput(RawMachineAssembler& raw, Node* value) {
     352       10400 :     Node* base = raw.PointerConstant(&output);
     353       10400 :     Node* offset = raw.Int32Constant(0);
     354             :     return raw.Store(MachineTypeForC<CType>().representation(), base, offset,
     355       10400 :                      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             : void ArgsBuffer<int32_t>::Mutate() {
     372       14320 :   uint32_t base = 1111111111u * seed_;
     373     1099104 :   for (int j = 0; j < count_ && j < kMaxParamCount; j++) {
     374      540960 :     input[j] = static_cast<int32_t>(256 + base + j + seed_ * 13);
     375             :   }
     376       17184 :   output = -1;
     377       17184 :   seed_++;
     378             : }
     379             : 
     380             : 
     381             : template <>
     382             : void ArgsBuffer<int64_t>::Mutate() {
     383        3680 :   uint64_t base = 11111111111111111ull * seed_;
     384       22080 :   for (int j = 0; j < count_ && j < kMaxParamCount; j++) {
     385        8832 :     input[j] = static_cast<int64_t>(256 + base + j + seed_ * 13);
     386             :   }
     387        4416 :   output = -1;
     388        4416 :   seed_++;
     389             : }
     390             : 
     391             : 
     392             : template <>
     393        4776 : void ArgsBuffer<float32>::Mutate() {
     394        4776 :   float64 base = -33.25 * seed_;
     395       25080 :   for (int j = 0; j < count_ && j < kMaxParamCount; j++) {
     396       10152 :     input[j] = 256 + base + j + seed_ * 13;
     397             :   }
     398        4776 :   output = std::numeric_limits<float32>::quiet_NaN();
     399        4776 :   seed_++;
     400        4776 : }
     401             : 
     402             : 
     403             : template <>
     404        4824 : void ArgsBuffer<float64>::Mutate() {
     405        4824 :   float64 base = -111.25 * seed_;
     406       25320 :   for (int j = 0; j < count_ && j < kMaxParamCount; j++) {
     407       10248 :     input[j] = 256 + base + j + seed_ * 13;
     408             :   }
     409        4824 :   output = std::numeric_limits<float64>::quiet_NaN();
     410        4824 :   seed_++;
     411        4824 : }
     412             : 
     413             : int ParamCount(CallDescriptor* call_descriptor) {
     414       39608 :   return static_cast<int>(call_descriptor->ParameterCount());
     415             : }
     416             : 
     417             : 
     418             : template <typename CType>
     419             : class Computer {
     420             :  public:
     421        5200 :   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        5200 :     CHECK_LE(num_params, kMaxParamCount);
     427             :     Isolate* isolate = CcTest::InitIsolateOnce();
     428             :     HandleScope scope(isolate);
     429             :     Handle<Code> inner = Handle<Code>::null();
     430             :     {
     431             :       // Build the graph for the computation.
     432       10400 :       Zone zone(isolate->allocator(), ZONE_NAME);
     433        5200 :       Graph graph(&zone);
     434        5200 :       RawMachineAssembler raw(isolate, &graph, desc);
     435        5200 :       build(desc, raw);
     436        5200 :       inner = CompileGraph("Compute", desc, &graph, raw.Export());
     437             :     }
     438             : 
     439             :     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       10400 :         Zone zone(isolate->allocator(), ZONE_NAME);
     448        5200 :         Graph graph(&zone);
     449        5200 :         CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig);
     450        5200 :         RawMachineAssembler raw(isolate, &graph, cdesc);
     451        5200 :         Node* target = raw.HeapConstant(inner);
     452        5200 :         Node** inputs = zone.NewArray<Node*>(num_params + 1);
     453             :         int input_count = 0;
     454        5200 :         inputs[input_count++] = target;
     455      195264 :         for (int i = 0; i < num_params; i++) {
     456      190064 :           inputs[input_count++] = io.MakeConstant(raw, io.input[i]);
     457             :         }
     458             : 
     459        5200 :         Node* call = raw.CallN(desc, input_count, inputs);
     460        5200 :         Node* store = io.StoreOutput(raw, call);
     461             :         USE(store);
     462        5200 :         raw.Return(raw.Int32Constant(seed));
     463        5200 :         wrapper =
     464        5200 :             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        5200 :       CType expected = compute(desc, io.input);
     471             :       int32_t check_seed = runnable.Call();
     472        5200 :       CHECK_EQ(seed, check_seed);
     473        5200 :       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       10400 :         Zone zone(isolate->allocator(), ZONE_NAME);
     482        5200 :         Graph graph(&zone);
     483        5200 :         CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig);
     484        5200 :         RawMachineAssembler raw(isolate, &graph, cdesc);
     485             :         Node* base = raw.PointerConstant(io.input);
     486        5200 :         Node* target = raw.HeapConstant(inner);
     487             :         Node** inputs = zone.NewArray<Node*>(kMaxParamCount + 1);
     488             :         int input_count = 0;
     489        5200 :         inputs[input_count++] = target;
     490      195264 :         for (int i = 0; i < num_params; i++) {
     491       95032 :           inputs[input_count++] = io.LoadInput(raw, base, i);
     492             :         }
     493             : 
     494        5200 :         Node* call = raw.CallN(desc, input_count, inputs);
     495        5200 :         Node* store = io.StoreOutput(raw, call);
     496             :         USE(store);
     497        5200 :         raw.Return(raw.Int32Constant(seed));
     498        5200 :         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       57200 :       for (int i = 0; i < 5; i++) {
     505       26000 :         CType expected = compute(desc, io.input);
     506             :         int32_t check_seed = runnable.Call();
     507       26000 :         CHECK_EQ(seed, check_seed);
     508       26000 :         CHECK_EQ(expected, io.output);
     509        8000 :         io.Mutate();
     510             :       }
     511             :     }
     512        5200 :   }
     513             : };
     514             : 
     515             : }  // namespace
     516             : 
     517             : 
     518        4816 : static void TestInt32Sub(CallDescriptor* desc) {
     519             :   Isolate* isolate = CcTest::InitIsolateOnce();
     520             :   HandleScope scope(isolate);
     521        9632 :   Zone zone(isolate->allocator(), ZONE_NAME);
     522        4816 :   GraphAndBuilders inner(&zone);
     523             :   {
     524             :     // Build the add function.
     525             :     GraphAndBuilders& b = inner;
     526        4816 :     Node* start = b.graph()->NewNode(b.common()->Start(5));
     527             :     b.graph()->SetStart(start);
     528        4816 :     Node* p0 = b.graph()->NewNode(b.common()->Parameter(0), start);
     529        4816 :     Node* p1 = b.graph()->NewNode(b.common()->Parameter(1), start);
     530        4816 :     Node* add = b.graph()->NewNode(b.machine()->Int32Sub(), p0, p1);
     531        4816 :     Node* zero = b.graph()->NewNode(b.common()->Int32Constant(0));
     532             :     Node* ret =
     533        4816 :         b.graph()->NewNode(b.common()->Return(), zero, add, start, start);
     534             :     b.graph()->SetEnd(ret);
     535             :   }
     536             : 
     537        4816 :   Handle<Code> inner_code = CompileGraph("Int32Sub", desc, inner.graph());
     538        4816 :   Handle<Code> wrapper = WrapWithCFunction(inner_code, desc);
     539        4816 :   MachineSignature* msig = desc->GetMachineSignature(&zone);
     540             :   CodeRunner<int32_t> runnable(isolate, wrapper,
     541             :                                CSignature::FromMachine(&zone, msig));
     542             : 
     543      563472 :   FOR_INT32_INPUTS(i) {
     544    32681376 :     FOR_INT32_INPUTS(j) {
     545    16201024 :       int32_t expected = static_cast<int32_t>(static_cast<uint32_t>(i) -
     546    16201024 :                                               static_cast<uint32_t>(j));
     547    16201024 :       int32_t result = runnable.Call(i, j);
     548    16201024 :       CHECK_EQ(expected, result);
     549             :     }
     550             :   }
     551        4816 : }
     552             : 
     553             : 
     554         368 : static void CopyTwentyInt32(CallDescriptor* desc) {
     555             :   const int kNumParams = 20;
     556             :   int32_t input[kNumParams];
     557             :   int32_t output[kNumParams];
     558             :   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         736 :     Zone zone(isolate->allocator(), ZONE_NAME);
     564         368 :     Graph graph(&zone);
     565         368 :     RawMachineAssembler raw(isolate, &graph, desc);
     566             :     Node* base = raw.PointerConstant(output);
     567       15088 :     for (int i = 0; i < kNumParams; i++) {
     568        7360 :       Node* offset = raw.Int32Constant(i * sizeof(int32_t));
     569        7360 :       raw.Store(MachineRepresentation::kWord32, base, offset, raw.Parameter(i),
     570        7360 :                 kNoWriteBarrier);
     571             :     }
     572         368 :     raw.Return(raw.Int32Constant(42));
     573         368 :     inner = CompileGraph("CopyTwentyInt32", desc, &graph, raw.Export());
     574             :   }
     575             : 
     576             :   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         736 :     Zone zone(isolate->allocator(), ZONE_NAME);
     581         368 :     Graph graph(&zone);
     582         368 :     CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig);
     583         368 :     RawMachineAssembler raw(isolate, &graph, cdesc);
     584             :     Node* base = raw.PointerConstant(input);
     585         368 :     Node* target = raw.HeapConstant(inner);
     586             :     Node** inputs = zone.NewArray<Node*>(kNumParams + 1);
     587             :     int input_count = 0;
     588         368 :     inputs[input_count++] = target;
     589       15088 :     for (int i = 0; i < kNumParams; i++) {
     590        7360 :       Node* offset = raw.Int32Constant(i * sizeof(int32_t));
     591        7360 :       inputs[input_count++] = raw.Load(MachineType::Int32(), base, offset);
     592             :     }
     593             : 
     594         368 :     Node* call = raw.CallN(desc, input_count, inputs);
     595         368 :     raw.Return(call);
     596             :     wrapper =
     597         368 :         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        4048 :   for (int i = 0; i < 5; i++) {
     604        1840 :     uint32_t base = 1111111111u * i;
     605       75440 :     for (int j = 0; j < kNumParams; j++) {
     606       36800 :       input[j] = static_cast<int32_t>(base + 13 * j);
     607             :     }
     608             : 
     609             :     memset(output, 0, sizeof(output));
     610        1840 :     CHECK_EQ(42, runnable.Call());
     611             : 
     612       75440 :     for (int j = 0; j < kNumParams; j++) {
     613       36800 :       CHECK_EQ(input[j], output[j]);
     614             :     }
     615             :   }
     616         368 : }
     617             : 
     618             : 
     619          48 : static void Test_RunInt32SubWithRet(int retreg) {
     620             :   Int32Signature sig(2);
     621          96 :   v8::internal::AccountingAllocator allocator;
     622          96 :   Zone zone(&allocator, ZONE_NAME);
     623          48 :   RegisterPairs pairs;
     624        8880 :   while (pairs.More()) {
     625             :     int parray[2];
     626        4416 :     int rarray[] = {retreg};
     627        4416 :     pairs.Next(&parray[0], &parray[1], false);
     628        8832 :     Allocator params(parray, 2, nullptr, 0);
     629        8832 :     Allocator rets(rarray, 1, nullptr, 0);
     630             :     RegisterConfig config(params, rets);
     631        4416 :     TestInt32Sub(config.Create(&zone, &sig));
     632             :   }
     633          48 : }
     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       26664 : TEST_INT32_SUB_WITH_RET(0)
     646       26664 : TEST_INT32_SUB_WITH_RET(1)
     647       26664 : TEST_INT32_SUB_WITH_RET(2)
     648       26664 : TEST_INT32_SUB_WITH_RET(3)
     649       26664 : TEST_INT32_SUB_WITH_RET(4)
     650       26664 : TEST_INT32_SUB_WITH_RET(5)
     651       26664 : TEST_INT32_SUB_WITH_RET(6)
     652       26664 : TEST_INT32_SUB_WITH_RET(7)
     653       26664 : TEST_INT32_SUB_WITH_RET(8)
     654       26664 : TEST_INT32_SUB_WITH_RET(9)
     655       26664 : TEST_INT32_SUB_WITH_RET(10)
     656       26664 : TEST_INT32_SUB_WITH_RET(11)
     657       26664 : TEST_INT32_SUB_WITH_RET(12)
     658       26664 : TEST_INT32_SUB_WITH_RET(13)
     659       26664 : TEST_INT32_SUB_WITH_RET(14)
     660       26664 : TEST_INT32_SUB_WITH_RET(15)
     661       26660 : TEST_INT32_SUB_WITH_RET(16)
     662       26660 : TEST_INT32_SUB_WITH_RET(17)
     663       26660 : TEST_INT32_SUB_WITH_RET(18)
     664       26660 : TEST_INT32_SUB_WITH_RET(19)
     665             : 
     666             : 
     667       26660 : TEST(Run_Int32Sub_all_allocatable_single) {
     668             :   Int32Signature sig(2);
     669           4 :   RegisterPairs pairs;
     670         804 :   while (pairs.More()) {
     671         800 :     v8::internal::AccountingAllocator allocator;
     672         800 :     Zone zone(&allocator, ZONE_NAME);
     673             :     int parray[1];
     674             :     int rarray[1];
     675         400 :     pairs.Next(&rarray[0], &parray[0], true);
     676         800 :     Allocator params(parray, 1, nullptr, 0);
     677         800 :     Allocator rets(rarray, 1, nullptr, 0);
     678             :     RegisterConfig config(params, rets);
     679         400 :     TestInt32Sub(config.Create(&zone, &sig));
     680             :   }
     681           4 : }
     682             : 
     683             : 
     684       26660 : TEST(Run_CopyTwentyInt32_all_allocatable_pairs) {
     685             :   Int32Signature sig(20);
     686           4 :   RegisterPairs pairs;
     687         740 :   while (pairs.More()) {
     688         736 :     v8::internal::AccountingAllocator allocator;
     689         736 :     Zone zone(&allocator, ZONE_NAME);
     690             :     int parray[2];
     691         736 :     int rarray[] = {GetRegConfig()->GetAllocatableGeneralCode(0)};
     692         368 :     pairs.Next(&parray[0], &parray[1], false);
     693         736 :     Allocator params(parray, 2, nullptr, 0);
     694         736 :     Allocator rets(rarray, 1, nullptr, 0);
     695             :     RegisterConfig config(params, rets);
     696         368 :     CopyTwentyInt32(config.Create(&zone, &sig));
     697             :   }
     698           4 : }
     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        5196 :   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         480 : static void Build_Int32_WeightedSum(CallDescriptor* desc,
     715             :                                     RawMachineAssembler& raw) {
     716         480 :   Node* result = raw.Int32Constant(0);
     717        7968 :   for (int i = 0; i < ParamCount(desc); i++) {
     718        3744 :     Node* term = raw.Int32Mul(raw.Parameter(i), raw.Int32Constant(coeff[i]));
     719        3744 :     result = raw.Int32Add(result, term);
     720             :   }
     721         480 :   raw.Return(result);
     722         480 : }
     723             : 
     724             : 
     725        2880 : static int32_t Compute_Int32_WeightedSum(CallDescriptor* desc, int32_t* input) {
     726             :   uint32_t result = 0;
     727       47808 :   for (int i = 0; i < ParamCount(desc); i++) {
     728       22464 :     result += static_cast<uint32_t>(input[i]) * coeff[i];
     729             :   }
     730        2880 :   return static_cast<int32_t>(result);
     731             : }
     732             : 
     733             : 
     734          40 : static void Test_Int32_WeightedSum_of_size(int count) {
     735             :   Int32Signature sig(count);
     736        1320 :   for (int p0 = 0; p0 < Register::kNumRegisters; p0++) {
     737        1280 :     if (GetRegConfig()->IsAllocatableGeneralCode(p0)) {
     738         960 :       v8::internal::AccountingAllocator allocator;
     739         960 :       Zone zone(&allocator, ZONE_NAME);
     740             : 
     741         480 :       int parray[] = {p0};
     742         960 :       int rarray[] = {GetRegConfig()->GetAllocatableGeneralCode(0)};
     743         960 :       Allocator params(parray, 1, nullptr, 0);
     744         960 :       Allocator rets(rarray, 1, nullptr, 0);
     745             :       RegisterConfig config(params, rets);
     746         480 :       CallDescriptor* desc = config.Create(&zone, &sig);
     747         480 :       Run_Computation<int32_t>(desc, Build_Int32_WeightedSum,
     748             :                                Compute_Int32_WeightedSum, 257 + count);
     749             :     }
     750             :   }
     751          40 : }
     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       26660 : TEST_INT32_WEIGHTEDSUM(1)
     760       26660 : TEST_INT32_WEIGHTEDSUM(2)
     761       26660 : TEST_INT32_WEIGHTEDSUM(3)
     762       26660 : TEST_INT32_WEIGHTEDSUM(4)
     763       26660 : TEST_INT32_WEIGHTEDSUM(5)
     764       26660 : TEST_INT32_WEIGHTEDSUM(7)
     765       26660 : TEST_INT32_WEIGHTEDSUM(9)
     766       26660 : TEST_INT32_WEIGHTEDSUM(11)
     767       26660 : TEST_INT32_WEIGHTEDSUM(17)
     768       26660 : TEST_INT32_WEIGHTEDSUM(19)
     769             : 
     770             : 
     771             : template <int which>
     772        4712 : static void Build_Select(CallDescriptor* desc, RawMachineAssembler& raw) {
     773        4712 :   raw.Return(raw.Parameter(which));
     774        4712 : }
     775             : 
     776             : 
     777             : template <typename CType, int which>
     778       28320 : static CType Compute_Select(CallDescriptor* desc, CType* inputs) {
     779       28320 :   return inputs[which];
     780             : }
     781             : 
     782             : 
     783             : template <typename CType, int which>
     784             : static void RunSelect(CallDescriptor* desc) {
     785             :   int count = ParamCount(desc);
     786        4832 :   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          52 : void Test_Int32_Select() {
     795         104 :   int parray[] = {GetRegConfig()->GetAllocatableGeneralCode(0)};
     796         104 :   int rarray[] = {GetRegConfig()->GetAllocatableGeneralCode(0)};
     797         104 :   Allocator params(parray, 1, nullptr, 0);
     798         104 :   Allocator rets(rarray, 1, nullptr, 0);
     799             :   RegisterConfig config(params, rets);
     800             : 
     801         104 :   v8::internal::AccountingAllocator allocator;
     802         104 :   Zone zone(&allocator, ZONE_NAME);
     803             : 
     804        4820 :   for (int i = which + 1; i <= 64; i++) {
     805             :     Int32Signature sig(i);
     806        2384 :     CallDescriptor* desc = config.Create(&zone, &sig);
     807             :     RunSelect<int32_t, which>(desc);
     808             :   }
     809          52 : }
     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       26660 : TEST_INT32_SELECT(0)
     818       26660 : TEST_INT32_SELECT(1)
     819       26660 : TEST_INT32_SELECT(2)
     820       26660 : TEST_INT32_SELECT(3)
     821       26660 : TEST_INT32_SELECT(4)
     822       26660 : TEST_INT32_SELECT(5)
     823       26660 : TEST_INT32_SELECT(6)
     824       26660 : TEST_INT32_SELECT(11)
     825       26660 : TEST_INT32_SELECT(15)
     826       26660 : TEST_INT32_SELECT(19)
     827       26660 : TEST_INT32_SELECT(45)
     828       26660 : TEST_INT32_SELECT(62)
     829       26660 : TEST_INT32_SELECT(63)
     830             : 
     831             : 
     832       26660 : TEST(Int64Select_registers) {
     833           4 :   if (GetRegConfig()->num_allocatable_general_registers() < 2) return;
     834             :   // TODO(titzer): int64 on 32-bit platforms
     835             :   if (kSystemPointerSize < 8) return;
     836             : 
     837           8 :   int rarray[] = {GetRegConfig()->GetAllocatableGeneralCode(0)};
     838           4 :   ArgsBuffer<int64_t>::Sig sig(2);
     839             : 
     840           4 :   RegisterPairs pairs;
     841           8 :   v8::internal::AccountingAllocator allocator;
     842           8 :   Zone zone(&allocator, ZONE_NAME);
     843         740 :   while (pairs.More()) {
     844             :     int parray[2];
     845         368 :     pairs.Next(&parray[0], &parray[1], false);
     846         736 :     Allocator params(parray, 2, nullptr, 0);
     847         736 :     Allocator rets(rarray, 1, nullptr, 0);
     848             :     RegisterConfig config(params, rets);
     849             : 
     850         368 :     CallDescriptor* desc = config.Create(&zone, &sig);
     851             :     RunSelect<int64_t, 0>(desc);
     852             :     RunSelect<int64_t, 1>(desc);
     853             :   }
     854             : }
     855             : 
     856             : 
     857       26660 : TEST(Float32Select_registers) {
     858           4 :   if (GetRegConfig()->num_allocatable_double_registers() < 2) {
     859           0 :     return;
     860             :   }
     861             : 
     862           8 :   int rarray[] = {GetRegConfig()->GetAllocatableFloatCode(0)};
     863           4 :   ArgsBuffer<float32>::Sig sig(2);
     864             : 
     865           4 :   Float32RegisterPairs pairs;
     866           8 :   v8::internal::AccountingAllocator allocator;
     867           8 :   Zone zone(&allocator, ZONE_NAME);
     868         740 :   while (pairs.More()) {
     869             :     int parray[2];
     870         368 :     pairs.Next(&parray[0], &parray[1], false);
     871         736 :     Allocator params(nullptr, 0, parray, 2);
     872         736 :     Allocator rets(nullptr, 0, rarray, 1);
     873             :     RegisterConfig config(params, rets);
     874             : 
     875         368 :     CallDescriptor* desc = config.Create(&zone, &sig);
     876             :     RunSelect<float32, 0>(desc);
     877             :     RunSelect<float32, 1>(desc);
     878             :   }
     879             : }
     880             : 
     881             : 
     882       26660 : TEST(Float64Select_registers) {
     883           4 :   if (GetRegConfig()->num_allocatable_double_registers() < 2) return;
     884           4 :   if (GetRegConfig()->num_allocatable_general_registers() < 2) return;
     885           8 :   int rarray[] = {GetRegConfig()->GetAllocatableDoubleCode(0)};
     886           4 :   ArgsBuffer<float64>::Sig sig(2);
     887             : 
     888           4 :   Float64RegisterPairs pairs;
     889           8 :   v8::internal::AccountingAllocator allocator;
     890           8 :   Zone zone(&allocator, ZONE_NAME);
     891         740 :   while (pairs.More()) {
     892             :     int parray[2];
     893         368 :     pairs.Next(&parray[0], &parray[1], false);
     894         736 :     Allocator params(nullptr, 0, parray, 2);
     895         736 :     Allocator rets(nullptr, 0, rarray, 1);
     896             :     RegisterConfig config(params, rets);
     897             : 
     898         368 :     CallDescriptor* desc = config.Create(&zone, &sig);
     899             :     RunSelect<float64, 0>(desc);
     900             :     RunSelect<float64, 1>(desc);
     901             :   }
     902             : }
     903             : 
     904             : 
     905       26660 : TEST(Float32Select_stack_params_return_reg) {
     906           8 :   int rarray[] = {GetRegConfig()->GetAllocatableFloatCode(0)};
     907           8 :   Allocator params(nullptr, 0, nullptr, 0);
     908           8 :   Allocator rets(nullptr, 0, rarray, 1);
     909             :   RegisterConfig config(params, rets);
     910             : 
     911           8 :   v8::internal::AccountingAllocator allocator;
     912           8 :   Zone zone(&allocator, ZONE_NAME);
     913          44 :   for (int count = 1; count < 6; count++) {
     914          20 :     ArgsBuffer<float32>::Sig sig(count);
     915          20 :     CallDescriptor* desc = config.Create(&zone, &sig);
     916             :     RunSelect<float32, 0>(desc);
     917             :     RunSelect<float32, 1>(desc);
     918             :     RunSelect<float32, 2>(desc);
     919             :     RunSelect<float32, 3>(desc);
     920             :     RunSelect<float32, 4>(desc);
     921             :     RunSelect<float32, 5>(desc);
     922             :   }
     923           4 : }
     924             : 
     925             : 
     926       26660 : TEST(Float64Select_stack_params_return_reg) {
     927           8 :   int rarray[] = {GetRegConfig()->GetAllocatableDoubleCode(0)};
     928           8 :   Allocator params(nullptr, 0, nullptr, 0);
     929           8 :   Allocator rets(nullptr, 0, rarray, 1);
     930             :   RegisterConfig config(params, rets);
     931             : 
     932           8 :   v8::internal::AccountingAllocator allocator;
     933           8 :   Zone zone(&allocator, ZONE_NAME);
     934          44 :   for (int count = 1; count < 6; count++) {
     935          20 :     ArgsBuffer<float64>::Sig sig(count);
     936          20 :     CallDescriptor* desc = config.Create(&zone, &sig);
     937             :     RunSelect<float64, 0>(desc);
     938             :     RunSelect<float64, 1>(desc);
     939             :     RunSelect<float64, 2>(desc);
     940             :     RunSelect<float64, 3>(desc);
     941             :     RunSelect<float64, 4>(desc);
     942             :     RunSelect<float64, 5>(desc);
     943             :   }
     944           4 : }
     945             : 
     946             : 
     947             : template <typename CType, int which>
     948           8 : static void Build_Select_With_Call(CallDescriptor* desc,
     949             :                                    RawMachineAssembler& raw) {
     950             :   Handle<Code> inner = Handle<Code>::null();
     951             :   int num_params = ParamCount(desc);
     952           8 :   CHECK_LE(num_params, kMaxParamCount);
     953             :   {
     954             :     Isolate* isolate = CcTest::InitIsolateOnce();
     955             :     // Build the actual select.
     956          16 :     Zone zone(isolate->allocator(), ZONE_NAME);
     957           8 :     Graph graph(&zone);
     958           8 :     RawMachineAssembler raw(isolate, &graph, desc);
     959           8 :     raw.Return(raw.Parameter(which));
     960           8 :     inner = CompileGraph("Select-indirection", desc, &graph, raw.Export());
     961           8 :     CHECK(!inner.is_null());
     962           8 :     CHECK(inner->IsCode());
     963             :   }
     964             : 
     965             :   {
     966             :     // Build a call to the function that does the select.
     967           8 :     Node* target = raw.HeapConstant(inner);
     968           8 :     Node** inputs = raw.zone()->NewArray<Node*>(num_params + 1);
     969             :     int input_count = 0;
     970           8 :     inputs[input_count++] = target;
     971          40 :     for (int i = 0; i < num_params; i++) {
     972          16 :       inputs[input_count++] = raw.Parameter(i);
     973             :     }
     974             : 
     975           8 :     Node* call = raw.CallN(desc, input_count, inputs);
     976           8 :     raw.Return(call);
     977             :   }
     978           8 : }
     979             : 
     980             : 
     981       26660 : TEST(Float64StackParamsToStackParams) {
     982           8 :   int rarray[] = {GetRegConfig()->GetAllocatableDoubleCode(0)};
     983           8 :   Allocator params(nullptr, 0, nullptr, 0);
     984           8 :   Allocator rets(nullptr, 0, rarray, 1);
     985             : 
     986           8 :   v8::internal::AccountingAllocator allocator;
     987           8 :   Zone zone(&allocator, ZONE_NAME);
     988           4 :   ArgsBuffer<float64>::Sig sig(2);
     989             :   RegisterConfig config(params, rets);
     990           4 :   CallDescriptor* desc = config.Create(&zone, &sig);
     991             : 
     992             :   Run_Computation<float64>(desc, Build_Select_With_Call<float64, 0>,
     993             :                            Compute_Select<float64, 0>, 1098);
     994             : 
     995             :   Run_Computation<float64>(desc, Build_Select_With_Call<float64, 1>,
     996             :                            Compute_Select<float64, 1>, 1099);
     997           4 : }
     998             : 
     999             : 
    1000          16 : void MixedParamTest(int start) {
    1001          16 :   if (GetRegConfig()->num_double_registers() < 2) return;
    1002             : 
    1003             : // TODO(titzer): mix in 64-bit types on all platforms when supported.
    1004             : #if V8_TARGET_ARCH_32_BIT
    1005             :   static MachineType types[] = {
    1006             :       MachineType::Int32(),   MachineType::Float32(), MachineType::Float64(),
    1007             :       MachineType::Int32(),   MachineType::Float64(), MachineType::Float32(),
    1008             :       MachineType::Float32(), MachineType::Float64(), MachineType::Int32(),
    1009             :       MachineType::Float32(), MachineType::Int32(),   MachineType::Float64(),
    1010             :       MachineType::Float64(), MachineType::Float32(), MachineType::Int32(),
    1011             :       MachineType::Float64(), MachineType::Int32(),   MachineType::Float32()};
    1012             : #else
    1013             :   static MachineType types[] = {
    1014             :       MachineType::Int32(),   MachineType::Int64(),   MachineType::Float32(),
    1015             :       MachineType::Float64(), MachineType::Int32(),   MachineType::Float64(),
    1016             :       MachineType::Float32(), MachineType::Int64(),   MachineType::Int64(),
    1017             :       MachineType::Float32(), MachineType::Float32(), MachineType::Int32(),
    1018             :       MachineType::Float64(), MachineType::Float64(), MachineType::Int64(),
    1019             :       MachineType::Int32(),   MachineType::Float64(), MachineType::Int32(),
    1020             :       MachineType::Float32()};
    1021             : #endif
    1022             : 
    1023             :   Isolate* isolate = CcTest::InitIsolateOnce();
    1024             : 
    1025             :   // Build machine signature
    1026          16 :   MachineType* params = &types[start];
    1027          16 :   const int num_params = static_cast<int>(arraysize(types) - start);
    1028             : 
    1029             :   // Build call descriptor
    1030          16 :   int parray_gp[] = {GetRegConfig()->GetAllocatableGeneralCode(0),
    1031          32 :                      GetRegConfig()->GetAllocatableGeneralCode(1)};
    1032          32 :   int rarray_gp[] = {GetRegConfig()->GetAllocatableGeneralCode(0)};
    1033          16 :   int parray_fp[] = {GetRegConfig()->GetAllocatableDoubleCode(0),
    1034          32 :                      GetRegConfig()->GetAllocatableDoubleCode(1)};
    1035          32 :   int rarray_fp[] = {GetRegConfig()->GetAllocatableDoubleCode(0)};
    1036          32 :   Allocator palloc(parray_gp, 2, parray_fp, 2);
    1037          32 :   Allocator ralloc(rarray_gp, 1, rarray_fp, 1);
    1038             :   RegisterConfig config(palloc, ralloc);
    1039             : 
    1040         576 :   for (int which = 0; which < num_params; which++) {
    1041         560 :     v8::internal::AccountingAllocator allocator;
    1042         560 :     Zone zone(&allocator, ZONE_NAME);
    1043             :     HandleScope scope(isolate);
    1044         280 :     MachineSignature::Builder builder(&zone, 1, num_params);
    1045         280 :     builder.AddReturn(params[which]);
    1046       10120 :     for (int j = 0; j < num_params; j++) builder.AddParam(params[j]);
    1047             :     MachineSignature* sig = builder.Build();
    1048         280 :     CallDescriptor* desc = config.Create(&zone, sig);
    1049             : 
    1050             :     Handle<Code> select;
    1051             :     {
    1052             :       // build the select.
    1053         560 :       Zone zone(&allocator, ZONE_NAME);
    1054         280 :       Graph graph(&zone);
    1055         280 :       RawMachineAssembler raw(isolate, &graph, desc);
    1056         280 :       raw.Return(raw.Parameter(which));
    1057         280 :       select = CompileGraph("Compute", desc, &graph, raw.Export());
    1058             :     }
    1059             : 
    1060             :     {
    1061             :       // call the select.
    1062             :       Handle<Code> wrapper = Handle<Code>::null();
    1063             :       int32_t expected_ret;
    1064             :       char bytes[kDoubleSize];
    1065             :       alignas(8) char output[kDoubleSize];
    1066             :       int expected_size = 0;
    1067             :       CSignatureOf<int32_t> csig;
    1068             :       {
    1069             :         // Wrap the select code with a callable function that passes constants.
    1070         560 :         Zone zone(&allocator, ZONE_NAME);
    1071         280 :         Graph graph(&zone);
    1072         280 :         CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig);
    1073         280 :         RawMachineAssembler raw(isolate, &graph, cdesc);
    1074         280 :         Node* target = raw.HeapConstant(select);
    1075         280 :         Node** inputs = zone.NewArray<Node*>(num_params + 1);
    1076             :         int input_count = 0;
    1077         280 :         inputs[input_count++] = target;
    1078             :         int64_t constant = 0x0102030405060708;
    1079       10120 :         for (int i = 0; i < num_params; i++) {
    1080        4920 :           MachineType param_type = sig->GetParam(i);
    1081             :           Node* konst = nullptr;
    1082        4920 :           if (param_type == MachineType::Int32()) {
    1083        1196 :             int32_t value[] = {static_cast<int32_t>(constant)};
    1084        1196 :             konst = raw.Int32Constant(value[0]);
    1085        1196 :             if (i == which) memcpy(bytes, value, expected_size = 4);
    1086             :           }
    1087        4920 :           if (param_type == MachineType::Int64()) {
    1088             :             int64_t value[] = {static_cast<int64_t>(constant)};
    1089         988 :             konst = raw.Int64Constant(value[0]);
    1090         988 :             if (i == which) memcpy(bytes, value, expected_size = 8);
    1091             :           }
    1092        4920 :           if (param_type == MachineType::Float32()) {
    1093        1336 :             float32 value[] = {static_cast<float32>(constant)};
    1094        1336 :             konst = raw.Float32Constant(value[0]);
    1095        1336 :             if (i == which) memcpy(bytes, value, expected_size = 4);
    1096             :           }
    1097        4920 :           if (param_type == MachineType::Float64()) {
    1098        1400 :             float64 value[] = {static_cast<float64>(constant)};
    1099        1400 :             konst = raw.Float64Constant(value[0]);
    1100        1400 :             if (i == which) memcpy(bytes, value, expected_size = 8);
    1101             :           }
    1102        4920 :           CHECK_NOT_NULL(konst);
    1103             : 
    1104        4920 :           inputs[input_count++] = konst;
    1105             :           const int64_t kIncrement = 0x1010101010101010;
    1106             :           constant = base::AddWithWraparound(constant, kIncrement);
    1107             :         }
    1108             : 
    1109         280 :         Node* call = raw.CallN(desc, input_count, inputs);
    1110             :         Node* store =
    1111         280 :             raw.StoreToPointer(output, sig->GetReturn().representation(), call);
    1112             :         USE(store);
    1113         280 :         expected_ret = static_cast<int32_t>(constant);
    1114         280 :         raw.Return(raw.Int32Constant(expected_ret));
    1115             :         wrapper = CompileGraph("Select-mixed-wrapper-const", cdesc, &graph,
    1116         280 :                                raw.Export());
    1117             :       }
    1118             : 
    1119             :       CodeRunner<int32_t> runnable(isolate, wrapper, &csig);
    1120         280 :       CHECK_EQ(expected_ret, runnable.Call());
    1121        3608 :       for (int i = 0; i < expected_size; i++) {
    1122        1664 :         CHECK_EQ(static_cast<int>(bytes[i]), static_cast<int>(output[i]));
    1123             :       }
    1124             :     }
    1125             :   }
    1126             : }
    1127             : 
    1128             : 
    1129       26660 : TEST(MixedParams_0) { MixedParamTest(0); }
    1130       26660 : TEST(MixedParams_1) { MixedParamTest(1); }
    1131       26660 : TEST(MixedParams_2) { MixedParamTest(2); }
    1132       26660 : TEST(MixedParams_3) { MixedParamTest(3); }
    1133             : 
    1134             : template <typename T>
    1135          16 : void TestStackSlot(MachineType slot_type, T expected) {
    1136             :   // Test: Generate with a function f which reserves a stack slot, call an inner
    1137             :   // function g from f which writes into the stack slot of f.
    1138             : 
    1139          16 :   if (GetRegConfig()->num_allocatable_double_registers() < 2) return;
    1140             : 
    1141             :   Isolate* isolate = CcTest::InitIsolateOnce();
    1142             : 
    1143             :   // Lots of code to generate the build descriptor for the inner function.
    1144          16 :   int parray_gp[] = {GetRegConfig()->GetAllocatableGeneralCode(0),
    1145          32 :                      GetRegConfig()->GetAllocatableGeneralCode(1)};
    1146          32 :   int rarray_gp[] = {GetRegConfig()->GetAllocatableGeneralCode(0)};
    1147          16 :   int parray_fp[] = {GetRegConfig()->GetAllocatableDoubleCode(0),
    1148          32 :                      GetRegConfig()->GetAllocatableDoubleCode(1)};
    1149          32 :   int rarray_fp[] = {GetRegConfig()->GetAllocatableDoubleCode(0)};
    1150          32 :   Allocator palloc(parray_gp, 2, parray_fp, 2);
    1151          32 :   Allocator ralloc(rarray_gp, 1, rarray_fp, 1);
    1152             :   RegisterConfig config(palloc, ralloc);
    1153             : 
    1154          32 :   Zone zone(isolate->allocator(), ZONE_NAME);
    1155             :   HandleScope scope(isolate);
    1156             :   MachineSignature::Builder builder(&zone, 1, 12);
    1157             :   builder.AddReturn(MachineType::Int32());
    1158         336 :   for (int i = 0; i < 10; i++) {
    1159             :     builder.AddParam(MachineType::Int32());
    1160             :   }
    1161             :   builder.AddParam(slot_type);
    1162             :   builder.AddParam(MachineType::Pointer());
    1163             :   MachineSignature* sig = builder.Build();
    1164          16 :   CallDescriptor* desc = config.Create(&zone, sig);
    1165             : 
    1166             :   // Create inner function g. g has lots of parameters so that they are passed
    1167             :   // over the stack.
    1168             :   Handle<Code> inner;
    1169          16 :   Graph graph(&zone);
    1170          16 :   RawMachineAssembler g(isolate, &graph, desc);
    1171             : 
    1172          16 :   g.Store(slot_type.representation(), g.Parameter(11), g.Parameter(10),
    1173             :           WriteBarrierKind::kNoWriteBarrier);
    1174          16 :   g.Return(g.Parameter(9));
    1175          16 :   inner = CompileGraph("Compute", desc, &graph, g.Export());
    1176             : 
    1177             :   // Create function f with a stack slot which calls the inner function g.
    1178          16 :   BufferedRawMachineAssemblerTester<T> f(slot_type);
    1179          16 :   Node* target = f.HeapConstant(inner);
    1180          16 :   Node* stack_slot = f.StackSlot(slot_type.representation());
    1181             :   Node* nodes[14];
    1182             :   int input_count = 0;
    1183          16 :   nodes[input_count++] = target;
    1184         336 :   for (int i = 0; i < 10; i++) {
    1185         160 :     nodes[input_count++] = f.Int32Constant(i);
    1186             :   }
    1187          32 :   nodes[input_count++] = f.Parameter(0);
    1188          16 :   nodes[input_count++] = stack_slot;
    1189             : 
    1190          16 :   f.CallN(desc, input_count, nodes);
    1191          16 :   f.Return(f.Load(slot_type, stack_slot, f.IntPtrConstant(0)));
    1192             : 
    1193          16 :   CHECK_EQ(expected, f.Call(expected));
    1194             : }
    1195             : 
    1196       26660 : TEST(RunStackSlotInt32) {
    1197             :   int32_t magic = 0x12345678;
    1198           4 :   TestStackSlot(MachineType::Int32(), magic);
    1199           4 : }
    1200             : 
    1201             : #if !V8_TARGET_ARCH_32_BIT
    1202       26660 : TEST(RunStackSlotInt64) {
    1203             :   int64_t magic = 0x123456789ABCDEF0;
    1204           4 :   TestStackSlot(MachineType::Int64(), magic);
    1205           4 : }
    1206             : #endif
    1207             : 
    1208       26660 : TEST(RunStackSlotFloat32) {
    1209             :   float magic = 1234.125f;
    1210           4 :   TestStackSlot(MachineType::Float32(), magic);
    1211           4 : }
    1212             : 
    1213       26660 : TEST(RunStackSlotFloat64) {
    1214             :   double magic = 3456.375;
    1215           4 :   TestStackSlot(MachineType::Float64(), magic);
    1216           4 : }
    1217             : 
    1218             : }  // namespace test_run_native_calls
    1219             : }  // namespace compiler
    1220             : }  // namespace internal
    1221       79968 : }  // namespace v8

Generated by: LCOV version 1.10