1// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_COMPILER_BACKEND_BLOCK_BUILDER_H_
6#define RUNTIME_VM_COMPILER_BACKEND_BLOCK_BUILDER_H_
7
8#if defined(DART_PRECOMPILED_RUNTIME)
9#error "AOT runtime should not use compiler sources (including header files)"
10#endif // defined(DART_PRECOMPILED_RUNTIME)
11
12#include "vm/compiler/backend/flow_graph.h"
13#include "vm/compiler/backend/il.h"
14
15namespace dart {
16namespace compiler {
17
18// Helper class for building basic blocks in SSA form.
19class BlockBuilder : public ValueObject {
20 public:
21 BlockBuilder(FlowGraph* flow_graph, BlockEntryInstr* entry)
22 : flow_graph_(flow_graph),
23 entry_(entry),
24 current_(entry),
25 dummy_env_(
26 new Environment(0, 0, flow_graph->parsed_function(), nullptr)) {
27 // Some graph transformations use environments from block entries.
28 entry->SetEnvironment(dummy_env_);
29 }
30
31 Definition* AddToInitialDefinitions(Definition* def) {
32 def->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index());
33 if (FlowGraph::NeedsPairLocation(def->representation())) {
34 flow_graph_->alloc_ssa_temp_index();
35 }
36 auto normal_entry = flow_graph_->graph_entry()->normal_entry();
37 flow_graph_->AddToInitialDefinitions(normal_entry, def);
38 return def;
39 }
40
41 template <typename T>
42 T* AddDefinition(T* def) {
43 flow_graph_->AllocateSSAIndexes(def);
44 AddInstruction(def);
45 return def;
46 }
47
48 template <typename T>
49 T* AddInstruction(T* instr) {
50 if (instr->ComputeCanDeoptimize() ||
51 instr->CanBecomeDeoptimizationTarget()) {
52 // All instructions that can deoptimize must have an environment attached
53 // to them.
54 instr->SetEnvironment(dummy_env_);
55 }
56 current_ = current_->AppendInstruction(instr);
57 return instr;
58 }
59
60 const Function& function() const { return flow_graph_->function(); }
61
62 ReturnInstr* AddReturn(Value* value) {
63 const auto& function = flow_graph_->function();
64 const auto representation = FlowGraph::ReturnRepresentationOf(function);
65 ReturnInstr* instr = new ReturnInstr(
66 TokenPos(), value, CompilerState::Current().GetNextDeoptId(),
67 PcDescriptorsLayout::kInvalidYieldIndex, representation);
68 AddInstruction(instr);
69 entry_->set_last_instruction(instr);
70 return instr;
71 }
72
73 Definition* AddParameter(intptr_t index, bool with_frame) {
74 const auto& function = flow_graph_->function();
75 const intptr_t param_offset = FlowGraph::ParameterOffsetAt(function, index);
76 const auto representation =
77 FlowGraph::ParameterRepresentationAt(function, index);
78 return AddParameter(index, param_offset, with_frame, representation);
79 }
80
81 Definition* AddParameter(intptr_t index,
82 intptr_t param_offset,
83 bool with_frame,
84 Representation representation) {
85 auto normal_entry = flow_graph_->graph_entry()->normal_entry();
86 return AddToInitialDefinitions(
87 new ParameterInstr(index, param_offset, normal_entry, representation,
88 with_frame ? FPREG : SPREG));
89 }
90
91 TokenPosition TokenPos() { return flow_graph_->function().token_pos(); }
92
93 Definition* AddNullDefinition() {
94 return flow_graph_->GetConstant(Object::ZoneHandle());
95 }
96
97 Definition* AddUnboxInstr(Representation rep, Value* value, bool is_checked) {
98 Definition* unboxed_value =
99 AddDefinition(UnboxInstr::Create(rep, value, DeoptId::kNone));
100 if (is_checked) {
101 // The type of |value| has already been checked and it is safe to
102 // adjust reaching type. This is done manually because there is no type
103 // propagation when building intrinsics.
104 unboxed_value->AsUnbox()->value()->SetReachingType(
105 TypeForRepresentation(rep));
106 }
107 return unboxed_value;
108 }
109
110 Definition* AddUnboxInstr(Representation rep,
111 Definition* boxed,
112 bool is_checked) {
113 return AddUnboxInstr(rep, new Value(boxed), is_checked);
114 }
115
116 BranchInstr* AddBranch(ComparisonInstr* comp,
117 TargetEntryInstr* true_successor,
118 TargetEntryInstr* false_successor) {
119 auto branch =
120 new BranchInstr(comp, CompilerState::Current().GetNextDeoptId());
121 // Some graph transformations use environments from branches.
122 branch->SetEnvironment(dummy_env_);
123 current_->AppendInstruction(branch);
124 current_ = nullptr;
125
126 *branch->true_successor_address() = true_successor;
127 *branch->false_successor_address() = false_successor;
128
129 return branch;
130 }
131
132 void AddPhi(PhiInstr* phi) {
133 phi->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index());
134 if (FlowGraph::NeedsPairLocation(phi->representation())) {
135 flow_graph_->alloc_ssa_temp_index();
136 }
137 phi->mark_alive();
138 entry_->AsJoinEntry()->InsertPhi(phi);
139 }
140
141 private:
142 static CompileType* TypeForRepresentation(Representation rep) {
143 switch (rep) {
144 case kUnboxedDouble:
145 return new CompileType(CompileType::FromCid(kDoubleCid));
146 case kUnboxedFloat32x4:
147 return new CompileType(CompileType::FromCid(kFloat32x4Cid));
148 case kUnboxedInt32x4:
149 return new CompileType(CompileType::FromCid(kInt32x4Cid));
150 case kUnboxedFloat64x2:
151 return new CompileType(CompileType::FromCid(kFloat64x2Cid));
152 case kUnboxedUint32:
153 case kUnboxedInt64:
154 return new CompileType(CompileType::Int());
155 default:
156 UNREACHABLE();
157 return nullptr;
158 }
159 }
160
161 FlowGraph* flow_graph_;
162 BlockEntryInstr* entry_;
163 Instruction* current_;
164 Environment* dummy_env_;
165};
166
167} // namespace compiler
168} // namespace dart
169
170#endif // RUNTIME_VM_COMPILER_BACKEND_BLOCK_BUILDER_H_
171