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