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 
9 #include "PassDetail.h"
11 #include "mlir/IR/BuiltinOps.h"
12 #include "mlir/IR/Operation.h"
13 #include "mlir/IR/Threading.h"
14 #include "mlir/Pass/Pass.h"
15 #include "llvm/ADT/SmallVector.h"
16 
17 using namespace mlir;
18 
19 template <typename OpOrBlockArgument>
20 static void updateLocIfChanged(OpOrBlockArgument *op, Location newLoc) {
21  if (op->getLoc() != newLoc)
22  op->setLoc(newLoc);
23 }
24 
25 namespace {
26 struct StripDebugInfoWithPred
27  : public circt::StripDebugInfoWithPredBase<StripDebugInfoWithPred> {
28  StripDebugInfoWithPred(const std::function<bool(mlir::Location)> &pred)
29  : pred(pred) {}
30  void runOnOperation() override;
31 
32  // Return stripped location for the given `loc`.
33  mlir::Location getStrippedLoc(Location loc) {
34  // If `pred` return true, strip the location.
35  if (pred(loc))
36  return UnknownLoc::get(loc.getContext());
37 
38  if (auto fusedLoc = loc.dyn_cast<FusedLoc>()) {
39  SmallVector<mlir::Location> newLocations;
40  newLocations.reserve(fusedLoc.getLocations().size());
41  for (auto loc : fusedLoc.getLocations())
42  newLocations.push_back(getStrippedLoc(loc));
43  return FusedLoc::get(&getContext(), newLocations, fusedLoc.getMetadata());
44  }
45 
46  // TODO: Handle other loc type.
47  return loc;
48  }
49 
50  void updateLocArray(Operation *op, StringRef attributeName) {
51  SmallVector<Attribute> newLocs;
52  if (auto resLocs = op->getAttrOfType<ArrayAttr>(attributeName)) {
53  bool changed = false;
54  for (auto loc : resLocs.getAsRange<LocationAttr>()) {
55  auto newLoc = getStrippedLoc(loc);
56  changed |= newLoc != loc;
57  newLocs.push_back(newLoc);
58  }
59  if (changed)
60  op->setAttr(attributeName, ArrayAttr::get(&getContext(), newLocs));
61  }
62  }
63 
64 private:
65  std::function<bool(mlir::Location)> pred;
66 };
67 } // namespace
68 
69 void StripDebugInfoWithPred::runOnOperation() {
70  // If pred is null and dropSuffix is non-empty, initialize the predicate to
71  // strip file info with that suffix.
72  if (!pred && !dropSuffix.empty()) {
73  pred = [&](mlir::Location loc) {
74  if (auto fileLoc = loc.dyn_cast<FileLineColLoc>())
75  return fileLoc.getFilename().getValue().ends_with(dropSuffix);
76  return false;
77  };
78  }
79 
80  if (!pred) {
81  getOperation().emitWarning()
82  << "predicate is uninitialized. No debug information is stripped.";
83  return;
84  }
85 
86  auto stripLocsOnOp = [this](Operation *op) {
87  updateLocIfChanged(op, getStrippedLoc(op->getLoc()));
88  updateLocArray(op, "arg_locs");
89  updateLocArray(op, "result_locs");
90  updateLocArray(op, "port_locs");
91  };
92 
93  // Handle operations sequentially if they have no regions,
94  // and parallelize walking over the remainder.
95  // If not for this special sequential-vs-parallel handling, would instead
96  // only do a simple walk and defer to pass scheduling for parallelism.
97  SmallVector<Operation *> topLevelOpsToWalk;
98  for (auto &op : getOperation().getOps()) {
99  // Gather operations with regions for parallel processing.
100  if (op.getNumRegions() != 0) {
101  topLevelOpsToWalk.push_back(&op);
102  continue;
103  }
104 
105  // Otherwise, handle right now -- not worth the cost.
106  stripLocsOnOp(&op);
107  }
108 
109  parallelForEach(&getContext(), topLevelOpsToWalk, [&](Operation *toplevelOp) {
110  toplevelOp->walk([&](Operation *op) {
111  stripLocsOnOp(op);
112  // Strip block arguments debug info.
113  for (Region &region : op->getRegions())
114  for (Block &block : region.getBlocks())
115  for (BlockArgument &arg : block.getArguments())
116  updateLocIfChanged(&arg, getStrippedLoc(arg.getLoc()));
117  });
118  });
119 }
120 
121 namespace circt {
122 /// Creates a pass to strip debug information from a function.
123 std::unique_ptr<Pass> createStripDebugInfoWithPredPass(
124  const std::function<bool(mlir::Location)> &pred) {
125  return std::make_unique<StripDebugInfoWithPred>(pred);
126 }
127 } // 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
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
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.