2014-07-30 13:54:45 +00:00
|
|
|
// 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;
|
|
|
|
}
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(current_expression_ == NULL);
|
2014-07-30 13:54:45 +00:00
|
|
|
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() {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(current_expression_ == NULL || current_expression_->parent == NULL);
|
2014-07-30 13:54:45 +00:00
|
|
|
current_expression_ = NULL;
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(current_node_->then_node == NULL);
|
2014-07-30 13:54:45 +00:00
|
|
|
current_node_->then_node = new (zone_) Node(current_node_);
|
|
|
|
}
|
|
|
|
void Else() {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(current_expression_ == NULL || current_expression_->parent == NULL);
|
2014-07-30 13:54:45 +00:00
|
|
|
current_expression_ = NULL;
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(current_node_->else_node == NULL);
|
2014-07-30 13:54:45 +00:00
|
|
|
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) {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(!expression->disjunction);
|
2014-07-30 13:54:45 +00:00
|
|
|
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()
|
2014-07-30 15:34:09 +00:00
|
|
|
: StructuredMachineAssemblerTester<int32_t>(
|
|
|
|
MachineOperatorBuilder::pointer_rep(),
|
|
|
|
MachineOperatorBuilder::pointer_rep()),
|
2014-07-30 13:54:45 +00:00
|
|
|
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);
|
2014-08-14 09:19:54 +00:00
|
|
|
Store(kMachInt32, Parameter(1), offset, var_.Get());
|
2014-07-30 13:54:45 +00:00
|
|
|
var_.Set(Int32Add(var_.Get(), Int32Constant(kIfInc)));
|
2014-08-14 09:19:54 +00:00
|
|
|
c_.If(Load(kMachInt32, Parameter(0), offset));
|
2014-07-30 13:54:45 +00:00
|
|
|
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 < ARRAY_SIZE(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 < ARRAY_SIZE(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
|