v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
loop-finder.h
Go to the documentation of this file.
1// Copyright 2023 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_COMPILER_TURBOSHAFT_LOOP_FINDER_H_
6#define V8_COMPILER_TURBOSHAFT_LOOP_FINDER_H_
7
8#include "src/base/logging.h"
12
14
16 // This analyzer finds which loop each Block of a graph belongs to, and
17 // computes a list of all of the loops headers.
18 //
19 // A block is considered to "belong to a loop" if there is a forward-path (ie,
20 // without taking backedges) from this block to the backedge of the loop.
21 //
22 // This analysis runs in O(number of blocks), iterating each block once, and
23 // iterating blocks that are in a loop twice.
24 //
25 // Implementation:
26 // LoopFinder::Run walks the blocks of the graph backwards, and when it
27 // reaches a LoopHeader, it calls LoopFinder::VisitLoop.
28 // LoopFinder::VisitLoop iterates all of the blocks of the loop backwards,
29 // starting from the backedge, and stopping upon reaching the loop header. It
30 // marks the blocks that don't have a `parent_loops_` set as being part of the
31 // current loop (= sets their `parent_loops_` to the current loop header). If
32 // it finds a block that already has a `parent_loops_` set, it means that this
33 // loop contains an inner loop, so we skip this inner block as set the
34 // `has_inner_loops` bit.
35 //
36 // By iterating the blocks backwards in Run, we are guaranteed that inner
37 // loops are visited before their outer loops. Walking the graph forward
38 // doesn't work quite as nicely:
39 // - When seeing loop headers for the 1st time, we wouldn't have visited
40 // their inner loops yet.
41 // - If we decided to still iterate forward but to call VisitLoop when
42 // reaching their backedge rather than their header, it would work in most
43 // cases but not all, since the backedge of an outer loop can have a
44 // BlockIndex that is smaller than the one of an inner loop.
45 public:
46 struct LoopInfo {
47 const Block* start = nullptr;
48 const Block* end = nullptr;
49 bool has_inner_loops = false;
50 size_t block_count = 0; // Number of blocks in this loop
51 // (excluding inner loops)
52 size_t op_count = 0; // Upper bound on the number of operations in this
53 // loop (excluding inner loops). This is computed
54 // using "end - begin" for each block, which can be
55 // more than the number of operations when some
56 // operations are large (like CallOp and
57 // FrameStateOp typically).
58 };
59 LoopFinder(Zone* phase_zone, const Graph* input_graph)
60 : phase_zone_(phase_zone),
61 input_graph_(input_graph),
62 loop_headers_(input_graph->block_count(), nullptr, phase_zone),
63 loop_header_info_(phase_zone),
64 queue_(phase_zone) {
65 Run();
66 }
67
69 return loop_header_info_;
70 }
71 const Block* GetLoopHeader(const Block* block) const {
72 return loop_headers_[block->index()];
73 }
74 LoopInfo GetLoopInfo(const Block* block) const {
75 DCHECK(block->IsLoop());
76 auto it = loop_header_info_.find(block);
77 DCHECK_NE(it, loop_header_info_.end());
78 return it->second;
79 }
80
81 struct BlockCmp {
82 bool operator()(const Block* a, const Block* b) const {
83 return a->index().id() < b->index().id();
84 }
85 };
86 ZoneSet<const Block*, BlockCmp> GetLoopBody(const Block* loop_header);
87
88 private:
89 void Run();
90 LoopInfo VisitLoop(const Block* header);
91
94
95 // Map from block to the loop header of the closest enclosing loop. For loop
96 // headers, this map contains the enclosing loop header, rather than the
97 // identity.
98 // For instance, if a loop B1 contains a loop B2 which contains a block B3,
99 // {loop_headers_} will map:
100 // B3 -> B2
101 // B2 -> B1
102 // B1 -> nullptr (if B1 is an outermost loop)
104
105 // Map from Loop headers to the LoopInfo for their loops. Only Loop blocks
106 // have entries in this map.
108
109 // {queue_} is used in `VisitLoop`, but is declared as a class variable to
110 // reuse memory.
112};
113
114} // namespace v8::internal::compiler::turboshaft
115
116#endif // V8_COMPILER_TURBOSHAFT_LOOP_FINDER_H_
FixedBlockSidetable< const Block * > loop_headers_
const Block * GetLoopHeader(const Block *block) const
Definition loop-finder.h:71
LoopInfo GetLoopInfo(const Block *block) const
Definition loop-finder.h:74
const ZoneUnorderedMap< const Block *, LoopInfo > & LoopHeaders() const
Definition loop-finder.h:68
ZoneUnorderedMap< const Block *, LoopInfo > loop_header_info_
LoopFinder(Zone *phase_zone, const Graph *input_graph)
Definition loop-finder.h:59
int start
int end
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK(condition)
Definition logging.h:482
#define V8_EXPORT_PRIVATE
Definition macros.h:460
bool operator()(const Block *a, const Block *b) const
Definition loop-finder.h:82