|  | // 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(), | 
|  | 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( | 
|  | /*env_index=*/index, /*param_index=*/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); | 
|  | } | 
|  |  | 
|  | Instruction* last() const { return current_; } | 
|  |  | 
|  | 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_ |