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

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

Issue 544053002: [turbofan] Get rid of the StructuredMacroAssembler. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 3 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 DCHECK(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 DCHECK(current_expression_ == NULL || current_expression_->parent == NULL);
61 current_expression_ = NULL;
62 DCHECK(current_node_->then_node == NULL);
63 current_node_->then_node = new (zone_) Node(current_node_);
64 }
65 void Else() {
66 DCHECK(current_expression_ == NULL || current_expression_->parent == NULL);
67 current_expression_ = NULL;
68 DCHECK(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 DCHECK(!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<int32_t>(kMachPtr, kMachPtr),
271 var_(NewVariable(Int32Constant(kInitalVar))),
272 c_(this),
273 m_(this->zone()),
274 one_(Int32Constant(1)),
275 offset_(0) {}
276
277 static void GenerateExpression(v8::base::RandomNumberGenerator* rng,
278 std::vector<char>* v, int n_vars) {
279 int depth = 1;
280 v->push_back('(');
281 bool need_if = true;
282 bool populated = false;
283 while (n_vars != 0) {
284 if (need_if) {
285 // can nest a paren or do a variable
286 if (rng->NextBool()) {
287 v->push_back('v');
288 n_vars--;
289 need_if = false;
290 populated = true;
291 } else {
292 v->push_back('(');
293 depth++;
294 populated = false;
295 }
296 } else {
297 // can pop, do && or do ||
298 int options = 3;
299 if (depth == 1 || !populated) {
300 options--;
301 }
302 switch (rng->NextInt(options)) {
303 case 0:
304 v->push_back('&');
305 need_if = true;
306 break;
307 case 1:
308 v->push_back('|');
309 need_if = true;
310 break;
311 case 2:
312 v->push_back(')');
313 depth--;
314 break;
315 }
316 }
317 }
318 CHECK(!need_if);
319 while (depth != 0) {
320 v->push_back(')');
321 depth--;
322 }
323 }
324
325 static void GenerateIfThenElse(v8::base::RandomNumberGenerator* rng,
326 std::vector<char>* v, int n_ifs,
327 int max_exp_length) {
328 CHECK_GT(n_ifs, 0);
329 CHECK_GT(max_exp_length, 0);
330 bool have_env = true;
331 bool then_done = false;
332 bool else_done = false;
333 bool first_iteration = true;
334 while (n_ifs != 0) {
335 if (have_env) {
336 int options = 3;
337 if (else_done || first_iteration) { // Don't do else or return
338 options -= 2;
339 first_iteration = false;
340 }
341 switch (rng->NextInt(options)) {
342 case 0:
343 v->push_back('i');
344 n_ifs--;
345 have_env = false;
346 GenerateExpression(rng, v, rng->NextInt(max_exp_length) + 1);
347 break;
348 case 1:
349 v->push_back('r');
350 have_env = false;
351 break;
352 case 2:
353 v->push_back('e');
354 else_done = true;
355 then_done = false;
356 break;
357 default:
358 CHECK(false);
359 }
360 } else { // Can only do then or else
361 int options = 2;
362 if (then_done) options--;
363 switch (rng->NextInt(options)) {
364 case 0:
365 v->push_back('e');
366 else_done = true;
367 then_done = false;
368 break;
369 case 1:
370 v->push_back('t');
371 then_done = true;
372 else_done = false;
373 break;
374 default:
375 CHECK(false);
376 }
377 have_env = true;
378 }
379 }
380 // Last instruction must have been an if, can complete it in several ways.
381 int options = 2;
382 if (then_done && !else_done) options++;
383 switch (rng->NextInt(3)) {
384 case 0:
385 // Do nothing.
386 break;
387 case 1:
388 v->push_back('t');
389 switch (rng->NextInt(3)) {
390 case 0:
391 v->push_back('r');
392 break;
393 case 1:
394 v->push_back('e');
395 break;
396 case 2:
397 v->push_back('e');
398 v->push_back('r');
399 break;
400 default:
401 CHECK(false);
402 }
403 break;
404 case 2:
405 v->push_back('e');
406 if (rng->NextBool()) v->push_back('r');
407 break;
408 default:
409 CHECK(false);
410 }
411 }
412
413 std::string::const_iterator ParseExpression(std::string::const_iterator it,
414 std::string::const_iterator end) {
415 // Prepare for expression.
416 m_.If();
417 c_.If();
418 int depth = 0;
419 for (; it != end; ++it) {
420 switch (*it) {
421 case 'v':
422 m_.IfNode();
423 {
424 Node* offset = Int32Constant(offset_ * 4);
425 Store(kMachInt32, Parameter(1), offset, var_.Get());
426 var_.Set(Int32Add(var_.Get(), Int32Constant(kIfInc)));
427 c_.If(Load(kMachInt32, Parameter(0), offset));
428 offset_++;
429 }
430 break;
431 case '&':
432 m_.And();
433 c_.And();
434 var_.Set(Int32Add(var_.Get(), Int32Constant(kConjunctionInc)));
435 break;
436 case '|':
437 m_.Or();
438 c_.Or();
439 var_.Set(Int32Add(var_.Get(), Int32Constant(kDisjunctionInc)));
440 break;
441 case '(':
442 if (depth != 0) {
443 m_.OpenParen();
444 c_.OpenParen();
445 }
446 depth++;
447 break;
448 case ')':
449 depth--;
450 if (depth == 0) return it;
451 m_.CloseParen();
452 c_.CloseParen();
453 break;
454 default:
455 CHECK(false);
456 }
457 }
458 CHECK(false);
459 return it;
460 }
461
462 void ParseIfThenElse(const std::string& str) {
463 int n_vars = 0;
464 for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
465 if (*it == 'v') n_vars++;
466 }
467 InitializeConstants(n_vars);
468 for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
469 switch (*it) {
470 case 'i': {
471 it++;
472 CHECK(it != str.end());
473 CHECK_EQ('(', *it);
474 it = ParseExpression(it, str.end());
475 CHECK_EQ(')', *it);
476 break;
477 }
478 case 't':
479 m_.Then();
480 c_.Then();
481 var_.Set(Int32Add(var_.Get(), Int32Constant(kThenInc)));
482 break;
483 case 'e':
484 m_.Else();
485 c_.Else();
486 var_.Set(Int32Add(var_.Get(), Int32Constant(kElseInc)));
487 break;
488 case 'r':
489 m_.Return();
490 Return(var_.Get());
491 break;
492 default:
493 CHECK(false);
494 }
495 }
496 m_.End();
497 c_.End();
498 Return(var_.Get());
499 // Compare generated model to parsed version.
500 {
501 std::vector<char> v;
502 m_.Print(&v);
503 std::string m_str(v.begin(), v.end());
504 CHECK(m_str == str);
505 }
506 }
507
508 void ParseExpression(const std::string& str) {
509 CHECK(inputs_.is_empty());
510 std::string wrapped = "i(" + str + ")te";
511 ParseIfThenElse(wrapped);
512 }
513
514 void ParseRandomIfThenElse(v8::base::RandomNumberGenerator* rng, int n_ifs,
515 int n_vars) {
516 std::vector<char> v;
517 GenerateIfThenElse(rng, &v, n_ifs, n_vars);
518 std::string str(v.begin(), v.end());
519 ParseIfThenElse(str);
520 }
521
522 void RunRandom(v8::base::RandomNumberGenerator* rng) {
523 // TODO(dcarney): permute inputs via model.
524 // TODO(dcarney): compute test_cases from n_ifs and n_vars.
525 int test_cases = 100;
526 for (int test = 0; test < test_cases; test++) {
527 Initialize();
528 for (int i = 0; i < offset_; i++) {
529 inputs_[i] = rng->NextBool();
530 }
531 DoCall();
532 }
533 }
534
535 void Run(const std::string& str, int32_t expected) {
536 Initialize();
537 int offset = 0;
538 for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
539 switch (*it) {
540 case 't':
541 inputs_[offset++] = 1;
542 break;
543 case 'f':
544 inputs_[offset++] = 0;
545 break;
546 default:
547 CHECK(false);
548 }
549 }
550 CHECK_EQ(offset_, offset);
551 // Call.
552 int32_t result = DoCall();
553 CHECK_EQ(result, expected);
554 }
555
556 private:
557 typedef std::vector<int32_t, zone_allocator<int32_t> > IOVector;
558
559 void InitializeConstants(int n_vars) {
560 CHECK(inputs_.is_empty());
561 inputs_.Reset(new int32_t[n_vars]);
562 outputs_.Reset(new int32_t[n_vars]);
563 }
564
565 void Initialize() {
566 for (int i = 0; i < offset_; i++) {
567 inputs_[i] = 0;
568 outputs_[i] = kUninitializedOutput;
569 }
570 }
571
572 int32_t DoCall() {
573 int32_t result = Call(inputs_.get(), outputs_.get());
574 int32_t expected = m_.Verify(offset_, inputs_.get(), outputs_.get());
575 CHECK_EQ(result, expected);
576 return result;
577 }
578
579 const v8::internal::compiler::Variable var_;
580 IfBuilder c_;
581 IfBuilderModel m_;
582 Node* one_;
583 int32_t offset_;
584 SmartArrayPointer<int32_t> inputs_;
585 SmartArrayPointer<int32_t> outputs_;
586 };
587
588
589 TEST(RunExpressionString) {
590 IfBuilderGenerator m;
591 m.ParseExpression("((v|v)|v)");
592 m.Run("ttt", kInitalVar + 1 * kIfInc + kThenInc);
593 m.Run("ftt", kInitalVar + 2 * kIfInc + kDisjunctionInc + kThenInc);
594 m.Run("fft", kInitalVar + 3 * kIfInc + 2 * kDisjunctionInc + kThenInc);
595 m.Run("fff", kInitalVar + 3 * kIfInc + 2 * kDisjunctionInc + kElseInc);
596 }
597
598
599 TEST(RunExpressionStrings) {
600 const char* strings[] = {
601 "v", "(v)", "((v))", "v|v",
602 "(v|v)", "((v|v))", "v&v", "(v&v)",
603 "((v&v))", "v&(v)", "v&(v|v)", "v&(v|v)&v",
604 "v|(v)", "v|(v&v)", "v|(v&v)|v", "v|(((v)|(v&v)|(v)|v)&(v))|v",
605 };
606 v8::base::RandomNumberGenerator rng;
607 for (size_t i = 0; i < arraysize(strings); i++) {
608 IfBuilderGenerator m;
609 m.ParseExpression(strings[i]);
610 m.RunRandom(&rng);
611 }
612 }
613
614
615 TEST(RunSimpleIfElseTester) {
616 const char* tests[] = {
617 "i(v)", "i(v)t", "i(v)te",
618 "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"};
619 v8::base::RandomNumberGenerator rng;
620 for (size_t i = 0; i < arraysize(tests); ++i) {
621 IfBuilderGenerator m;
622 m.ParseIfThenElse(tests[i]);
623 m.RunRandom(&rng);
624 }
625 }
626
627
628 TEST(RunRandomExpressions) {
629 v8::base::RandomNumberGenerator rng;
630 for (int n_vars = 1; n_vars < 12; n_vars++) {
631 for (int i = 0; i < n_vars * n_vars + 10; i++) {
632 IfBuilderGenerator m;
633 m.ParseRandomIfThenElse(&rng, 1, n_vars);
634 m.RunRandom(&rng);
635 }
636 }
637 }
638
639
640 TEST(RunRandomIfElse) {
641 v8::base::RandomNumberGenerator rng;
642 for (int n_ifs = 1; n_ifs < 12; n_ifs++) {
643 for (int i = 0; i < n_ifs * n_ifs + 10; i++) {
644 IfBuilderGenerator m;
645 m.ParseRandomIfThenElse(&rng, n_ifs, 1);
646 m.RunRandom(&rng);
647 }
648 }
649 }
650
651
652 TEST(RunRandomIfElseExpressions) {
653 v8::base::RandomNumberGenerator rng;
654 for (int n_vars = 2; n_vars < 6; n_vars++) {
655 for (int n_ifs = 2; n_ifs < 7; n_ifs++) {
656 for (int i = 0; i < n_ifs * n_vars + 10; i++) {
657 IfBuilderGenerator m;
658 m.ParseRandomIfThenElse(&rng, n_ifs, n_vars);
659 m.RunRandom(&rng);
660 }
661 }
662 }
663 }
664
665 #endif
OLDNEW
« no previous file with comments | « test/cctest/compiler/structured-machine-assembler.cc ('k') | test/cctest/compiler/test-structured-machine-assembler.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698