CIRCT 21.0.0git
Loading...
Searching...
No Matches
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
16namespace circt {
17#define GEN_PASS_DEF_STRIPDEBUGINFOWITHPRED
18#include "circt/Transforms/Passes.h.inc"
19} // namespace circt
20
21using namespace mlir;
22template <typename OpOrBlockArgument>
23static void updateLocIfChanged(OpOrBlockArgument *op, Location newLoc) {
24 if (op->getLoc() != newLoc)
25 op->setLoc(newLoc);
26}
27
28namespace {
29struct 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
70private:
71 std::function<bool(mlir::Location)> pred;
72};
73} // namespace
74
75void 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
127namespace circt {
128/// Creates a pass to strip debug information from a function.
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)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
std::unique_ptr< mlir::Pass > createStripDebugInfoWithPredPass(const std::function< bool(mlir::Location)> &pred)
Creates a pass to strip debug information from a function.