blob: 9c4dc6855454ecb1606c23a46f118a2b5986e058 [file] [log] [blame]
// 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 <typename T>
T* AddDefinition(T* def) {
flow_graph_->AllocateSSAIndexes(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) {
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_