CIRCT  20.0.0git
StripDebugInfoWithPred.cpp
Go to the documentation of this file.
1 //===- StripDebugInfoWithPred.cpp - Strip debug information selectively ---===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
10 #include "mlir/IR/BuiltinOps.h"
11 #include "mlir/IR/Operation.h"
12 #include "mlir/IR/Threading.h"
13 #include "mlir/Pass/Pass.h"
14 #include "llvm/ADT/SmallVector.h"
15 
16 namespace circt {
17 #define GEN_PASS_DEF_STRIPDEBUGINFOWITHPRED
18 #include "circt/Transforms/Passes.h.inc"
19 } // namespace circt
20 
21 using namespace mlir;
22 template <typename OpOrBlockArgument>
23 static void updateLocIfChanged(OpOrBlockArgument *op, Location newLoc) {
24  if (op->getLoc() != newLoc)
25  op->setLoc(newLoc);
26 }
27 
28 namespace {
29 struct StripDebugInfoWithPred
30  : public circt::impl::StripDebugInfoWithPredBase<StripDebugInfoWithPred> {
31  StripDebugInfoWithPred(const std::function<bool(mlir::Location)> &pred)
32  : pred(pred) {}
33  void runOnOperation() override;
34 
35  // Return stripped location for the given `loc`.
36  mlir::Location getStrippedLoc(Location loc) {
37  // If `pred` return true, strip the location.
38  if (pred(loc))
39  return UnknownLoc::get(loc.getContext());
40 
41  if (auto fusedLoc = dyn_cast<FusedLoc>(loc)) {
42  SmallVector<mlir::Location> newLocations;
43  newLocations.reserve(fusedLoc.getLocations().size());
44  for (auto loc : fusedLoc.getLocations())
45  newLocations.push_back(getStrippedLoc(loc));
46  // NOTE: Don't use FusedLoc::get(&getContext(), newLocations,
47  // fusedLoc.getMetadata()) to avoid a bytecode reader bug
48  // llvm-project#99626.
49  return FusedLoc::get(newLocations, fusedLoc.getMetadata(), &getContext());
50  }
51 
52  // TODO: Handle other loc type.
53  return loc;
54  }
55 
56  void updateLocArray(Operation *op, StringRef attributeName) {
57  SmallVector<Attribute> newLocs;
58  if (auto resLocs = op->getAttrOfType<ArrayAttr>(attributeName)) {
59  bool changed = false;
60  for (auto loc : resLocs.getAsRange<LocationAttr>()) {
61  auto newLoc = getStrippedLoc(loc);
62  changed |= newLoc != loc;
63  newLocs.push_back(newLoc);
64  }
65  if (changed)
66  op->setAttr(attributeName, ArrayAttr::get(&getContext(), newLocs));
67  }
68  }
69 
70 private:
71  std::function<bool(mlir::Location)> pred;
72 };
73 } // namespace
74 
75 void StripDebugInfoWithPred::runOnOperation() {
76  // If pred is null and dropSuffix is non-empty, initialize the predicate to
77  // strip file info with that suffix.
78  if (!pred && !dropSuffix.empty()) {
79  pred = [&](mlir::Location loc) {
80  if (auto fileLoc = dyn_cast<FileLineColLoc>(loc))
81  return fileLoc.getFilename().getValue().ends_with(dropSuffix);
82  return false;
83  };
84  }
85 
86  if (!pred) {
87  getOperation().emitWarning()
88  << "predicate is uninitialized. No debug information is stripped.";
89  return;
90  }
91 
92  auto stripLocsOnOp = [this](Operation *op) {
93  updateLocIfChanged(op, getStrippedLoc(op->getLoc()));
94  updateLocArray(op, "arg_locs");
95  updateLocArray(op, "result_locs");
96  updateLocArray(op, "port_locs");
97  };
98 
99  // Handle operations sequentially if they have no regions,
100  // and parallelize walking over the remainder.
101  // If not for this special sequential-vs-parallel handling, would instead
102  // only do a simple walk and defer to pass scheduling for parallelism.
103  SmallVector<Operation *> topLevelOpsToWalk;
104  for (auto &op : getOperation().getOps()) {
105  // Gather operations with regions for parallel processing.
106  if (op.getNumRegions() != 0) {
107  topLevelOpsToWalk.push_back(&op);
108  continue;
109  }
110 
111  // Otherwise, handle right now -- not worth the cost.
112  stripLocsOnOp(&op);
113  }
114 
115  parallelForEach(&getContext(), topLevelOpsToWalk, [&](Operation *toplevelOp) {
116  toplevelOp->walk([&](Operation *op) {
117  stripLocsOnOp(op);
118  // Strip block arguments debug info.
119  for (Region &region : op->getRegions())
120  for (Block &block : region.getBlocks())
121  for (BlockArgument &arg : block.getArguments())
122  updateLocIfChanged(&arg, getStrippedLoc(arg.getLoc()));
123  });
124  });
125 }
126 
127 namespace circt {
128 /// Creates a pass to strip debug information from a function.
129 std::unique_ptr<Pass> createStripDebugInfoWithPredPass(
130  const std::function<bool(mlir::Location)> &pred) {
131  return std::make_unique<StripDebugInfoWithPred>(pred);
132 }
133 } // namespace circt
static void updateLocIfChanged(OpOrBlockArgument *op, Location newLoc)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition: CalyxOps.cpp:55
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
std::unique_ptr< mlir::Pass > createStripDebugInfoWithPredPass(const std::function< bool(mlir::Location)> &pred)
Creates a pass to strip debug information from a function.