11cb0ef41Sopenharmony_ci// Copyright 2019 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#ifndef V8_COMPILER_DECOMPRESSION_OPTIMIZER_H_
61cb0ef41Sopenharmony_ci#define V8_COMPILER_DECOMPRESSION_OPTIMIZER_H_
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci#include "src/compiler/common-operator.h"
91cb0ef41Sopenharmony_ci#include "src/compiler/machine-operator.h"
101cb0ef41Sopenharmony_ci#include "src/compiler/node-marker.h"
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_cinamespace v8 {
131cb0ef41Sopenharmony_cinamespace internal {
141cb0ef41Sopenharmony_cinamespace compiler {
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ci// Forward declare.
171cb0ef41Sopenharmony_ciclass Graph;
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_ci// DecompressionOptimizer purpose is to hide the distinction between 32 bit and
201cb0ef41Sopenharmony_ci// 64 bit tagged values, while being able to use the compressed version of nodes
211cb0ef41Sopenharmony_ci// whenever possible. Its scope is narrowed down to loads of TaggedPointer and
221cb0ef41Sopenharmony_ci// AnyTagged (since TaggedSigned avoids full decompression always), and
231cb0ef41Sopenharmony_ci// HeapConstants.
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci// DecompressionOptimizer will run only when pointer compression is enabled.
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ci// The phase needs to be run when Machine are present in the graph, i.e
281cb0ef41Sopenharmony_ci// at the very end of the pipeline. Also, since this phase may change
291cb0ef41Sopenharmony_ci// the load's MachineRepresentation from Tagged to Compressed, it's best
301cb0ef41Sopenharmony_ci// to run it as late as possible in order to keep the phases that know
311cb0ef41Sopenharmony_ci// about Compressed MachineRepresentation to a minimum.
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ci// As an example, if we Load a Tagged value only to Store it back again (i.e
341cb0ef41Sopenharmony_ci// Load -> Store nodes, with the Load's value being the Store's value) we don't
351cb0ef41Sopenharmony_ci// need to fully decompress it since the Store will ignore the top bits.
361cb0ef41Sopenharmony_ciclass V8_EXPORT_PRIVATE DecompressionOptimizer final {
371cb0ef41Sopenharmony_ci public:
381cb0ef41Sopenharmony_ci  DecompressionOptimizer(Zone* zone, Graph* graph,
391cb0ef41Sopenharmony_ci                         CommonOperatorBuilder* common,
401cb0ef41Sopenharmony_ci                         MachineOperatorBuilder* machine);
411cb0ef41Sopenharmony_ci  ~DecompressionOptimizer() = default;
421cb0ef41Sopenharmony_ci  DecompressionOptimizer(const DecompressionOptimizer&) = delete;
431cb0ef41Sopenharmony_ci  DecompressionOptimizer& operator=(const DecompressionOptimizer&) = delete;
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ci  // Assign States to the nodes, and then change the node's Operator to use the
461cb0ef41Sopenharmony_ci  // compressed version if possible.
471cb0ef41Sopenharmony_ci  void Reduce();
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci private:
501cb0ef41Sopenharmony_ci  // State refers to the node's state as follows:
511cb0ef41Sopenharmony_ci  // * kUnvisited === This node has yet to be visited.
521cb0ef41Sopenharmony_ci  // * kOnly32BitsObserved === This node either has been visited, or is on
531cb0ef41Sopenharmony_ci  // to_visit_. We couldn't find a node that observes the upper bits.
541cb0ef41Sopenharmony_ci  // * kEverythingObserved === This node either has been visited, or is on
551cb0ef41Sopenharmony_ci  // to_visit_. We found at least one node that observes the upper bits.
561cb0ef41Sopenharmony_ci  enum class State : uint8_t {
571cb0ef41Sopenharmony_ci    kUnvisited = 0,
581cb0ef41Sopenharmony_ci    kOnly32BitsObserved,
591cb0ef41Sopenharmony_ci    kEverythingObserved,
601cb0ef41Sopenharmony_ci    kNumberOfStates
611cb0ef41Sopenharmony_ci  };
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ci  // Change node's op from HeapConstant to CompressedHeapConstant.
641cb0ef41Sopenharmony_ci  void ChangeHeapConstant(Node* const node);
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci  // Change the phi's representation from Tagged to Compressed.
671cb0ef41Sopenharmony_ci  void ChangePhi(Node* const node);
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_ci  // Change node's load into a compressed one.
701cb0ef41Sopenharmony_ci  void ChangeLoad(Node* const node);
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci  // Go through the already marked nodes and changed the operation for the nodes
731cb0ef41Sopenharmony_ci  // that can use compressed outputs.
741cb0ef41Sopenharmony_ci  void ChangeNodes();
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ci  // Goes through the nodes to mark them all as appropriate. It will visit each
771cb0ef41Sopenharmony_ci  // node at most twice: only when the node was unvisited, then marked as
781cb0ef41Sopenharmony_ci  // kOnly32BitsObserved and visited, and finally marked as kEverythingObserved
791cb0ef41Sopenharmony_ci  // and visited.
801cb0ef41Sopenharmony_ci  void MarkNodes();
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci  // Mark node's input as appropriate, according to node's opcode. Some input
831cb0ef41Sopenharmony_ci  // State may be updated, and therefore has to be revisited.
841cb0ef41Sopenharmony_ci  void MarkNodeInputs(Node* node);
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ci  // Mark node's State to be state. We only do this if we have new information,
871cb0ef41Sopenharmony_ci  // i.e either if:
881cb0ef41Sopenharmony_ci  // * We are marking an unvisited node, or
891cb0ef41Sopenharmony_ci  // * We are marking a node as needing 64 bits when we previously had the
901cb0ef41Sopenharmony_ci  // information that it could output 32 bits. Also, we store the HeapConstant
911cb0ef41Sopenharmony_ci  // and TaggedPointer and AnyTagged loads that have their state set as
921cb0ef41Sopenharmony_ci  // kOnly32BitsObserved. If the node's state changes, we queue it for revisit.
931cb0ef41Sopenharmony_ci  void MaybeMarkAndQueueForRevisit(Node* const node, State state);
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_ci  bool IsEverythingObserved(Node* const node) {
961cb0ef41Sopenharmony_ci    return states_.Get(node) == State::kEverythingObserved;
971cb0ef41Sopenharmony_ci  }
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ci  bool IsOnly32BitsObserved(Node* const node) {
1001cb0ef41Sopenharmony_ci    return states_.Get(node) == State::kOnly32BitsObserved;
1011cb0ef41Sopenharmony_ci  }
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci  Graph* graph() const { return graph_; }
1041cb0ef41Sopenharmony_ci  CommonOperatorBuilder* common() const { return common_; }
1051cb0ef41Sopenharmony_ci  MachineOperatorBuilder* machine() const { return machine_; }
1061cb0ef41Sopenharmony_ci
1071cb0ef41Sopenharmony_ci  Graph* const graph_;
1081cb0ef41Sopenharmony_ci  CommonOperatorBuilder* const common_;
1091cb0ef41Sopenharmony_ci  MachineOperatorBuilder* const machine_;
1101cb0ef41Sopenharmony_ci  NodeMarker<State> states_;
1111cb0ef41Sopenharmony_ci  // to_visit_ is a Deque but it's used as if it were a Queue. The reason why we
1121cb0ef41Sopenharmony_ci  // are using NodeDeque is because it attempts to reuse 'freed' zone memory
1131cb0ef41Sopenharmony_ci  // instead of always allocating a new region.
1141cb0ef41Sopenharmony_ci  NodeDeque to_visit_;
1151cb0ef41Sopenharmony_ci  // Contains the nodes that can be changed into a compressed version of
1161cb0ef41Sopenharmony_ci  // themselves. In a way, it functions as a NodeSet since each node will be
1171cb0ef41Sopenharmony_ci  // contained at most once. It's a Vector since we care about insertion speed.
1181cb0ef41Sopenharmony_ci  NodeVector compressed_candidate_nodes_;
1191cb0ef41Sopenharmony_ci};
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_ci}  // namespace compiler
1221cb0ef41Sopenharmony_ci}  // namespace internal
1231cb0ef41Sopenharmony_ci}  // namespace v8
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_ci#endif  // V8_COMPILER_DECOMPRESSION_OPTIMIZER_H_
126