| // Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| #ifndef RUNTIME_VM_COMPILER_BACKEND_BLOCK_BUILDER_H_ | |
| #define RUNTIME_VM_COMPILER_BACKEND_BLOCK_BUILDER_H_ | |
| #if defined(DART_PRECOMPILED_RUNTIME) | |
| #error "AOT runtime should not use compiler sources (including header files)" | |
| #endif // defined(DART_PRECOMPILED_RUNTIME) | |
| #include "vm/compiler/backend/flow_graph.h" | |
| #include "vm/compiler/backend/il.h" | |
| namespace dart { | |
| namespace compiler { | |
| // Helper class for building basic blocks in SSA form. | |
| class BlockBuilder : public ValueObject { | |
| public: | |
| BlockBuilder(FlowGraph* flow_graph, | |
| BlockEntryInstr* entry, | |
| bool with_frame = true) | |
| : flow_graph_(flow_graph), | |
| source_(InstructionSource(flow_graph_->function().token_pos(), | |
| flow_graph->inlining_id())), | |
| entry_(entry), | |
| current_(entry), | |
| dummy_env_(new Environment(0, 0, 0, flow_graph->function(), nullptr)), | |
| with_frame_(with_frame) { | |
| // Some graph transformations use environments from block entries. | |
| entry->SetEnvironment(dummy_env_); | |
| } | |
| Definition* AddToInitialDefinitions(Definition* def) { | |
| flow_graph_->AllocateSSAIndex(def); | |
| auto normal_entry = flow_graph_->graph_entry()->normal_entry(); | |
| flow_graph_->AddToInitialDefinitions(normal_entry, def); | |
| return def; | |
| } | |
| template <typename T> | |
| T* AddDefinition(T* def) { | |
| flow_graph_->AllocateSSAIndex(def); | |
| AddInstruction(def); | |
| return def; | |
| } | |
| template <typename T> | |
| T* AddInstruction(T* instr) { | |
| if (instr->ComputeCanDeoptimize() || | |
| instr->ComputeCanDeoptimizeAfterCall() || | |
| instr->CanBecomeDeoptimizationTarget()) { | |
| // All instructions that can deoptimize must have an environment attached | |
| // to them. | |
| instr->SetEnvironment(dummy_env_); | |
| } | |
| current_ = current_->AppendInstruction(instr); | |
| return instr; | |
| } | |
| const Function& function() const { return flow_graph_->function(); } | |
| DartReturnInstr* AddReturn(Value* value) { | |
| const auto& function = flow_graph_->function(); | |
| const auto representation = FlowGraph::ReturnRepresentationOf(function); | |
| return AddReturn(value, representation); | |
| } | |
| DartReturnInstr* AddReturn(Value* value, Representation representation) { | |
| DartReturnInstr* instr = new DartReturnInstr( | |
| Source(), value, CompilerState::Current().GetNextDeoptId(), | |
| representation); | |
| AddInstruction(instr); | |
| entry_->set_last_instruction(instr); | |
| return instr; | |
| } | |
| Definition* AddParameter(intptr_t index) { | |
| const auto [location, representation] = | |
| flow_graph_->GetDirectParameterInfoAt(index); | |
| return AddParameter(index, representation, | |
| with_frame_ ? location : location.ToEntrySpRelative()); | |
| } | |
| Definition* AddParameter(intptr_t index, | |
| Representation representation, | |
| Location location = Location()) { | |
| auto normal_entry = flow_graph_->graph_entry()->normal_entry(); | |
| return AddToInitialDefinitions( | |
| new ParameterInstr(normal_entry, | |
| /*env_index=*/index, | |
| /*param_index=*/index, location, representation)); | |
| } | |
| TokenPosition TokenPos() const { return source_.token_pos; } | |
| const InstructionSource& Source() const { return source_; } | |
| Definition* AddNullDefinition() { | |
| return flow_graph_->GetConstant(Object::ZoneHandle()); | |
| } | |
| Definition* AddUnboxInstr(Representation rep, | |
| Value* value, | |
| UnboxInstr::ValueMode value_mode) { | |
| // Unbox floats by first unboxing a double then converting it to a float. | |
| auto const unbox_rep = rep == kUnboxedFloat | |
| ? kUnboxedDouble | |
| : Boxing::NativeRepresentation(rep); | |
| Definition* unboxed_value = AddDefinition( | |
| UnboxInstr::Create(unbox_rep, value, DeoptId::kNone, value_mode)); | |
| ASSERT((rep == unbox_rep) || !unboxed_value->IsUnboxInteger() || | |
| (RepresentationUtils::ValueSize(rep) < | |
| RepresentationUtils::ValueSize(unbox_rep))); | |
| if (value_mode == UnboxInstr::ValueMode::kHasValidType) { | |
| // The type of |value| has already been checked and it is safe to | |
| // adjust reaching type. This is done manually because there is no type | |
| // propagation when building intrinsics. | |
| unboxed_value->AsUnbox()->value()->SetReachingType( | |
| new CompileType(CompileType::FromUnboxedRepresentation(rep))); | |
| } | |
| if (rep == kUnboxedFloat) { | |
| unboxed_value = AddDefinition( | |
| new DoubleToFloatInstr(new Value(unboxed_value), DeoptId::kNone)); | |
| } | |
| return unboxed_value; | |
| } | |
| Definition* AddUnboxInstr(Representation rep, | |
| Definition* boxed, | |
| UnboxInstr::ValueMode value_mode) { | |
| return AddUnboxInstr(rep, new Value(boxed), value_mode); | |
| } | |
| BranchInstr* AddBranch(ConditionInstr* cond, | |
| TargetEntryInstr* true_successor, | |
| TargetEntryInstr* false_successor) { | |
| auto branch = | |
| new BranchInstr(cond, CompilerState::Current().GetNextDeoptId()); | |
| // Some graph transformations use environments from branches. | |
| branch->SetEnvironment(dummy_env_); | |
| current_->AppendInstruction(branch); | |
| current_ = nullptr; | |
| *branch->true_successor_address() = true_successor; | |
| *branch->false_successor_address() = false_successor; | |
| return branch; | |
| } | |
| void AddPhi(PhiInstr* phi) { | |
| flow_graph_->AllocateSSAIndex(phi); | |
| phi->mark_alive(); | |
| entry_->AsJoinEntry()->InsertPhi(phi); | |
| } | |
| Instruction* last() const { return current_; } | |
| private: | |
| FlowGraph* const flow_graph_; | |
| const InstructionSource source_; | |
| BlockEntryInstr* entry_; | |
| Instruction* current_; | |
| Environment* dummy_env_; | |
| const bool with_frame_; | |
| }; | |
| } // namespace compiler | |
| } // namespace dart | |
| #endif // RUNTIME_VM_COMPILER_BACKEND_BLOCK_BUILDER_H_ |