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