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/compiler/access-builder.h"
      6 #include "src/compiler/diamond.h"
      7 #include "src/compiler/js-graph.h"
      8 #include "src/compiler/js-intrinsic-lowering.h"
      9 #include "src/compiler/js-operator.h"
     10 #include "test/unittests/compiler/graph-unittest.h"
     11 #include "test/unittests/compiler/node-test-utils.h"
     12 #include "testing/gmock-support.h"
     13 
     14 
     15 using testing::_;
     16 using testing::AllOf;
     17 using testing::BitEq;
     18 using testing::Capture;
     19 using testing::CaptureEq;
     20 
     21 
     22 namespace v8 {
     23 namespace internal {
     24 namespace compiler {
     25 
     26 class JSIntrinsicLoweringTest : public GraphTest {
     27  public:
     28   JSIntrinsicLoweringTest() : GraphTest(3), javascript_(zone()) {}
     29   ~JSIntrinsicLoweringTest() override {}
     30 
     31  protected:
     32   Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags =
     33                                    MachineOperatorBuilder::kNoFlags) {
     34     MachineOperatorBuilder machine(zone(), MachineType::PointerRepresentation(),
     35                                    flags);
     36     SimplifiedOperatorBuilder simplified(zone());
     37     JSGraph jsgraph(isolate(), graph(), common(), javascript(), &simplified,
     38                     &machine);
     39     // TODO(titzer): mock the GraphReducer here for better unit testing.
     40     GraphReducer graph_reducer(zone(), graph());
     41     JSIntrinsicLowering reducer(&graph_reducer, &jsgraph,
     42                                 JSIntrinsicLowering::kDeoptimizationEnabled);
     43     return reducer.Reduce(node);
     44   }
     45 
     46   JSOperatorBuilder* javascript() { return &javascript_; }
     47 
     48  private:
     49   JSOperatorBuilder javascript_;
     50 };
     51 
     52 
     53 // -----------------------------------------------------------------------------
     54 // %_DoubleLo
     55 
     56 
     57 TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleLo) {
     58   Node* const input = Parameter(0);
     59   Node* const context = Parameter(1);
     60   Node* const effect = graph()->start();
     61   Node* const control = graph()->start();
     62   Reduction const r = Reduce(
     63       graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineDoubleLo, 1),
     64                        input, context, effect, control));
     65   ASSERT_TRUE(r.Changed());
     66   EXPECT_THAT(r.replacement(),
     67               IsFloat64ExtractLowWord32(IsTypeGuard(Type::Number(), input, _)));
     68 }
     69 
     70 
     71 // -----------------------------------------------------------------------------
     72 // %_DoubleHi
     73 
     74 
     75 TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleHi) {
     76   Node* const input = Parameter(0);
     77   Node* const context = Parameter(1);
     78   Node* const effect = graph()->start();
     79   Node* const control = graph()->start();
     80   Reduction const r = Reduce(
     81       graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineDoubleHi, 1),
     82                        input, context, effect, control));
     83   ASSERT_TRUE(r.Changed());
     84   EXPECT_THAT(r.replacement(), IsFloat64ExtractHighWord32(
     85                                    IsTypeGuard(Type::Number(), input, _)));
     86 }
     87 
     88 
     89 // -----------------------------------------------------------------------------
     90 // %_IsSmi
     91 
     92 
     93 TEST_F(JSIntrinsicLoweringTest, InlineIsSmi) {
     94   Node* const input = Parameter(0);
     95   Node* const context = Parameter(1);
     96   Node* const effect = graph()->start();
     97   Node* const control = graph()->start();
     98   Reduction const r = Reduce(
     99       graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsSmi, 1),
    100                        input, context, effect, control));
    101   ASSERT_TRUE(r.Changed());
    102   EXPECT_THAT(r.replacement(), IsObjectIsSmi(input));
    103 }
    104 
    105 
    106 // -----------------------------------------------------------------------------
    107 // %_IsArray
    108 
    109 
    110 TEST_F(JSIntrinsicLoweringTest, InlineIsArray) {
    111   Node* const input = Parameter(0);
    112   Node* const context = Parameter(1);
    113   Node* const effect = graph()->start();
    114   Node* const control = graph()->start();
    115   Reduction const r = Reduce(
    116       graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsArray, 1),
    117                        input, context, effect, control));
    118   ASSERT_TRUE(r.Changed());
    119 
    120   Node* phi = r.replacement();
    121   Capture<Node*> branch, if_false;
    122   EXPECT_THAT(
    123       phi,
    124       IsPhi(
    125           MachineRepresentation::kTagged, IsFalseConstant(),
    126           IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(),
    127                                     IsLoadField(AccessBuilder::ForMap(), input,
    128                                                 effect, CaptureEq(&if_false)),
    129                                     effect, _),
    130                         IsInt32Constant(JS_ARRAY_TYPE)),
    131           IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
    132                                  IsBranch(IsObjectIsSmi(input), control))),
    133                   AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
    134 }
    135 
    136 
    137 // -----------------------------------------------------------------------------
    138 // %_IsTypedArray
    139 
    140 
    141 TEST_F(JSIntrinsicLoweringTest, InlineIsTypedArray) {
    142   Node* const input = Parameter(0);
    143   Node* const context = Parameter(1);
    144   Node* const effect = graph()->start();
    145   Node* const control = graph()->start();
    146   Reduction const r = Reduce(graph()->NewNode(
    147       javascript()->CallRuntime(Runtime::kInlineIsTypedArray, 1), input,
    148       context, effect, control));
    149   ASSERT_TRUE(r.Changed());
    150 
    151   Node* phi = r.replacement();
    152   Capture<Node*> branch, if_false;
    153   EXPECT_THAT(
    154       phi,
    155       IsPhi(
    156           MachineRepresentation::kTagged, IsFalseConstant(),
    157           IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(),
    158                                     IsLoadField(AccessBuilder::ForMap(), input,
    159                                                 effect, CaptureEq(&if_false)),
    160                                     effect, _),
    161                         IsInt32Constant(JS_TYPED_ARRAY_TYPE)),
    162           IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
    163                                  IsBranch(IsObjectIsSmi(input), control))),
    164                   AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
    165 }
    166 
    167 
    168 // -----------------------------------------------------------------------------
    169 // %_IsRegExp
    170 
    171 
    172 TEST_F(JSIntrinsicLoweringTest, InlineIsRegExp) {
    173   Node* const input = Parameter(0);
    174   Node* const context = Parameter(1);
    175   Node* const effect = graph()->start();
    176   Node* const control = graph()->start();
    177   Reduction const r = Reduce(
    178       graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsRegExp, 1),
    179                        input, context, effect, control));
    180   ASSERT_TRUE(r.Changed());
    181 
    182   Node* phi = r.replacement();
    183   Capture<Node*> branch, if_false;
    184   EXPECT_THAT(
    185       phi,
    186       IsPhi(
    187           MachineRepresentation::kTagged, IsFalseConstant(),
    188           IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(),
    189                                     IsLoadField(AccessBuilder::ForMap(), input,
    190                                                 effect, CaptureEq(&if_false)),
    191                                     effect, _),
    192                         IsInt32Constant(JS_REGEXP_TYPE)),
    193           IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
    194                                  IsBranch(IsObjectIsSmi(input), control))),
    195                   AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
    196 }
    197 
    198 
    199 // -----------------------------------------------------------------------------
    200 // %_IsJSReceiver
    201 
    202 
    203 TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiver) {
    204   Node* const input = Parameter(0);
    205   Node* const context = Parameter(1);
    206   Node* const effect = graph()->start();
    207   Node* const control = graph()->start();
    208   Reduction const r = Reduce(graph()->NewNode(
    209       javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1), input,
    210       context, effect, control));
    211   ASSERT_TRUE(r.Changed());
    212   EXPECT_THAT(r.replacement(), IsObjectIsReceiver(input));
    213 }
    214 
    215 
    216 // -----------------------------------------------------------------------------
    217 // %_ValueOf
    218 
    219 
    220 TEST_F(JSIntrinsicLoweringTest, InlineValueOf) {
    221   Node* const input = Parameter(0);
    222   Node* const context = Parameter(1);
    223   Node* const effect = graph()->start();
    224   Node* const control = graph()->start();
    225   Reduction const r = Reduce(
    226       graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineValueOf, 1),
    227                        input, context, effect, control));
    228   ASSERT_TRUE(r.Changed());
    229 
    230   Node* phi = r.replacement();
    231   Capture<Node*> branch0, if_false0, branch1, if_true1;
    232   EXPECT_THAT(
    233       phi,
    234       IsPhi(
    235           MachineRepresentation::kTagged, input,
    236           IsPhi(MachineRepresentation::kTagged,
    237                 IsLoadField(AccessBuilder::ForValue(), input, effect,
    238                             CaptureEq(&if_true1)),
    239                 input,
    240                 IsMerge(
    241                     AllOf(CaptureEq(&if_true1), IsIfTrue(CaptureEq(&branch1))),
    242                     IsIfFalse(AllOf(
    243                         CaptureEq(&branch1),
    244                         IsBranch(
    245                             IsWord32Equal(
    246                                 IsLoadField(
    247                                     AccessBuilder::ForMapInstanceType(),
    248                                     IsLoadField(AccessBuilder::ForMap(), input,
    249                                                 effect, CaptureEq(&if_false0)),
    250                                     effect, _),
    251                                 IsInt32Constant(JS_VALUE_TYPE)),
    252                             CaptureEq(&if_false0)))))),
    253           IsMerge(
    254               IsIfTrue(AllOf(CaptureEq(&branch0),
    255                              IsBranch(IsObjectIsSmi(input), control))),
    256               AllOf(CaptureEq(&if_false0), IsIfFalse(CaptureEq(&branch0))))));
    257 }
    258 
    259 }  // namespace compiler
    260 }  // namespace internal
    261 }  // namespace v8
    262