v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
cfg.cc
Go to the documentation of this file.
1// Copyright 2018 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/torque/cfg.h"
6
7#include <optional>
8
10
11namespace v8::internal::torque {
12
13void Block::SetInputTypes(const Stack<const Type*>& input_types) {
14 if (!input_types_) {
15 input_types_ = input_types;
16 return;
17 } else if (*input_types_ == input_types) {
18 return;
19 }
20
21 DCHECK_EQ(input_types.Size(), input_types_->Size());
22 Stack<const Type*> merged_types;
23 bool widened = false;
24 auto c2_iterator = input_types.begin();
25 for (const Type* c1 : *input_types_) {
26 const Type* merged_type = TypeOracle::GetUnionType(c1, *c2_iterator++);
27 if (!merged_type->IsSubtypeOf(c1)) {
28 widened = true;
29 }
30 merged_types.Push(merged_type);
31 }
32 if (merged_types.Size() == input_types_->Size()) {
33 if (widened) {
34 input_types_ = merged_types;
35 Retype();
36 }
37 return;
38 }
39
40 std::stringstream error;
41 error << "incompatible types at branch:\n";
42 for (intptr_t i = std::max(input_types_->Size(), input_types.Size()) - 1;
43 i >= 0; --i) {
44 std::optional<const Type*> left;
45 std::optional<const Type*> right;
46 if (static_cast<size_t>(i) < input_types.Size()) {
47 left = input_types.Peek(BottomOffset{static_cast<size_t>(i)});
48 }
49 if (static_cast<size_t>(i) < input_types_->Size()) {
50 right = input_types_->Peek(BottomOffset{static_cast<size_t>(i)});
51 }
52 if (left && right && *left == *right) {
53 error << **left << "\n";
54 } else {
55 if (left) {
56 error << **left;
57 } else {
58 error << "/*missing*/";
59 }
60 error << " => ";
61 if (right) {
62 error << **right;
63 } else {
64 error << "/*missing*/";
65 }
66 error << "\n";
67 }
68 }
69 ReportError(error.str());
70}
71
74 DCHECK(block->instructions().empty());
75 DCHECK(block->HasInputTypes());
77 current_stack_ = block->InputTypes();
78 cfg_.PlaceBlock(block);
79}
80
82 if (block->HasInputTypes()) {
83 DropTo(block->InputTypes().AboveTop());
84 }
85 Emit(GotoInstruction{block});
86}
87
88StackRange CfgAssembler::Goto(Block* block, size_t preserved_slots) {
89 DCHECK(block->HasInputTypes());
90 DCHECK_GE(CurrentStack().Size(), block->InputTypes().Size());
92 StackRange{block->InputTypes().AboveTop() - preserved_slots,
93 CurrentStack().AboveTop() - preserved_slots}});
94 StackRange preserved_slot_range = TopRange(preserved_slots);
95 Emit(GotoInstruction{block});
96 return preserved_slot_range;
97}
98
99void CfgAssembler::Branch(Block* if_true, Block* if_false) {
100 Emit(BranchInstruction{if_true, if_false});
101}
102
103// Delete the specified range of slots, moving upper slots to fill the gap.
105 DCHECK_LE(range.end(), current_stack_.AboveTop());
106 if (range.Size() == 0) return;
108}
109
111 DeleteRange(StackRange{new_level, CurrentStack().AboveTop()});
112}
113
115 std::optional<const Type*> type) {
116 std::vector<const Type*> lowered_types;
117 if (type) {
118 lowered_types = LowerType(*type);
119 DCHECK_EQ(lowered_types.size(), range.Size());
120 }
121 for (size_t i = 0; i < range.Size(); ++i) {
123 range.begin() + i,
124 type ? lowered_types[i] : std::optional<const Type*>{}});
125 }
126 return TopRange(range.Size());
127}
128
130 std::optional<const Type*> type) {
131 DCHECK_EQ(destination.Size(), origin.Size());
132 DCHECK_LE(destination.end(), origin.begin());
133 DCHECK_EQ(origin.end(), CurrentStack().AboveTop());
134 std::vector<const Type*> lowered_types;
135 if (type) {
136 lowered_types = LowerType(*type);
137 DCHECK_EQ(lowered_types.size(), origin.Size());
138 }
139 for (intptr_t i = origin.Size() - 1; i >= 0; --i) {
141 destination.begin() + i,
142 type ? lowered_types[i] : std::optional<const Type*>{}});
143 }
144}
145
146void CfgAssembler::Print(std::string s) {
147 Emit(PrintErrorInstruction{std::move(s)});
148}
149
150void CfgAssembler::AssertionFailure(std::string message) {
152 std::move(message)});
153}
154
158
162
163std::vector<std::size_t> CountBlockPredecessors(const ControlFlowGraph& cfg) {
164 std::vector<std::size_t> count(cfg.NumberOfBlockIds(), 0);
165 count[cfg.start()->id()] = 1;
166
167 for (const Block* block : cfg.blocks()) {
168 std::vector<Block*> successors;
169 for (const auto& instruction : block->instructions()) {
170 instruction->AppendSuccessorBlocks(&successors);
171 }
172 for (Block* successor : successors) {
173 DCHECK_LT(successor->id(), count.size());
174 ++count[successor->id()];
175 }
176 }
177
178 return count;
179}
180
182 auto predecessor_count = CountBlockPredecessors(cfg_);
183
184 for (Block* block : cfg_.blocks()) {
185 if (cfg_.end() && *cfg_.end() == block) continue;
186 if (predecessor_count[block->id()] == 0) continue;
187
188 while (!block->instructions().empty()) {
189 const auto& instruction = block->instructions().back();
190 if (!instruction.Is<GotoInstruction>()) break;
191 Block* destination = instruction.Cast<GotoInstruction>().destination;
192 if (destination == block) break;
193 if (cfg_.end() && *cfg_.end() == destination) break;
194 DCHECK_GT(predecessor_count[destination->id()], 0);
195 if (predecessor_count[destination->id()] != 1) break;
196
197 DCHECK_GT(destination->instructions().size(), 0);
198 block->instructions().pop_back();
199 block->instructions().insert(block->instructions().end(),
200 destination->instructions().begin(),
201 destination->instructions().end());
202
203 --predecessor_count[destination->id()];
204 DCHECK_EQ(predecessor_count[destination->id()], 0);
205 }
206 }
207
209 [&](Block* b) { return predecessor_count[b->id()] == 0; });
210}
211
213 Worklist<Block*> worklist;
214
215 // Setup start block.
216 Stack<DefinitionLocation> parameter_defs;
217 for (std::size_t i = 0; i < cfg_.ParameterCount(); ++i) {
218 parameter_defs.Push(DefinitionLocation::Parameter(i));
219 }
220 cfg_.start()->MergeInputDefinitions(parameter_defs, &worklist);
221
222 // Run fixpoint algorithm.
223 while (!worklist.IsEmpty()) {
224 Block* block = worklist.Dequeue();
225 Stack<DefinitionLocation> definitions = block->InputDefinitions();
226
227 // Propagate through block's instructions.
228 for (const auto& instruction : block->instructions()) {
229 instruction.RecomputeDefinitionLocations(&definitions, &worklist);
230 }
231 }
232
233 for (Block* block : cfg_.blocks()) {
234 DCHECK_IMPLIES(!block->IsDead(), block->InputDefinitions().Size() ==
235 block->InputTypes().Size());
236 USE(block);
237 }
238}
239
240} // namespace v8::internal::torque
bool IsComplete() const
Definition cfg.h:49
const Stack< const Type * > & InputTypes() const
Definition cfg.h:38
void MergeInputDefinitions(const Stack< DefinitionLocation > &input_definitions, Worklist< Block * > *worklist)
Definition cfg.h:55
std::optional< Stack< const Type * > > input_types_
Definition cfg.h:89
void SetInputTypes(const Stack< const Type * > &input_types)
Definition cfg.cc:13
size_t id() const
Definition cfg.h:52
void Bind(Block *block)
Definition cfg.cc:72
StackRange Peek(StackRange range, std::optional< const Type * > type)
Definition cfg.cc:114
StackRange TopRange(size_t slot_count) const
Definition cfg.h:182
void AssertionFailure(std::string message)
Definition cfg.cc:150
Stack< const Type * > current_stack_
Definition cfg.h:213
const Stack< const Type * > & CurrentStack() const
Definition cfg.h:180
void Branch(Block *if_true, Block *if_false)
Definition cfg.cc:99
void DropTo(BottomOffset new_level)
Definition cfg.cc:110
void Poke(StackRange destination, StackRange origin, std::optional< const Type * > type)
Definition cfg.cc:129
void Print(std::string s)
Definition cfg.cc:146
void Emit(Instruction instruction)
Definition cfg.h:175
void DeleteRange(StackRange range)
Definition cfg.cc:104
void Goto(Block *block)
Definition cfg.cc:81
std::size_t ParameterCount() const
Definition cfg.h:134
void UnplaceBlockIf(UnaryPredicate &&predicate)
Definition cfg.h:110
void PlaceBlock(Block *block)
Definition cfg.h:108
const std::vector< Block * > & blocks() const
Definition cfg.h:132
std::optional< Block * > end() const
Definition cfg.h:116
static DefinitionLocation Parameter(std::size_t index)
BottomOffset end() const
Definition utils.h:224
BottomOffset begin() const
Definition utils.h:223
const T & Peek(BottomOffset from_bottom) const
Definition utils.h:244
size_t Size() const
Definition utils.h:243
static const Type * GetUnionType(UnionType type)
virtual bool IsSubtypeOf(const Type *supertype) const
Definition types.cc:101
uint32_t count
RpoNumber block
InstructionOperand destination
void ReportError(Args &&... args)
Definition utils.h:96
TypeVector LowerType(const Type *type)
Definition types.cc:1210
std::vector< std::size_t > CountBlockPredecessors(const ControlFlowGraph &cfg)
Definition cfg.cc:163
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define USE(...)
Definition macros.h:293