| OLD | NEW |
| (Empty) |
| 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 "test/compiler-unittests/node-matchers.h" | |
| 6 | |
| 7 #include <ostream> // NOLINT(readability/streams) | |
| 8 | |
| 9 #include "src/compiler/node-properties-inl.h" | |
| 10 | |
| 11 using testing::MakeMatcher; | |
| 12 using testing::MatcherInterface; | |
| 13 using testing::MatchResultListener; | |
| 14 using testing::StringMatchResultListener; | |
| 15 | |
| 16 namespace v8 { | |
| 17 namespace internal { | |
| 18 | |
| 19 // TODO(bmeurer): Find a new home for these functions. | |
| 20 template <typename T> | |
| 21 inline std::ostream& operator<<(std::ostream& os, | |
| 22 const PrintableUnique<T>& value) { | |
| 23 return os << value.string(); | |
| 24 } | |
| 25 | |
| 26 namespace compiler { | |
| 27 | |
| 28 namespace { | |
| 29 | |
| 30 template <typename T> | |
| 31 bool PrintMatchAndExplain(const T& value, const char* value_name, | |
| 32 const Matcher<T>& value_matcher, | |
| 33 MatchResultListener* listener) { | |
| 34 StringMatchResultListener value_listener; | |
| 35 if (!value_matcher.MatchAndExplain(value, &value_listener)) { | |
| 36 *listener << "whose " << value_name << " " << value << " doesn't match"; | |
| 37 if (value_listener.str() != "") { | |
| 38 *listener << ", " << value_listener.str(); | |
| 39 } | |
| 40 return false; | |
| 41 } | |
| 42 return true; | |
| 43 } | |
| 44 | |
| 45 | |
| 46 class NodeMatcher : public MatcherInterface<Node*> { | |
| 47 public: | |
| 48 explicit NodeMatcher(IrOpcode::Value opcode) : opcode_(opcode) {} | |
| 49 | |
| 50 virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE { | |
| 51 *os << "is a " << IrOpcode::Mnemonic(opcode_) << " node"; | |
| 52 } | |
| 53 | |
| 54 virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const | |
| 55 V8_OVERRIDE { | |
| 56 if (node == NULL) { | |
| 57 *listener << "which is NULL"; | |
| 58 return false; | |
| 59 } | |
| 60 if (node->opcode() != opcode_) { | |
| 61 *listener << "whose opcode is " << IrOpcode::Mnemonic(node->opcode()); | |
| 62 return false; | |
| 63 } | |
| 64 return true; | |
| 65 } | |
| 66 | |
| 67 private: | |
| 68 const IrOpcode::Value opcode_; | |
| 69 }; | |
| 70 | |
| 71 | |
| 72 class IsBranchMatcher V8_FINAL : public NodeMatcher { | |
| 73 public: | |
| 74 IsBranchMatcher(const Matcher<Node*>& value_matcher, | |
| 75 const Matcher<Node*>& control_matcher) | |
| 76 : NodeMatcher(IrOpcode::kBranch), | |
| 77 value_matcher_(value_matcher), | |
| 78 control_matcher_(control_matcher) {} | |
| 79 | |
| 80 virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE { | |
| 81 NodeMatcher::DescribeTo(os); | |
| 82 *os << " whose value ("; | |
| 83 value_matcher_.DescribeTo(os); | |
| 84 *os << ") and control ("; | |
| 85 control_matcher_.DescribeTo(os); | |
| 86 *os << ")"; | |
| 87 } | |
| 88 | |
| 89 virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const | |
| 90 V8_OVERRIDE { | |
| 91 return (NodeMatcher::MatchAndExplain(node, listener) && | |
| 92 PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), | |
| 93 "value", value_matcher_, listener) && | |
| 94 PrintMatchAndExplain(NodeProperties::GetControlInput(node), | |
| 95 "control", control_matcher_, listener)); | |
| 96 } | |
| 97 | |
| 98 private: | |
| 99 const Matcher<Node*> value_matcher_; | |
| 100 const Matcher<Node*> control_matcher_; | |
| 101 }; | |
| 102 | |
| 103 | |
| 104 template <typename T> | |
| 105 class IsConstantMatcher V8_FINAL : public NodeMatcher { | |
| 106 public: | |
| 107 IsConstantMatcher(IrOpcode::Value opcode, const Matcher<T>& value_matcher) | |
| 108 : NodeMatcher(opcode), value_matcher_(value_matcher) {} | |
| 109 | |
| 110 virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE { | |
| 111 NodeMatcher::DescribeTo(os); | |
| 112 *os << " whose value ("; | |
| 113 value_matcher_.DescribeTo(os); | |
| 114 *os << ")"; | |
| 115 } | |
| 116 | |
| 117 virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const | |
| 118 V8_OVERRIDE { | |
| 119 return (NodeMatcher::MatchAndExplain(node, listener) && | |
| 120 PrintMatchAndExplain(OpParameter<T>(node), "value", value_matcher_, | |
| 121 listener)); | |
| 122 } | |
| 123 | |
| 124 private: | |
| 125 const Matcher<T> value_matcher_; | |
| 126 }; | |
| 127 | |
| 128 | |
| 129 class IsPhiMatcher V8_FINAL : public NodeMatcher { | |
| 130 public: | |
| 131 IsPhiMatcher(const Matcher<Node*>& value0_matcher, | |
| 132 const Matcher<Node*>& value1_matcher, | |
| 133 const Matcher<Node*>& control_matcher) | |
| 134 : NodeMatcher(IrOpcode::kPhi), | |
| 135 value0_matcher_(value0_matcher), | |
| 136 value1_matcher_(value1_matcher), | |
| 137 control_matcher_(control_matcher) {} | |
| 138 | |
| 139 virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE { | |
| 140 NodeMatcher::DescribeTo(os); | |
| 141 *os << " whose value0 ("; | |
| 142 value0_matcher_.DescribeTo(os); | |
| 143 *os << "), value1 ("; | |
| 144 value1_matcher_.DescribeTo(os); | |
| 145 *os << ") and control ("; | |
| 146 control_matcher_.DescribeTo(os); | |
| 147 *os << ")"; | |
| 148 } | |
| 149 | |
| 150 virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const | |
| 151 V8_OVERRIDE { | |
| 152 return (NodeMatcher::MatchAndExplain(node, listener) && | |
| 153 PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), | |
| 154 "value0", value0_matcher_, listener) && | |
| 155 PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1), | |
| 156 "value1", value1_matcher_, listener) && | |
| 157 PrintMatchAndExplain(NodeProperties::GetControlInput(node), | |
| 158 "control", control_matcher_, listener)); | |
| 159 } | |
| 160 | |
| 161 private: | |
| 162 const Matcher<Node*> value0_matcher_; | |
| 163 const Matcher<Node*> value1_matcher_; | |
| 164 const Matcher<Node*> control_matcher_; | |
| 165 }; | |
| 166 | |
| 167 | |
| 168 class IsProjectionMatcher V8_FINAL : public NodeMatcher { | |
| 169 public: | |
| 170 IsProjectionMatcher(const Matcher<int32_t>& index_matcher, | |
| 171 const Matcher<Node*>& base_matcher) | |
| 172 : NodeMatcher(IrOpcode::kProjection), | |
| 173 index_matcher_(index_matcher), | |
| 174 base_matcher_(base_matcher) {} | |
| 175 | |
| 176 virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE { | |
| 177 NodeMatcher::DescribeTo(os); | |
| 178 *os << " whose index ("; | |
| 179 index_matcher_.DescribeTo(os); | |
| 180 *os << ") and base ("; | |
| 181 base_matcher_.DescribeTo(os); | |
| 182 *os << ")"; | |
| 183 } | |
| 184 | |
| 185 virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const | |
| 186 V8_OVERRIDE { | |
| 187 return (NodeMatcher::MatchAndExplain(node, listener) && | |
| 188 PrintMatchAndExplain(OpParameter<int32_t>(node), "index", | |
| 189 index_matcher_, listener) && | |
| 190 PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base", | |
| 191 base_matcher_, listener)); | |
| 192 } | |
| 193 | |
| 194 private: | |
| 195 const Matcher<int32_t> index_matcher_; | |
| 196 const Matcher<Node*> base_matcher_; | |
| 197 }; | |
| 198 | |
| 199 | |
| 200 class IsLoadMatcher V8_FINAL : public NodeMatcher { | |
| 201 public: | |
| 202 IsLoadMatcher(const Matcher<MachineType>& type_matcher, | |
| 203 const Matcher<Node*>& base_matcher, | |
| 204 const Matcher<Node*>& index_matcher, | |
| 205 const Matcher<Node*>& effect_matcher) | |
| 206 : NodeMatcher(IrOpcode::kLoad), | |
| 207 type_matcher_(type_matcher), | |
| 208 base_matcher_(base_matcher), | |
| 209 index_matcher_(index_matcher), | |
| 210 effect_matcher_(effect_matcher) {} | |
| 211 | |
| 212 virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE { | |
| 213 NodeMatcher::DescribeTo(os); | |
| 214 *os << " whose type ("; | |
| 215 type_matcher_.DescribeTo(os); | |
| 216 *os << "), base ("; | |
| 217 base_matcher_.DescribeTo(os); | |
| 218 *os << "), index ("; | |
| 219 index_matcher_.DescribeTo(os); | |
| 220 *os << ") and effect ("; | |
| 221 effect_matcher_.DescribeTo(os); | |
| 222 *os << ")"; | |
| 223 } | |
| 224 | |
| 225 virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const | |
| 226 V8_OVERRIDE { | |
| 227 return (NodeMatcher::MatchAndExplain(node, listener) && | |
| 228 PrintMatchAndExplain(OpParameter<MachineType>(node), "type", | |
| 229 type_matcher_, listener) && | |
| 230 PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base", | |
| 231 base_matcher_, listener) && | |
| 232 PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1), | |
| 233 "index", index_matcher_, listener) && | |
| 234 PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect", | |
| 235 effect_matcher_, listener)); | |
| 236 } | |
| 237 | |
| 238 private: | |
| 239 const Matcher<MachineType> type_matcher_; | |
| 240 const Matcher<Node*> base_matcher_; | |
| 241 const Matcher<Node*> index_matcher_; | |
| 242 const Matcher<Node*> effect_matcher_; | |
| 243 }; | |
| 244 | |
| 245 | |
| 246 class IsStoreMatcher V8_FINAL : public NodeMatcher { | |
| 247 public: | |
| 248 IsStoreMatcher(const Matcher<MachineType>& type_matcher, | |
| 249 const Matcher<WriteBarrierKind> write_barrier_matcher, | |
| 250 const Matcher<Node*>& base_matcher, | |
| 251 const Matcher<Node*>& index_matcher, | |
| 252 const Matcher<Node*>& value_matcher, | |
| 253 const Matcher<Node*>& effect_matcher, | |
| 254 const Matcher<Node*>& control_matcher) | |
| 255 : NodeMatcher(IrOpcode::kStore), | |
| 256 type_matcher_(type_matcher), | |
| 257 write_barrier_matcher_(write_barrier_matcher), | |
| 258 base_matcher_(base_matcher), | |
| 259 index_matcher_(index_matcher), | |
| 260 value_matcher_(value_matcher), | |
| 261 effect_matcher_(effect_matcher), | |
| 262 control_matcher_(control_matcher) {} | |
| 263 | |
| 264 virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE { | |
| 265 NodeMatcher::DescribeTo(os); | |
| 266 *os << " whose type ("; | |
| 267 type_matcher_.DescribeTo(os); | |
| 268 *os << "), write barrier ("; | |
| 269 write_barrier_matcher_.DescribeTo(os); | |
| 270 *os << "), base ("; | |
| 271 base_matcher_.DescribeTo(os); | |
| 272 *os << "), index ("; | |
| 273 index_matcher_.DescribeTo(os); | |
| 274 *os << "), value ("; | |
| 275 value_matcher_.DescribeTo(os); | |
| 276 *os << "), effect ("; | |
| 277 effect_matcher_.DescribeTo(os); | |
| 278 *os << ") and control ("; | |
| 279 control_matcher_.DescribeTo(os); | |
| 280 *os << ")"; | |
| 281 } | |
| 282 | |
| 283 virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const | |
| 284 V8_OVERRIDE { | |
| 285 return (NodeMatcher::MatchAndExplain(node, listener) && | |
| 286 PrintMatchAndExplain( | |
| 287 OpParameter<StoreRepresentation>(node).machine_type, "type", | |
| 288 type_matcher_, listener) && | |
| 289 PrintMatchAndExplain( | |
| 290 OpParameter<StoreRepresentation>(node).write_barrier_kind, | |
| 291 "write barrier", write_barrier_matcher_, listener) && | |
| 292 PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base", | |
| 293 base_matcher_, listener) && | |
| 294 PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1), | |
| 295 "index", index_matcher_, listener) && | |
| 296 PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2), | |
| 297 "value", value_matcher_, listener) && | |
| 298 PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect", | |
| 299 effect_matcher_, listener) && | |
| 300 PrintMatchAndExplain(NodeProperties::GetControlInput(node), | |
| 301 "control", control_matcher_, listener)); | |
| 302 } | |
| 303 | |
| 304 private: | |
| 305 const Matcher<MachineType> type_matcher_; | |
| 306 const Matcher<WriteBarrierKind> write_barrier_matcher_; | |
| 307 const Matcher<Node*> base_matcher_; | |
| 308 const Matcher<Node*> index_matcher_; | |
| 309 const Matcher<Node*> value_matcher_; | |
| 310 const Matcher<Node*> effect_matcher_; | |
| 311 const Matcher<Node*> control_matcher_; | |
| 312 }; | |
| 313 | |
| 314 | |
| 315 class IsBinopMatcher V8_FINAL : public NodeMatcher { | |
| 316 public: | |
| 317 IsBinopMatcher(IrOpcode::Value opcode, const Matcher<Node*>& lhs_matcher, | |
| 318 const Matcher<Node*>& rhs_matcher) | |
| 319 : NodeMatcher(opcode), | |
| 320 lhs_matcher_(lhs_matcher), | |
| 321 rhs_matcher_(rhs_matcher) {} | |
| 322 | |
| 323 virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE { | |
| 324 NodeMatcher::DescribeTo(os); | |
| 325 *os << " whose lhs ("; | |
| 326 lhs_matcher_.DescribeTo(os); | |
| 327 *os << ") and rhs ("; | |
| 328 rhs_matcher_.DescribeTo(os); | |
| 329 *os << ")"; | |
| 330 } | |
| 331 | |
| 332 virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const | |
| 333 V8_OVERRIDE { | |
| 334 return (NodeMatcher::MatchAndExplain(node, listener) && | |
| 335 PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "lhs", | |
| 336 lhs_matcher_, listener) && | |
| 337 PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1), "rhs", | |
| 338 rhs_matcher_, listener)); | |
| 339 } | |
| 340 | |
| 341 private: | |
| 342 const Matcher<Node*> lhs_matcher_; | |
| 343 const Matcher<Node*> rhs_matcher_; | |
| 344 }; | |
| 345 | |
| 346 | |
| 347 class IsUnopMatcher V8_FINAL : public NodeMatcher { | |
| 348 public: | |
| 349 IsUnopMatcher(IrOpcode::Value opcode, const Matcher<Node*>& input_matcher) | |
| 350 : NodeMatcher(opcode), input_matcher_(input_matcher) {} | |
| 351 | |
| 352 virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE { | |
| 353 NodeMatcher::DescribeTo(os); | |
| 354 *os << " whose input ("; | |
| 355 input_matcher_.DescribeTo(os); | |
| 356 *os << ")"; | |
| 357 } | |
| 358 | |
| 359 virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const | |
| 360 V8_OVERRIDE { | |
| 361 return (NodeMatcher::MatchAndExplain(node, listener) && | |
| 362 PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), | |
| 363 "input", input_matcher_, listener)); | |
| 364 } | |
| 365 | |
| 366 private: | |
| 367 const Matcher<Node*> input_matcher_; | |
| 368 }; | |
| 369 | |
| 370 } | |
| 371 | |
| 372 | |
| 373 Matcher<Node*> IsBranch(const Matcher<Node*>& value_matcher, | |
| 374 const Matcher<Node*>& control_matcher) { | |
| 375 return MakeMatcher(new IsBranchMatcher(value_matcher, control_matcher)); | |
| 376 } | |
| 377 | |
| 378 | |
| 379 Matcher<Node*> IsInt32Constant(const Matcher<int32_t>& value_matcher) { | |
| 380 return MakeMatcher( | |
| 381 new IsConstantMatcher<int32_t>(IrOpcode::kInt32Constant, value_matcher)); | |
| 382 } | |
| 383 | |
| 384 | |
| 385 Matcher<Node*> IsHeapConstant( | |
| 386 const Matcher<PrintableUnique<HeapObject> >& value_matcher) { | |
| 387 return MakeMatcher(new IsConstantMatcher<PrintableUnique<HeapObject> >( | |
| 388 IrOpcode::kHeapConstant, value_matcher)); | |
| 389 } | |
| 390 | |
| 391 | |
| 392 Matcher<Node*> IsPhi(const Matcher<Node*>& value0_matcher, | |
| 393 const Matcher<Node*>& value1_matcher, | |
| 394 const Matcher<Node*>& merge_matcher) { | |
| 395 return MakeMatcher( | |
| 396 new IsPhiMatcher(value0_matcher, value1_matcher, merge_matcher)); | |
| 397 } | |
| 398 | |
| 399 | |
| 400 Matcher<Node*> IsProjection(const Matcher<int32_t>& index_matcher, | |
| 401 const Matcher<Node*>& base_matcher) { | |
| 402 return MakeMatcher(new IsProjectionMatcher(index_matcher, base_matcher)); | |
| 403 } | |
| 404 | |
| 405 | |
| 406 Matcher<Node*> IsLoad(const Matcher<MachineType>& type_matcher, | |
| 407 const Matcher<Node*>& base_matcher, | |
| 408 const Matcher<Node*>& index_matcher, | |
| 409 const Matcher<Node*>& effect_matcher) { | |
| 410 return MakeMatcher(new IsLoadMatcher(type_matcher, base_matcher, | |
| 411 index_matcher, effect_matcher)); | |
| 412 } | |
| 413 | |
| 414 | |
| 415 Matcher<Node*> IsStore(const Matcher<MachineType>& type_matcher, | |
| 416 const Matcher<WriteBarrierKind>& write_barrier_matcher, | |
| 417 const Matcher<Node*>& base_matcher, | |
| 418 const Matcher<Node*>& index_matcher, | |
| 419 const Matcher<Node*>& value_matcher, | |
| 420 const Matcher<Node*>& effect_matcher, | |
| 421 const Matcher<Node*>& control_matcher) { | |
| 422 return MakeMatcher(new IsStoreMatcher( | |
| 423 type_matcher, write_barrier_matcher, base_matcher, index_matcher, | |
| 424 value_matcher, effect_matcher, control_matcher)); | |
| 425 } | |
| 426 | |
| 427 | |
| 428 #define IS_BINOP_MATCHER(Name) \ | |
| 429 Matcher<Node*> Is##Name(const Matcher<Node*>& lhs_matcher, \ | |
| 430 const Matcher<Node*>& rhs_matcher) { \ | |
| 431 return MakeMatcher( \ | |
| 432 new IsBinopMatcher(IrOpcode::k##Name, lhs_matcher, rhs_matcher)); \ | |
| 433 } | |
| 434 IS_BINOP_MATCHER(Word32And) | |
| 435 IS_BINOP_MATCHER(Word32Sar) | |
| 436 IS_BINOP_MATCHER(Word32Ror) | |
| 437 IS_BINOP_MATCHER(Word32Equal) | |
| 438 IS_BINOP_MATCHER(Word64And) | |
| 439 IS_BINOP_MATCHER(Word64Sar) | |
| 440 IS_BINOP_MATCHER(Word64Shl) | |
| 441 IS_BINOP_MATCHER(Word64Equal) | |
| 442 IS_BINOP_MATCHER(Int32AddWithOverflow) | |
| 443 #undef IS_BINOP_MATCHER | |
| 444 | |
| 445 | |
| 446 #define IS_UNOP_MATCHER(Name) \ | |
| 447 Matcher<Node*> Is##Name(const Matcher<Node*>& input_matcher) { \ | |
| 448 return MakeMatcher(new IsUnopMatcher(IrOpcode::k##Name, input_matcher)); \ | |
| 449 } | |
| 450 IS_UNOP_MATCHER(ConvertInt64ToInt32) | |
| 451 IS_UNOP_MATCHER(ChangeInt32ToFloat64) | |
| 452 #undef IS_UNOP_MATCHER | |
| 453 | |
| 454 } // namespace compiler | |
| 455 } // namespace internal | |
| 456 } // namespace v8 | |
| OLD | NEW |