Index: test/cctest/compiler/test-structured-ifbuilder-fuzzer.cc |
diff --git a/test/cctest/compiler/test-structured-ifbuilder-fuzzer.cc b/test/cctest/compiler/test-structured-ifbuilder-fuzzer.cc |
deleted file mode 100644 |
index e1c82862ec2cf5b660040693515e18f0ff8d0bf9..0000000000000000000000000000000000000000 |
--- a/test/cctest/compiler/test-structured-ifbuilder-fuzzer.cc |
+++ /dev/null |
@@ -1,665 +0,0 @@ |
-// Copyright 2014 the V8 project authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include <string> |
- |
-#include "src/v8.h" |
-#include "test/cctest/cctest.h" |
- |
-#include "src/base/utils/random-number-generator.h" |
-#include "test/cctest/compiler/codegen-tester.h" |
- |
-#if V8_TURBOFAN_TARGET |
- |
-using namespace v8::internal; |
-using namespace v8::internal::compiler; |
- |
-typedef StructuredMachineAssembler::IfBuilder IfBuilder; |
-typedef StructuredMachineAssembler::LoopBuilder Loop; |
- |
-static const int32_t kUninitializedVariableOffset = -1; |
-static const int32_t kUninitializedOutput = -1; |
-static const int32_t kVerifiedOutput = -2; |
- |
-static const int32_t kInitalVar = 1013; |
-static const int32_t kConjunctionInc = 1069; |
-static const int32_t kDisjunctionInc = 1151; |
-static const int32_t kThenInc = 1223; |
-static const int32_t kElseInc = 1291; |
-static const int32_t kIfInc = 1373; |
- |
-class IfBuilderModel { |
- public: |
- explicit IfBuilderModel(Zone* zone) |
- : zone_(zone), |
- variable_offset_(0), |
- root_(new (zone_) Node(NULL)), |
- current_node_(root_), |
- current_expression_(NULL) {} |
- |
- void If() { |
- if (current_node_->else_node != NULL) { |
- current_node_ = current_node_->else_node; |
- } else if (current_node_->then_node != NULL) { |
- current_node_ = current_node_->then_node; |
- } |
- DCHECK(current_expression_ == NULL); |
- current_expression_ = new (zone_) Expression(zone_, NULL); |
- current_node_->condition = current_expression_; |
- } |
- void IfNode() { LastChild()->variable_offset = variable_offset_++; } |
- |
- void OpenParen() { current_expression_ = LastChild(); } |
- void CloseParen() { current_expression_ = current_expression_->parent; } |
- |
- void And() { NewChild()->conjunction = true; } |
- void Or() { NewChild()->disjunction = true; } |
- |
- void Then() { |
- DCHECK(current_expression_ == NULL || current_expression_->parent == NULL); |
- current_expression_ = NULL; |
- DCHECK(current_node_->then_node == NULL); |
- current_node_->then_node = new (zone_) Node(current_node_); |
- } |
- void Else() { |
- DCHECK(current_expression_ == NULL || current_expression_->parent == NULL); |
- current_expression_ = NULL; |
- DCHECK(current_node_->else_node == NULL); |
- current_node_->else_node = new (zone_) Node(current_node_); |
- } |
- void Return() { |
- if (current_node_->else_node != NULL) { |
- current_node_->else_node->returns = true; |
- } else if (current_node_->then_node != NULL) { |
- current_node_->then_node->returns = true; |
- } else { |
- CHECK(false); |
- } |
- } |
- void End() {} |
- |
- void Print(std::vector<char>* v) { PrintRecursive(v, root_); } |
- |
- struct VerificationState { |
- int32_t* inputs; |
- int32_t* outputs; |
- int32_t var; |
- }; |
- |
- int32_t Verify(int length, int32_t* inputs, int32_t* outputs) { |
- CHECK_EQ(variable_offset_, length); |
- // Input/Output verification. |
- for (int i = 0; i < length; ++i) { |
- CHECK(inputs[i] == 0 || inputs[i] == 1); |
- CHECK(outputs[i] == kUninitializedOutput || outputs[i] >= 0); |
- } |
- // Do verification. |
- VerificationState state; |
- state.inputs = inputs; |
- state.outputs = outputs; |
- state.var = kInitalVar; |
- VerifyRecursive(root_, &state); |
- // Verify all outputs marked. |
- for (int i = 0; i < length; ++i) { |
- CHECK(outputs[i] == kUninitializedOutput || |
- outputs[i] == kVerifiedOutput); |
- } |
- return state.var; |
- } |
- |
- private: |
- struct Expression; |
- typedef std::vector<Expression*, zone_allocator<Expression*> > Expressions; |
- |
- struct Expression : public ZoneObject { |
- Expression(Zone* zone, Expression* p) |
- : variable_offset(kUninitializedVariableOffset), |
- disjunction(false), |
- conjunction(false), |
- parent(p), |
- children(Expressions::allocator_type(zone)) {} |
- int variable_offset; |
- bool disjunction; |
- bool conjunction; |
- Expression* parent; |
- Expressions children; |
- |
- private: |
- DISALLOW_COPY_AND_ASSIGN(Expression); |
- }; |
- |
- struct Node : public ZoneObject { |
- explicit Node(Node* p) |
- : parent(p), |
- condition(NULL), |
- then_node(NULL), |
- else_node(NULL), |
- returns(false) {} |
- Node* parent; |
- Expression* condition; |
- Node* then_node; |
- Node* else_node; |
- bool returns; |
- |
- private: |
- DISALLOW_COPY_AND_ASSIGN(Node); |
- }; |
- |
- Expression* LastChild() { |
- if (current_expression_->children.empty()) { |
- current_expression_->children.push_back( |
- new (zone_) Expression(zone_, current_expression_)); |
- } |
- return current_expression_->children.back(); |
- } |
- |
- Expression* NewChild() { |
- Expression* child = new (zone_) Expression(zone_, current_expression_); |
- current_expression_->children.push_back(child); |
- return child; |
- } |
- |
- static void PrintRecursive(std::vector<char>* v, Expression* expression) { |
- CHECK(expression != NULL); |
- if (expression->conjunction) { |
- DCHECK(!expression->disjunction); |
- v->push_back('&'); |
- } else if (expression->disjunction) { |
- v->push_back('|'); |
- } |
- if (expression->variable_offset != kUninitializedVariableOffset) { |
- v->push_back('v'); |
- } |
- Expressions& children = expression->children; |
- if (children.empty()) return; |
- v->push_back('('); |
- for (Expressions::iterator i = children.begin(); i != children.end(); ++i) { |
- PrintRecursive(v, *i); |
- } |
- v->push_back(')'); |
- } |
- |
- static void PrintRecursive(std::vector<char>* v, Node* node) { |
- // Termination condition. |
- if (node->condition == NULL) { |
- CHECK(node->then_node == NULL && node->else_node == NULL); |
- if (node->returns) v->push_back('r'); |
- return; |
- } |
- CHECK(!node->returns); |
- v->push_back('i'); |
- PrintRecursive(v, node->condition); |
- if (node->then_node != NULL) { |
- v->push_back('t'); |
- PrintRecursive(v, node->then_node); |
- } |
- if (node->else_node != NULL) { |
- v->push_back('e'); |
- PrintRecursive(v, node->else_node); |
- } |
- } |
- |
- static bool VerifyRecursive(Expression* expression, |
- VerificationState* state) { |
- bool result = false; |
- bool first_iteration = true; |
- Expressions& children = expression->children; |
- CHECK(!children.empty()); |
- for (Expressions::iterator i = children.begin(); i != children.end(); ++i) { |
- Expression* child = *i; |
- // Short circuit evaluation, |
- // but mixes of &&s and ||s have weird semantics. |
- if ((child->conjunction && !result) || (child->disjunction && result)) { |
- continue; |
- } |
- if (child->conjunction) state->var += kConjunctionInc; |
- if (child->disjunction) state->var += kDisjunctionInc; |
- bool child_result; |
- if (child->variable_offset != kUninitializedVariableOffset) { |
- // Verify output |
- CHECK_EQ(state->var, state->outputs[child->variable_offset]); |
- state->outputs[child->variable_offset] = kVerifiedOutput; // Mark seen. |
- child_result = state->inputs[child->variable_offset]; |
- CHECK(child->children.empty()); |
- state->var += kIfInc; |
- } else { |
- child_result = VerifyRecursive(child, state); |
- } |
- if (child->conjunction) { |
- result &= child_result; |
- } else if (child->disjunction) { |
- result |= child_result; |
- } else { |
- CHECK(first_iteration); |
- result = child_result; |
- } |
- first_iteration = false; |
- } |
- return result; |
- } |
- |
- static void VerifyRecursive(Node* node, VerificationState* state) { |
- if (node->condition == NULL) return; |
- bool result = VerifyRecursive(node->condition, state); |
- if (result) { |
- if (node->then_node) { |
- state->var += kThenInc; |
- return VerifyRecursive(node->then_node, state); |
- } |
- } else { |
- if (node->else_node) { |
- state->var += kElseInc; |
- return VerifyRecursive(node->else_node, state); |
- } |
- } |
- } |
- |
- Zone* zone_; |
- int variable_offset_; |
- Node* root_; |
- Node* current_node_; |
- Expression* current_expression_; |
- DISALLOW_COPY_AND_ASSIGN(IfBuilderModel); |
-}; |
- |
- |
-class IfBuilderGenerator : public StructuredMachineAssemblerTester<int32_t> { |
- public: |
- IfBuilderGenerator() |
- : StructuredMachineAssemblerTester<int32_t>(kMachPtr, kMachPtr), |
- var_(NewVariable(Int32Constant(kInitalVar))), |
- c_(this), |
- m_(this->zone()), |
- one_(Int32Constant(1)), |
- offset_(0) {} |
- |
- static void GenerateExpression(v8::base::RandomNumberGenerator* rng, |
- std::vector<char>* v, int n_vars) { |
- int depth = 1; |
- v->push_back('('); |
- bool need_if = true; |
- bool populated = false; |
- while (n_vars != 0) { |
- if (need_if) { |
- // can nest a paren or do a variable |
- if (rng->NextBool()) { |
- v->push_back('v'); |
- n_vars--; |
- need_if = false; |
- populated = true; |
- } else { |
- v->push_back('('); |
- depth++; |
- populated = false; |
- } |
- } else { |
- // can pop, do && or do || |
- int options = 3; |
- if (depth == 1 || !populated) { |
- options--; |
- } |
- switch (rng->NextInt(options)) { |
- case 0: |
- v->push_back('&'); |
- need_if = true; |
- break; |
- case 1: |
- v->push_back('|'); |
- need_if = true; |
- break; |
- case 2: |
- v->push_back(')'); |
- depth--; |
- break; |
- } |
- } |
- } |
- CHECK(!need_if); |
- while (depth != 0) { |
- v->push_back(')'); |
- depth--; |
- } |
- } |
- |
- static void GenerateIfThenElse(v8::base::RandomNumberGenerator* rng, |
- std::vector<char>* v, int n_ifs, |
- int max_exp_length) { |
- CHECK_GT(n_ifs, 0); |
- CHECK_GT(max_exp_length, 0); |
- bool have_env = true; |
- bool then_done = false; |
- bool else_done = false; |
- bool first_iteration = true; |
- while (n_ifs != 0) { |
- if (have_env) { |
- int options = 3; |
- if (else_done || first_iteration) { // Don't do else or return |
- options -= 2; |
- first_iteration = false; |
- } |
- switch (rng->NextInt(options)) { |
- case 0: |
- v->push_back('i'); |
- n_ifs--; |
- have_env = false; |
- GenerateExpression(rng, v, rng->NextInt(max_exp_length) + 1); |
- break; |
- case 1: |
- v->push_back('r'); |
- have_env = false; |
- break; |
- case 2: |
- v->push_back('e'); |
- else_done = true; |
- then_done = false; |
- break; |
- default: |
- CHECK(false); |
- } |
- } else { // Can only do then or else |
- int options = 2; |
- if (then_done) options--; |
- switch (rng->NextInt(options)) { |
- case 0: |
- v->push_back('e'); |
- else_done = true; |
- then_done = false; |
- break; |
- case 1: |
- v->push_back('t'); |
- then_done = true; |
- else_done = false; |
- break; |
- default: |
- CHECK(false); |
- } |
- have_env = true; |
- } |
- } |
- // Last instruction must have been an if, can complete it in several ways. |
- int options = 2; |
- if (then_done && !else_done) options++; |
- switch (rng->NextInt(3)) { |
- case 0: |
- // Do nothing. |
- break; |
- case 1: |
- v->push_back('t'); |
- switch (rng->NextInt(3)) { |
- case 0: |
- v->push_back('r'); |
- break; |
- case 1: |
- v->push_back('e'); |
- break; |
- case 2: |
- v->push_back('e'); |
- v->push_back('r'); |
- break; |
- default: |
- CHECK(false); |
- } |
- break; |
- case 2: |
- v->push_back('e'); |
- if (rng->NextBool()) v->push_back('r'); |
- break; |
- default: |
- CHECK(false); |
- } |
- } |
- |
- std::string::const_iterator ParseExpression(std::string::const_iterator it, |
- std::string::const_iterator end) { |
- // Prepare for expression. |
- m_.If(); |
- c_.If(); |
- int depth = 0; |
- for (; it != end; ++it) { |
- switch (*it) { |
- case 'v': |
- m_.IfNode(); |
- { |
- Node* offset = Int32Constant(offset_ * 4); |
- Store(kMachInt32, Parameter(1), offset, var_.Get()); |
- var_.Set(Int32Add(var_.Get(), Int32Constant(kIfInc))); |
- c_.If(Load(kMachInt32, Parameter(0), offset)); |
- offset_++; |
- } |
- break; |
- case '&': |
- m_.And(); |
- c_.And(); |
- var_.Set(Int32Add(var_.Get(), Int32Constant(kConjunctionInc))); |
- break; |
- case '|': |
- m_.Or(); |
- c_.Or(); |
- var_.Set(Int32Add(var_.Get(), Int32Constant(kDisjunctionInc))); |
- break; |
- case '(': |
- if (depth != 0) { |
- m_.OpenParen(); |
- c_.OpenParen(); |
- } |
- depth++; |
- break; |
- case ')': |
- depth--; |
- if (depth == 0) return it; |
- m_.CloseParen(); |
- c_.CloseParen(); |
- break; |
- default: |
- CHECK(false); |
- } |
- } |
- CHECK(false); |
- return it; |
- } |
- |
- void ParseIfThenElse(const std::string& str) { |
- int n_vars = 0; |
- for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) { |
- if (*it == 'v') n_vars++; |
- } |
- InitializeConstants(n_vars); |
- for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) { |
- switch (*it) { |
- case 'i': { |
- it++; |
- CHECK(it != str.end()); |
- CHECK_EQ('(', *it); |
- it = ParseExpression(it, str.end()); |
- CHECK_EQ(')', *it); |
- break; |
- } |
- case 't': |
- m_.Then(); |
- c_.Then(); |
- var_.Set(Int32Add(var_.Get(), Int32Constant(kThenInc))); |
- break; |
- case 'e': |
- m_.Else(); |
- c_.Else(); |
- var_.Set(Int32Add(var_.Get(), Int32Constant(kElseInc))); |
- break; |
- case 'r': |
- m_.Return(); |
- Return(var_.Get()); |
- break; |
- default: |
- CHECK(false); |
- } |
- } |
- m_.End(); |
- c_.End(); |
- Return(var_.Get()); |
- // Compare generated model to parsed version. |
- { |
- std::vector<char> v; |
- m_.Print(&v); |
- std::string m_str(v.begin(), v.end()); |
- CHECK(m_str == str); |
- } |
- } |
- |
- void ParseExpression(const std::string& str) { |
- CHECK(inputs_.is_empty()); |
- std::string wrapped = "i(" + str + ")te"; |
- ParseIfThenElse(wrapped); |
- } |
- |
- void ParseRandomIfThenElse(v8::base::RandomNumberGenerator* rng, int n_ifs, |
- int n_vars) { |
- std::vector<char> v; |
- GenerateIfThenElse(rng, &v, n_ifs, n_vars); |
- std::string str(v.begin(), v.end()); |
- ParseIfThenElse(str); |
- } |
- |
- void RunRandom(v8::base::RandomNumberGenerator* rng) { |
- // TODO(dcarney): permute inputs via model. |
- // TODO(dcarney): compute test_cases from n_ifs and n_vars. |
- int test_cases = 100; |
- for (int test = 0; test < test_cases; test++) { |
- Initialize(); |
- for (int i = 0; i < offset_; i++) { |
- inputs_[i] = rng->NextBool(); |
- } |
- DoCall(); |
- } |
- } |
- |
- void Run(const std::string& str, int32_t expected) { |
- Initialize(); |
- int offset = 0; |
- for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) { |
- switch (*it) { |
- case 't': |
- inputs_[offset++] = 1; |
- break; |
- case 'f': |
- inputs_[offset++] = 0; |
- break; |
- default: |
- CHECK(false); |
- } |
- } |
- CHECK_EQ(offset_, offset); |
- // Call. |
- int32_t result = DoCall(); |
- CHECK_EQ(result, expected); |
- } |
- |
- private: |
- typedef std::vector<int32_t, zone_allocator<int32_t> > IOVector; |
- |
- void InitializeConstants(int n_vars) { |
- CHECK(inputs_.is_empty()); |
- inputs_.Reset(new int32_t[n_vars]); |
- outputs_.Reset(new int32_t[n_vars]); |
- } |
- |
- void Initialize() { |
- for (int i = 0; i < offset_; i++) { |
- inputs_[i] = 0; |
- outputs_[i] = kUninitializedOutput; |
- } |
- } |
- |
- int32_t DoCall() { |
- int32_t result = Call(inputs_.get(), outputs_.get()); |
- int32_t expected = m_.Verify(offset_, inputs_.get(), outputs_.get()); |
- CHECK_EQ(result, expected); |
- return result; |
- } |
- |
- const v8::internal::compiler::Variable var_; |
- IfBuilder c_; |
- IfBuilderModel m_; |
- Node* one_; |
- int32_t offset_; |
- SmartArrayPointer<int32_t> inputs_; |
- SmartArrayPointer<int32_t> outputs_; |
-}; |
- |
- |
-TEST(RunExpressionString) { |
- IfBuilderGenerator m; |
- m.ParseExpression("((v|v)|v)"); |
- m.Run("ttt", kInitalVar + 1 * kIfInc + kThenInc); |
- m.Run("ftt", kInitalVar + 2 * kIfInc + kDisjunctionInc + kThenInc); |
- m.Run("fft", kInitalVar + 3 * kIfInc + 2 * kDisjunctionInc + kThenInc); |
- m.Run("fff", kInitalVar + 3 * kIfInc + 2 * kDisjunctionInc + kElseInc); |
-} |
- |
- |
-TEST(RunExpressionStrings) { |
- const char* strings[] = { |
- "v", "(v)", "((v))", "v|v", |
- "(v|v)", "((v|v))", "v&v", "(v&v)", |
- "((v&v))", "v&(v)", "v&(v|v)", "v&(v|v)&v", |
- "v|(v)", "v|(v&v)", "v|(v&v)|v", "v|(((v)|(v&v)|(v)|v)&(v))|v", |
- }; |
- v8::base::RandomNumberGenerator rng; |
- for (size_t i = 0; i < arraysize(strings); i++) { |
- IfBuilderGenerator m; |
- m.ParseExpression(strings[i]); |
- m.RunRandom(&rng); |
- } |
-} |
- |
- |
-TEST(RunSimpleIfElseTester) { |
- const char* tests[] = { |
- "i(v)", "i(v)t", "i(v)te", |
- "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"}; |
- v8::base::RandomNumberGenerator rng; |
- for (size_t i = 0; i < arraysize(tests); ++i) { |
- IfBuilderGenerator m; |
- m.ParseIfThenElse(tests[i]); |
- m.RunRandom(&rng); |
- } |
-} |
- |
- |
-TEST(RunRandomExpressions) { |
- v8::base::RandomNumberGenerator rng; |
- for (int n_vars = 1; n_vars < 12; n_vars++) { |
- for (int i = 0; i < n_vars * n_vars + 10; i++) { |
- IfBuilderGenerator m; |
- m.ParseRandomIfThenElse(&rng, 1, n_vars); |
- m.RunRandom(&rng); |
- } |
- } |
-} |
- |
- |
-TEST(RunRandomIfElse) { |
- v8::base::RandomNumberGenerator rng; |
- for (int n_ifs = 1; n_ifs < 12; n_ifs++) { |
- for (int i = 0; i < n_ifs * n_ifs + 10; i++) { |
- IfBuilderGenerator m; |
- m.ParseRandomIfThenElse(&rng, n_ifs, 1); |
- m.RunRandom(&rng); |
- } |
- } |
-} |
- |
- |
-TEST(RunRandomIfElseExpressions) { |
- v8::base::RandomNumberGenerator rng; |
- for (int n_vars = 2; n_vars < 6; n_vars++) { |
- for (int n_ifs = 2; n_ifs < 7; n_ifs++) { |
- for (int i = 0; i < n_ifs * n_vars + 10; i++) { |
- IfBuilderGenerator m; |
- m.ParseRandomIfThenElse(&rng, n_ifs, n_vars); |
- m.RunRandom(&rng); |
- } |
- } |
- } |
-} |
- |
-#endif |