v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
revectorizer.h
Go to the documentation of this file.
1// Copyright 2022 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_REVECTORIZER_H_
6#define V8_COMPILER_REVECTORIZER_H_
7
8// Revectorizer is an optimization to promote pairs of simd128 nodes to new
9// simd256 nodes accelerated by wider vector available from hardware e.g. the
10// YMM registers from AVX2 instruction set when possible and beneficial. The
11// main algorithm is based on the Superword Level Parallel (SLP) vectorization
12// technique.
13
14#include <vector>
15
22#include "src/compiler/node.h"
26
27namespace v8 {
28namespace internal {
29namespace compiler {
30
31class SourcePositionTable;
32
34 bool operator()(const Node* lhs, const Node* rhs) const;
35};
36
38
39// A PackNode consists of a fixed number of isomorphic simd128 nodes which can
40// execute in parallel and convert to a 256-bit simd node later. The nodes in a
41// PackNode must satisfy that they can be scheduled in the same basic block and
42// are mutually independent.
43class PackNode final : public NON_EXPORTED_BASE(ZoneObject) {
44 public:
45 explicit PackNode(Zone* zone, const ZoneVector<Node*>& node_group)
46 : nodes_(node_group.cbegin(), node_group.cend(), zone),
47 operands_(zone),
48 revectorized_node_(nullptr) {}
49 const ZoneVector<Node*>& Nodes() const { return nodes_; }
50 bool IsSame(const ZoneVector<Node*>& node_group) const {
51 return nodes_ == node_group;
52 }
55 // returns the index operand of this PackNode.
56 PackNode* GetOperand(size_t index) {
57 DCHECK_LT(index, operands_.size());
58 return operands_[index];
59 }
60
64
65 void SetOperand(size_t index, PackNode* pnode) {
66 if (operands_.size() < index + 1) operands_.resize(index + 1);
67 operands_[index] = pnode;
68 }
69
70 void Print() const;
71
72 private:
76};
77
78// An auxillary tree structure with a set of PackNodes based on the Superword
79// Level Parallelism (SLP) vectorization technique. The BuildTree method will
80// start from a selected root, e.g. a group of consecutive stores, and extend
81// through value inputs to create new PackNodes if the inputs are valid, or
82// conclude that the current PackNode is a leaf and terminate the tree.
83// Below is an example of SLPTree where loads and stores in each PackNode are
84// all consecutive.
85// [Load0, Load1] [Load2, Load3]
86// \ /
87// [Add0, Add1]
88// |
89// [Store0, Store1]
90class SLPTree : public NON_EXPORTED_BASE(ZoneObject) {
91 public:
92 explicit SLPTree(Zone* zone, TFGraph* graph)
93 : zone_(zone),
94 graph_(graph),
95 root_(nullptr),
97 stack_(zone),
100 }
101
102 PackNode* BuildTree(const ZoneVector<Node*>& roots);
103 void DeleteTree();
104
105 PackNode* GetPackNode(Node* node);
106
107 void Print(const char* info);
108
109 template <typename FunctionType>
111
115
116 private:
117 friend class LinearScheduler;
118
119 // This is the recursive part of BuildTree.
120 PackNode* BuildTreeRec(const ZoneVector<Node*>& node_group, unsigned depth);
121
122 // Baseline: create a new PackNode, and return.
123 PackNode* NewPackNode(const ZoneVector<Node*>& node_group);
124
125 // Recursion: create a new PackNode and call BuildTreeRec recursively
127 int start_index, int count, unsigned depth);
128
129 bool CanBePacked(const ZoneVector<Node*>& node_group);
130
131 TFGraph* graph() const { return graph_; }
132 Zone* zone() const { return zone_; }
133
134 // Node stack operations.
135 void PopStack();
136 void PushStack(const ZoneVector<Node*>& node_group);
137 void ClearStack();
138 bool OnStack(Node* node);
139 bool AllOnStack(const ZoneVector<Node*>& node_group);
140 bool StackTopIsPhi();
141
142 void TryReduceLoadChain(const ZoneVector<Node*>& loads);
143 bool IsSideEffectFreeLoad(const ZoneVector<Node*>& node_group);
144 bool SameBasicBlock(Node* node0, Node* node1) {
145 return scheduler_->SameBasicBlock(node0, node1);
146 }
147
148 Zone* const zone_;
154 // Maps a specific node to PackNode.
156 static constexpr size_t RecursionMaxDepth = 1000;
157};
158
159// The Revectorizer pass will firstly collect seeds with valid group of
160// consecutive stores as the root to build the SLPTree. If the SLPTree is built
161// successfully, it will estimate the cost of the 256-bit transformation for
162// each PackNode and conduct the final revectorization if benefitial.
164 : public NON_EXPORTED_BASE(ZoneObject) {
165 public:
166 Revectorizer(Zone* zone, TFGraph* graph, MachineGraph* mcgraph,
168 void DetectCPUFeatures();
169 bool TryRevectorize(const char* name);
170
171 private:
172 void CollectSeeds();
173
174 bool ReduceStoreChains(ZoneMap<Node*, StoreNodeSet>* store_chains);
175 bool ReduceStoreChain(const ZoneVector<Node*>& Stores);
176
177 void PrintStores(ZoneMap<Node*, StoreNodeSet>* store_chains);
178 Zone* zone() const { return zone_; }
179 TFGraph* graph() const { return graph_; }
180 MachineGraph* mcgraph() const { return mcgraph_; }
181
182 PackNode* GetPackNode(Node* node) const {
183 return slp_tree_->GetPackNode(node);
184 }
185
186 bool DecideVectorize();
187
188 void SetEffectInput(PackNode* pnode, int index, Node*& nput);
189 void SetMemoryOpInputs(base::SmallVector<Node*, 2>& inputs, PackNode* pnode,
190 int index);
191 Node* VectorizeTree(PackNode* pnode);
192 void UpdateSources();
193
194 Zone* const zone_;
198 std::unordered_set<Node*> sources_;
201
203
205};
206
207} // namespace compiler
208} // namespace internal
209} // namespace v8
210
211#endif // V8_COMPILER_REVECTORIZER_H_
T * New(Args &&... args)
Definition zone.h:114
bool SameBasicBlock(Node *node0, Node *node1)
PackNode * GetOperand(size_t index)
ZoneVector< PackNode * > operands_
ZoneVector< PackNode * >::size_type GetOperandsSize() const
void SetRevectorizedNode(Node *node)
void SetOperand(size_t index, PackNode *pnode)
ZoneVector< Node * > nodes_
bool IsSame(const ZoneVector< Node * > &node_group) const
const ZoneVector< Node * > & Nodes() const
PackNode(Zone *zone, const ZoneVector< Node * > &node_group)
PackNode * GetPackNode(Node *node) const
std::unordered_set< Node * > sources_
SourcePositionTable * source_positions_
ZoneMap< Node *, ZoneMap< Node *, StoreNodeSet > * > group_of_stores_
compiler::NodeObserver * node_observer_for_test_
static constexpr size_t RecursionMaxDepth
void Print(const char *info)
bool IsSideEffectFreeLoad(const ZoneVector< Node * > &node_group)
Node * GetEarlySchedulePosition(Node *node)
PackNode * BuildTree(const ZoneVector< Node * > &roots)
SLPTree(Zone *zone, TFGraph *graph)
PackNode * NewPackNodeAndRecurs(const ZoneVector< Node * > &node_group, int start_index, int count, unsigned depth)
PackNode * GetPackNode(Node *node)
PackNode * NewPackNode(const ZoneVector< Node * > &node_group)
PackNode * BuildTreeRec(const ZoneVector< Node * > &node_group, unsigned depth)
void TryReduceLoadChain(const ZoneVector< Node * > &loads)
bool CanBePacked(const ZoneVector< Node * > &node_group)
bool SameBasicBlock(Node *node0, Node *node1)
ZoneStack< ZoneVector< Node * > > stack_
void PushStack(const ZoneVector< Node * > &node_group)
ZoneUnorderedMap< Node *, PackNode * > node_to_packnode_
void ForEach(FunctionType callback)
bool AllOnStack(const ZoneVector< Node * > &node_group)
Zone * zone_
SourcePositionTable * source_positions
TNode< Object > callback
Node * node
bool(* FunctionType)(const Operation &op, Zone *zone)
Definition use-map.h:12
#define NON_EXPORTED_BASE(code)
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define V8_EXPORT_PRIVATE
Definition macros.h:460
TFGraph * graph_
MachineGraph * mcgraph_