Home | History | Annotate | Download | only in compiler
      1 // Copyright 2014 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 <limits>
      6 
      7 #include "src/ast/scopes.h"
      8 #include "src/compiler/change-lowering.h"
      9 #include "src/compiler/control-builders.h"
     10 #include "src/compiler/js-graph.h"
     11 #include "src/compiler/node-properties.h"
     12 #include "src/compiler/pipeline.h"
     13 #include "src/compiler/select-lowering.h"
     14 #include "src/compiler/simplified-lowering.h"
     15 #include "src/compiler/typer.h"
     16 #include "src/compiler/verifier.h"
     17 #include "src/execution.h"
     18 #include "src/globals.h"
     19 #include "src/parsing/parser.h"
     20 #include "src/parsing/rewriter.h"
     21 #include "test/cctest/cctest.h"
     22 #include "test/cctest/compiler/codegen-tester.h"
     23 #include "test/cctest/compiler/function-tester.h"
     24 #include "test/cctest/compiler/graph-builder-tester.h"
     25 #include "test/cctest/compiler/value-helper.h"
     26 
     27 namespace v8 {
     28 namespace internal {
     29 namespace compiler {
     30 
     31 template <typename ReturnType>
     32 class ChangesLoweringTester : public GraphBuilderTester<ReturnType> {
     33  public:
     34   explicit ChangesLoweringTester(MachineType p0 = MachineType::None())
     35       : GraphBuilderTester<ReturnType>(p0),
     36         javascript(this->zone()),
     37         jsgraph(this->isolate(), this->graph(), this->common(), &javascript,
     38                 nullptr, this->machine()),
     39         function(Handle<JSFunction>::null()) {}
     40 
     41   JSOperatorBuilder javascript;
     42   JSGraph jsgraph;
     43   Handle<JSFunction> function;
     44 
     45   Node* start() { return this->graph()->start(); }
     46 
     47   template <typename T>
     48   T* CallWithPotentialGC() {
     49     // TODO(titzer): we wrap the code in a JSFunction here to reuse the
     50     // JSEntryStub; that could be done with a special prologue or other stub.
     51     if (function.is_null()) {
     52       function = FunctionTester::ForMachineGraph(this->graph());
     53     }
     54     Handle<Object>* args = NULL;
     55     MaybeHandle<Object> result =
     56         Execution::Call(this->isolate(), function, factory()->undefined_value(),
     57                         0, args, false);
     58     return T::cast(*result.ToHandleChecked());
     59   }
     60 
     61   void StoreFloat64(Node* node, double* ptr) {
     62     Node* ptr_node = this->PointerConstant(ptr);
     63     this->Store(MachineType::Float64(), ptr_node, node);
     64   }
     65 
     66   Node* LoadInt32(int32_t* ptr) {
     67     Node* ptr_node = this->PointerConstant(ptr);
     68     return this->Load(MachineType::Int32(), ptr_node);
     69   }
     70 
     71   Node* LoadUint32(uint32_t* ptr) {
     72     Node* ptr_node = this->PointerConstant(ptr);
     73     return this->Load(MachineType::Uint32(), ptr_node);
     74   }
     75 
     76   Node* LoadFloat64(double* ptr) {
     77     Node* ptr_node = this->PointerConstant(ptr);
     78     return this->Load(MachineType::Float64(), ptr_node);
     79   }
     80 
     81   void CheckNumber(double expected, Object* number) {
     82     CHECK(this->isolate()->factory()->NewNumber(expected)->SameValue(number));
     83   }
     84 
     85   void BuildAndLower(const Operator* op) {
     86     // We build a graph by hand here, because the raw machine assembler
     87     // does not add the correct control and effect nodes.
     88     Node* p0 = this->Parameter(0);
     89     Node* change = this->graph()->NewNode(op, p0);
     90     Node* ret = this->graph()->NewNode(this->common()->Return(), change,
     91                                        this->start(), this->start());
     92     Node* end = this->graph()->NewNode(this->common()->End(1), ret);
     93     this->graph()->SetEnd(end);
     94     LowerChange(change);
     95   }
     96 
     97   void BuildStoreAndLower(const Operator* op, const Operator* store_op,
     98                           void* location) {
     99     // We build a graph by hand here, because the raw machine assembler
    100     // does not add the correct control and effect nodes.
    101     Node* p0 = this->Parameter(0);
    102     Node* change = this->graph()->NewNode(op, p0);
    103     Node* store = this->graph()->NewNode(
    104         store_op, this->PointerConstant(location), this->Int32Constant(0),
    105         change, this->start(), this->start());
    106     Node* ret = this->graph()->NewNode(
    107         this->common()->Return(), this->Int32Constant(0), store, this->start());
    108     Node* end = this->graph()->NewNode(this->common()->End(1), ret);
    109     this->graph()->SetEnd(end);
    110     LowerChange(change);
    111   }
    112 
    113   void BuildLoadAndLower(const Operator* op, const Operator* load_op,
    114                          void* location) {
    115     // We build a graph by hand here, because the raw machine assembler
    116     // does not add the correct control and effect nodes.
    117     Node* load = this->graph()->NewNode(
    118         load_op, this->PointerConstant(location), this->Int32Constant(0),
    119         this->start(), this->start());
    120     Node* change = this->graph()->NewNode(op, load);
    121     Node* ret = this->graph()->NewNode(this->common()->Return(), change,
    122                                        this->start(), this->start());
    123     Node* end = this->graph()->NewNode(this->common()->End(1), ret);
    124     this->graph()->SetEnd(end);
    125     LowerChange(change);
    126   }
    127 
    128   void LowerChange(Node* change) {
    129     // Run the graph reducer with changes lowering on a single node.
    130     Typer typer(this->isolate(), this->graph());
    131     typer.Run();
    132     ChangeLowering change_lowering(&jsgraph);
    133     SelectLowering select_lowering(this->graph(), this->common());
    134     GraphReducer reducer(this->zone(), this->graph());
    135     reducer.AddReducer(&change_lowering);
    136     reducer.AddReducer(&select_lowering);
    137     reducer.ReduceNode(change);
    138     Verifier::Run(this->graph(), Verifier::UNTYPED);
    139   }
    140 
    141   Factory* factory() { return this->isolate()->factory(); }
    142   Heap* heap() { return this->isolate()->heap(); }
    143 };
    144 
    145 
    146 TEST(RunChangeTaggedToInt32) {
    147   // Build and lower a graph by hand.
    148   ChangesLoweringTester<int32_t> t(MachineType::AnyTagged());
    149   t.BuildAndLower(t.simplified()->ChangeTaggedToInt32());
    150 
    151     FOR_INT32_INPUTS(i) {
    152       int32_t input = *i;
    153 
    154       if (Smi::IsValid(input)) {
    155         int32_t result = t.Call(Smi::FromInt(input));
    156         CHECK_EQ(input, result);
    157       }
    158 
    159       {
    160         Handle<Object> number = t.factory()->NewNumber(input);
    161         int32_t result = t.Call(*number);
    162         CHECK_EQ(input, result);
    163       }
    164 
    165       {
    166         Handle<HeapNumber> number = t.factory()->NewHeapNumber(input);
    167         int32_t result = t.Call(*number);
    168         CHECK_EQ(input, result);
    169       }
    170   }
    171 }
    172 
    173 
    174 TEST(RunChangeTaggedToUint32) {
    175   // Build and lower a graph by hand.
    176   ChangesLoweringTester<uint32_t> t(MachineType::AnyTagged());
    177   t.BuildAndLower(t.simplified()->ChangeTaggedToUint32());
    178 
    179     FOR_UINT32_INPUTS(i) {
    180       uint32_t input = *i;
    181 
    182       if (Smi::IsValid(input)) {
    183         uint32_t result = t.Call(Smi::FromInt(input));
    184         CHECK_EQ(static_cast<int32_t>(input), static_cast<int32_t>(result));
    185       }
    186 
    187       {
    188         Handle<Object> number = t.factory()->NewNumber(input);
    189         uint32_t result = t.Call(*number);
    190         CHECK_EQ(static_cast<int32_t>(input), static_cast<int32_t>(result));
    191       }
    192 
    193       {
    194         Handle<HeapNumber> number = t.factory()->NewHeapNumber(input);
    195         uint32_t result = t.Call(*number);
    196         CHECK_EQ(static_cast<int32_t>(input), static_cast<int32_t>(result));
    197       }
    198     }
    199 }
    200 
    201 
    202 TEST(RunChangeTaggedToFloat64) {
    203   ChangesLoweringTester<int32_t> t(MachineType::AnyTagged());
    204   double result;
    205 
    206   t.BuildStoreAndLower(t.simplified()->ChangeTaggedToFloat64(),
    207                        t.machine()->Store(StoreRepresentation(
    208                            MachineRepresentation::kFloat64, kNoWriteBarrier)),
    209                        &result);
    210 
    211   {
    212     FOR_INT32_INPUTS(i) {
    213       int32_t input = *i;
    214 
    215       if (Smi::IsValid(input)) {
    216         t.Call(Smi::FromInt(input));
    217         CHECK_EQ(input, static_cast<int32_t>(result));
    218       }
    219 
    220       {
    221         Handle<Object> number = t.factory()->NewNumber(input);
    222         t.Call(*number);
    223         CHECK_EQ(input, static_cast<int32_t>(result));
    224       }
    225 
    226       {
    227         Handle<HeapNumber> number = t.factory()->NewHeapNumber(input);
    228         t.Call(*number);
    229         CHECK_EQ(input, static_cast<int32_t>(result));
    230       }
    231     }
    232   }
    233 
    234   {
    235     FOR_FLOAT64_INPUTS(i) {
    236       double input = *i;
    237       {
    238         Handle<Object> number = t.factory()->NewNumber(input);
    239         t.Call(*number);
    240         CheckDoubleEq(input, result);
    241       }
    242 
    243       {
    244         Handle<HeapNumber> number = t.factory()->NewHeapNumber(input);
    245         t.Call(*number);
    246         CheckDoubleEq(input, result);
    247       }
    248     }
    249   }
    250 }
    251 
    252 
    253 TEST(RunChangeBoolToBit) {
    254   ChangesLoweringTester<int32_t> t(MachineType::AnyTagged());
    255   t.BuildAndLower(t.simplified()->ChangeBoolToBit());
    256 
    257   {
    258     Object* true_obj = t.heap()->true_value();
    259     int32_t result = t.Call(true_obj);
    260     CHECK_EQ(1, result);
    261   }
    262 
    263   {
    264     Object* false_obj = t.heap()->false_value();
    265     int32_t result = t.Call(false_obj);
    266     CHECK_EQ(0, result);
    267   }
    268 }
    269 
    270 
    271 TEST(RunChangeBitToBool) {
    272   ChangesLoweringTester<Object*> t(MachineType::Int32());
    273   t.BuildAndLower(t.simplified()->ChangeBitToBool());
    274 
    275   {
    276     Object* result = t.Call(1);
    277     Object* true_obj = t.heap()->true_value();
    278     CHECK_EQ(true_obj, result);
    279   }
    280 
    281   {
    282     Object* result = t.Call(0);
    283     Object* false_obj = t.heap()->false_value();
    284     CHECK_EQ(false_obj, result);
    285   }
    286 }
    287 
    288 }  // namespace compiler
    289 }  // namespace internal
    290 }  // namespace v8
    291