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 "src/compiler/graph-unittest.h"
      6 #include "src/compiler/js-builtin-reducer.h"
      7 #include "src/compiler/js-graph.h"
      8 #include "src/compiler/node-properties-inl.h"
      9 #include "src/compiler/typer.h"
     10 #include "testing/gmock-support.h"
     11 
     12 using testing::Capture;
     13 
     14 namespace v8 {
     15 namespace internal {
     16 namespace compiler {
     17 
     18 class JSBuiltinReducerTest : public GraphTest {
     19  public:
     20   JSBuiltinReducerTest() : javascript_(zone()) {}
     21 
     22  protected:
     23   Reduction Reduce(Node* node) {
     24     Typer typer(zone());
     25     MachineOperatorBuilder machine;
     26     JSGraph jsgraph(graph(), common(), javascript(), &typer, &machine);
     27     JSBuiltinReducer reducer(&jsgraph);
     28     return reducer.Reduce(node);
     29   }
     30 
     31   Node* Parameter(Type* t, int32_t index = 0) {
     32     Node* n = graph()->NewNode(common()->Parameter(index), graph()->start());
     33     NodeProperties::SetBounds(n, Bounds(Type::None(), t));
     34     return n;
     35   }
     36 
     37   Node* UndefinedConstant() {
     38     return HeapConstant(
     39         Unique<HeapObject>::CreateImmovable(factory()->undefined_value()));
     40   }
     41 
     42   JSOperatorBuilder* javascript() { return &javascript_; }
     43 
     44  private:
     45   JSOperatorBuilder javascript_;
     46 };
     47 
     48 
     49 namespace {
     50 
     51 // TODO(mstarzinger): Find a common place and unify with test-js-typed-lowering.
     52 Type* const kNumberTypes[] = {
     53     Type::UnsignedSmall(),   Type::OtherSignedSmall(), Type::OtherUnsigned31(),
     54     Type::OtherUnsigned32(), Type::OtherSigned32(),    Type::SignedSmall(),
     55     Type::Signed32(),        Type::Unsigned32(),       Type::Integral32(),
     56     Type::MinusZero(),       Type::NaN(),              Type::OtherNumber(),
     57     Type::OrderedNumber(),   Type::Number()};
     58 
     59 }  // namespace
     60 
     61 
     62 // -----------------------------------------------------------------------------
     63 // Math.sqrt
     64 
     65 
     66 TEST_F(JSBuiltinReducerTest, MathSqrt) {
     67   Handle<JSFunction> f(isolate()->context()->math_sqrt_fun());
     68 
     69   TRACED_FOREACH(Type*, t0, kNumberTypes) {
     70     Node* p0 = Parameter(t0, 0);
     71     Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
     72     Node* call = graph()->NewNode(javascript()->Call(3, NO_CALL_FUNCTION_FLAGS),
     73                                   fun, UndefinedConstant(), p0);
     74     Reduction r = Reduce(call);
     75 
     76     ASSERT_TRUE(r.Changed());
     77     EXPECT_THAT(r.replacement(), IsFloat64Sqrt(p0));
     78   }
     79 }
     80 
     81 
     82 // -----------------------------------------------------------------------------
     83 // Math.max
     84 
     85 
     86 TEST_F(JSBuiltinReducerTest, MathMax0) {
     87   Handle<JSFunction> f(isolate()->context()->math_max_fun());
     88 
     89   Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
     90   Node* call = graph()->NewNode(javascript()->Call(2, NO_CALL_FUNCTION_FLAGS),
     91                                 fun, UndefinedConstant());
     92   Reduction r = Reduce(call);
     93 
     94   ASSERT_TRUE(r.Changed());
     95   EXPECT_THAT(r.replacement(), IsNumberConstant(-V8_INFINITY));
     96 }
     97 
     98 
     99 TEST_F(JSBuiltinReducerTest, MathMax1) {
    100   Handle<JSFunction> f(isolate()->context()->math_max_fun());
    101 
    102   TRACED_FOREACH(Type*, t0, kNumberTypes) {
    103     Node* p0 = Parameter(t0, 0);
    104     Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
    105     Node* call = graph()->NewNode(javascript()->Call(3, NO_CALL_FUNCTION_FLAGS),
    106                                   fun, UndefinedConstant(), p0);
    107     Reduction r = Reduce(call);
    108 
    109     ASSERT_TRUE(r.Changed());
    110     EXPECT_THAT(r.replacement(), p0);
    111   }
    112 }
    113 
    114 
    115 TEST_F(JSBuiltinReducerTest, MathMax2) {
    116   Handle<JSFunction> f(isolate()->context()->math_max_fun());
    117 
    118   TRACED_FOREACH(Type*, t0, kNumberTypes) {
    119     TRACED_FOREACH(Type*, t1, kNumberTypes) {
    120       Node* p0 = Parameter(t0, 0);
    121       Node* p1 = Parameter(t1, 1);
    122       Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
    123       Node* call =
    124           graph()->NewNode(javascript()->Call(4, NO_CALL_FUNCTION_FLAGS), fun,
    125                            UndefinedConstant(), p0, p1);
    126       Reduction r = Reduce(call);
    127 
    128       if (t0->Is(Type::Integral32()) && t1->Is(Type::Integral32())) {
    129         Capture<Node*> branch;
    130         ASSERT_TRUE(r.Changed());
    131         EXPECT_THAT(
    132             r.replacement(),
    133             IsPhi(kMachNone, p1, p0,
    134                   IsMerge(IsIfTrue(CaptureEq(&branch)),
    135                           IsIfFalse(AllOf(CaptureEq(&branch),
    136                                           IsBranch(IsNumberLessThan(p0, p1),
    137                                                    graph()->start()))))));
    138       } else {
    139         ASSERT_FALSE(r.Changed());
    140         EXPECT_EQ(IrOpcode::kJSCallFunction, call->opcode());
    141       }
    142     }
    143   }
    144 }
    145 
    146 
    147 // -----------------------------------------------------------------------------
    148 // Math.imul
    149 
    150 
    151 TEST_F(JSBuiltinReducerTest, MathImul) {
    152   Handle<JSFunction> f(isolate()->context()->math_imul_fun());
    153 
    154   TRACED_FOREACH(Type*, t0, kNumberTypes) {
    155     TRACED_FOREACH(Type*, t1, kNumberTypes) {
    156       Node* p0 = Parameter(t0, 0);
    157       Node* p1 = Parameter(t1, 1);
    158       Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
    159       Node* call =
    160           graph()->NewNode(javascript()->Call(4, NO_CALL_FUNCTION_FLAGS), fun,
    161                            UndefinedConstant(), p0, p1);
    162       Reduction r = Reduce(call);
    163 
    164       if (t0->Is(Type::Integral32()) && t1->Is(Type::Integral32())) {
    165         ASSERT_TRUE(r.Changed());
    166         EXPECT_THAT(r.replacement(), IsInt32Mul(p0, p1));
    167       } else {
    168         ASSERT_FALSE(r.Changed());
    169         EXPECT_EQ(IrOpcode::kJSCallFunction, call->opcode());
    170       }
    171     }
    172   }
    173 }
    174 
    175 }  // namespace compiler
    176 }  // namespace internal
    177 }  // namespace v8
    178