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 "src/types-inl.h"
     11 #include "test/unittests/compiler/graph-unittest.h"
     12 #include "test/unittests/compiler/node-test-utils.h"
     13 #include "testing/gmock-support.h"
     14 
     15 
     16 using testing::_;
     17 using testing::AllOf;
     18 using testing::BitEq;
     19 using testing::Capture;
     20 using testing::CaptureEq;
     21 
     22 
     23 namespace v8 {
     24 namespace internal {
     25 namespace compiler {
     26 
     27 class JSIntrinsicLoweringTest : public TypedGraphTest {
     28  public:
     29   JSIntrinsicLoweringTest() : TypedGraphTest(3), javascript_(zone()) {}
     30   ~JSIntrinsicLoweringTest() override {}
     31 
     32  protected:
     33   Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags =
     34                                    MachineOperatorBuilder::kNoFlags) {
     35     MachineOperatorBuilder machine(zone(), MachineType::PointerRepresentation(),
     36                                    flags);
     37     SimplifiedOperatorBuilder simplified(zone());
     38     JSGraph jsgraph(isolate(), graph(), common(), javascript(), &simplified,
     39                     &machine);
     40     // TODO(titzer): mock the GraphReducer here for better unit testing.
     41     GraphReducer graph_reducer(zone(), graph());
     42     JSIntrinsicLowering reducer(&graph_reducer, &jsgraph,
     43                                 JSIntrinsicLowering::kDeoptimizationEnabled);
     44     return reducer.Reduce(node);
     45   }
     46 
     47   Node* EmptyFrameState() {
     48     MachineOperatorBuilder machine(zone());
     49     JSGraph jsgraph(isolate(), graph(), common(), javascript(), nullptr,
     50                     &machine);
     51     return jsgraph.EmptyFrameState();
     52   }
     53 
     54   JSOperatorBuilder* javascript() { return &javascript_; }
     55 
     56  private:
     57   JSOperatorBuilder javascript_;
     58 };
     59 
     60 
     61 // -----------------------------------------------------------------------------
     62 // %_ConstructDouble
     63 
     64 
     65 TEST_F(JSIntrinsicLoweringTest, InlineOptimizedConstructDouble) {
     66   Node* const input0 = Parameter(0);
     67   Node* const input1 = Parameter(1);
     68   Node* const context = Parameter(2);
     69   Node* const effect = graph()->start();
     70   Node* const control = graph()->start();
     71   Reduction const r = Reduce(graph()->NewNode(
     72       javascript()->CallRuntime(Runtime::kInlineConstructDouble, 2), input0,
     73       input1, context, effect, control));
     74   ASSERT_TRUE(r.Changed());
     75   EXPECT_THAT(r.replacement(), IsFloat64InsertHighWord32(
     76                                    IsFloat64InsertLowWord32(
     77                                        IsNumberConstant(BitEq(0.0)), input1),
     78                                    input0));
     79 }
     80 
     81 
     82 // -----------------------------------------------------------------------------
     83 // %_DoubleLo
     84 
     85 
     86 TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleLo) {
     87   Node* const input = Parameter(0);
     88   Node* const context = Parameter(1);
     89   Node* const effect = graph()->start();
     90   Node* const control = graph()->start();
     91   Reduction const r = Reduce(
     92       graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineDoubleLo, 1),
     93                        input, context, effect, control));
     94   ASSERT_TRUE(r.Changed());
     95   EXPECT_THAT(r.replacement(), IsFloat64ExtractLowWord32(input));
     96 }
     97 
     98 
     99 // -----------------------------------------------------------------------------
    100 // %_DoubleHi
    101 
    102 
    103 TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleHi) {
    104   Node* const input = Parameter(0);
    105   Node* const context = Parameter(1);
    106   Node* const effect = graph()->start();
    107   Node* const control = graph()->start();
    108   Reduction const r = Reduce(
    109       graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineDoubleHi, 1),
    110                        input, context, effect, control));
    111   ASSERT_TRUE(r.Changed());
    112   EXPECT_THAT(r.replacement(), IsFloat64ExtractHighWord32(input));
    113 }
    114 
    115 
    116 // -----------------------------------------------------------------------------
    117 // %_IsSmi
    118 
    119 
    120 TEST_F(JSIntrinsicLoweringTest, InlineIsSmi) {
    121   Node* const input = Parameter(0);
    122   Node* const context = Parameter(1);
    123   Node* const effect = graph()->start();
    124   Node* const control = graph()->start();
    125   Reduction const r = Reduce(
    126       graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsSmi, 1),
    127                        input, context, effect, control));
    128   ASSERT_TRUE(r.Changed());
    129   EXPECT_THAT(r.replacement(), IsObjectIsSmi(input));
    130 }
    131 
    132 
    133 // -----------------------------------------------------------------------------
    134 // %_IsArray
    135 
    136 
    137 TEST_F(JSIntrinsicLoweringTest, InlineIsArray) {
    138   Node* const input = Parameter(0);
    139   Node* const context = Parameter(1);
    140   Node* const effect = graph()->start();
    141   Node* const control = graph()->start();
    142   Reduction const r = Reduce(
    143       graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsArray, 1),
    144                        input, context, effect, control));
    145   ASSERT_TRUE(r.Changed());
    146 
    147   Node* phi = r.replacement();
    148   Capture<Node*> branch, if_false;
    149   EXPECT_THAT(
    150       phi,
    151       IsPhi(
    152           MachineRepresentation::kTagged, IsFalseConstant(),
    153           IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(),
    154                                     IsLoadField(AccessBuilder::ForMap(), input,
    155                                                 effect, CaptureEq(&if_false)),
    156                                     effect, _),
    157                         IsInt32Constant(JS_ARRAY_TYPE)),
    158           IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
    159                                  IsBranch(IsObjectIsSmi(input), control))),
    160                   AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
    161 }
    162 
    163 
    164 // -----------------------------------------------------------------------------
    165 // %_IsDate
    166 
    167 
    168 TEST_F(JSIntrinsicLoweringTest, InlineIsDate) {
    169   Node* const input = Parameter(0);
    170   Node* const context = Parameter(1);
    171   Node* const effect = graph()->start();
    172   Node* const control = graph()->start();
    173   Reduction const r = Reduce(
    174       graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsDate, 1),
    175                        input, context, effect, control));
    176   ASSERT_TRUE(r.Changed());
    177 
    178   Node* phi = r.replacement();
    179   Capture<Node*> branch, if_false;
    180   EXPECT_THAT(
    181       phi,
    182       IsPhi(
    183           MachineRepresentation::kTagged, IsFalseConstant(),
    184           IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(),
    185                                     IsLoadField(AccessBuilder::ForMap(), input,
    186                                                 effect, CaptureEq(&if_false)),
    187                                     effect, _),
    188                         IsInt32Constant(JS_DATE_TYPE)),
    189           IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
    190                                  IsBranch(IsObjectIsSmi(input), control))),
    191                   AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
    192 }
    193 
    194 
    195 // -----------------------------------------------------------------------------
    196 // %_IsTypedArray
    197 
    198 
    199 TEST_F(JSIntrinsicLoweringTest, InlineIsTypedArray) {
    200   Node* const input = Parameter(0);
    201   Node* const context = Parameter(1);
    202   Node* const effect = graph()->start();
    203   Node* const control = graph()->start();
    204   Reduction const r = Reduce(graph()->NewNode(
    205       javascript()->CallRuntime(Runtime::kInlineIsTypedArray, 1), input,
    206       context, effect, control));
    207   ASSERT_TRUE(r.Changed());
    208 
    209   Node* phi = r.replacement();
    210   Capture<Node*> branch, if_false;
    211   EXPECT_THAT(
    212       phi,
    213       IsPhi(
    214           MachineRepresentation::kTagged, IsFalseConstant(),
    215           IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(),
    216                                     IsLoadField(AccessBuilder::ForMap(), input,
    217                                                 effect, CaptureEq(&if_false)),
    218                                     effect, _),
    219                         IsInt32Constant(JS_TYPED_ARRAY_TYPE)),
    220           IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
    221                                  IsBranch(IsObjectIsSmi(input), control))),
    222                   AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
    223 }
    224 
    225 
    226 // -----------------------------------------------------------------------------
    227 // %_IsFunction
    228 
    229 
    230 TEST_F(JSIntrinsicLoweringTest, InlineIsFunction) {
    231   Node* const input = Parameter(Type::Any());
    232   Node* const context = Parameter(Type::Any());
    233   Node* const effect = graph()->start();
    234   Node* const control = graph()->start();
    235   Reduction const r = Reduce(
    236       graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsFunction, 1),
    237                        input, context, effect, control));
    238   ASSERT_TRUE(r.Changed());
    239 
    240   Node* phi = r.replacement();
    241   Capture<Node*> branch, if_false;
    242   EXPECT_THAT(
    243       phi,
    244       IsPhi(
    245           MachineRepresentation::kTagged, IsFalseConstant(),
    246           IsUint32LessThanOrEqual(
    247               IsInt32Constant(FIRST_FUNCTION_TYPE),
    248               IsLoadField(AccessBuilder::ForMapInstanceType(),
    249                           IsLoadField(AccessBuilder::ForMap(), input, effect,
    250                                       CaptureEq(&if_false)),
    251                           effect, _)),
    252           IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
    253                                  IsBranch(IsObjectIsSmi(input), control))),
    254                   AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
    255 }
    256 
    257 
    258 // -----------------------------------------------------------------------------
    259 // %_IsRegExp
    260 
    261 
    262 TEST_F(JSIntrinsicLoweringTest, InlineIsRegExp) {
    263   Node* const input = Parameter(0);
    264   Node* const context = Parameter(1);
    265   Node* const effect = graph()->start();
    266   Node* const control = graph()->start();
    267   Reduction const r = Reduce(
    268       graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsRegExp, 1),
    269                        input, context, effect, control));
    270   ASSERT_TRUE(r.Changed());
    271 
    272   Node* phi = r.replacement();
    273   Capture<Node*> branch, if_false;
    274   EXPECT_THAT(
    275       phi,
    276       IsPhi(
    277           MachineRepresentation::kTagged, IsFalseConstant(),
    278           IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(),
    279                                     IsLoadField(AccessBuilder::ForMap(), input,
    280                                                 effect, CaptureEq(&if_false)),
    281                                     effect, _),
    282                         IsInt32Constant(JS_REGEXP_TYPE)),
    283           IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
    284                                  IsBranch(IsObjectIsSmi(input), control))),
    285                   AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
    286 }
    287 
    288 
    289 // -----------------------------------------------------------------------------
    290 // %_IsJSReceiver
    291 
    292 
    293 TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiverWithAny) {
    294   Node* const input = Parameter(Type::Any());
    295   Node* const context = Parameter(Type::Any());
    296   Node* const effect = graph()->start();
    297   Node* const control = graph()->start();
    298   Reduction const r = Reduce(graph()->NewNode(
    299       javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1), input,
    300       context, effect, control));
    301   ASSERT_TRUE(r.Changed());
    302 
    303   Node* phi = r.replacement();
    304   Capture<Node *> branch, if_false;
    305   EXPECT_THAT(
    306       phi,
    307       IsPhi(
    308           MachineRepresentation::kTagged, IsFalseConstant(),
    309           IsUint32LessThanOrEqual(
    310               IsInt32Constant(FIRST_JS_RECEIVER_TYPE),
    311               IsLoadField(AccessBuilder::ForMapInstanceType(),
    312                           IsLoadField(AccessBuilder::ForMap(), input, effect,
    313                                       CaptureEq(&if_false)),
    314                           effect, _)),
    315           IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
    316                                  IsBranch(IsObjectIsSmi(input), control))),
    317                   AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
    318 }
    319 
    320 
    321 TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiverWithReceiver) {
    322   Node* const input = Parameter(Type::Receiver());
    323   Node* const context = Parameter(Type::Any());
    324   Node* const effect = graph()->start();
    325   Node* const control = graph()->start();
    326   Reduction const r = Reduce(graph()->NewNode(
    327       javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1), input,
    328       context, effect, control));
    329   ASSERT_TRUE(r.Changed());
    330   EXPECT_THAT(r.replacement(), IsTrueConstant());
    331 }
    332 
    333 
    334 TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiverWithUndefined) {
    335   Node* const input = Parameter(Type::Undefined());
    336   Node* const context = Parameter(Type::Any());
    337   Node* const effect = graph()->start();
    338   Node* const control = graph()->start();
    339   Reduction const r = Reduce(graph()->NewNode(
    340       javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1), input,
    341       context, effect, control));
    342   ASSERT_TRUE(r.Changed());
    343   EXPECT_THAT(r.replacement(), IsFalseConstant());
    344 }
    345 
    346 
    347 // -----------------------------------------------------------------------------
    348 // %_JSValueGetValue
    349 
    350 
    351 TEST_F(JSIntrinsicLoweringTest, InlineJSValueGetValue) {
    352   Node* const input = Parameter(0);
    353   Node* const context = Parameter(1);
    354   Node* const effect = graph()->start();
    355   Node* const control = graph()->start();
    356   Reduction const r = Reduce(graph()->NewNode(
    357       javascript()->CallRuntime(Runtime::kInlineJSValueGetValue, 1), input,
    358       context, effect, control));
    359   ASSERT_TRUE(r.Changed());
    360   EXPECT_THAT(r.replacement(),
    361               IsLoadField(AccessBuilder::ForValue(), input, effect, control));
    362 }
    363 
    364 
    365 // -----------------------------------------------------------------------------
    366 // %_MathFloor
    367 
    368 
    369 TEST_F(JSIntrinsicLoweringTest, InlineMathFloor) {
    370   Node* const input = Parameter(0);
    371   Node* const context = Parameter(1);
    372   Node* const effect = graph()->start();
    373   Node* const control = graph()->start();
    374   Reduction const r = Reduce(
    375       graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineMathFloor, 1),
    376                        input, context, effect, control),
    377       MachineOperatorBuilder::kFloat64RoundDown);
    378   ASSERT_TRUE(r.Changed());
    379   EXPECT_THAT(r.replacement(), IsFloat64RoundDown(input));
    380 }
    381 
    382 
    383 // -----------------------------------------------------------------------------
    384 // %_MathSqrt
    385 
    386 
    387 TEST_F(JSIntrinsicLoweringTest, InlineMathSqrt) {
    388   Node* const input = Parameter(0);
    389   Node* const context = Parameter(1);
    390   Node* const effect = graph()->start();
    391   Node* const control = graph()->start();
    392   Reduction const r = Reduce(
    393       graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineMathSqrt, 1),
    394                        input, context, effect, control));
    395   ASSERT_TRUE(r.Changed());
    396   EXPECT_THAT(r.replacement(), IsFloat64Sqrt(input));
    397 }
    398 
    399 
    400 // -----------------------------------------------------------------------------
    401 // %_MathClz32
    402 
    403 
    404 TEST_F(JSIntrinsicLoweringTest, InlineMathClz32) {
    405   Node* const input = Parameter(0);
    406   Node* const context = Parameter(1);
    407   Node* const effect = graph()->start();
    408   Node* const control = graph()->start();
    409   Reduction const r = Reduce(
    410       graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineMathClz32, 1),
    411                        input, context, effect, control));
    412   ASSERT_TRUE(r.Changed());
    413   EXPECT_THAT(r.replacement(), IsWord32Clz(input));
    414 }
    415 
    416 
    417 // -----------------------------------------------------------------------------
    418 // %_ValueOf
    419 
    420 
    421 TEST_F(JSIntrinsicLoweringTest, InlineValueOf) {
    422   Node* const input = Parameter(0);
    423   Node* const context = Parameter(1);
    424   Node* const effect = graph()->start();
    425   Node* const control = graph()->start();
    426   Reduction const r = Reduce(
    427       graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineValueOf, 1),
    428                        input, context, effect, control));
    429   ASSERT_TRUE(r.Changed());
    430 
    431   Node* phi = r.replacement();
    432   Capture<Node*> branch0, if_false0, branch1, if_true1;
    433   EXPECT_THAT(
    434       phi,
    435       IsPhi(
    436           MachineRepresentation::kTagged, input,
    437           IsPhi(MachineRepresentation::kTagged,
    438                 IsLoadField(AccessBuilder::ForValue(), input, effect,
    439                             CaptureEq(&if_true1)),
    440                 input,
    441                 IsMerge(
    442                     AllOf(CaptureEq(&if_true1), IsIfTrue(CaptureEq(&branch1))),
    443                     IsIfFalse(AllOf(
    444                         CaptureEq(&branch1),
    445                         IsBranch(
    446                             IsWord32Equal(
    447                                 IsLoadField(
    448                                     AccessBuilder::ForMapInstanceType(),
    449                                     IsLoadField(AccessBuilder::ForMap(), input,
    450                                                 effect, CaptureEq(&if_false0)),
    451                                     effect, _),
    452                                 IsInt32Constant(JS_VALUE_TYPE)),
    453                             CaptureEq(&if_false0)))))),
    454           IsMerge(
    455               IsIfTrue(AllOf(CaptureEq(&branch0),
    456                              IsBranch(IsObjectIsSmi(input), control))),
    457               AllOf(CaptureEq(&if_false0), IsIfFalse(CaptureEq(&branch0))))));
    458 }
    459 
    460 }  // namespace compiler
    461 }  // namespace internal
    462 }  // namespace v8
    463