CIRCT  19.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  return FusedLoc::get(&getContext(), newLocations, fusedLoc.getMetadata());
47  }
48 
49  // TODO: Handle other loc type.
50  return loc;
51  }
52 
53  void updateLocArray(Operation *op, StringRef attributeName) {
54  SmallVector<Attribute> newLocs;
55  if (auto resLocs = op->getAttrOfType<ArrayAttr>(attributeName)) {
56  bool changed = false;
57  for (auto loc : resLocs.getAsRange<LocationAttr>()) {
58  auto newLoc = getStrippedLoc(loc);
59  changed |= newLoc != loc;
60  newLocs.push_back(newLoc);
61  }
62  if (changed)
63  op->setAttr(attributeName, ArrayAttr::get(&getContext(), newLocs));
64  }
65  }
66 
67 private:
68  std::function<bool(mlir::Location)> pred;
69 };
70 } // namespace
71 
72 void StripDebugInfoWithPred::runOnOperation() {
73  // If pred is null and dropSuffix is non-empty, initialize the predicate to
74  // strip file info with that suffix.
75  if (!pred && !dropSuffix.empty()) {
76  pred = [&](mlir::Location loc) {
77  if (auto fileLoc = dyn_cast<FileLineColLoc>(loc))
78  return fileLoc.getFilename().getValue().ends_with(dropSuffix);
79  return false;
80  };
81  }
82 
83  if (!pred) {
84  getOperation().emitWarning()
85  << "predicate is uninitialized. No debug information is stripped.";
86  return;
87  }
88 
89  auto stripLocsOnOp = [this](Operation *op) {
90  updateLocIfChanged(op, getStrippedLoc(op->getLoc()));
91  updateLocArray(op, "arg_locs");
92  updateLocArray(op, "result_locs");
93  updateLocArray(op, "port_locs");
94  };
95 
96  // Handle operations sequentially if they have no regions,
97  // and parallelize walking over the remainder.
98  // If not for this special sequential-vs-parallel handling, would instead
99  // only do a simple walk and defer to pass scheduling for parallelism.
100  SmallVector<Operation *> topLevelOpsToWalk;
101  for (auto &op : getOperation().getOps()) {
102  // Gather operations with regions for parallel processing.
103  if (op.getNumRegions() != 0) {
104  topLevelOpsToWalk.push_back(&op);
105  continue;
106  }
107 
108  // Otherwise, handle right now -- not worth the cost.
109  stripLocsOnOp(&op);
110  }
111 
112  parallelForEach(&getContext(), topLevelOpsToWalk, [&](Operation *toplevelOp) {
113  toplevelOp->walk([&](Operation *op) {
114  stripLocsOnOp(op);
115  // Strip block arguments debug info.
116  for (Region &region : op->getRegions())
117  for (Block &block : region.getBlocks())
118  for (BlockArgument &arg : block.getArguments())
119  updateLocIfChanged(&arg, getStrippedLoc(arg.getLoc()));
120  });
121  });
122 }
123 
124 namespace circt {
125 /// Creates a pass to strip debug information from a function.
126 std::unique_ptr<Pass> createStripDebugInfoWithPredPass(
127  const std::function<bool(mlir::Location)> &pred) {
128  return std::make_unique<StripDebugInfoWithPred>(pred);
129 }
130 } // 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:54
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.