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

Side by Side Diff: test/cctest/compiler/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: Review feedback, rebase and "git cl format" 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(); i != children.end(); ++i) {
178 PrintRecursive(v, *i);
179 }
180 v->push_back(')');
181 }
182
183 static void PrintRecursive(std::vector<char>* v, Node* node) {
184 // Termination condition.
185 if (node->condition == NULL) {
186 CHECK(node->then_node == NULL && node->else_node == NULL);
187 if (node->returns) v->push_back('r');
188 return;
189 }
190 CHECK(!node->returns);
191 v->push_back('i');
192 PrintRecursive(v, node->condition);
193 if (node->then_node != NULL) {
194 v->push_back('t');
195 PrintRecursive(v, node->then_node);
196 }
197 if (node->else_node != NULL) {
198 v->push_back('e');
199 PrintRecursive(v, node->else_node);
200 }
201 }
202
203 static bool VerifyRecursive(Expression* expression,
204 VerificationState* state) {
205 bool result = false;
206 bool first_iteration = true;
207 Expressions& children = expression->children;
208 CHECK(!children.empty());
209 for (Expressions::iterator i = children.begin(); i != children.end(); ++i) {
210 Expression* child = *i;
211 // Short circuit evaluation,
212 // but mixes of &&s and ||s have weird semantics.
213 if ((child->conjunction && !result) || (child->disjunction && result)) {
214 continue;
215 }
216 if (child->conjunction) state->var += kConjunctionInc;
217 if (child->disjunction) state->var += kDisjunctionInc;
218 bool child_result;
219 if (child->variable_offset != kUninitializedVariableOffset) {
220 // Verify output
221 CHECK_EQ(state->var, state->outputs[child->variable_offset]);
222 state->outputs[child->variable_offset] = kVerifiedOutput; // Mark seen.
223 child_result = state->inputs[child->variable_offset];
224 CHECK(child->children.empty());
225 state->var += kIfInc;
226 } else {
227 child_result = VerifyRecursive(child, state);
228 }
229 if (child->conjunction) {
230 result &= child_result;
231 } else if (child->disjunction) {
232 result |= child_result;
233 } else {
234 CHECK(first_iteration);
235 result = child_result;
236 }
237 first_iteration = false;
238 }
239 return result;
240 }
241
242 static void VerifyRecursive(Node* node, VerificationState* state) {
243 if (node->condition == NULL) return;
244 bool result = VerifyRecursive(node->condition, state);
245 if (result) {
246 if (node->then_node) {
247 state->var += kThenInc;
248 return VerifyRecursive(node->then_node, state);
249 }
250 } else {
251 if (node->else_node) {
252 state->var += kElseInc;
253 return VerifyRecursive(node->else_node, state);
254 }
255 }
256 }
257
258 Zone* zone_;
259 int variable_offset_;
260 Node* root_;
261 Node* current_node_;
262 Expression* current_expression_;
263 DISALLOW_COPY_AND_ASSIGN(IfBuilderModel);
264 };
265
266
267 class IfBuilderGenerator : public StructuredMachineAssemblerTester<int32_t> {
268 public:
269 IfBuilderGenerator()
270 : StructuredMachineAssemblerTester(MachineOperatorBuilder::pointer_rep(),
271 MachineOperatorBuilder::pointer_rep()),
272 var_(NewVariable(Int32Constant(kInitalVar))),
273 c_(this),
274 m_(this->zone()),
275 one_(Int32Constant(1)),
276 offset_(0) {}
277
278 static void GenerateExpression(v8::base::RandomNumberGenerator* rng,
279 std::vector<char>* v, int n_vars) {
280 int depth = 1;
281 v->push_back('(');
282 bool need_if = true;
283 bool populated = false;
284 while (n_vars != 0) {
285 if (need_if) {
286 // can nest a paren or do a variable
287 if (rng->NextBool()) {
288 v->push_back('v');
289 n_vars--;
290 need_if = false;
291 populated = true;
292 } else {
293 v->push_back('(');
294 depth++;
295 populated = false;
296 }
297 } else {
298 // can pop, do && or do ||
299 int options = 3;
300 if (depth == 1 || !populated) {
301 options--;
302 }
303 switch (rng->NextInt(options)) {
304 case 0:
305 v->push_back('&');
306 need_if = true;
307 break;
308 case 1:
309 v->push_back('|');
310 need_if = true;
311 break;
312 case 2:
313 v->push_back(')');
314 depth--;
315 break;
316 }
317 }
318 }
319 CHECK(!need_if);
320 while (depth != 0) {
321 v->push_back(')');
322 depth--;
323 }
324 }
325
326 static void GenerateIfThenElse(v8::base::RandomNumberGenerator* rng,
327 std::vector<char>* v, int n_ifs,
328 int max_exp_length) {
329 CHECK_GT(n_ifs, 0);
330 CHECK_GT(max_exp_length, 0);
331 bool have_env = true;
332 bool then_done = false;
333 bool else_done = false;
334 bool first_iteration = true;
335 while (n_ifs != 0) {
336 if (have_env) {
337 int options = 3;
338 if (else_done || first_iteration) { // Don't do else or return
339 options -= 2;
340 first_iteration = false;
341 }
342 switch (rng->NextInt(options)) {
343 case 0:
344 v->push_back('i');
345 n_ifs--;
346 have_env = false;
347 GenerateExpression(rng, v, rng->NextInt(max_exp_length) + 1);
348 break;
349 case 1:
350 v->push_back('r');
351 have_env = false;
352 break;
353 case 2:
354 v->push_back('e');
355 else_done = true;
356 then_done = false;
357 break;
358 default:
359 CHECK(false);
360 }
361 } else { // Can only do then or else
362 int options = 2;
363 if (then_done) options--;
364 switch (rng->NextInt(options)) {
365 case 0:
366 v->push_back('e');
367 else_done = true;
368 then_done = false;
369 break;
370 case 1:
371 v->push_back('t');
372 then_done = true;
373 else_done = false;
374 break;
375 default:
376 CHECK(false);
377 }
378 have_env = true;
379 }
380 }
381 // Last instruction must have been an if, can complete it in several ways.
382 int options = 2;
383 if (then_done && !else_done) options++;
384 switch (rng->NextInt(3)) {
385 case 0:
386 // Do nothing.
387 break;
388 case 1:
389 v->push_back('t');
390 switch (rng->NextInt(3)) {
391 case 0:
392 v->push_back('r');
393 break;
394 case 1:
395 v->push_back('e');
396 break;
397 case 2:
398 v->push_back('e');
399 v->push_back('r');
400 break;
401 default:
402 CHECK(false);
403 }
404 break;
405 case 2:
406 v->push_back('e');
407 if (rng->NextBool()) v->push_back('r');
408 break;
409 default:
410 CHECK(false);
411 }
412 }
413
414 std::string::const_iterator ParseExpression(std::string::const_iterator it,
415 std::string::const_iterator end) {
416 // Prepare for expression.
417 m_.If();
418 c_.If();
419 int depth = 0;
420 for (; it != end; ++it) {
421 switch (*it) {
422 case 'v':
423 m_.IfNode();
424 {
425 Node* offset = Int32Constant(offset_ * 4);
426 Store(kMachineWord32, Parameter(1), offset, var_.Get());
427 var_.Set(Int32Add(var_.Get(), Int32Constant(kIfInc)));
428 c_.If(Load(kMachineWord32, Parameter(0), offset));
429 offset_++;
430 }
431 break;
432 case '&':
433 m_.And();
434 c_.And();
435 var_.Set(Int32Add(var_.Get(), Int32Constant(kConjunctionInc)));
436 break;
437 case '|':
438 m_.Or();
439 c_.Or();
440 var_.Set(Int32Add(var_.Get(), Int32Constant(kDisjunctionInc)));
441 break;
442 case '(':
443 if (depth != 0) {
444 m_.OpenParen();
445 c_.OpenParen();
446 }
447 depth++;
448 break;
449 case ')':
450 depth--;
451 if (depth == 0) return it;
452 m_.CloseParen();
453 c_.CloseParen();
454 break;
455 default:
456 CHECK(false);
457 }
458 }
459 CHECK(false);
460 return it;
461 }
462
463 void ParseIfThenElse(const std::string& str) {
464 int n_vars = 0;
465 for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
466 if (*it == 'v') n_vars++;
467 }
468 InitializeConstants(n_vars);
469 for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
470 switch (*it) {
471 case 'i': {
472 it++;
473 CHECK(it != str.end());
474 CHECK_EQ('(', *it);
475 it = ParseExpression(it, str.end());
476 CHECK_EQ(')', *it);
477 break;
478 }
479 case 't':
480 m_.Then();
481 c_.Then();
482 var_.Set(Int32Add(var_.Get(), Int32Constant(kThenInc)));
483 break;
484 case 'e':
485 m_.Else();
486 c_.Else();
487 var_.Set(Int32Add(var_.Get(), Int32Constant(kElseInc)));
488 break;
489 case 'r':
490 m_.Return();
491 Return(var_.Get());
492 break;
493 default:
494 CHECK(false);
495 }
496 }
497 m_.End();
498 c_.End();
499 Return(var_.Get());
500 // Compare generated model to parsed version.
501 {
502 std::vector<char> v;
503 m_.Print(&v);
504 std::string m_str(v.begin(), v.end());
505 CHECK(m_str == str);
506 }
507 }
508
509 void ParseExpression(const std::string& str) {
510 CHECK(inputs_.is_empty());
511 std::string wrapped = "i(" + str + ")te";
512 ParseIfThenElse(wrapped);
513 }
514
515 void ParseRandomIfThenElse(v8::base::RandomNumberGenerator* rng, int n_ifs,
516 int n_vars) {
517 std::vector<char> v;
518 GenerateIfThenElse(rng, &v, n_ifs, n_vars);
519 std::string str(v.begin(), v.end());
520 ParseIfThenElse(str);
521 }
522
523 void RunRandom(v8::base::RandomNumberGenerator* rng) {
524 // TODO(dcarney): permute inputs via model.
525 // TODO(dcarney): compute test_cases from n_ifs and n_vars.
526 int test_cases = 100;
527 for (int test = 0; test < test_cases; test++) {
528 Initialize();
529 for (int i = 0; i < offset_; i++) {
530 inputs_[i] = rng->NextBool();
531 }
532 DoCall();
533 }
534 }
535
536 void Run(const std::string& str, int32_t expected) {
537 Initialize();
538 int offset = 0;
539 for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
540 switch (*it) {
541 case 't':
542 inputs_[offset++] = 1;
543 break;
544 case 'f':
545 inputs_[offset++] = 0;
546 break;
547 default:
548 CHECK(false);
549 }
550 }
551 CHECK_EQ(offset_, offset);
552 // Call.
553 int32_t result = DoCall();
554 CHECK_EQ(result, expected);
555 }
556
557 private:
558 typedef std::vector<int32_t, zone_allocator<int32_t> > IOVector;
559
560 void InitializeConstants(int n_vars) {
561 CHECK(inputs_.is_empty());
562 inputs_.Reset(new int32_t[n_vars]);
563 outputs_.Reset(new int32_t[n_vars]);
564 }
565
566 void Initialize() {
567 for (int i = 0; i < offset_; i++) {
568 inputs_[i] = 0;
569 outputs_[i] = kUninitializedOutput;
570 }
571 }
572
573 int32_t DoCall() {
574 int32_t result = Call(inputs_.get(), outputs_.get());
575 int32_t expected = m_.Verify(offset_, inputs_.get(), outputs_.get());
576 CHECK_EQ(result, expected);
577 return result;
578 }
579
580 const v8::internal::compiler::Variable var_;
581 IfBuilder c_;
582 IfBuilderModel m_;
583 Node* one_;
584 int32_t offset_;
585 SmartArrayPointer<int32_t> inputs_;
586 SmartArrayPointer<int32_t> outputs_;
587 };
588
589
590 TEST(RunExpressionString) {
591 IfBuilderGenerator m;
592 m.ParseExpression("((v|v)|v)");
593 m.Run("ttt", kInitalVar + 1 * kIfInc + kThenInc);
594 m.Run("ftt", kInitalVar + 2 * kIfInc + kDisjunctionInc + kThenInc);
595 m.Run("fft", kInitalVar + 3 * kIfInc + 2 * kDisjunctionInc + kThenInc);
596 m.Run("fff", kInitalVar + 3 * kIfInc + 2 * kDisjunctionInc + kElseInc);
597 }
598
599
600 TEST(RunExpressionStrings) {
601 const char* strings[] = {
602 "v", "(v)", "((v))", "v|v",
603 "(v|v)", "((v|v))", "v&v", "(v&v)",
604 "((v&v))", "v&(v)", "v&(v|v)", "v&(v|v)&v",
605 "v|(v)", "v|(v&v)", "v|(v&v)|v", "v|(((v)|(v&v)|(v)|v)&(v))|v",
606 };
607 v8::base::RandomNumberGenerator rng;
608 for (size_t i = 0; i < ARRAY_SIZE(strings); i++) {
609 IfBuilderGenerator m;
610 m.ParseExpression(strings[i]);
611 m.RunRandom(&rng);
612 }
613 }
614
615
616 TEST(RunSimpleIfElseTester) {
617 const char* tests[] = {
618 "i(v)", "i(v)t", "i(v)te",
619 "i(v)er", "i(v)ter", "i(v)ti(v)trei(v)ei(v)ei(v)ei(v)ei(v)ei(v)ei(v)e"};
620 v8::base::RandomNumberGenerator rng;
621 for (size_t i = 0; i < ARRAY_SIZE(tests); ++i) {
622 IfBuilderGenerator m;
623 m.ParseIfThenElse(tests[i]);
624 m.RunRandom(&rng);
625 }
626 }
627
628
629 TEST(RunRandomExpressions) {
630 v8::base::RandomNumberGenerator rng;
631 for (int n_vars = 1; n_vars < 12; n_vars++) {
632 for (int i = 0; i < n_vars * n_vars + 10; i++) {
633 IfBuilderGenerator m;
634 m.ParseRandomIfThenElse(&rng, 1, n_vars);
635 m.RunRandom(&rng);
636 }
637 }
638 }
639
640
641 TEST(RunRandomIfElse) {
642 v8::base::RandomNumberGenerator rng;
643 for (int n_ifs = 1; n_ifs < 12; n_ifs++) {
644 for (int i = 0; i < n_ifs * n_ifs + 10; i++) {
645 IfBuilderGenerator m;
646 m.ParseRandomIfThenElse(&rng, n_ifs, 1);
647 m.RunRandom(&rng);
648 }
649 }
650 }
651
652
653 TEST(RunRandomIfElseExpressions) {
654 v8::base::RandomNumberGenerator rng;
655 for (int n_vars = 2; n_vars < 6; n_vars++) {
656 for (int n_ifs = 2; n_ifs < 7; n_ifs++) {
657 for (int i = 0; i < n_ifs * n_vars + 10; i++) {
658 IfBuilderGenerator m;
659 m.ParseRandomIfThenElse(&rng, n_ifs, n_vars);
660 m.RunRandom(&rng);
661 }
662 }
663 }
664 }
665
666 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698