Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(227)

Side by Side Diff: test/cctest/compiler/test-structured-ifbuilder-fuzzer.cc

Issue 426233002: Land the Fan (disabled) (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 <string>
6
7 #include "src/v8.h"
8 #include "test/cctest/cctest.h"
9
10 #include "src/base/utils/random-number-generator.h"
11 #include "test/cctest/compiler/codegen-tester.h"
12
13 #if V8_TURBOFAN_TARGET
14
15 using namespace v8::internal;
16 using namespace v8::internal::compiler;
17
18 typedef StructuredMachineAssembler::IfBuilder IfBuilder;
19 typedef StructuredMachineAssembler::LoopBuilder Loop;
20
21 static const int32_t kUninitializedVariableOffset = -1;
22 static const int32_t kUninitializedOutput = -1;
23 static const int32_t kVerifiedOutput = -2;
24
25 static const int32_t kInitalVar = 1013;
26 static const int32_t kConjunctionInc = 1069;
27 static const int32_t kDisjunctionInc = 1151;
28 static const int32_t kThenInc = 1223;
29 static const int32_t kElseInc = 1291;
30 static const int32_t kIfInc = 1373;
31
32 class IfBuilderModel {
33 public:
34 explicit IfBuilderModel(Zone* zone)
35 : zone_(zone),
36 variable_offset_(0),
37 root_(new(zone_) Node(NULL)),
38 current_node_(root_),
39 current_expression_(NULL) {}
40
41 void If() {
42 if (current_node_->else_node != NULL) {
43 current_node_ = current_node_->else_node;
44 } else if (current_node_->then_node != NULL) {
45 current_node_ = current_node_->then_node;
46 }
47 ASSERT(current_expression_ == NULL);
48 current_expression_ = new(zone_) Expression(zone_, NULL);
49 current_node_->condition = current_expression_;
50 }
51 void IfNode() { LastChild()->variable_offset = variable_offset_++; }
52
53 void OpenParen() { current_expression_ = LastChild(); }
54 void CloseParen() { current_expression_ = current_expression_->parent; }
55
56 void And() { NewChild()->conjunction = true; }
57 void Or() { NewChild()->disjunction = true; }
58
59 void Then() {
60 ASSERT(current_expression_ == NULL || current_expression_->parent == NULL);
61 current_expression_ = NULL;
62 ASSERT(current_node_->then_node == NULL);
63 current_node_->then_node = new(zone_) Node(current_node_);
64 }
65 void Else() {
66 ASSERT(current_expression_ == NULL || current_expression_->parent == NULL);
67 current_expression_ = NULL;
68 ASSERT(current_node_->else_node == NULL);
69 current_node_->else_node = new(zone_) Node(current_node_);
70 }
71 void Return() {
72 if (current_node_->else_node != NULL) {
73 current_node_->else_node->returns = true;
74 } else if (current_node_->then_node != NULL) {
75 current_node_->then_node->returns = true;
76 } else {
77 CHECK(false);
78 }
79 }
80 void End() {}
81
82 void Print(std::vector<char>* v) { PrintRecursive(v, root_); }
83
84 struct VerificationState {
85 int32_t* inputs;
86 int32_t* outputs;
87 int32_t var;
88 };
89
90 int32_t Verify(int length, int32_t* inputs, int32_t* outputs) {
91 CHECK_EQ(variable_offset_, length);
92 // Input/Output verification.
93 for (int i = 0; i < length; ++i) {
94 CHECK(inputs[i] == 0 || inputs[i] == 1);
95 CHECK(outputs[i] == kUninitializedOutput || outputs[i] >= 0);
96 }
97 // Do verification.
98 VerificationState state;
99 state.inputs = inputs;
100 state.outputs = outputs;
101 state.var = kInitalVar;
102 VerifyRecursive(root_, &state);
103 // Verify all outputs marked.
104 for (int i = 0; i < length; ++i) {
105 CHECK(outputs[i] == kUninitializedOutput ||
106 outputs[i] == kVerifiedOutput);
107 }
108 return state.var;
109 }
110
111 private:
112 struct Expression;
113 typedef std::vector<Expression*, zone_allocator<Expression*> > Expressions;
114
115 struct Expression : public ZoneObject {
116 Expression(Zone* zone, Expression* p)
117 : variable_offset(kUninitializedVariableOffset),
118 disjunction(false),
119 conjunction(false),
120 parent(p),
121 children(Expressions::allocator_type(zone)) {}
122 int variable_offset;
123 bool disjunction;
124 bool conjunction;
125 Expression* parent;
126 Expressions children;
127
128 private:
129 DISALLOW_COPY_AND_ASSIGN(Expression);
130 };
131
132 struct Node : public ZoneObject {
133 explicit Node(Node* p)
134 : parent(p),
135 condition(NULL),
136 then_node(NULL),
137 else_node(NULL),
138 returns(false) {}
139 Node* parent;
140 Expression* condition;
141 Node* then_node;
142 Node* else_node;
143 bool returns;
144
145 private:
146 DISALLOW_COPY_AND_ASSIGN(Node);
147 };
148
149 Expression* LastChild() {
150 if (current_expression_->children.empty()) {
151 current_expression_->children.push_back(
152 new(zone_) Expression(zone_, current_expression_));
153 }
154 return current_expression_->children.back();
155 }
156
157 Expression* NewChild() {
158 Expression* child = new(zone_) Expression(zone_, current_expression_);
159 current_expression_->children.push_back(child);
160 return child;
161 }
162
163 static void PrintRecursive(std::vector<char>* v, Expression* expression) {
164 CHECK(expression != NULL);
165 if (expression->conjunction) {
166 ASSERT(!expression->disjunction);
167 v->push_back('&');
168 } else if (expression->disjunction) {
169 v->push_back('|');
170 }
171 if (expression->variable_offset != kUninitializedVariableOffset) {
172 v->push_back('v');
173 }
174 Expressions& children = expression->children;
175 if (children.empty()) return;
176 v->push_back('(');
177 for (Expressions::iterator i = children.begin();
178 i != children.end(); ++i) {
179 PrintRecursive(v, *i);
180 }
181 v->push_back(')');
182 }
183
184 static void PrintRecursive(std::vector<char>* v, Node* node) {
185 // Termination condition.
186 if (node->condition == NULL) {
187 CHECK(node->then_node == NULL &&
188 node->else_node == NULL);
189 if (node->returns) v->push_back('r');
190 return;
191 }
192 CHECK(!node->returns);
193 v->push_back('i');
194 PrintRecursive(v, node->condition);
195 if (node->then_node != NULL) {
196 v->push_back('t');
197 PrintRecursive(v, node->then_node);
198 }
199 if (node->else_node != NULL) {
200 v->push_back('e');
201 PrintRecursive(v, node->else_node);
202 }
203 }
204
205 static bool VerifyRecursive(Expression* expression,
206 VerificationState* state) {
207 bool result = false;
208 bool first_iteration = true;
209 Expressions& children = expression->children;
210 CHECK(!children.empty());
211 for (Expressions::iterator i = children.begin();
212 i != children.end(); ++i) {
213 Expression* child = *i;
214 // Short circuit evaluation,
215 // but mixes of &&s and ||s have weird semantics.
216 if ((child->conjunction && !result) ||
217 (child->disjunction && result)) {
218 continue;
219 }
220 if (child->conjunction) state->var += kConjunctionInc;
221 if (child->disjunction) state->var += kDisjunctionInc;
222 bool child_result;
223 if (child->variable_offset != kUninitializedVariableOffset) {
224 // Verify output
225 CHECK_EQ(state->var, state->outputs[child->variable_offset]);
226 state->outputs[child->variable_offset] = kVerifiedOutput; // Mark seen.
227 child_result = state->inputs[child->variable_offset];
228 CHECK(child->children.empty());
229 state->var += kIfInc;
230 } else {
231 child_result = VerifyRecursive(child, state);
232 }
233 if (child->conjunction) {
234 result &= child_result;
235 } else if (child->disjunction) {
236 result |= child_result;
237 } else {
238 CHECK(first_iteration);
239 result = child_result;
240 }
241 first_iteration = false;
242 }
243 return result;
244 }
245
246 static void VerifyRecursive(Node* node, VerificationState* state) {
247 if (node->condition == NULL) return;
248 bool result = VerifyRecursive(node->condition, state);
249 if (result) {
250 if (node->then_node) {
251 state->var += kThenInc;
252 return VerifyRecursive(node->then_node, state);
253 }
254 } else {
255 if (node->else_node) {
256 state->var += kElseInc;
257 return VerifyRecursive(node->else_node, state);
258 }
259 }
260 }
261
262 Zone* zone_;
263 int variable_offset_;
264 Node* root_;
265 Node* current_node_;
266 Expression* current_expression_;
267 DISALLOW_COPY_AND_ASSIGN(IfBuilderModel);
268 };
269
270
271 class IfBuilderGenerator : public StructuredMachineAssemblerTester<int32_t> {
272 public:
273 IfBuilderGenerator()
274 : StructuredMachineAssemblerTester(MachineOperatorBuilder::pointer_rep(),
275 MachineOperatorBuilder::pointer_rep()),
276 var_(NewVariable(Int32Constant(kInitalVar))),
277 c_(this),
278 m_(this->zone()),
279 one_(Int32Constant(1)),
280 offset_(0) {}
281
282 static void GenerateExpression(v8::base::RandomNumberGenerator* rng,
283 std::vector<char>* v,
284 int n_vars) {
285 int depth = 1;
286 v->push_back('(');
287 bool need_if = true;
288 bool populated = false;
289 while (n_vars != 0) {
290 if (need_if) {
291 // can nest a paren or do a variable
292 if (rng->NextBool()) {
293 v->push_back('v');
294 n_vars--;
295 need_if = false;
296 populated = true;
297 } else {
298 v->push_back('(');
299 depth++;
300 populated = false;
301 }
302 } else {
303 // can pop, do && or do ||
304 int options = 3;
305 if (depth == 1 || !populated) {
306 options--;
307 }
308 switch (rng->NextInt(options)) {
309 case 0:
310 v->push_back('&');
311 need_if = true;
312 break;
313 case 1:
314 v->push_back('|');
315 need_if = true;
316 break;
317 case 2:
318 v->push_back(')');
319 depth--;
320 break;
321 }
322 }
323 }
324 CHECK(!need_if);
325 while (depth != 0) {
326 v->push_back(')');
327 depth--;
328 }
329 }
330
331 static void GenerateIfThenElse(v8::base::RandomNumberGenerator* rng,
332 std::vector<char>* v,
333 int n_ifs,
334 int max_exp_length) {
335 CHECK_GT(n_ifs, 0);
336 CHECK_GT(max_exp_length, 0);
337 bool have_env = true;
338 bool then_done = false;
339 bool else_done = false;
340 bool first_iteration = true;
341 while (n_ifs != 0) {
342 if (have_env) {
343 int options = 3;
344 if (else_done || first_iteration) { // Don't do else or return
345 options -= 2;
346 first_iteration = false;
347 }
348 switch (rng->NextInt(options)) {
349 case 0:
350 v->push_back('i');
351 n_ifs--;
352 have_env = false;
353 GenerateExpression(rng, v, rng->NextInt(max_exp_length) + 1);
354 break;
355 case 1:
356 v->push_back('r');
357 have_env = false;
358 break;
359 case 2:
360 v->push_back('e');
361 else_done = true;
362 then_done = false;
363 break;
364 default:
365 CHECK(false);
366 }
367 } else { // Can only do then or else
368 int options = 2;
369 if (then_done) options--;
370 switch (rng->NextInt(options)) {
371 case 0:
372 v->push_back('e');
373 else_done = true;
374 then_done = false;
375 break;
376 case 1:
377 v->push_back('t');
378 then_done = true;
379 else_done = false;
380 break;
381 default:
382 CHECK(false);
383 }
384 have_env = true;
385 }
386 }
387 // Last instruction must have been an if, can complete it in several ways.
388 int options = 2;
389 if (then_done && !else_done) options++;
390 switch (rng->NextInt(3)) {
391 case 0:
392 // Do nothing.
393 break;
394 case 1:
395 v->push_back('t');
396 switch (rng->NextInt(3)) {
397 case 0:
398 v->push_back('r');
399 break;
400 case 1:
401 v->push_back('e');
402 break;
403 case 2:
404 v->push_back('e');
405 v->push_back('r');
406 break;
407 default:
408 CHECK(false);
409 }
410 break;
411 case 2:
412 v->push_back('e');
413 if (rng->NextBool()) v->push_back('r');
414 break;
415 default:
416 CHECK(false);
417 }
418 }
419
420 std::string::const_iterator ParseExpression(std::string::const_iterator it,
421 std::string::const_iterator end) {
422 // Prepare for expression.
423 m_.If();
424 c_.If();
425 int depth = 0;
426 for (; it != end; ++it) {
427 switch (*it) {
428 case 'v':
429 m_.IfNode();
430 {
431 Node* offset = Int32Constant(offset_ * 4);
432 Store(kMachineWord32, Parameter(1), offset, var_.Get());
433 var_.Set(Int32Add(var_.Get(), Int32Constant(kIfInc)));
434 c_.If(Load(kMachineWord32, Parameter(0), offset));
435 offset_++;
436 }
437 break;
438 case '&':
439 m_.And();
440 c_.And();
441 var_.Set(Int32Add(var_.Get(), Int32Constant(kConjunctionInc)));
442 break;
443 case '|':
444 m_.Or();
445 c_.Or();
446 var_.Set(Int32Add(var_.Get(), Int32Constant(kDisjunctionInc)));
447 break;
448 case '(':
449 if (depth != 0) {
450 m_.OpenParen();
451 c_.OpenParen();
452 }
453 depth++;
454 break;
455 case ')':
456 depth--;
457 if (depth == 0) return it;
458 m_.CloseParen();
459 c_.CloseParen();
460 break;
461 default:
462 CHECK(false);
463 }
464 }
465 CHECK(false);
466 return it;
467 }
468
469 void ParseIfThenElse(const std::string& str) {
470 int n_vars = 0;
471 for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
472 if (*it == 'v') n_vars++;
473 }
474 InitializeConstants(n_vars);
475 for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
476 switch (*it) {
477 case 'i':
478 {
479 it++;
480 CHECK(it != str.end());
481 CHECK_EQ('(', *it);
482 it = ParseExpression(it, str.end());
483 CHECK_EQ(')', *it);
484 break;
485 }
486 case 't':
487 m_.Then();
488 c_.Then();
489 var_.Set(Int32Add(var_.Get(), Int32Constant(kThenInc)));
490 break;
491 case 'e':
492 m_.Else();
493 c_.Else();
494 var_.Set(Int32Add(var_.Get(), Int32Constant(kElseInc)));
495 break;
496 case 'r':
497 m_.Return();
498 Return(var_.Get());
499 break;
500 default:
501 CHECK(false);
502 }
503 }
504 m_.End();
505 c_.End();
506 Return(var_.Get());
507 // Compare generated model to parsed version.
508 {
509 std::vector<char> v;
510 m_.Print(&v);
511 std::string m_str(v.begin(), v.end());
512 CHECK(m_str == str);
513 }
514 }
515
516 void ParseExpression(const std::string& str) {
517 CHECK(inputs_.is_empty());
518 std::string wrapped = "i(" + str + ")te";
519 ParseIfThenElse(wrapped);
520 }
521
522 void ParseRandomIfThenElse(v8::base::RandomNumberGenerator* rng,
523 int n_ifs,
524 int n_vars) {
525 std::vector<char> v;
526 GenerateIfThenElse(rng, &v, n_ifs, n_vars);
527 std::string str(v.begin(), v.end());
528 ParseIfThenElse(str);
529 }
530
531 void RunRandom(v8::base::RandomNumberGenerator* rng) {
532 // TODO(dcarney): permute inputs via model.
533 // TODO(dcarney): compute test_cases from n_ifs and n_vars.
534 int test_cases = 100;
535 for (int test = 0; test < test_cases; test++) {
536 Initialize();
537 for (int i = 0; i < offset_; i++) {
538 inputs_[i] = rng->NextBool();
539 }
540 DoCall();
541 }
542 }
543
544 void Run(const std::string& str, int32_t expected) {
545 Initialize();
546 int offset = 0;
547 for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
548 switch (*it) {
549 case 't':
550 inputs_[offset++] = 1;
551 break;
552 case 'f':
553 inputs_[offset++] = 0;
554 break;
555 default:
556 CHECK(false);
557 }
558 }
559 CHECK_EQ(offset_, offset);
560 // Call.
561 int32_t result = DoCall();
562 CHECK_EQ(result, expected);
563 }
564
565 private:
566 typedef std::vector<int32_t, zone_allocator<int32_t> > IOVector;
567
568 void InitializeConstants(int n_vars) {
569 CHECK(inputs_.is_empty());
570 inputs_.Reset(new int32_t[n_vars]);
571 outputs_.Reset(new int32_t[n_vars]);
572 }
573
574 void Initialize() {
575 for (int i = 0; i < offset_; i++) {
576 inputs_[i] = 0;
577 outputs_[i] = kUninitializedOutput;
578 }
579 }
580
581 int32_t DoCall() {
582 int32_t result = Call(inputs_.get(), outputs_.get());
583 int32_t expected = m_.Verify(offset_, inputs_.get(), outputs_.get());
584 CHECK_EQ(result, expected);
585 return result;
586 }
587
588 const v8::internal::compiler::Variable var_;
589 IfBuilder c_;
590 IfBuilderModel m_;
591 Node* one_;
592 int32_t offset_;
593 SmartArrayPointer<int32_t> inputs_;
594 SmartArrayPointer<int32_t> outputs_;
595 };
596
597
598 TEST(RunExpressionString) {
599 IfBuilderGenerator m;
600 m.ParseExpression("((v|v)|v)");
601 m.Run("ttt", kInitalVar + 1 * kIfInc + kThenInc);
602 m.Run("ftt", kInitalVar + 2 * kIfInc + kDisjunctionInc + kThenInc);
603 m.Run("fft", kInitalVar + 3 * kIfInc + 2 * kDisjunctionInc + kThenInc);
604 m.Run("fff", kInitalVar + 3 * kIfInc + 2 * kDisjunctionInc + kElseInc);
605 }
606
607
608 TEST(RunExpressionStrings) {
609 const char* strings[] = {
610 "v", "(v)", "((v))",
611 "v|v", "(v|v)", "((v|v))",
612 "v&v", "(v&v)", "((v&v))",
613 "v&(v)", "v&(v|v)", "v&(v|v)&v",
614 "v|(v)", "v|(v&v)", "v|(v&v)|v",
615 "v|(((v)|(v&v)|(v)|v)&(v))|v",
616 };
617 v8::base::RandomNumberGenerator rng;
618 for (size_t i = 0; i < ARRAY_SIZE(strings); i++) {
619 IfBuilderGenerator m;
620 m.ParseExpression(strings[i]);
621 m.RunRandom(&rng);
622 }
623 }
624
625
626 TEST(RunSimpleIfElseTester) {
627 const char* tests[] = {
628 "i(v)", "i(v)t", "i(v)te", "i(v)er",
629 "i(v)ter", "i(v)ti(v)trei(v)ei(v)ei(v)ei(v)ei(v)ei(v)ei(v)e"
630 };
631 v8::base::RandomNumberGenerator rng;
632 for (size_t i = 0; i < ARRAY_SIZE(tests); ++i) {
633 IfBuilderGenerator m;
634 m.ParseIfThenElse(tests[i]);
635 m.RunRandom(&rng);
636 }
637 }
638
639
640 TEST(RunRandomExpressions) {
641 v8::base::RandomNumberGenerator rng;
642 for (int n_vars = 1; n_vars < 12; n_vars++) {
643 for (int i = 0; i < n_vars * n_vars + 10; i++) {
644 IfBuilderGenerator m;
645 m.ParseRandomIfThenElse(&rng, 1, n_vars);
646 m.RunRandom(&rng);
647 }
648 }
649 }
650
651
652 TEST(RunRandomIfElse) {
653 v8::base::RandomNumberGenerator rng;
654 for (int n_ifs = 1; n_ifs < 12; n_ifs++) {
655 for (int i = 0; i < n_ifs * n_ifs + 10; i++) {
656 IfBuilderGenerator m;
657 m.ParseRandomIfThenElse(&rng, n_ifs, 1);
658 m.RunRandom(&rng);
659 }
660 }
661 }
662
663
664 TEST(RunRandomIfElseExpressions) {
665 v8::base::RandomNumberGenerator rng;
666 for (int n_vars = 2; n_vars < 6; n_vars++) {
667 for (int n_ifs = 2; n_ifs < 7; n_ifs++) {
668 for (int i = 0; i < n_ifs * n_vars + 10; i++) {
669 IfBuilderGenerator m;
670 m.ParseRandomIfThenElse(&rng, n_ifs, n_vars);
671 m.RunRandom(&rng);
672 }
673 }
674 }
675 }
676
677 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698