v8/test/cctest/compiler/structured-machine-assembler.h

300 lines
9.6 KiB
C++

// 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-node-factory.h"
#include "src/compiler/machine-operator.h"
#include "src/compiler/node.h"
#include "src/compiler/operator.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 GraphBuilder,
public MachineNodeFactory<StructuredMachineAssembler> {
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() {}
Isolate* isolate() const { return zone()->isolate(); }
Zone* zone() const { return graph()->zone(); }
MachineOperatorBuilder* machine() { return &machine_; }
CommonOperatorBuilder* common() { return &common_; }
CallDescriptor* call_descriptor() const { return call_descriptor_; }
size_t parameter_count() const { return machine_sig_->parameter_count(); }
MachineSignature* machine_sig() const { return machine_sig_; }
// Parameters.
Node* Parameter(size_t index);
// Variables.
Variable NewVariable(Node* initial_value);
// Control flow.
void Return(Node* value);
// MachineAssembler is invalid after export.
Schedule* Export();
protected:
virtual Node* MakeNode(Operator* op, int input_count, Node** inputs);
Schedule* schedule() {
DCHECK(ScheduleValid());
return schedule_;
}
private:
bool ScheduleValid() { return schedule_ != NULL; }
typedef ZoneVector<Environment*> EnvironmentVector;
NodeVector* CurrentVars() { return &current_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);
Schedule* schedule_;
MachineOperatorBuilder machine_;
CommonOperatorBuilder common_;
MachineSignature* machine_sig_;
CallDescriptor* call_descriptor_;
Node** parameters_;
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_