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