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

Unified Diff: src/compiler/graph-assembler.h

Issue 2571903004: [turbofan] Introduce graph assembler to build effect-control-linearizer sub-graphs. (Closed)
Patch Set: Address reviewer comments Created 3 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/effect-control-linearizer.cc ('k') | src/compiler/graph-assembler.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/graph-assembler.h
diff --git a/src/compiler/graph-assembler.h b/src/compiler/graph-assembler.h
new file mode 100644
index 0000000000000000000000000000000000000000..b7a198fcabcdaa6fe3a0b85ffe5a4c195697be72
--- /dev/null
+++ b/src/compiler/graph-assembler.h
@@ -0,0 +1,426 @@
+// Copyright 2016 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_COMPILER_GRAPH_ASSEMBLER_H_
+#define V8_COMPILER_GRAPH_ASSEMBLER_H_
+
+#include "src/compiler/js-graph.h"
+#include "src/compiler/node.h"
+#include "src/compiler/simplified-operator.h"
+
+namespace v8 {
+namespace internal {
+
+class JSGraph;
+class Graph;
+
+namespace compiler {
+
+#define PURE_ASSEMBLER_MACH_UNOP_LIST(V) \
+ V(ChangeInt32ToInt64) \
+ V(ChangeInt32ToFloat64) \
+ V(ChangeUint32ToFloat64) \
+ V(ChangeUint32ToUint64) \
+ V(ChangeFloat64ToInt32) \
+ V(ChangeFloat64ToUint32) \
+ V(TruncateInt64ToInt32) \
+ V(RoundFloat64ToInt32) \
+ V(TruncateFloat64ToWord32) \
+ V(Float64ExtractHighWord32) \
+ V(Float64Abs)
+
+#define PURE_ASSEMBLER_MACH_BINOP_LIST(V) \
+ V(WordShl) \
+ V(WordSar) \
+ V(WordAnd) \
+ V(Word32Or) \
+ V(Word32And) \
+ V(Word32Shr) \
+ V(Word32Shl) \
+ V(Int32Add) \
+ V(Int32Sub) \
+ V(Int32Mul) \
+ V(Int32LessThanOrEqual) \
+ V(Uint32LessThanOrEqual) \
+ V(Uint32LessThan) \
+ V(Int32LessThan) \
+ V(Float64Add) \
+ V(Float64Sub) \
+ V(Float64Mod) \
+ V(Float64Equal) \
+ V(Float64LessThan) \
+ V(Float64LessThanOrEqual) \
+ V(Word32Equal) \
+ V(WordEqual)
+
+#define CHECKED_ASSEMBLER_MACH_BINOP_LIST(V) \
+ V(Int32AddWithOverflow) \
+ V(Int32SubWithOverflow) \
+ V(Int32MulWithOverflow) \
+ V(Int32Mod) \
+ V(Int32Div) \
+ V(Uint32Mod) \
+ V(Uint32Div)
+
+class GraphAssembler;
+
+enum class GraphAssemblerLabelType { kDeferred, kNonDeferred };
+
+// Label with statically known count of incoming branches and phis.
+template <size_t MergeCount, size_t VarCount = 0u>
+class GraphAssemblerStaticLabel {
+ public:
+ Node* PhiAt(size_t index);
+
+ template <typename... Reps>
+ explicit GraphAssemblerStaticLabel(GraphAssemblerLabelType is_deferred,
+ Reps... reps)
+ : is_deferred_(is_deferred == GraphAssemblerLabelType::kDeferred) {
+ STATIC_ASSERT(VarCount == sizeof...(reps));
+ MachineRepresentation reps_array[] = {MachineRepresentation::kNone,
+ reps...};
+ for (size_t i = 0; i < VarCount; i++) {
+ representations_[i] = reps_array[i + 1];
+ }
+ }
+
+ ~GraphAssemblerStaticLabel() { DCHECK(IsBound() || MergedCount() == 0); }
+
+ private:
+ friend class GraphAssembler;
+
+ void SetBound() {
+ DCHECK(!IsBound());
+ DCHECK_EQ(merged_count_, MergeCount);
+ is_bound_ = true;
+ }
+ bool IsBound() const { return is_bound_; }
+
+ size_t PhiCount() const { return VarCount; }
+ size_t MaxMergeCount() const { return MergeCount; }
+ size_t MergedCount() const { return merged_count_; }
+ bool IsDeferred() const { return is_deferred_; }
+
+ // For each phi, the buffer must have at least MaxMergeCount() + 1
+ // node entries.
+ Node** GetBindingsPtrFor(size_t phi_index) {
+ DCHECK_LT(phi_index, PhiCount());
+ return &bindings_[phi_index * (MergeCount + 1)];
+ }
+ void SetBinding(size_t phi_index, size_t merge_index, Node* binding) {
+ DCHECK_LT(phi_index, PhiCount());
+ DCHECK_LT(merge_index, MergeCount);
+ bindings_[phi_index * (MergeCount + 1) + merge_index] = binding;
+ }
+ MachineRepresentation GetRepresentationFor(size_t phi_index) {
+ DCHECK_LT(phi_index, PhiCount());
+ return representations_[phi_index];
+ }
+ // The controls buffer must have at least MaxMergeCount() entries.
+ Node** GetControlsPtr() { return controls_; }
+ // The effects buffer must have at least MaxMergeCount() + 1 entries.
+ Node** GetEffectsPtr() { return effects_; }
+ void IncrementMergedCount() { merged_count_++; }
+
+ bool is_bound_ = false;
+ bool is_deferred_;
+ size_t merged_count_ = 0;
+ Node* effects_[MergeCount + 1]; // Extra element for control edge,
+ // so that we can use the array to
+ // construct EffectPhi.
+ Node* controls_[MergeCount];
+ Node* bindings_[(MergeCount + 1) * VarCount + 1];
+ MachineRepresentation representations_[VarCount + 1];
+};
+
+// General label (with zone allocated buffers for incoming branches and phi
+// inputs).
+class GraphAssemblerLabel {
+ public:
+ Node* PhiAt(size_t index);
+
+ GraphAssemblerLabel(GraphAssemblerLabelType is_deferred, size_t merge_count,
+ size_t var_count, MachineRepresentation* representations,
+ Zone* zone);
+
+ ~GraphAssemblerLabel();
+
+ private:
+ friend class GraphAssembler;
+
+ void SetBound() {
+ DCHECK(!is_bound_);
+ is_bound_ = true;
+ }
+ bool IsBound() const { return is_bound_; }
+ size_t PhiCount() const { return var_count_; }
+ size_t MaxMergeCount() const { return max_merge_count_; }
+ size_t MergedCount() const { return merged_count_; }
+ bool IsDeferred() const { return is_deferred_; }
+
+ // For each phi, the buffer must have at least MaxMergeCount() + 1
+ // node entries.
+ Node** GetBindingsPtrFor(size_t phi_index);
+ void SetBinding(size_t phi_index, size_t merge_index, Node* binding);
+ MachineRepresentation GetRepresentationFor(size_t phi_index);
+ // The controls buffer must have at least MaxMergeCount() entries.
+ Node** GetControlsPtr();
+ // The effects buffer must have at least MaxMergeCount() + 1 entries.
+ Node** GetEffectsPtr();
+ void IncrementMergedCount() { merged_count_++; }
+
+ bool is_bound_ = false;
+ bool is_deferred_;
+ size_t merged_count_ = 0;
+ size_t max_merge_count_;
+ size_t var_count_;
+ Node** effects_ = nullptr;
+ Node** controls_ = nullptr;
+ Node** bindings_ = nullptr;
+ MachineRepresentation* representations_ = nullptr;
+};
+
+class GraphAssembler {
+ public:
+ GraphAssembler(JSGraph* jsgraph, Node* effect, Node* control, Zone* zone);
+
+ void Reset(Node* effect, Node* control);
+
+ // Create non-deferred label with statically known number of incoming
+ // gotos/branches.
+ template <size_t MergeCount, typename... Reps>
+ static GraphAssemblerStaticLabel<MergeCount, sizeof...(Reps)> MakeLabel(
+ Reps... reps) {
+ return GraphAssemblerStaticLabel<MergeCount, sizeof...(Reps)>(
+ GraphAssemblerLabelType::kNonDeferred, reps...);
+ }
+
+ // Create deferred label with statically known number of incoming
+ // gotos/branches.
+ template <size_t MergeCount, typename... Reps>
+ static GraphAssemblerStaticLabel<MergeCount, sizeof...(Reps)>
+ MakeDeferredLabel(Reps... reps) {
+ return GraphAssemblerStaticLabel<MergeCount, sizeof...(Reps)>(
+ GraphAssemblerLabelType::kDeferred, reps...);
+ }
+
+ // Create label with number of incoming branches supplied at runtime.
+ template <typename... Reps>
+ GraphAssemblerLabel MakeLabelFor(GraphAssemblerLabelType is_deferred,
+ size_t merge_count, Reps... reps) {
+ MachineRepresentation reps_array[] = {MachineRepresentation::kNone,
+ reps...};
+ return GraphAssemblerLabel(is_deferred, merge_count, sizeof...(reps),
+ &(reps_array[1]), temp_zone());
+ }
+
+ // Value creation.
+ Node* TrueConstant();
+ Node* FalseConstant();
+ Node* HeapNumberMapConstant();
+ Node* IntPtrConstant(intptr_t value);
+ Node* Uint32Constant(int32_t value);
+ Node* Int32Constant(int32_t value);
+ Node* SmiConstant(int32_t value);
+ Node* Float64Constant(double value);
+ Node* Projection(int index, Node* value);
+ Node* HeapConstant(Handle<HeapObject> object);
+ Node* NoContextConstant();
+ Node* CEntryStubConstant(int result_size);
+ Node* ExternalConstant(ExternalReference ref);
+ Node* EmptyStringConstant();
+ Node* UndefinedConstant();
+ Node* TheHoleConstant();
+ Node* FixedArrayMapConstant();
+
+#define PURE_UNOP_DECL(Name) Node* Name(Node* input);
+ PURE_ASSEMBLER_MACH_UNOP_LIST(PURE_UNOP_DECL)
+#undef PURE_UNOP_DECL
+
+#define BINOP_DECL(Name) Node* Name(Node* left, Node* right);
+ PURE_ASSEMBLER_MACH_BINOP_LIST(BINOP_DECL)
+ CHECKED_ASSEMBLER_MACH_BINOP_LIST(BINOP_DECL)
+#undef BINOP_DECL
+
+ Node* Float64RoundDown(Node* value);
+
+ Node* ToNumber(Node* value);
+ Node* Allocate(PretenureFlag pretenure, Node* size);
+ Node* LoadField(FieldAccess const&, Node* object);
+ Node* LoadElement(ElementAccess const&, Node* object, Node* index);
+ Node* StoreField(FieldAccess const&, Node* object, Node* value);
+ Node* StoreElement(ElementAccess const&, Node* object, Node* index,
+ Node* value);
+
+ Node* Store(StoreRepresentation rep, Node* object, Node* offset, Node* value);
+
+ Node* Retain(Node* buffer);
+ Node* UnsafePointerAdd(Node* base, Node* external);
+
+ Node* DeoptimizeIf(DeoptimizeReason reason, Node* condition,
+ Node* frame_state);
+ Node* DeoptimizeUnless(DeoptimizeReason reason, Node* condition,
+ Node* frame_state);
+ template <typename... Args>
+ Node* Call(const CallDescriptor* desc, Args... args);
+
+ // Basic control operations.
+ template <class LabelType>
+ void Bind(LabelType* label);
+
+ template <class LabelType, typename... vars>
+ void Goto(LabelType* label, vars...);
+
+ void Branch(Node* condition, GraphAssemblerStaticLabel<1>* if_true,
+ GraphAssemblerStaticLabel<1>* if_false);
+
+ // Control helpers.
+ // {GotoIf(c, l)} is equivalent to {Branch(c, l, templ);Bind(templ)}.
+ template <class LabelType, typename... vars>
+ void GotoIf(Node* condition, LabelType* label, vars...);
+
+ // {GotoUnless(c, l)} is equivalent to {Branch(c, templ, l);Bind(templ)}.
+ template <class LabelType, typename... vars>
+ void GotoUnless(Node* condition, LabelType* label, vars...);
+
+ // Extractors (should be only used when destructing/resetting the assembler).
+ Node* ExtractCurrentControl();
+ Node* ExtractCurrentEffect();
+
+ private:
+ template <class LabelType, typename... Vars>
+ void MergeState(LabelType label, Vars... vars);
+
+ Operator const* ToNumberOperator();
+
+ JSGraph* jsgraph() const { return jsgraph_; }
+ Graph* graph() const { return jsgraph_->graph(); }
+ Zone* temp_zone() const { return temp_zone_; }
+ CommonOperatorBuilder* common() const { return jsgraph()->common(); }
+ MachineOperatorBuilder* machine() const { return jsgraph()->machine(); }
+ SimplifiedOperatorBuilder* simplified() const {
+ return jsgraph()->simplified();
+ }
+
+ SetOncePointer<Operator const> to_number_operator_;
+ Zone* temp_zone_;
+ JSGraph* jsgraph_;
+ Node* current_effect_;
+ Node* current_control_;
+};
+
+template <size_t MergeCount, size_t VarCount>
+Node* GraphAssemblerStaticLabel<MergeCount, VarCount>::PhiAt(size_t index) {
+ DCHECK(IsBound());
+ return GetBindingsPtrFor(index)[0];
+}
+
+template <class LabelType, typename... Vars>
+void GraphAssembler::MergeState(LabelType label, Vars... vars) {
+ DCHECK(!label->IsBound());
+ size_t merged_count = label->MergedCount();
+ DCHECK_LT(merged_count, label->MaxMergeCount());
+ DCHECK_EQ(label->PhiCount(), sizeof...(vars));
+ label->GetEffectsPtr()[merged_count] = current_effect_;
+ label->GetControlsPtr()[merged_count] = current_control_;
+ // We need to start with nullptr to avoid 0-length arrays.
+ Node* var_array[] = {nullptr, vars...};
+ for (size_t i = 0; i < sizeof...(vars); i++) {
+ label->SetBinding(i, merged_count, var_array[i + 1]);
+ }
+ label->IncrementMergedCount();
+}
+
+template <class LabelType>
+void GraphAssembler::Bind(LabelType* label) {
+ DCHECK(current_control_ == nullptr);
+ DCHECK(current_effect_ == nullptr);
+ DCHECK(label->MaxMergeCount() > 0);
+ DCHECK_EQ(label->MaxMergeCount(), label->MergedCount());
+
+ int merge_count = static_cast<int>(label->MaxMergeCount());
+ if (merge_count == 1) {
+ current_control_ = label->GetControlsPtr()[0];
+ current_effect_ = label->GetEffectsPtr()[0];
+ label->SetBound();
+ return;
+ }
+
+ current_control_ = graph()->NewNode(common()->Merge(merge_count), merge_count,
+ label->GetControlsPtr());
+
+ Node** effects = label->GetEffectsPtr();
+ current_effect_ = effects[0];
+ for (size_t i = 1; i < label->MaxMergeCount(); i++) {
+ if (current_effect_ != effects[i]) {
+ effects[label->MaxMergeCount()] = current_control_;
+ current_effect_ = graph()->NewNode(common()->EffectPhi(merge_count),
+ merge_count + 1, effects);
+ break;
+ }
+ }
+
+ for (size_t var = 0; var < label->PhiCount(); var++) {
+ Node** bindings = label->GetBindingsPtrFor(var);
+ bindings[label->MaxMergeCount()] = current_control_;
+ bindings[0] = graph()->NewNode(
+ common()->Phi(label->GetRepresentationFor(var), merge_count),
+ merge_count + 1, bindings);
+ }
+
+ label->SetBound();
+}
+
+template <class LabelType, typename... Vars>
+void GraphAssembler::Goto(LabelType* label, Vars... vars) {
+ DCHECK_NOT_NULL(current_control_);
+ DCHECK_NOT_NULL(current_effect_);
+ MergeState(label, vars...);
+ current_control_ = nullptr;
+ current_effect_ = nullptr;
+}
+
+template <class LabelType, typename... Vars>
+void GraphAssembler::GotoIf(Node* condition, LabelType* label, Vars... vars) {
+ BranchHint hint =
+ label->IsDeferred() ? BranchHint::kFalse : BranchHint::kNone;
+ Node* branch =
+ graph()->NewNode(common()->Branch(hint), condition, current_control_);
+
+ current_control_ = graph()->NewNode(common()->IfTrue(), branch);
+ MergeState(label, vars...);
+
+ current_control_ = graph()->NewNode(common()->IfFalse(), branch);
+}
+
+template <class LabelType, typename... Vars>
+void GraphAssembler::GotoUnless(Node* condition, LabelType* label,
+ Vars... vars) {
+ BranchHint hint = label->IsDeferred() ? BranchHint::kTrue : BranchHint::kNone;
+ Node* branch =
+ graph()->NewNode(common()->Branch(hint), condition, current_control_);
+
+ current_control_ = graph()->NewNode(common()->IfFalse(), branch);
+ MergeState(label, vars...);
+
+ current_control_ = graph()->NewNode(common()->IfTrue(), branch);
+}
+
+template <typename... Args>
+Node* GraphAssembler::Call(const CallDescriptor* desc, Args... args) {
+ const Operator* op = common()->Call(desc);
+ Node* args_array[] = {args..., current_effect_, current_control_};
+ int size = static_cast<int>(sizeof...(args)) + op->EffectInputCount() +
+ op->ControlInputCount();
+ Node* call = graph()->NewNode(op, size, args_array);
+ DCHECK_EQ(0, op->ControlOutputCount());
+ current_effect_ = call;
+ return call;
+}
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
+
+#endif // V8_COMPILER_GRAPH_ASSEMBLER_H_
« no previous file with comments | « src/compiler/effect-control-linearizer.cc ('k') | src/compiler/graph-assembler.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698