v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
cfg.h
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#ifndef V8_TORQUE_CFG_H_
6#define V8_TORQUE_CFG_H_
7
8#include <list>
9#include <memory>
10#include <optional>
11#include <unordered_map>
12#include <vector>
13
14#include "src/torque/ast.h"
17#include "src/torque/types.h"
18
19namespace v8::internal::torque {
20
21class ControlFlowGraph;
22
23class Block {
24 public:
25 explicit Block(ControlFlowGraph* cfg, size_t id,
26 std::optional<Stack<const Type*>> input_types,
27 bool is_deferred)
28 : cfg_(cfg),
29 input_types_(std::move(input_types)),
30 id_(id),
31 is_deferred_(is_deferred) {}
32 void Add(Instruction instruction) {
34 instructions_.push_back(std::move(instruction));
35 }
36
37 bool HasInputTypes() const { return input_types_ != std::nullopt; }
38 const Stack<const Type*>& InputTypes() const { return *input_types_; }
39 void SetInputTypes(const Stack<const Type*>& input_types);
40 void Retype() {
41 Stack<const Type*> current_stack = InputTypes();
42 for (const Instruction& instruction : instructions()) {
43 instruction.TypeInstruction(&current_stack, cfg_);
44 }
45 }
46
47 std::vector<Instruction>& instructions() { return instructions_; }
48 const std::vector<Instruction>& instructions() const { return instructions_; }
49 bool IsComplete() const {
50 return !instructions_.empty() && instructions_.back()->IsBlockTerminator();
51 }
52 size_t id() const { return id_; }
53 bool IsDeferred() const { return is_deferred_; }
54
55 void MergeInputDefinitions(const Stack<DefinitionLocation>& input_definitions,
56 Worklist<Block*>* worklist) {
57 if (!input_definitions_) {
58 input_definitions_ = input_definitions;
59 if (worklist) worklist->Enqueue(this);
60 return;
61 }
62
63 DCHECK_EQ(input_definitions_->Size(), input_definitions.Size());
64 bool changed = false;
65 for (BottomOffset i = {0}; i < input_definitions.AboveTop(); ++i) {
66 auto& current = input_definitions_->Peek(i);
67 auto& input = input_definitions.Peek(i);
68 if (current == input) continue;
69 if (current == DefinitionLocation::Phi(this, i.offset)) continue;
70 input_definitions_->Poke(i, DefinitionLocation::Phi(this, i.offset));
71 changed = true;
72 }
73
74 if (changed && worklist) worklist->Enqueue(this);
75 }
76 bool HasInputDefinitions() const {
77 return input_definitions_ != std::nullopt;
78 }
83
84 bool IsDead() const { return !HasInputDefinitions(); }
85
86 private:
88 std::vector<Instruction> instructions_;
89 std::optional<Stack<const Type*>> input_types_;
90 std::optional<Stack<DefinitionLocation>> input_definitions_;
91 const size_t id_;
93};
94
96 public:
97 explicit ControlFlowGraph(Stack<const Type*> input_types) {
98 start_ = NewBlock(std::move(input_types), false);
100 }
101
102 Block* NewBlock(std::optional<Stack<const Type*>> input_types,
103 bool is_deferred) {
104 blocks_.emplace_back(this, next_block_id_++, std::move(input_types),
105 is_deferred);
106 return &blocks_.back();
107 }
108 void PlaceBlock(Block* block) { placed_blocks_.push_back(block); }
109 template <typename UnaryPredicate>
110 void UnplaceBlockIf(UnaryPredicate&& predicate) {
111 auto newEnd = std::remove_if(placed_blocks_.begin(), placed_blocks_.end(),
112 std::forward<UnaryPredicate>(predicate));
113 placed_blocks_.erase(newEnd, placed_blocks_.end());
114 }
115 Block* start() const { return start_; }
116 std::optional<Block*> end() const { return end_; }
117 void set_end(Block* end) { end_ = end; }
119 if (!return_type_) {
120 return_type_ = t;
121 return;
122 }
123 if (t != *return_type_) {
124 std::stringstream message;
125 message << "expected return type ";
127 message << " instead of ";
128 PrintCommaSeparatedList(message, t);
129 ReportError(message.str());
130 }
131 }
132 const std::vector<Block*>& blocks() const { return placed_blocks_; }
133 size_t NumberOfBlockIds() const { return next_block_id_; }
134 std::size_t ParameterCount() const {
135 return start_ ? start_->InputTypes().Size() : 0;
136 }
137
138 private:
139 std::list<Block> blocks_;
141 std::vector<Block*> placed_blocks_;
142 std::optional<Block*> end_;
143 std::optional<TypeVector> return_type_;
144 size_t next_block_id_ = 0;
145};
146
148 public:
149 explicit CfgAssembler(Stack<const Type*> input_types)
150 : current_stack_(std::move(input_types)), cfg_(current_stack_) {}
151
153 if (!CurrentBlockIsComplete()) {
155 }
156 OptimizeCfg();
159 return cfg_;
160 }
161
162 Block* NewBlock(std::optional<Stack<const Type*>> input_types = std::nullopt,
163 bool is_deferred = false) {
164 return cfg_.NewBlock(std::move(input_types), is_deferred);
165 }
166
168 bool CfgIsComplete() const {
169 return std::all_of(
170 cfg_.blocks().begin(), cfg_.blocks().end(), [this](Block* block) {
171 return (cfg_.end() && *cfg_.end() == block) || block->IsComplete();
172 });
173 }
174
175 void Emit(Instruction instruction) {
176 instruction.TypeInstruction(&current_stack_, &cfg_);
177 current_block_->Add(std::move(instruction));
178 }
179
181
182 StackRange TopRange(size_t slot_count) const {
183 return CurrentStack().TopRange(slot_count);
184 }
185
186 void Bind(Block* block);
187 void Goto(Block* block);
188 // Goto block while keeping {preserved_slots} many slots on the top and
189 // deleting additional the slots below these to match the input type of the
190 // target block.
191 // Returns the StackRange of the preserved slots in the target block.
192 StackRange Goto(Block* block, size_t preserved_slots);
193 // The condition must be of type bool and on the top of stack. It is removed
194 // from the stack before branching.
195 void Branch(Block* if_true, Block* if_false);
196 // Delete the specified range of slots, moving upper slots to fill the gap.
197 void DeleteRange(StackRange range);
198 void DropTo(BottomOffset new_level);
199 StackRange Peek(StackRange range, std::optional<const Type*> type);
201 std::optional<const Type*> type);
202 void Print(std::string s);
203 void AssertionFailure(std::string message);
204 void Unreachable();
205 void DebugBreak();
206
207 void PrintCurrentStack(std::ostream& s) { s << "stack: " << current_stack_; }
208 void OptimizeCfg();
210
211 private:
216};
217
219 public:
221 : assembler_(assembler), saved_block_(block) {
222 saved_stack_ = block->InputTypes();
223 DCHECK(!assembler->CurrentBlockIsComplete());
224 std::swap(saved_block_, assembler->current_block_);
225 std::swap(saved_stack_, assembler->current_stack_);
226 assembler->cfg_.PlaceBlock(block);
227 }
228
230 DCHECK(assembler_->CurrentBlockIsComplete());
231 std::swap(saved_block_, assembler_->current_block_);
232 std::swap(saved_stack_, assembler_->current_stack_);
233 }
234
235 private:
239};
240
241} // namespace v8::internal::torque
242
243#endif // V8_TORQUE_CFG_H_
const std::vector< Instruction > & instructions() const
Definition cfg.h:48
std::optional< Stack< DefinitionLocation > > input_definitions_
Definition cfg.h:90
bool IsDead() const
Definition cfg.h:84
bool IsDeferred() const
Definition cfg.h:53
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::vector< Instruction > & instructions()
Definition cfg.h:47
const size_t id_
Definition cfg.h:91
bool HasInputDefinitions() const
Definition cfg.h:76
bool HasInputTypes() const
Definition cfg.h:37
Block(ControlFlowGraph *cfg, size_t id, std::optional< Stack< const Type * > > input_types, bool is_deferred)
Definition cfg.h:25
void Add(Instruction instruction)
Definition cfg.h:32
std::optional< Stack< const Type * > > input_types_
Definition cfg.h:89
const Stack< DefinitionLocation > & InputDefinitions() const
Definition cfg.h:79
void SetInputTypes(const Stack< const Type * > &input_types)
Definition cfg.cc:13
ControlFlowGraph * cfg_
Definition cfg.h:87
std::vector< Instruction > instructions_
Definition cfg.h:88
size_t id() const
Definition cfg.h:52
CfgAssemblerScopedTemporaryBlock(CfgAssembler *assembler, Block *block)
Definition cfg.h:220
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 PrintCurrentStack(std::ostream &s)
Definition cfg.h:207
void Poke(StackRange destination, StackRange origin, std::optional< const Type * > type)
Definition cfg.cc:129
bool CurrentBlockIsComplete() const
Definition cfg.h:167
Block * NewBlock(std::optional< Stack< const Type * > > input_types=std::nullopt, bool is_deferred=false)
Definition cfg.h:162
void Print(std::string s)
Definition cfg.cc:146
void Emit(Instruction instruction)
Definition cfg.h:175
const ControlFlowGraph & Result()
Definition cfg.h:152
void DeleteRange(StackRange range)
Definition cfg.cc:104
void Goto(Block *block)
Definition cfg.cc:81
CfgAssembler(Stack< const Type * > input_types)
Definition cfg.h:149
std::vector< Block * > placed_blocks_
Definition cfg.h:141
std::optional< TypeVector > return_type_
Definition cfg.h:143
std::size_t ParameterCount() const
Definition cfg.h:134
Block * NewBlock(std::optional< Stack< const Type * > > input_types, bool is_deferred)
Definition cfg.h:102
ControlFlowGraph(Stack< const Type * > input_types)
Definition cfg.h:97
std::optional< Block * > end_
Definition cfg.h:142
void UnplaceBlockIf(UnaryPredicate &&predicate)
Definition cfg.h:110
void SetReturnType(TypeVector t)
Definition cfg.h:118
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 Phi(const Block *block, std::size_t index)
BottomOffset AboveTop() const
Definition utils.h:280
const T & Peek(BottomOffset from_bottom) const
Definition utils.h:244
size_t Size() const
Definition utils.h:243
BytecodeAssembler & assembler_
InstructionOperand destination
STL namespace.
void ReportError(Args &&... args)
Definition utils.h:96
std::vector< const Type * > TypeVector
Definition types.h:85
void PrintCommaSeparatedList(std::ostream &os, const T &list, C &&transform)
Definition utils.h:163
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define V8_NODISCARD
Definition v8config.h:693