• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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_DECOMPRESSION_OPTIMIZER_H_
6 #define V8_COMPILER_DECOMPRESSION_OPTIMIZER_H_
7 
8 #include "src/compiler/common-operator.h"
9 #include "src/compiler/machine-operator.h"
10 #include "src/compiler/node-marker.h"
11 
12 namespace v8 {
13 namespace internal {
14 namespace compiler {
15 
16 // Forward declare.
17 class Graph;
18 
19 // DecompressionOptimizer purpose is to hide the distinction between 32 bit and
20 // 64 bit tagged values, while being able to use the compressed version of nodes
21 // whenever possible. Its scope is narrowed down to loads of TaggedPointer and
22 // AnyTagged (since TaggedSigned avoids full decompression always), and
23 // HeapConstants.
24 
25 // DecompressionOptimizer will run only when pointer compression is enabled.
26 
27 // The phase needs to be run when Machine are present in the graph, i.e
28 // at the very end of the pipeline. Also, since this phase may change
29 // the load's MachineRepresentation from Tagged to Compressed, it's best
30 // to run it as late as possible in order to keep the phases that know
31 // about Compressed MachineRepresentation to a minimum.
32 
33 // As an example, if we Load a Tagged value only to Store it back again (i.e
34 // Load -> Store nodes, with the Load's value being the Store's value) we don't
35 // need to fully decompress it since the Store will ignore the top bits.
36 class V8_EXPORT_PRIVATE DecompressionOptimizer final {
37  public:
38   DecompressionOptimizer(Zone* zone, Graph* graph,
39                          CommonOperatorBuilder* common,
40                          MachineOperatorBuilder* machine);
41   ~DecompressionOptimizer() = default;
42   DecompressionOptimizer(const DecompressionOptimizer&) = delete;
43   DecompressionOptimizer& operator=(const DecompressionOptimizer&) = delete;
44 
45   // Assign States to the nodes, and then change the node's Operator to use the
46   // compressed version if possible.
47   void Reduce();
48 
49  private:
50   // State refers to the node's state as follows:
51   // * kUnvisited === This node has yet to be visited.
52   // * kOnly32BitsObserved === This node either has been visited, or is on
53   // to_visit_. We couldn't find a node that observes the upper bits.
54   // * kEverythingObserved === This node either has been visited, or is on
55   // to_visit_. We found at least one node that observes the upper bits.
56   enum class State : uint8_t {
57     kUnvisited = 0,
58     kOnly32BitsObserved,
59     kEverythingObserved,
60     kNumberOfStates
61   };
62 
63   // Change node's op from HeapConstant to CompressedHeapConstant.
64   void ChangeHeapConstant(Node* const node);
65 
66   // Change the phi's representation from Tagged to Compressed.
67   void ChangePhi(Node* const node);
68 
69   // Change node's load into a compressed one.
70   void ChangeLoad(Node* const node);
71 
72   // Go through the already marked nodes and changed the operation for the nodes
73   // that can use compressed outputs.
74   void ChangeNodes();
75 
76   // Goes through the nodes to mark them all as appropriate. It will visit each
77   // node at most twice: only when the node was unvisited, then marked as
78   // kOnly32BitsObserved and visited, and finally marked as kEverythingObserved
79   // and visited.
80   void MarkNodes();
81 
82   // Mark node's input as appropriate, according to node's opcode. Some input
83   // State may be updated, and therefore has to be revisited.
84   void MarkNodeInputs(Node* node);
85 
86   // Mark node's State to be state. We only do this if we have new information,
87   // i.e either if:
88   // * We are marking an unvisited node, or
89   // * We are marking a node as needing 64 bits when we previously had the
90   // information that it could output 32 bits. Also, we store the HeapConstant
91   // and TaggedPointer and AnyTagged loads that have their state set as
92   // kOnly32BitsObserved. If the node's state changes, we queue it for revisit.
93   void MaybeMarkAndQueueForRevisit(Node* const node, State state);
94 
IsEverythingObserved(Node * const node)95   bool IsEverythingObserved(Node* const node) {
96     return states_.Get(node) == State::kEverythingObserved;
97   }
98 
IsOnly32BitsObserved(Node * const node)99   bool IsOnly32BitsObserved(Node* const node) {
100     return states_.Get(node) == State::kOnly32BitsObserved;
101   }
102 
graph()103   Graph* graph() const { return graph_; }
common()104   CommonOperatorBuilder* common() const { return common_; }
machine()105   MachineOperatorBuilder* machine() const { return machine_; }
106 
107   Graph* const graph_;
108   CommonOperatorBuilder* const common_;
109   MachineOperatorBuilder* const machine_;
110   NodeMarker<State> states_;
111   // to_visit_ is a Deque but it's used as if it were a Queue. The reason why we
112   // are using NodeDeque is because it attempts to reuse 'freed' zone memory
113   // instead of always allocating a new region.
114   NodeDeque to_visit_;
115   // Contains the nodes that can be changed into a compressed version of
116   // themselves. In a way, it functions as a NodeSet since each node will be
117   // contained at most once. It's a Vector since we care about insertion speed.
118   NodeVector compressed_candidate_nodes_;
119 };
120 
121 }  // namespace compiler
122 }  // namespace internal
123 }  // namespace v8
124 
125 #endif  // V8_COMPILER_DECOMPRESSION_OPTIMIZER_H_
126