Coverage Report

Created: 2023-02-22 06:51

/src/hermes/lib/Optimizer/Scalar/CSE.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) Meta Platforms, Inc. and affiliates.
3
 *
4
 * This source code is licensed under the MIT license found in the
5
 * LICENSE file in the root directory of this source tree.
6
 */
7
8
#define DEBUG_TYPE "cse"
9
#include "hermes/Optimizer/Scalar/CSE.h"
10
#include "hermes/IR/Analysis.h"
11
#include "hermes/IR/CFG.h"
12
#include "hermes/IR/Instrs.h"
13
#include "hermes/Optimizer/Scalar/Utils.h"
14
#include "hermes/Support/Statistic.h"
15
16
#include "llvh/ADT/DenseMap.h"
17
#include "llvh/ADT/DenseSet.h"
18
#include "llvh/ADT/Hashing.h"
19
#include "llvh/ADT/STLExtras.h"
20
#include "llvh/ADT/ScopedHashTable.h"
21
#include "llvh/Support/RecyclingAllocator.h"
22
23
using namespace hermes;
24
25
STATISTIC(NumCSE, "Number of instructions CSE'd");
26
27
//===----------------------------------------------------------------------===//
28
//                                Simple Value
29
//===----------------------------------------------------------------------===//
30
31
namespace {
32
/// CSEValue - Instances of this struct represent available values in the
33
/// scoped hash table.
34
struct CSEValue {
35
  Instruction *inst_;
36
37
0
  CSEValue(Instruction *I) : inst_(I) {
38
0
    assert((isSentinel() || canHandle(I)) && "Inst can't be handled!");
39
0
  }
40
41
0
  bool isSentinel() const {
42
0
    return inst_ == llvh::DenseMapInfo<Instruction *>::getEmptyKey() ||
43
0
        inst_ == llvh::DenseMapInfo<Instruction *>::getTombstoneKey();
44
0
  }
45
46
  /// Return true if we know how to CSE this instruction.
47
0
  static bool canHandle(Instruction *Inst) {
48
0
    return isSimpleSideEffectFreeInstruction(Inst);
49
0
  }
50
};
51
} // end anonymous namespace
52
53
namespace llvh {
54
template <>
55
struct DenseMapInfo<CSEValue> {
56
0
  static inline CSEValue getEmptyKey() {
57
0
    return DenseMapInfo<hermes::Instruction *>::getEmptyKey();
58
0
  }
59
0
  static inline CSEValue getTombstoneKey() {
60
0
    return DenseMapInfo<hermes::Instruction *>::getTombstoneKey();
61
0
  }
62
  static unsigned getHashValue(CSEValue Val);
63
  static bool isEqual(CSEValue LHS, CSEValue RHS);
64
};
65
} // end namespace llvh
66
67
0
unsigned llvh::DenseMapInfo<CSEValue>::getHashValue(CSEValue Val) {
68
0
  return Val.inst_->getHashCode();
69
0
}
70
71
0
bool llvh::DenseMapInfo<CSEValue>::isEqual(CSEValue LHS, CSEValue RHS) {
72
0
  hermes::Instruction *LHSI = LHS.inst_, *RHSI = RHS.inst_;
73
0
  if (LHS.isSentinel() || RHS.isSentinel())
74
0
    return LHSI == RHSI;
75
76
0
  return LHSI->getKind() == RHSI->getKind() && LHSI->isIdenticalTo(RHSI);
77
0
}
78
79
//===----------------------------------------------------------------------===//
80
//                               CSE Interface
81
//===----------------------------------------------------------------------===//
82
83
namespace {
84
85
class CSEContext;
86
87
using CSEValueHTType = llvh::ScopedHashTableVal<CSEValue, Value *>;
88
using AllocatorTy =
89
    llvh::RecyclingAllocator<llvh::BumpPtrAllocator, CSEValueHTType>;
90
using ScopedHTType = llvh::ScopedHashTable<
91
    CSEValue,
92
    Value *,
93
    llvh::DenseMapInfo<CSEValue>,
94
    AllocatorTy>;
95
96
// StackNode - contains all the needed information to create a stack for doing
97
// a depth first traversal of the tree. This includes scopes for values and
98
// loads as well as the generation. There is a child iterator so that the
99
// children do not need to be store spearately.
100
class StackNode : public DomTreeDFS::StackNode<CSEContext> {
101
 public:
102
  inline StackNode(CSEContext *ctx, const DominanceInfoNode *n);
103
104
 private:
105
  /// RAII to create and pop a scope when the stack node is created and
106
  /// destroyed.
107
  ScopedHTType::ScopeTy scope_;
108
};
109
110
/// CSEContext - This pass does a simple depth-first walk of the dominator
111
/// tree, eliminating trivially redundant instructions.
112
class CSEContext : public DomTreeDFS::Visitor<CSEContext, StackNode> {
113
 public:
114
  CSEContext(const DominanceInfo &DT)
115
0
      : DomTreeDFS::Visitor<CSEContext, StackNode>(DT) {}
116
117
0
  bool run() {
118
0
    return DFS();
119
0
  }
120
121
  bool processNode(StackNode *SN);
122
123
 private:
124
  friend StackNode;
125
126
  /// AvailableValues - This scoped hash table contains the current values of
127
  /// all of our simple scalar expressions.  As we walk down the domtree, we
128
  /// look to see if instructions are in this. If so, we replace them with what
129
  /// we find, otherwise we insert them so that dominated values can succeed in
130
  /// their lookup.
131
  ScopedHTType availableValues_{};
132
};
133
134
inline StackNode::StackNode(CSEContext *ctx, const DominanceInfoNode *n)
135
    : DomTreeDFS::StackNode<CSEContext>(ctx, n),
136
0
      scope_{ctx->availableValues_} {}
137
} // end anonymous namespace
138
139
//===----------------------------------------------------------------------===//
140
//                             CSE Implementation
141
//===----------------------------------------------------------------------===//
142
143
0
bool CSEContext::processNode(StackNode *SN) {
144
0
  BasicBlock *BB = SN->node()->getBlock();
145
0
  bool changed = false;
146
147
  // Keep a list of instructions that should be deleted when the basic block
148
  // is processed.
149
0
  IRBuilder::InstructionDestroyer destroyer;
150
151
  // See if any instructions in the block can be eliminated.  If so, do it.  If
152
  // not, add them to AvailableValues.
153
0
  for (auto &Inst : *BB) {
154
    // If this is not a simple instruction that we can value number, skip it.
155
0
    if (!CSEValue::canHandle(&Inst))
156
0
      continue;
157
158
    // Now that we know we have an instruction we understand see if the
159
    // instruction has an available value.  If so, use it.
160
0
    if (Value *V = availableValues_.lookup(&Inst)) {
161
0
      Inst.replaceAllUsesWith(V);
162
0
      destroyer.add(&Inst);
163
0
      changed = true;
164
0
      ++NumCSE;
165
0
      continue;
166
0
    }
167
168
    // Otherwise, just remember that this value is available.
169
0
    availableValues_.insert(&Inst, &Inst);
170
0
  }
171
172
0
  return changed;
173
0
}
174
175
0
bool CSE::runOnFunction(Function *F) {
176
0
  DominanceInfo DT{F};
177
0
  CSEContext CCtx{DT};
178
0
  return CCtx.run();
179
0
}
180
181
0
std::unique_ptr<Pass> hermes::createCSE() {
182
0
  return std::make_unique<CSE>();
183
0
}
184
185
#undef DEBUG_TYPE