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 |