'compiler/graph-tester.h',
'compiler/simplified-graph-builder.cc',
'compiler/simplified-graph-builder.h',
- 'compiler/structured-machine-assembler.cc',
- 'compiler/structured-machine-assembler.h',
'compiler/test-branch-combine.cc',
'compiler/test-changes-lowering.cc',
'compiler/test-codegen-deopt.cc',
'compiler/test-schedule.cc',
'compiler/test-scheduler.cc',
'compiler/test-simplified-lowering.cc',
- 'compiler/test-structured-ifbuilder-fuzzer.cc',
- 'compiler/test-structured-machine-assembler.cc',
'cctest.cc',
'gay-fixed.cc',
'gay-precision.cc',
#include "src/compiler/raw-machine-assembler.h"
#include "src/simulator.h"
#include "test/cctest/compiler/call-tester.h"
-#include "test/cctest/compiler/structured-machine-assembler.h"
namespace v8 {
namespace internal {
};
-template <typename ReturnType>
-class StructuredMachineAssemblerTester
- : public MachineAssemblerTester<StructuredMachineAssembler>,
- public CallHelper2<ReturnType,
- StructuredMachineAssemblerTester<ReturnType> > {
- public:
- StructuredMachineAssemblerTester(MachineType p0 = kMachNone,
- MachineType p1 = kMachNone,
- MachineType p2 = kMachNone,
- MachineType p3 = kMachNone,
- MachineType p4 = kMachNone)
- : MachineAssemblerTester<StructuredMachineAssembler>(
- ReturnValueTraits<ReturnType>::Representation(), p0, p1, p2, p3,
- p4) {}
-};
-
-
static const bool USE_RESULT_BUFFER = true;
static const bool USE_RETURN_REGISTER = false;
static const int32_t CHECK_VALUE = 0x99BEEDCE;
+++ /dev/null
-// 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 "src/compiler/pipeline.h"
-#include "src/compiler/scheduler.h"
-#include "test/cctest/compiler/structured-machine-assembler.h"
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-Node* Variable::Get() const { return smasm_->GetVariable(offset_); }
-
-
-void Variable::Set(Node* value) const { smasm_->SetVariable(offset_, value); }
-
-
-StructuredMachineAssembler::StructuredMachineAssembler(
- Graph* graph, MachineSignature* machine_sig, MachineType word)
- : RawMachineAssembler(graph, machine_sig, word),
- current_environment_(new (zone())
- Environment(zone(), schedule()->start(), false)),
- number_of_variables_(0) {}
-
-
-Node* StructuredMachineAssembler::MakeNode(Operator* op, int input_count,
- Node** inputs) {
- DCHECK(ScheduleValid());
- DCHECK(current_environment_ != NULL);
- Node* node = graph()->NewNode(op, input_count, inputs);
- BasicBlock* block = NULL;
- switch (op->opcode()) {
- case IrOpcode::kParameter:
- case IrOpcode::kInt32Constant:
- case IrOpcode::kInt64Constant:
- case IrOpcode::kFloat64Constant:
- case IrOpcode::kExternalConstant:
- case IrOpcode::kNumberConstant:
- case IrOpcode::kHeapConstant:
- // Parameters and constants must be in start.
- block = schedule()->start();
- break;
- default:
- // Verify all leaf nodes handled above.
- DCHECK((op->OutputCount() == 0) == (op->opcode() == IrOpcode::kStore));
- block = current_environment_->block_;
- break;
- }
- if (block != NULL) {
- schedule()->AddNode(block, node);
- }
- return node;
-}
-
-
-Variable StructuredMachineAssembler::NewVariable(Node* initial_value) {
- CHECK(initial_value != NULL);
- int offset = number_of_variables_++;
- // Extend current environment to correct number of values.
- NodeVector* variables = CurrentVars();
- size_t to_add = number_of_variables_ - variables->size();
- if (to_add != 0) {
- variables->reserve(number_of_variables_);
- variables->insert(variables->end(), to_add, NULL);
- }
- variables->at(offset) = initial_value;
- return Variable(this, offset);
-}
-
-
-Node* StructuredMachineAssembler::GetVariable(int offset) {
- DCHECK(ScheduleValid());
- return VariableAt(current_environment_, offset);
-}
-
-
-void StructuredMachineAssembler::SetVariable(int offset, Node* value) {
- DCHECK(ScheduleValid());
- Node*& ref = VariableAt(current_environment_, offset);
- ref = value;
-}
-
-
-Node*& StructuredMachineAssembler::VariableAt(Environment* environment,
- int32_t offset) {
- // Variable used out of scope.
- CHECK(static_cast<size_t>(offset) < environment->variables_.size());
- Node*& value = environment->variables_.at(offset);
- CHECK(value != NULL); // Variable used out of scope.
- return value;
-}
-
-
-void StructuredMachineAssembler::Return(Node* value) {
- BasicBlock* block = current_environment_->block_;
- if (block != NULL) {
- schedule()->AddReturn(block, value);
- }
- CopyCurrentAsDead();
-}
-
-
-void StructuredMachineAssembler::CopyCurrentAsDead() {
- DCHECK(current_environment_ != NULL);
- bool is_dead = current_environment_->is_dead_;
- current_environment_->is_dead_ = true;
- Environment* next = Copy(current_environment_);
- current_environment_->is_dead_ = is_dead;
- current_environment_ = next;
-}
-
-
-StructuredMachineAssembler::Environment* StructuredMachineAssembler::Copy(
- Environment* env, int truncate_at) {
- Environment* new_env = new (zone()) Environment(zone(), NULL, env->is_dead_);
- if (!new_env->is_dead_) {
- new_env->block_ = schedule()->NewBasicBlock();
- }
- new_env->variables_.reserve(truncate_at);
- NodeVectorIter end = env->variables_.end();
- DCHECK(truncate_at <= static_cast<int>(env->variables_.size()));
- end -= static_cast<int>(env->variables_.size()) - truncate_at;
- new_env->variables_.insert(new_env->variables_.begin(),
- env->variables_.begin(), end);
- return new_env;
-}
-
-
-StructuredMachineAssembler::Environment*
-StructuredMachineAssembler::CopyForLoopHeader(Environment* env) {
- Environment* new_env = new (zone()) Environment(zone(), NULL, env->is_dead_);
- if (!new_env->is_dead_) {
- new_env->block_ = schedule()->NewBasicBlock();
- }
- new_env->variables_.reserve(env->variables_.size());
- for (NodeVectorIter i = env->variables_.begin(); i != env->variables_.end();
- ++i) {
- Node* phi = NULL;
- if (*i != NULL) {
- phi = graph()->NewNode(common()->Phi(1), *i);
- if (new_env->block_ != NULL) {
- schedule()->AddNode(new_env->block_, phi);
- }
- }
- new_env->variables_.push_back(phi);
- }
- return new_env;
-}
-
-
-void StructuredMachineAssembler::MergeBackEdgesToLoopHeader(
- Environment* header, EnvironmentVector* environments) {
- // Only merge as many variables are were declared before this loop.
- int n = static_cast<int>(header->variables_.size());
- // TODO(dcarney): invert loop order and extend phis once.
- for (EnvironmentVector::iterator i = environments->begin();
- i != environments->end(); ++i) {
- Environment* from = *i;
- if (from->is_dead_) continue;
- AddGoto(from, header);
- for (int i = 0; i < n; ++i) {
- Node* phi = header->variables_[i];
- if (phi == NULL) continue;
- phi->set_op(common()->Phi(phi->InputCount() + 1));
- phi->AppendInput(zone(), VariableAt(from, i));
- }
- }
-}
-
-
-void StructuredMachineAssembler::Merge(EnvironmentVector* environments,
- int truncate_at) {
- DCHECK(current_environment_ == NULL || current_environment_->is_dead_);
- Environment* next = new (zone()) Environment(zone(), NULL, false);
- current_environment_ = next;
- size_t n_vars = number_of_variables_;
- NodeVector& vars = next->variables_;
- vars.reserve(n_vars);
- Node** scratch = NULL;
- size_t n_envs = environments->size();
- Environment** live_environments =
- zone()->NewArray<Environment*>(static_cast<int>(n_envs));
- size_t n_live = 0;
- for (size_t i = 0; i < n_envs; i++) {
- if (environments->at(i)->is_dead_) continue;
- live_environments[n_live++] = environments->at(i);
- }
- n_envs = n_live;
- if (n_live == 0) next->is_dead_ = true;
- if (!next->is_dead_) {
- next->block_ = schedule()->NewBasicBlock();
- }
- for (size_t j = 0; j < n_vars; ++j) {
- Node* resolved = NULL;
- // Find first non equal variable.
- size_t i = 0;
- for (; i < n_envs; i++) {
- DCHECK(live_environments[i]->variables_.size() <= n_vars);
- Node* val = NULL;
- if (j < static_cast<size_t>(truncate_at)) {
- val = live_environments[i]->variables_.at(j);
- // TODO(dcarney): record start position at time of split.
- // all variables after this should not be NULL.
- if (val != NULL) {
- val = VariableAt(live_environments[i], static_cast<int>(j));
- }
- }
- if (val == resolved) continue;
- if (i != 0) break;
- resolved = val;
- }
- // Have to generate a phi.
- if (i < n_envs) {
- // All values thus far uninitialized, variable used out of scope.
- CHECK(resolved != NULL);
- // Init scratch buffer.
- if (scratch == NULL) {
- scratch = zone()->NewArray<Node*>(static_cast<int>(n_envs));
- }
- for (size_t k = 0; k < i; k++) {
- scratch[k] = resolved;
- }
- for (; i < n_envs; i++) {
- scratch[i] = live_environments[i]->variables_[j];
- }
- resolved = graph()->NewNode(common()->Phi(static_cast<int>(n_envs)),
- static_cast<int>(n_envs), scratch);
- if (next->block_ != NULL) {
- schedule()->AddNode(next->block_, resolved);
- }
- }
- vars.push_back(resolved);
- }
-}
-
-
-void StructuredMachineAssembler::AddGoto(Environment* from, Environment* to) {
- if (to->is_dead_) {
- DCHECK(from->is_dead_);
- return;
- }
- DCHECK(!from->is_dead_);
- schedule()->AddGoto(from->block_, to->block_);
-}
-
-
-// TODO(dcarney): add pass before rpo to schedule to compute these.
-BasicBlock* StructuredMachineAssembler::TrampolineFor(BasicBlock* block) {
- BasicBlock* trampoline = schedule()->NewBasicBlock();
- schedule()->AddGoto(trampoline, block);
- return trampoline;
-}
-
-
-void StructuredMachineAssembler::AddBranch(Environment* environment,
- Node* condition,
- Environment* true_val,
- Environment* false_val) {
- DCHECK(environment->is_dead_ == true_val->is_dead_);
- DCHECK(environment->is_dead_ == false_val->is_dead_);
- if (true_val->block_ == false_val->block_) {
- if (environment->is_dead_) return;
- AddGoto(environment, true_val);
- return;
- }
- Node* branch = graph()->NewNode(common()->Branch(), condition);
- if (environment->is_dead_) return;
- BasicBlock* true_block = TrampolineFor(true_val->block_);
- BasicBlock* false_block = TrampolineFor(false_val->block_);
- schedule()->AddBranch(environment->block_, branch, true_block, false_block);
-}
-
-
-StructuredMachineAssembler::Environment::Environment(Zone* zone,
- BasicBlock* block,
- bool is_dead)
- : block_(block), variables_(zone), is_dead_(is_dead) {}
-
-
-StructuredMachineAssembler::IfBuilder::IfBuilder(
- StructuredMachineAssembler* smasm)
- : smasm_(smasm),
- if_clauses_(smasm_->zone()),
- pending_exit_merges_(smasm_->zone()) {
- DCHECK(smasm_->current_environment_ != NULL);
- PushNewIfClause();
- DCHECK(!IsDone());
-}
-
-
-StructuredMachineAssembler::IfBuilder&
-StructuredMachineAssembler::IfBuilder::If() {
- DCHECK(smasm_->current_environment_ != NULL);
- IfClause* clause = CurrentClause();
- if (clause->then_environment_ != NULL || clause->else_environment_ != NULL) {
- PushNewIfClause();
- }
- return *this;
-}
-
-
-StructuredMachineAssembler::IfBuilder&
-StructuredMachineAssembler::IfBuilder::If(Node* condition) {
- If();
- IfClause* clause = CurrentClause();
- // Store branch for future resolution.
- UnresolvedBranch* next = new (smasm_->zone())
- UnresolvedBranch(smasm_->current_environment_, condition, NULL);
- if (clause->unresolved_list_tail_ != NULL) {
- clause->unresolved_list_tail_->next_ = next;
- }
- clause->unresolved_list_tail_ = next;
- // Push onto merge queues.
- clause->pending_else_merges_.push_back(next);
- clause->pending_then_merges_.push_back(next);
- smasm_->current_environment_ = NULL;
- return *this;
-}
-
-
-void StructuredMachineAssembler::IfBuilder::And() {
- CurrentClause()->ResolvePendingMerges(smasm_, kCombineThen, kExpressionTerm);
-}
-
-
-void StructuredMachineAssembler::IfBuilder::Or() {
- CurrentClause()->ResolvePendingMerges(smasm_, kCombineElse, kExpressionTerm);
-}
-
-
-void StructuredMachineAssembler::IfBuilder::Then() {
- CurrentClause()->ResolvePendingMerges(smasm_, kCombineThen, kExpressionDone);
-}
-
-
-void StructuredMachineAssembler::IfBuilder::Else() {
- AddCurrentToPending();
- CurrentClause()->ResolvePendingMerges(smasm_, kCombineElse, kExpressionDone);
-}
-
-
-void StructuredMachineAssembler::IfBuilder::AddCurrentToPending() {
- if (smasm_->current_environment_ != NULL &&
- !smasm_->current_environment_->is_dead_) {
- pending_exit_merges_.push_back(smasm_->current_environment_);
- }
- smasm_->current_environment_ = NULL;
-}
-
-
-void StructuredMachineAssembler::IfBuilder::PushNewIfClause() {
- int curr_size =
- static_cast<int>(smasm_->current_environment_->variables_.size());
- IfClause* clause = new (smasm_->zone()) IfClause(smasm_->zone(), curr_size);
- if_clauses_.push_back(clause);
-}
-
-
-StructuredMachineAssembler::IfBuilder::IfClause::IfClause(
- Zone* zone, int initial_environment_size)
- : unresolved_list_tail_(NULL),
- initial_environment_size_(initial_environment_size),
- expression_states_(zone),
- pending_then_merges_(zone),
- pending_else_merges_(zone),
- then_environment_(NULL),
- else_environment_(NULL) {
- PushNewExpressionState();
-}
-
-
-StructuredMachineAssembler::IfBuilder::PendingMergeStackRange
-StructuredMachineAssembler::IfBuilder::IfClause::ComputeRelevantMerges(
- CombineType combine_type) {
- DCHECK(!expression_states_.empty());
- PendingMergeStack* stack;
- int start;
- if (combine_type == kCombineThen) {
- stack = &pending_then_merges_;
- start = expression_states_.back().pending_then_size_;
- } else {
- DCHECK(combine_type == kCombineElse);
- stack = &pending_else_merges_;
- start = expression_states_.back().pending_else_size_;
- }
- PendingMergeStackRange data;
- data.merge_stack_ = stack;
- data.start_ = start;
- data.size_ = static_cast<int>(stack->size()) - start;
- return data;
-}
-
-
-void StructuredMachineAssembler::IfBuilder::IfClause::ResolvePendingMerges(
- StructuredMachineAssembler* smasm, CombineType combine_type,
- ResolutionType resolution_type) {
- DCHECK(smasm->current_environment_ == NULL);
- PendingMergeStackRange data = ComputeRelevantMerges(combine_type);
- DCHECK_EQ(data.merge_stack_->back(), unresolved_list_tail_);
- DCHECK(data.size_ > 0);
- // TODO(dcarney): assert no new variables created during expression building.
- int truncate_at = initial_environment_size_;
- if (data.size_ == 1) {
- // Just copy environment in common case.
- smasm->current_environment_ =
- smasm->Copy(unresolved_list_tail_->environment_, truncate_at);
- } else {
- EnvironmentVector environments(smasm->zone());
- environments.reserve(data.size_);
- CopyEnvironments(data, &environments);
- DCHECK(static_cast<int>(environments.size()) == data.size_);
- smasm->Merge(&environments, truncate_at);
- }
- Environment* then_environment = then_environment_;
- Environment* else_environment = NULL;
- if (resolution_type == kExpressionDone) {
- DCHECK(expression_states_.size() == 1);
- // Set the current then_ or else_environment_ to the new merged environment.
- if (combine_type == kCombineThen) {
- DCHECK(then_environment_ == NULL && else_environment_ == NULL);
- this->then_environment_ = smasm->current_environment_;
- } else {
- DCHECK(else_environment_ == NULL);
- this->else_environment_ = smasm->current_environment_;
- }
- } else {
- DCHECK(resolution_type == kExpressionTerm);
- DCHECK(then_environment_ == NULL && else_environment_ == NULL);
- }
- if (combine_type == kCombineThen) {
- then_environment = smasm->current_environment_;
- } else {
- DCHECK(combine_type == kCombineElse);
- else_environment = smasm->current_environment_;
- }
- // Finalize branches and clear the pending stack.
- FinalizeBranches(smasm, data, combine_type, then_environment,
- else_environment);
-}
-
-
-void StructuredMachineAssembler::IfBuilder::IfClause::CopyEnvironments(
- const PendingMergeStackRange& data, EnvironmentVector* environments) {
- PendingMergeStack::iterator i = data.merge_stack_->begin();
- PendingMergeStack::iterator end = data.merge_stack_->end();
- for (i += data.start_; i != end; ++i) {
- environments->push_back((*i)->environment_);
- }
-}
-
-
-void StructuredMachineAssembler::IfBuilder::IfClause::PushNewExpressionState() {
- ExpressionState next;
- next.pending_then_size_ = static_cast<int>(pending_then_merges_.size());
- next.pending_else_size_ = static_cast<int>(pending_else_merges_.size());
- expression_states_.push_back(next);
-}
-
-
-void StructuredMachineAssembler::IfBuilder::IfClause::PopExpressionState() {
- expression_states_.pop_back();
- DCHECK(!expression_states_.empty());
-}
-
-
-void StructuredMachineAssembler::IfBuilder::IfClause::FinalizeBranches(
- StructuredMachineAssembler* smasm, const PendingMergeStackRange& data,
- CombineType combine_type, Environment* const then_environment,
- Environment* const else_environment) {
- DCHECK(unresolved_list_tail_ != NULL);
- DCHECK(smasm->current_environment_ != NULL);
- if (data.size_ == 0) return;
- PendingMergeStack::iterator curr = data.merge_stack_->begin();
- PendingMergeStack::iterator end = data.merge_stack_->end();
- // Finalize everything but the head first,
- // in the order the branches enter the merge block.
- end -= 1;
- Environment* true_val = then_environment;
- Environment* false_val = else_environment;
- Environment** next;
- if (combine_type == kCombineThen) {
- next = &false_val;
- } else {
- DCHECK(combine_type == kCombineElse);
- next = &true_val;
- }
- for (curr += data.start_; curr != end; ++curr) {
- UnresolvedBranch* branch = *curr;
- *next = branch->next_->environment_;
- smasm->AddBranch(branch->environment_, branch->condition_, true_val,
- false_val);
- }
- DCHECK(curr + 1 == data.merge_stack_->end());
- // Now finalize the tail if possible.
- if (then_environment != NULL && else_environment != NULL) {
- UnresolvedBranch* branch = *curr;
- smasm->AddBranch(branch->environment_, branch->condition_, then_environment,
- else_environment);
- }
- // Clear the merge stack.
- PendingMergeStack::iterator begin = data.merge_stack_->begin();
- begin += data.start_;
- data.merge_stack_->erase(begin, data.merge_stack_->end());
- DCHECK_EQ(static_cast<int>(data.merge_stack_->size()), data.start_);
-}
-
-
-void StructuredMachineAssembler::IfBuilder::End() {
- DCHECK(!IsDone());
- AddCurrentToPending();
- size_t current_pending = pending_exit_merges_.size();
- // All unresolved branch edges are now set to pending.
- for (IfClauses::iterator i = if_clauses_.begin(); i != if_clauses_.end();
- ++i) {
- IfClause* clause = *i;
- DCHECK(clause->expression_states_.size() == 1);
- PendingMergeStackRange data;
- // Copy then environments.
- data = clause->ComputeRelevantMerges(kCombineThen);
- clause->CopyEnvironments(data, &pending_exit_merges_);
- Environment* head = NULL;
- // Will resolve the head node in the else_merge
- if (data.size_ > 0 && clause->then_environment_ == NULL &&
- clause->else_environment_ == NULL) {
- head = pending_exit_merges_.back();
- pending_exit_merges_.pop_back();
- }
- // Copy else environments.
- data = clause->ComputeRelevantMerges(kCombineElse);
- clause->CopyEnvironments(data, &pending_exit_merges_);
- if (head != NULL) {
- // Must have data to merge, or else head will never get a branch.
- DCHECK(data.size_ != 0);
- pending_exit_merges_.push_back(head);
- }
- }
- smasm_->Merge(&pending_exit_merges_,
- if_clauses_[0]->initial_environment_size_);
- // Anything initally pending jumps into the new environment.
- for (size_t i = 0; i < current_pending; ++i) {
- smasm_->AddGoto(pending_exit_merges_[i], smasm_->current_environment_);
- }
- // Resolve all branches.
- for (IfClauses::iterator i = if_clauses_.begin(); i != if_clauses_.end();
- ++i) {
- IfClause* clause = *i;
- // Must finalize all environments, so ensure they are set correctly.
- Environment* then_environment = clause->then_environment_;
- if (then_environment == NULL) {
- then_environment = smasm_->current_environment_;
- }
- Environment* else_environment = clause->else_environment_;
- PendingMergeStackRange data;
- // Finalize then environments.
- data = clause->ComputeRelevantMerges(kCombineThen);
- clause->FinalizeBranches(smasm_, data, kCombineThen, then_environment,
- else_environment);
- // Finalize else environments.
- // Now set the else environment so head is finalized for edge case above.
- if (else_environment == NULL) {
- else_environment = smasm_->current_environment_;
- }
- data = clause->ComputeRelevantMerges(kCombineElse);
- clause->FinalizeBranches(smasm_, data, kCombineElse, then_environment,
- else_environment);
- }
- // Future accesses to this builder should crash immediately.
- pending_exit_merges_.clear();
- if_clauses_.clear();
- DCHECK(IsDone());
-}
-
-
-StructuredMachineAssembler::LoopBuilder::LoopBuilder(
- StructuredMachineAssembler* smasm)
- : smasm_(smasm),
- header_environment_(NULL),
- pending_header_merges_(smasm_->zone()),
- pending_exit_merges_(smasm_->zone()) {
- DCHECK(smasm_->current_environment_ != NULL);
- // Create header environment.
- header_environment_ = smasm_->CopyForLoopHeader(smasm_->current_environment_);
- smasm_->AddGoto(smasm_->current_environment_, header_environment_);
- // Create body environment.
- Environment* body = smasm_->Copy(header_environment_);
- smasm_->AddGoto(header_environment_, body);
- smasm_->current_environment_ = body;
- DCHECK(!IsDone());
-}
-
-
-void StructuredMachineAssembler::LoopBuilder::Continue() {
- DCHECK(!IsDone());
- pending_header_merges_.push_back(smasm_->current_environment_);
- smasm_->CopyCurrentAsDead();
-}
-
-
-void StructuredMachineAssembler::LoopBuilder::Break() {
- DCHECK(!IsDone());
- pending_exit_merges_.push_back(smasm_->current_environment_);
- smasm_->CopyCurrentAsDead();
-}
-
-
-void StructuredMachineAssembler::LoopBuilder::End() {
- DCHECK(!IsDone());
- if (smasm_->current_environment_ != NULL) {
- Continue();
- }
- // Do loop header merges.
- smasm_->MergeBackEdgesToLoopHeader(header_environment_,
- &pending_header_merges_);
- int initial_size = static_cast<int>(header_environment_->variables_.size());
- // Do loop exit merges, truncating loop variables away.
- smasm_->Merge(&pending_exit_merges_, initial_size);
- for (EnvironmentVector::iterator i = pending_exit_merges_.begin();
- i != pending_exit_merges_.end(); ++i) {
- smasm_->AddGoto(*i, smasm_->current_environment_);
- }
- pending_header_merges_.clear();
- pending_exit_merges_.clear();
- header_environment_ = NULL;
- DCHECK(IsDone());
-}
-
-} // namespace compiler
-} // namespace internal
-} // namespace v8
+++ /dev/null
-// 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.
-
-#ifndef V8_CCTEST_COMPILER_STRUCTURED_MACHINE_ASSEMBLER_H_
-#define V8_CCTEST_COMPILER_STRUCTURED_MACHINE_ASSEMBLER_H_
-
-#include "src/v8.h"
-
-#include "src/compiler/common-operator.h"
-#include "src/compiler/graph-builder.h"
-#include "src/compiler/machine-operator.h"
-#include "src/compiler/node.h"
-#include "src/compiler/operator.h"
-#include "src/compiler/raw-machine-assembler.h"
-
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-class BasicBlock;
-class Schedule;
-class StructuredMachineAssembler;
-
-
-class Variable : public ZoneObject {
- public:
- Node* Get() const;
- void Set(Node* value) const;
-
- private:
- Variable(StructuredMachineAssembler* smasm, int offset)
- : smasm_(smasm), offset_(offset) {}
-
- friend class StructuredMachineAssembler;
- friend class StructuredMachineAssemblerFriend;
- StructuredMachineAssembler* const smasm_;
- const int offset_;
-};
-
-
-class StructuredMachineAssembler : public RawMachineAssembler {
- public:
- class Environment : public ZoneObject {
- public:
- Environment(Zone* zone, BasicBlock* block, bool is_dead_);
-
- private:
- BasicBlock* block_;
- NodeVector variables_;
- bool is_dead_;
- friend class StructuredMachineAssembler;
- DISALLOW_COPY_AND_ASSIGN(Environment);
- };
-
- class IfBuilder;
- friend class IfBuilder;
- class LoopBuilder;
- friend class LoopBuilder;
-
- StructuredMachineAssembler(Graph* graph, MachineSignature* machine_sig,
- MachineType word = kMachPtr);
- virtual ~StructuredMachineAssembler() {}
-
- // Variables.
- Variable NewVariable(Node* initial_value);
- // Control flow.
- void Return(Node* value);
-
- protected:
- virtual Node* MakeNode(Operator* op, int input_count, Node** inputs);
-
- private:
- typedef ZoneVector<Environment*> EnvironmentVector;
-
- NodeVector* CurrentVars() { return ¤t_environment_->variables_; }
- Node*& VariableAt(Environment* environment, int offset);
- Node* GetVariable(int offset);
- void SetVariable(int offset, Node* value);
-
- void AddBranch(Environment* environment, Node* condition,
- Environment* true_val, Environment* false_val);
- void AddGoto(Environment* from, Environment* to);
- BasicBlock* TrampolineFor(BasicBlock* block);
-
- void CopyCurrentAsDead();
- Environment* Copy(Environment* environment) {
- return Copy(environment, static_cast<int>(environment->variables_.size()));
- }
- Environment* Copy(Environment* environment, int truncate_at);
- void Merge(EnvironmentVector* environments, int truncate_at);
- Environment* CopyForLoopHeader(Environment* environment);
- void MergeBackEdgesToLoopHeader(Environment* header,
- EnvironmentVector* environments);
-
- Environment* current_environment_;
- int number_of_variables_;
-
- friend class Variable;
- // For testing only.
- friend class StructuredMachineAssemblerFriend;
- DISALLOW_COPY_AND_ASSIGN(StructuredMachineAssembler);
-};
-
-// IfBuilder constructs of nested if-else expressions which more or less follow
-// C semantics. Foe example:
-//
-// if (x) {do_x} else if (y) {do_y} else {do_z}
-//
-// would look like this:
-//
-// IfBuilder b;
-// b.If(x).Then();
-// do_x
-// b.Else();
-// b.If().Then();
-// do_y
-// b.Else();
-// do_z
-// b.End();
-//
-// Then() and Else() can be skipped, representing an empty block in C.
-// Combinations like If(x).Then().If(x).Then() are legitimate, but
-// Else().Else() is not. That is, once you've nested an If(), you can't get to a
-// higher level If() branch.
-// TODO(dcarney): describe expressions once the api is finalized.
-class StructuredMachineAssembler::IfBuilder {
- public:
- explicit IfBuilder(StructuredMachineAssembler* smasm);
- ~IfBuilder() {
- if (!IsDone()) End();
- }
-
- IfBuilder& If(); // TODO(dcarney): this should take an expression.
- IfBuilder& If(Node* condition);
- void Then();
- void Else();
- void End();
-
- // The next 4 functions are exposed for expression support.
- // They will be private once I have a nice expression api.
- void And();
- void Or();
- IfBuilder& OpenParen() {
- DCHECK(smasm_->current_environment_ != NULL);
- CurrentClause()->PushNewExpressionState();
- return *this;
- }
- IfBuilder& CloseParen() {
- DCHECK(smasm_->current_environment_ == NULL);
- CurrentClause()->PopExpressionState();
- return *this;
- }
-
- private:
- // UnresolvedBranch represents the chain of environments created while
- // generating an expression. At this point, a branch Node
- // cannot be created, as the target environments of the branch are not yet
- // available, so everything required to create the branch Node is
- // stored in this structure until the target environments are resolved.
- struct UnresolvedBranch : public ZoneObject {
- UnresolvedBranch(Environment* environment, Node* condition,
- UnresolvedBranch* next)
- : environment_(environment), condition_(condition), next_(next) {}
- // environment_ will eventually be terminated by a branch on condition_.
- Environment* environment_;
- Node* condition_;
- // next_ is the next link in the UnresolvedBranch chain, and will be
- // either the true or false branch jumped to from environment_.
- UnresolvedBranch* next_;
- };
-
- struct ExpressionState {
- int pending_then_size_;
- int pending_else_size_;
- };
-
- typedef ZoneVector<ExpressionState> ExpressionStates;
- typedef ZoneVector<UnresolvedBranch*> PendingMergeStack;
- struct IfClause;
- typedef ZoneVector<IfClause*> IfClauses;
-
- struct PendingMergeStackRange {
- PendingMergeStack* merge_stack_;
- int start_;
- int size_;
- };
-
- enum CombineType { kCombineThen, kCombineElse };
- enum ResolutionType { kExpressionTerm, kExpressionDone };
-
- // IfClause represents one level of if-then-else nesting plus the associated
- // expression.
- // A call to If() triggers creation of a new nesting level after expression
- // creation is complete - ie Then() or Else() has been called.
- struct IfClause : public ZoneObject {
- IfClause(Zone* zone, int initial_environment_size);
- void CopyEnvironments(const PendingMergeStackRange& data,
- EnvironmentVector* environments);
- void ResolvePendingMerges(StructuredMachineAssembler* smasm,
- CombineType combine_type,
- ResolutionType resolution_type);
- PendingMergeStackRange ComputeRelevantMerges(CombineType combine_type);
- void FinalizeBranches(StructuredMachineAssembler* smasm,
- const PendingMergeStackRange& offset_data,
- CombineType combine_type,
- Environment* then_environment,
- Environment* else_environment);
- void PushNewExpressionState();
- void PopExpressionState();
-
- // Each invocation of And or Or creates a new UnresolvedBranch.
- // These form a singly-linked list, of which we only need to keep track of
- // the tail. On creation of an UnresolvedBranch, pending_then_merges_ and
- // pending_else_merges_ each push a copy, which are removed on merges to the
- // respective environment.
- UnresolvedBranch* unresolved_list_tail_;
- int initial_environment_size_;
- // expression_states_ keeps track of the state of pending_*_merges_,
- // pushing and popping the lengths of these on
- // OpenParend() and CloseParend() respectively.
- ExpressionStates expression_states_;
- PendingMergeStack pending_then_merges_;
- PendingMergeStack pending_else_merges_;
- // then_environment_ is created iff there is a call to Then(), otherwise
- // branches which would merge to it merge to the exit environment instead.
- // Likewise for else_environment_.
- Environment* then_environment_;
- Environment* else_environment_;
- };
-
- IfClause* CurrentClause() { return if_clauses_.back(); }
- void AddCurrentToPending();
- void PushNewIfClause();
- bool IsDone() { return if_clauses_.empty(); }
-
- StructuredMachineAssembler* smasm_;
- IfClauses if_clauses_;
- EnvironmentVector pending_exit_merges_;
- DISALLOW_COPY_AND_ASSIGN(IfBuilder);
-};
-
-
-class StructuredMachineAssembler::LoopBuilder {
- public:
- explicit LoopBuilder(StructuredMachineAssembler* smasm);
- ~LoopBuilder() {
- if (!IsDone()) End();
- }
-
- void Break();
- void Continue();
- void End();
-
- private:
- friend class StructuredMachineAssembler;
- bool IsDone() { return header_environment_ == NULL; }
-
- StructuredMachineAssembler* smasm_;
- Environment* header_environment_;
- EnvironmentVector pending_header_merges_;
- EnvironmentVector pending_exit_merges_;
- DISALLOW_COPY_AND_ASSIGN(LoopBuilder);
-};
-
-} // namespace compiler
-} // namespace internal
-} // namespace v8
-
-#endif // V8_CCTEST_COMPILER_STRUCTURED_MACHINE_ASSEMBLER_H_
+++ /dev/null
-// 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
+++ /dev/null
-// 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 "src/v8.h"
-#include "test/cctest/cctest.h"
-
-#include "src/base/utils/random-number-generator.h"
-#include "test/cctest/compiler/codegen-tester.h"
-#include "test/cctest/compiler/structured-machine-assembler.h"
-#include "test/cctest/compiler/value-helper.h"
-
-#if V8_TURBOFAN_TARGET
-
-using namespace v8::internal::compiler;
-
-typedef StructuredMachineAssembler::IfBuilder IfBuilder;
-typedef StructuredMachineAssembler::LoopBuilder Loop;
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-class StructuredMachineAssemblerFriend {
- public:
- static bool VariableAlive(StructuredMachineAssembler* m,
- const Variable& var) {
- CHECK(m->current_environment_ != NULL);
- int offset = var.offset_;
- return offset < static_cast<int>(m->CurrentVars()->size()) &&
- m->CurrentVars()->at(offset) != NULL;
- }
-};
-}
-}
-} // namespace v8::internal::compiler
-
-
-TEST(RunVariable) {
- StructuredMachineAssemblerTester<int32_t> m;
-
- int32_t constant = 0x86c2bb16;
-
- Variable v1 = m.NewVariable(m.Int32Constant(constant));
- Variable v2 = m.NewVariable(v1.Get());
- m.Return(v2.Get());
-
- CHECK_EQ(constant, m.Call());
-}
-
-
-TEST(RunSimpleIf) {
- StructuredMachineAssemblerTester<int32_t> m(kMachInt32);
-
- int32_t constant = 0xc4a3e3a6;
- {
- IfBuilder cond(&m);
- cond.If(m.Parameter(0)).Then();
- m.Return(m.Int32Constant(constant));
- }
- m.Return(m.Word32Not(m.Int32Constant(constant)));
-
- CHECK_EQ(~constant, m.Call(0));
- CHECK_EQ(constant, m.Call(1));
-}
-
-
-TEST(RunSimpleIfVariable) {
- StructuredMachineAssemblerTester<int32_t> m(kMachInt32);
-
- int32_t constant = 0xdb6f20c2;
- Variable var = m.NewVariable(m.Int32Constant(constant));
- {
- IfBuilder cond(&m);
- cond.If(m.Parameter(0)).Then();
- var.Set(m.Word32Not(var.Get()));
- }
- m.Return(var.Get());
-
- CHECK_EQ(constant, m.Call(0));
- CHECK_EQ(~constant, m.Call(1));
-}
-
-
-TEST(RunSimpleElse) {
- StructuredMachineAssemblerTester<int32_t> m(kMachInt32);
-
- int32_t constant = 0xfc5eadf4;
- {
- IfBuilder cond(&m);
- cond.If(m.Parameter(0)).Else();
- m.Return(m.Int32Constant(constant));
- }
- m.Return(m.Word32Not(m.Int32Constant(constant)));
-
- CHECK_EQ(constant, m.Call(0));
- CHECK_EQ(~constant, m.Call(1));
-}
-
-
-TEST(RunSimpleIfElse) {
- StructuredMachineAssemblerTester<int32_t> m(kMachInt32);
-
- int32_t constant = 0xaa9c8cd3;
- {
- IfBuilder cond(&m);
- cond.If(m.Parameter(0)).Then();
- m.Return(m.Int32Constant(constant));
- cond.Else();
- m.Return(m.Word32Not(m.Int32Constant(constant)));
- }
-
- CHECK_EQ(~constant, m.Call(0));
- CHECK_EQ(constant, m.Call(1));
-}
-
-
-TEST(RunSimpleIfElseVariable) {
- StructuredMachineAssemblerTester<int32_t> m(kMachInt32);
-
- int32_t constant = 0x67b6f39c;
- Variable var = m.NewVariable(m.Int32Constant(constant));
- {
- IfBuilder cond(&m);
- cond.If(m.Parameter(0)).Then();
- var.Set(m.Word32Not(m.Word32Not(var.Get())));
- cond.Else();
- var.Set(m.Word32Not(var.Get()));
- }
- m.Return(var.Get());
-
- CHECK_EQ(~constant, m.Call(0));
- CHECK_EQ(constant, m.Call(1));
-}
-
-
-TEST(RunSimpleIfNoThenElse) {
- StructuredMachineAssemblerTester<int32_t> m(kMachInt32);
-
- int32_t constant = 0xd5e550ed;
- {
- IfBuilder cond(&m);
- cond.If(m.Parameter(0));
- }
- m.Return(m.Int32Constant(constant));
-
- CHECK_EQ(constant, m.Call(0));
- CHECK_EQ(constant, m.Call(1));
-}
-
-
-TEST(RunSimpleConjunctionVariable) {
- StructuredMachineAssemblerTester<int32_t> m(kMachInt32);
-
- int32_t constant = 0xf8fb9ec6;
- Variable var = m.NewVariable(m.Int32Constant(constant));
- {
- IfBuilder cond(&m);
- cond.If(m.Int32Constant(1)).And();
- var.Set(m.Word32Not(var.Get()));
- cond.If(m.Parameter(0)).Then();
- var.Set(m.Word32Not(m.Word32Not(var.Get())));
- cond.Else();
- var.Set(m.Word32Not(var.Get()));
- }
- m.Return(var.Get());
-
- CHECK_EQ(constant, m.Call(0));
- CHECK_EQ(~constant, m.Call(1));
-}
-
-
-TEST(RunSimpleDisjunctionVariable) {
- StructuredMachineAssemblerTester<int32_t> m(kMachInt32);
-
- int32_t constant = 0x118f6ffc;
- Variable var = m.NewVariable(m.Int32Constant(constant));
- {
- IfBuilder cond(&m);
- cond.If(m.Int32Constant(0)).Or();
- var.Set(m.Word32Not(var.Get()));
- cond.If(m.Parameter(0)).Then();
- var.Set(m.Word32Not(m.Word32Not(var.Get())));
- cond.Else();
- var.Set(m.Word32Not(var.Get()));
- }
- m.Return(var.Get());
-
- CHECK_EQ(constant, m.Call(0));
- CHECK_EQ(~constant, m.Call(1));
-}
-
-
-TEST(RunIfElse) {
- StructuredMachineAssemblerTester<int32_t> m(kMachInt32);
-
- {
- IfBuilder cond(&m);
- bool first = true;
- FOR_INT32_INPUTS(i) {
- Node* c = m.Int32Constant(*i);
- if (first) {
- cond.If(m.Word32Equal(m.Parameter(0), c)).Then();
- m.Return(c);
- first = false;
- } else {
- cond.Else();
- cond.If(m.Word32Equal(m.Parameter(0), c)).Then();
- m.Return(c);
- }
- }
- }
- m.Return(m.Int32Constant(333));
-
- FOR_INT32_INPUTS(i) { CHECK_EQ(*i, m.Call(*i)); }
-}
-
-
-enum IfBuilderBranchType { kSkipBranch, kBranchFallsThrough, kBranchReturns };
-
-
-static IfBuilderBranchType all_branch_types[] = {
- kSkipBranch, kBranchFallsThrough, kBranchReturns};
-
-
-static void RunIfBuilderDisjunction(size_t max, IfBuilderBranchType then_type,
- IfBuilderBranchType else_type) {
- StructuredMachineAssemblerTester<int32_t> m(kMachInt32);
-
- std::vector<int32_t> inputs = ValueHelper::int32_vector();
- std::vector<int32_t>::const_iterator i = inputs.begin();
- int32_t hit = 0x8c723c9a;
- int32_t miss = 0x88a6b9f3;
- {
- Node* p0 = m.Parameter(0);
- IfBuilder cond(&m);
- for (size_t j = 0; j < max; j++, ++i) {
- CHECK(i != inputs.end()); // Thank you STL.
- if (j > 0) cond.Or();
- cond.If(m.Word32Equal(p0, m.Int32Constant(*i)));
- }
- switch (then_type) {
- case kSkipBranch:
- break;
- case kBranchFallsThrough:
- cond.Then();
- break;
- case kBranchReturns:
- cond.Then();
- m.Return(m.Int32Constant(hit));
- break;
- }
- switch (else_type) {
- case kSkipBranch:
- break;
- case kBranchFallsThrough:
- cond.Else();
- break;
- case kBranchReturns:
- cond.Else();
- m.Return(m.Int32Constant(miss));
- break;
- }
- }
- if (then_type != kBranchReturns || else_type != kBranchReturns) {
- m.Return(m.Int32Constant(miss));
- }
-
- if (then_type != kBranchReturns) hit = miss;
-
- i = inputs.begin();
- for (size_t j = 0; i != inputs.end(); j++, ++i) {
- int32_t result = m.Call(*i);
- CHECK_EQ(j < max ? hit : miss, result);
- }
-}
-
-
-TEST(RunIfBuilderDisjunction) {
- size_t len = ValueHelper::int32_vector().size() - 1;
- size_t max = len > 10 ? 10 : len - 1;
- for (size_t i = 0; i < arraysize(all_branch_types); i++) {
- for (size_t j = 0; j < arraysize(all_branch_types); j++) {
- for (size_t size = 1; size < max; size++) {
- RunIfBuilderDisjunction(size, all_branch_types[i], all_branch_types[j]);
- }
- RunIfBuilderDisjunction(len, all_branch_types[i], all_branch_types[j]);
- }
- }
-}
-
-
-static void RunIfBuilderConjunction(size_t max, IfBuilderBranchType then_type,
- IfBuilderBranchType else_type) {
- StructuredMachineAssemblerTester<int32_t> m(kMachInt32);
-
- std::vector<int32_t> inputs = ValueHelper::int32_vector();
- std::vector<int32_t>::const_iterator i = inputs.begin();
- int32_t hit = 0xa0ceb9ca;
- int32_t miss = 0x226cafaa;
- {
- IfBuilder cond(&m);
- Node* p0 = m.Parameter(0);
- for (size_t j = 0; j < max; j++, ++i) {
- if (j > 0) cond.And();
- cond.If(m.Word32NotEqual(p0, m.Int32Constant(*i)));
- }
- switch (then_type) {
- case kSkipBranch:
- break;
- case kBranchFallsThrough:
- cond.Then();
- break;
- case kBranchReturns:
- cond.Then();
- m.Return(m.Int32Constant(hit));
- break;
- }
- switch (else_type) {
- case kSkipBranch:
- break;
- case kBranchFallsThrough:
- cond.Else();
- break;
- case kBranchReturns:
- cond.Else();
- m.Return(m.Int32Constant(miss));
- break;
- }
- }
- if (then_type != kBranchReturns || else_type != kBranchReturns) {
- m.Return(m.Int32Constant(miss));
- }
-
- if (then_type != kBranchReturns) hit = miss;
-
- i = inputs.begin();
- for (size_t j = 0; i != inputs.end(); j++, ++i) {
- int32_t result = m.Call(*i);
- CHECK_EQ(j >= max ? hit : miss, result);
- }
-}
-
-
-TEST(RunIfBuilderConjunction) {
- size_t len = ValueHelper::int32_vector().size() - 1;
- size_t max = len > 10 ? 10 : len - 1;
- for (size_t i = 0; i < arraysize(all_branch_types); i++) {
- for (size_t j = 0; j < arraysize(all_branch_types); j++) {
- for (size_t size = 1; size < max; size++) {
- RunIfBuilderConjunction(size, all_branch_types[i], all_branch_types[j]);
- }
- RunIfBuilderConjunction(len, all_branch_types[i], all_branch_types[j]);
- }
- }
-}
-
-
-static void RunDisjunctionVariables(int disjunctions, bool explicit_then,
- bool explicit_else) {
- StructuredMachineAssemblerTester<int32_t> m(kMachInt32);
-
- int32_t constant = 0x65a09535;
-
- Node* cmp_val = m.Int32Constant(constant);
- Node* one = m.Int32Constant(1);
- Variable var = m.NewVariable(m.Parameter(0));
- {
- IfBuilder cond(&m);
- cond.If(m.Word32Equal(var.Get(), cmp_val));
- for (int i = 0; i < disjunctions; i++) {
- cond.Or();
- var.Set(m.Int32Add(var.Get(), one));
- cond.If(m.Word32Equal(var.Get(), cmp_val));
- }
- if (explicit_then) {
- cond.Then();
- }
- if (explicit_else) {
- cond.Else();
- var.Set(m.Int32Add(var.Get(), one));
- }
- }
- m.Return(var.Get());
-
- int adds = disjunctions + (explicit_else ? 1 : 0);
- int32_t input = constant - 2 * adds;
- for (int i = 0; i < adds; i++) {
- CHECK_EQ(input + adds, m.Call(input));
- input++;
- }
- for (int i = 0; i < adds + 1; i++) {
- CHECK_EQ(constant, m.Call(input));
- input++;
- }
- for (int i = 0; i < adds; i++) {
- CHECK_EQ(input + adds, m.Call(input));
- input++;
- }
-}
-
-
-TEST(RunDisjunctionVariables) {
- for (int disjunctions = 0; disjunctions < 10; disjunctions++) {
- RunDisjunctionVariables(disjunctions, false, false);
- RunDisjunctionVariables(disjunctions, false, true);
- RunDisjunctionVariables(disjunctions, true, false);
- RunDisjunctionVariables(disjunctions, true, true);
- }
-}
-
-
-static void RunConjunctionVariables(int conjunctions, bool explicit_then,
- bool explicit_else) {
- StructuredMachineAssemblerTester<int32_t> m(kMachInt32);
-
- int32_t constant = 0x2c7f4b45;
- Node* cmp_val = m.Int32Constant(constant);
- Node* one = m.Int32Constant(1);
- Variable var = m.NewVariable(m.Parameter(0));
- {
- IfBuilder cond(&m);
- cond.If(m.Word32NotEqual(var.Get(), cmp_val));
- for (int i = 0; i < conjunctions; i++) {
- cond.And();
- var.Set(m.Int32Add(var.Get(), one));
- cond.If(m.Word32NotEqual(var.Get(), cmp_val));
- }
- if (explicit_then) {
- cond.Then();
- var.Set(m.Int32Add(var.Get(), one));
- }
- if (explicit_else) {
- cond.Else();
- }
- }
- m.Return(var.Get());
-
- int adds = conjunctions + (explicit_then ? 1 : 0);
- int32_t input = constant - 2 * adds;
- for (int i = 0; i < adds; i++) {
- CHECK_EQ(input + adds, m.Call(input));
- input++;
- }
- for (int i = 0; i < adds + 1; i++) {
- CHECK_EQ(constant, m.Call(input));
- input++;
- }
- for (int i = 0; i < adds; i++) {
- CHECK_EQ(input + adds, m.Call(input));
- input++;
- }
-}
-
-
-TEST(RunConjunctionVariables) {
- for (int conjunctions = 0; conjunctions < 10; conjunctions++) {
- RunConjunctionVariables(conjunctions, false, false);
- RunConjunctionVariables(conjunctions, false, true);
- RunConjunctionVariables(conjunctions, true, false);
- RunConjunctionVariables(conjunctions, true, true);
- }
-}
-
-
-TEST(RunSimpleNestedIf) {
- StructuredMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
- const size_t NUM_VALUES = 7;
- std::vector<int32_t> inputs = ValueHelper::int32_vector();
- CHECK(inputs.size() >= NUM_VALUES);
- Node* values[NUM_VALUES];
- for (size_t j = 0; j < NUM_VALUES; j++) {
- values[j] = m.Int32Constant(inputs[j]);
- }
- {
- IfBuilder if_0(&m);
- if_0.If(m.Word32Equal(m.Parameter(0), values[0])).Then();
- {
- IfBuilder if_1(&m);
- if_1.If(m.Word32Equal(m.Parameter(1), values[1])).Then();
- { m.Return(values[3]); }
- if_1.Else();
- { m.Return(values[4]); }
- }
- if_0.Else();
- {
- IfBuilder if_1(&m);
- if_1.If(m.Word32Equal(m.Parameter(1), values[2])).Then();
- { m.Return(values[5]); }
- if_1.Else();
- { m.Return(values[6]); }
- }
- }
-
- int32_t result = m.Call(inputs[0], inputs[1]);
- CHECK_EQ(inputs[3], result);
-
- result = m.Call(inputs[0], inputs[1] + 1);
- CHECK_EQ(inputs[4], result);
-
- result = m.Call(inputs[0] + 1, inputs[2]);
- CHECK_EQ(inputs[5], result);
-
- result = m.Call(inputs[0] + 1, inputs[2] + 1);
- CHECK_EQ(inputs[6], result);
-}
-
-
-TEST(RunUnreachableBlockAfterIf) {
- StructuredMachineAssemblerTester<int32_t> m;
- {
- IfBuilder cond(&m);
- cond.If(m.Int32Constant(0)).Then();
- m.Return(m.Int32Constant(1));
- cond.Else();
- m.Return(m.Int32Constant(2));
- }
- // This is unreachable.
- m.Return(m.Int32Constant(3));
- CHECK_EQ(2, m.Call());
-}
-
-
-TEST(RunUnreachableBlockAfterLoop) {
- StructuredMachineAssemblerTester<int32_t> m;
- {
- Loop loop(&m);
- m.Return(m.Int32Constant(1));
- }
- // This is unreachable.
- m.Return(m.Int32Constant(3));
- CHECK_EQ(1, m.Call());
-}
-
-
-TEST(RunSimpleLoop) {
- StructuredMachineAssemblerTester<int32_t> m;
- int32_t constant = 0x120c1f85;
- {
- Loop loop(&m);
- m.Return(m.Int32Constant(constant));
- }
- CHECK_EQ(constant, m.Call());
-}
-
-
-TEST(RunSimpleLoopBreak) {
- StructuredMachineAssemblerTester<int32_t> m;
- int32_t constant = 0x10ddb0a6;
- {
- Loop loop(&m);
- loop.Break();
- }
- m.Return(m.Int32Constant(constant));
- CHECK_EQ(constant, m.Call());
-}
-
-
-TEST(RunCountToTen) {
- StructuredMachineAssemblerTester<int32_t> m;
- Variable i = m.NewVariable(m.Int32Constant(0));
- Node* ten = m.Int32Constant(10);
- Node* one = m.Int32Constant(1);
- {
- Loop loop(&m);
- {
- IfBuilder cond(&m);
- cond.If(m.Word32Equal(i.Get(), ten)).Then();
- loop.Break();
- }
- i.Set(m.Int32Add(i.Get(), one));
- }
- m.Return(i.Get());
- CHECK_EQ(10, m.Call());
-}
-
-
-TEST(RunCountToTenAcc) {
- StructuredMachineAssemblerTester<int32_t> m;
- int32_t constant = 0xf27aed64;
- Variable i = m.NewVariable(m.Int32Constant(0));
- Variable var = m.NewVariable(m.Int32Constant(constant));
- Node* ten = m.Int32Constant(10);
- Node* one = m.Int32Constant(1);
- {
- Loop loop(&m);
- {
- IfBuilder cond(&m);
- cond.If(m.Word32Equal(i.Get(), ten)).Then();
- loop.Break();
- }
- i.Set(m.Int32Add(i.Get(), one));
- var.Set(m.Int32Add(var.Get(), i.Get()));
- }
- m.Return(var.Get());
-
- CHECK_EQ(constant + 10 + 9 * 5, m.Call());
-}
-
-
-TEST(RunSimpleNestedLoop) {
- StructuredMachineAssemblerTester<int32_t> m(kMachInt32);
-
- Node* zero = m.Int32Constant(0);
- Node* one = m.Int32Constant(1);
- Node* two = m.Int32Constant(2);
- Node* three = m.Int32Constant(3);
- {
- Loop l1(&m);
- {
- Loop l2(&m);
- {
- IfBuilder cond(&m);
- cond.If(m.Word32Equal(m.Parameter(0), one)).Then();
- l1.Break();
- }
- {
- Loop l3(&m);
- {
- IfBuilder cond(&m);
- cond.If(m.Word32Equal(m.Parameter(0), two)).Then();
- l2.Break();
- cond.Else();
- cond.If(m.Word32Equal(m.Parameter(0), three)).Then();
- l3.Break();
- }
- m.Return(three);
- }
- m.Return(two);
- }
- m.Return(one);
- }
- m.Return(zero);
-
- CHECK_EQ(0, m.Call(1));
- CHECK_EQ(1, m.Call(2));
- CHECK_EQ(2, m.Call(3));
- CHECK_EQ(3, m.Call(4));
-}
-
-
-TEST(RunFib) {
- StructuredMachineAssemblerTester<int32_t> m(kMachInt32);
-
- // Constants.
- Node* zero = m.Int32Constant(0);
- Node* one = m.Int32Constant(1);
- Node* two = m.Int32Constant(2);
- // Variables.
- // cnt = input
- Variable cnt = m.NewVariable(m.Parameter(0));
- // if (cnt < 2) return i
- {
- IfBuilder lt2(&m);
- lt2.If(m.Int32LessThan(cnt.Get(), two)).Then();
- m.Return(cnt.Get());
- }
- // cnt -= 2
- cnt.Set(m.Int32Sub(cnt.Get(), two));
- // res = 1
- Variable res = m.NewVariable(one);
- {
- // prv_0 = 1
- // prv_1 = 1
- Variable prv_0 = m.NewVariable(one);
- Variable prv_1 = m.NewVariable(one);
- // while (cnt != 0) {
- Loop main(&m);
- {
- IfBuilder nz(&m);
- nz.If(m.Word32Equal(cnt.Get(), zero)).Then();
- main.Break();
- }
- // res = prv_0 + prv_1
- // prv_0 = prv_1
- // prv_1 = res
- res.Set(m.Int32Add(prv_0.Get(), prv_1.Get()));
- prv_0.Set(prv_1.Get());
- prv_1.Set(res.Get());
- // cnt--
- cnt.Set(m.Int32Sub(cnt.Get(), one));
- }
- m.Return(res.Get());
-
- int32_t values[] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144};
- for (size_t i = 0; i < arraysize(values); i++) {
- CHECK_EQ(values[i], m.Call(static_cast<int32_t>(i)));
- }
-}
-
-
-static int VariableIntroduction() {
- while (true) {
- int ret = 0;
- for (int i = 0; i < 10; i++) {
- for (int j = i; j < 10; j++) {
- for (int k = j; k < 10; k++) {
- ret++;
- }
- ret++;
- }
- ret++;
- }
- return ret;
- }
-}
-
-
-TEST(RunVariableIntroduction) {
- StructuredMachineAssemblerTester<int32_t> m;
- Node* zero = m.Int32Constant(0);
- Node* one = m.Int32Constant(1);
- // Use an IfBuilder to get out of start block.
- {
- IfBuilder i0(&m);
- i0.If(zero).Then();
- m.Return(one);
- }
- Node* ten = m.Int32Constant(10);
- Variable v0 =
- m.NewVariable(zero); // Introduce variable outside of start block.
- {
- Loop l0(&m);
- Variable ret = m.NewVariable(zero); // Introduce loop variable.
- {
- Loop l1(&m);
- {
- IfBuilder i1(&m);
- i1.If(m.Word32Equal(v0.Get(), ten)).Then();
- l1.Break();
- }
- Variable v1 = m.NewVariable(v0.Get()); // Introduce loop variable.
- {
- Loop l2(&m);
- {
- IfBuilder i2(&m);
- i2.If(m.Word32Equal(v1.Get(), ten)).Then();
- l2.Break();
- }
- Variable v2 = m.NewVariable(v1.Get()); // Introduce loop variable.
- {
- Loop l3(&m);
- {
- IfBuilder i3(&m);
- i3.If(m.Word32Equal(v2.Get(), ten)).Then();
- l3.Break();
- }
- ret.Set(m.Int32Add(ret.Get(), one));
- v2.Set(m.Int32Add(v2.Get(), one));
- }
- ret.Set(m.Int32Add(ret.Get(), one));
- v1.Set(m.Int32Add(v1.Get(), one));
- }
- ret.Set(m.Int32Add(ret.Get(), one));
- v0.Set(m.Int32Add(v0.Get(), one));
- }
- m.Return(ret.Get()); // Return loop variable.
- }
- CHECK_EQ(VariableIntroduction(), m.Call());
-}
-
-
-TEST(RunIfBuilderVariableLiveness) {
- StructuredMachineAssemblerTester<int32_t> m;
- typedef i::compiler::StructuredMachineAssemblerFriend F;
- Node* zero = m.Int32Constant(0);
- Variable v_outer = m.NewVariable(zero);
- IfBuilder cond(&m);
- cond.If(zero).Then();
- Variable v_then = m.NewVariable(zero);
- CHECK(F::VariableAlive(&m, v_outer));
- CHECK(F::VariableAlive(&m, v_then));
- cond.Else();
- Variable v_else = m.NewVariable(zero);
- CHECK(F::VariableAlive(&m, v_outer));
- CHECK(F::VariableAlive(&m, v_else));
- CHECK(!F::VariableAlive(&m, v_then));
- cond.End();
- CHECK(F::VariableAlive(&m, v_outer));
- CHECK(!F::VariableAlive(&m, v_then));
- CHECK(!F::VariableAlive(&m, v_else));
-}
-
-
-TEST(RunSimpleExpression1) {
- StructuredMachineAssemblerTester<int32_t> m;
-
- int32_t constant = 0x0c2974ef;
- Node* zero = m.Int32Constant(0);
- Node* one = m.Int32Constant(1);
- {
- // if (((1 && 1) && 1) && 1) return constant; return 0;
- IfBuilder cond(&m);
- cond.OpenParen();
- cond.OpenParen().If(one).And();
- cond.If(one).CloseParen().And();
- cond.If(one).CloseParen().And();
- cond.If(one).Then();
- m.Return(m.Int32Constant(constant));
- }
- m.Return(zero);
-
- CHECK_EQ(constant, m.Call());
-}
-
-
-TEST(RunSimpleExpression2) {
- StructuredMachineAssemblerTester<int32_t> m;
-
- int32_t constant = 0x2eddc11b;
- Node* zero = m.Int32Constant(0);
- Node* one = m.Int32Constant(1);
- {
- // if (((0 || 1) && 1) && 1) return constant; return 0;
- IfBuilder cond(&m);
- cond.OpenParen();
- cond.OpenParen().If(zero).Or();
- cond.If(one).CloseParen().And();
- cond.If(one).CloseParen().And();
- cond.If(one).Then();
- m.Return(m.Int32Constant(constant));
- }
- m.Return(zero);
-
- CHECK_EQ(constant, m.Call());
-}
-
-
-TEST(RunSimpleExpression3) {
- StructuredMachineAssemblerTester<int32_t> m;
-
- int32_t constant = 0x9ed5e9ef;
- Node* zero = m.Int32Constant(0);
- Node* one = m.Int32Constant(1);
- {
- // if (1 && ((0 || 1) && 1) && 1) return constant; return 0;
- IfBuilder cond(&m);
- cond.If(one).And();
- cond.OpenParen();
- cond.OpenParen().If(zero).Or();
- cond.If(one).CloseParen().And();
- cond.If(one).CloseParen().And();
- cond.If(one).Then();
- m.Return(m.Int32Constant(constant));
- }
- m.Return(zero);
-
- CHECK_EQ(constant, m.Call());
-}
-
-
-TEST(RunSimpleExpressionVariable1) {
- StructuredMachineAssemblerTester<int32_t> m;
-
- int32_t constant = 0x4b40a986;
- Node* one = m.Int32Constant(1);
- Variable var = m.NewVariable(m.Int32Constant(constant));
- {
- // if (var.Get() && ((!var || var) && var) && var) {} return var;
- // incrementing var in each environment.
- IfBuilder cond(&m);
- cond.If(var.Get()).And();
- var.Set(m.Int32Add(var.Get(), one));
- cond.OpenParen().OpenParen().If(m.Word32BinaryNot(var.Get())).Or();
- var.Set(m.Int32Add(var.Get(), one));
- cond.If(var.Get()).CloseParen().And();
- var.Set(m.Int32Add(var.Get(), one));
- cond.If(var.Get()).CloseParen().And();
- var.Set(m.Int32Add(var.Get(), one));
- cond.If(var.Get());
- }
- m.Return(var.Get());
-
- CHECK_EQ(constant + 4, m.Call());
-}
-
-
-class QuicksortHelper : public StructuredMachineAssemblerTester<int32_t> {
- public:
- QuicksortHelper()
- : StructuredMachineAssemblerTester<int32_t>(kMachPtr, kMachInt32,
- kMachPtr, kMachInt32),
- input_(NULL),
- stack_limit_(NULL),
- one_(Int32Constant(1)),
- stack_frame_size_(Int32Constant(kFrameVariables * 4)),
- left_offset_(Int32Constant(0 * 4)),
- right_offset_(Int32Constant(1 * 4)) {
- Build();
- }
-
- int32_t DoCall(int32_t* input, int32_t input_length) {
- int32_t stack_space[20];
- // Do call.
- int32_t return_val = Call(input, input_length, stack_space,
- static_cast<int32_t>(arraysize(stack_space)));
- // Ran out of stack space.
- if (return_val != 0) return return_val;
- // Check sorted.
- int32_t last = input[0];
- for (int32_t i = 0; i < input_length; i++) {
- CHECK(last <= input[i]);
- last = input[i];
- }
- return return_val;
- }
-
- private:
- void Inc32(const Variable& var) { var.Set(Int32Add(var.Get(), one_)); }
- Node* Index(Node* index) { return Word32Shl(index, Int32Constant(2)); }
- Node* ArrayLoad(Node* index) {
- return Load(kMachInt32, input_, Index(index));
- }
- void Swap(Node* a_index, Node* b_index) {
- Node* a = ArrayLoad(a_index);
- Node* b = ArrayLoad(b_index);
- Store(kMachInt32, input_, Index(a_index), b);
- Store(kMachInt32, input_, Index(b_index), a);
- }
- void AddToCallStack(const Variable& fp, Node* left, Node* right) {
- {
- // Stack limit check.
- IfBuilder cond(this);
- cond.If(IntPtrLessThanOrEqual(fp.Get(), stack_limit_)).Then();
- Return(Int32Constant(-1));
- }
- Store(kMachInt32, fp.Get(), left_offset_, left);
- Store(kMachInt32, fp.Get(), right_offset_, right);
- fp.Set(IntPtrAdd(fp.Get(), ConvertInt32ToIntPtr(stack_frame_size_)));
- }
- void Build() {
- Variable left = NewVariable(Int32Constant(0));
- Variable right =
- NewVariable(Int32Sub(Parameter(kInputLengthParameter), one_));
- input_ = Parameter(kInputParameter);
- Node* top_of_stack = Parameter(kStackParameter);
- stack_limit_ = IntPtrSub(
- top_of_stack, ConvertInt32ToIntPtr(Parameter(kStackLengthParameter)));
- Variable fp = NewVariable(top_of_stack);
- {
- Loop outermost(this);
- // Edge case - 2 element array.
- {
- IfBuilder cond(this);
- cond.If(Word32Equal(left.Get(), Int32Sub(right.Get(), one_))).And();
- cond.If(Int32LessThanOrEqual(ArrayLoad(right.Get()),
- ArrayLoad(left.Get()))).Then();
- Swap(left.Get(), right.Get());
- }
- {
- IfBuilder cond(this);
- // Algorithm complete condition.
- cond.If(WordEqual(top_of_stack, fp.Get())).And();
- cond.If(Int32LessThanOrEqual(Int32Sub(right.Get(), one_), left.Get()))
- .Then();
- outermost.Break();
- // 'Recursion' exit condition. Pop frame and continue.
- cond.Else();
- cond.If(Int32LessThanOrEqual(Int32Sub(right.Get(), one_), left.Get()))
- .Then();
- fp.Set(IntPtrSub(fp.Get(), ConvertInt32ToIntPtr(stack_frame_size_)));
- left.Set(Load(kMachInt32, fp.Get(), left_offset_));
- right.Set(Load(kMachInt32, fp.Get(), right_offset_));
- outermost.Continue();
- }
- // Partition.
- Variable store_index = NewVariable(left.Get());
- {
- Node* pivot_index =
- Int32Div(Int32Add(left.Get(), right.Get()), Int32Constant(2));
- Node* pivot = ArrayLoad(pivot_index);
- Swap(pivot_index, right.Get());
- Variable i = NewVariable(left.Get());
- {
- Loop partition(this);
- {
- IfBuilder cond(this);
- // Parition complete.
- cond.If(Word32Equal(i.Get(), right.Get())).Then();
- partition.Break();
- // Need swap.
- cond.Else();
- cond.If(Int32LessThanOrEqual(ArrayLoad(i.Get()), pivot)).Then();
- Swap(i.Get(), store_index.Get());
- Inc32(store_index);
- }
- Inc32(i);
- } // End partition loop.
- Swap(store_index.Get(), right.Get());
- }
- // 'Recurse' left and right halves of partition.
- // Tail recurse second one.
- AddToCallStack(fp, left.Get(), Int32Sub(store_index.Get(), one_));
- left.Set(Int32Add(store_index.Get(), one_));
- } // End outermost loop.
- Return(Int32Constant(0));
- }
-
- static const int kFrameVariables = 2; // left, right
- // Parameter offsets.
- static const int kInputParameter = 0;
- static const int kInputLengthParameter = 1;
- static const int kStackParameter = 2;
- static const int kStackLengthParameter = 3;
- // Function inputs.
- Node* input_;
- Node* stack_limit_;
- // Constants.
- Node* const one_;
- // Frame constants.
- Node* const stack_frame_size_;
- Node* const left_offset_;
- Node* const right_offset_;
-};
-
-
-TEST(RunSimpleQuicksort) {
- QuicksortHelper m;
- int32_t inputs[] = {9, 7, 1, 8, 11};
- CHECK_EQ(0, m.DoCall(inputs, arraysize(inputs)));
-}
-
-
-TEST(RunRandomQuicksort) {
- QuicksortHelper m;
-
- v8::base::RandomNumberGenerator rng;
- static const int kMaxLength = 40;
- int32_t inputs[kMaxLength];
-
- for (int length = 1; length < kMaxLength; length++) {
- for (int i = 0; i < 70; i++) {
- // Randomize inputs.
- for (int j = 0; j < length; j++) {
- inputs[j] = rng.NextInt(10) - 5;
- }
- CHECK_EQ(0, m.DoCall(inputs, length));
- }
- }
-}
-
-
-TEST(MultipleScopes) {
- StructuredMachineAssemblerTester<int32_t> m;
- for (int i = 0; i < 10; i++) {
- IfBuilder b(&m);
- b.If(m.Int32Constant(0)).Then();
- m.NewVariable(m.Int32Constant(0));
- }
- m.Return(m.Int32Constant(0));
- CHECK_EQ(0, m.Call());
-}
-
-#endif