// 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->parsed_function(), nullptr)) { // Some graph transformations use environments from block entries. entry->SetEnvironment(dummy_env_); } Definition* AddToInitialDefinitions(Definition* def) { def->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); if (FlowGraph::NeedsPairLocation(def->representation())) { flow_graph_->alloc_ssa_temp_index(); } auto normal_entry = flow_graph_->graph_entry()->normal_entry(); flow_graph_->AddToInitialDefinitions(normal_entry, def); return def; } template T* AddDefinition(T* def) { flow_graph_->AllocateSSAIndexes(def); AddInstruction(def); return def; } template 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) { phi->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); if (FlowGraph::NeedsPairLocation(phi->representation())) { flow_graph_->alloc_ssa_temp_index(); } 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_