| // 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, bool is_checked) { | 
 |     // 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)); | 
 |     if (rep != unbox_rep && unboxed_value->IsUnboxInteger()) { | 
 |       ASSERT(RepresentationUtils::ValueSize(rep) < | 
 |              RepresentationUtils::ValueSize(unbox_rep)); | 
 |       // Mark unboxing of small unboxed integer representations as truncating. | 
 |       unboxed_value->AsUnboxInteger()->mark_truncating(); | 
 |     } | 
 |     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( | 
 |           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, | 
 |                             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); | 
 |   } | 
 |  | 
 |   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_ |