blob: 2c0eace3add98a63f6617d73e176c508ddeddf67 [file] [log] [blame] [edit]
// 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,
UnboxInstr::ValueMode value_mode) {
// 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, value_mode));
ASSERT((rep == unbox_rep) || !unboxed_value->IsUnboxInteger() ||
(RepresentationUtils::ValueSize(rep) <
RepresentationUtils::ValueSize(unbox_rep)));
if (value_mode == UnboxInstr::ValueMode::kHasValidType) {
// 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,
UnboxInstr::ValueMode value_mode) {
return AddUnboxInstr(rep, new Value(boxed), value_mode);
}
BranchInstr* AddBranch(ConditionInstr* cond,
TargetEntryInstr* true_successor,
TargetEntryInstr* false_successor) {
auto branch =
new BranchInstr(cond, 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_