| // 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) |
| : 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)) { |
| // 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(); } |
| |
| ReturnInstr* AddReturn(Value* value) { |
| const auto& function = flow_graph_->function(); |
| const auto representation = FlowGraph::ReturnRepresentationOf(function); |
| ReturnInstr* instr = new ReturnInstr( |
| Source(), value, CompilerState::Current().GetNextDeoptId(), |
| UntaggedPcDescriptors::kInvalidYieldIndex, representation); |
| AddInstruction(instr); |
| entry_->set_last_instruction(instr); |
| return instr; |
| } |
| |
| Definition* AddParameter(intptr_t index, bool with_frame) { |
| const auto& function = flow_graph_->function(); |
| const intptr_t param_offset = FlowGraph::ParameterOffsetAt(function, index); |
| const auto representation = |
| FlowGraph::ParameterRepresentationAt(function, index); |
| return AddParameter(index, param_offset, with_frame, representation); |
| } |
| |
| Definition* AddParameter(intptr_t index, |
| intptr_t param_offset, |
| bool with_frame, |
| Representation representation) { |
| auto normal_entry = flow_graph_->graph_entry()->normal_entry(); |
| return AddToInitialDefinitions( |
| new ParameterInstr(index, param_offset, normal_entry, representation, |
| with_frame ? FPREG : SPREG)); |
| } |
| |
| 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, bool is_checked) { |
| Definition* unboxed_value = |
| AddDefinition(UnboxInstr::Create(rep, value, DeoptId::kNone)); |
| if (is_checked) { |
| // 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( |
| TypeForRepresentation(rep)); |
| } |
| return unboxed_value; |
| } |
| |
| Definition* AddUnboxInstr(Representation rep, |
| Definition* boxed, |
| bool is_checked) { |
| return AddUnboxInstr(rep, new Value(boxed), is_checked); |
| } |
| |
| BranchInstr* AddBranch(ComparisonInstr* comp, |
| TargetEntryInstr* true_successor, |
| TargetEntryInstr* false_successor) { |
| auto branch = |
| new BranchInstr(comp, 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); |
| } |
| |
| private: |
| static CompileType* TypeForRepresentation(Representation rep) { |
| switch (rep) { |
| case kUnboxedDouble: |
| return new CompileType(CompileType::FromCid(kDoubleCid)); |
| case kUnboxedFloat32x4: |
| return new CompileType(CompileType::FromCid(kFloat32x4Cid)); |
| case kUnboxedInt32x4: |
| return new CompileType(CompileType::FromCid(kInt32x4Cid)); |
| case kUnboxedFloat64x2: |
| return new CompileType(CompileType::FromCid(kFloat64x2Cid)); |
| case kUnboxedUint32: |
| case kUnboxedInt64: |
| return new CompileType(CompileType::Int()); |
| default: |
| UNREACHABLE(); |
| return nullptr; |
| } |
| } |
| |
| FlowGraph* const flow_graph_; |
| const InstructionSource source_; |
| BlockEntryInstr* entry_; |
| Instruction* current_; |
| Environment* dummy_env_; |
| }; |
| |
| } // namespace compiler |
| } // namespace dart |
| |
| #endif // RUNTIME_VM_COMPILER_BACKEND_BLOCK_BUILDER_H_ |