17 #include "llvm/ADT/DenseMap.h"
18 #include "llvm/ADT/PostOrderIterator.h"
19 #include "llvm/ADT/SmallPtrSet.h"
20 #include "llvm/Support/FileSystem.h"
21 #include "llvm/Support/Path.h"
23 #define DEBUG_TYPE "firrtl-assign-output-dirs"
27 #define GEN_PASS_DEF_ASSIGNOUTPUTDIRS
28 #include "circt/Dialect/FIRRTL/Passes.h.inc"
32 using namespace circt;
33 using namespace firrtl;
34 namespace path = llvm::sys::path;
35 namespace fs = llvm::sys::fs;
37 using hw::OutputFileAttr;
42 SmallString<64> &moduleOutputDir) {
43 auto sep = llvm::sys::path::get_separator();
44 if (!moduleOutputDir.empty())
45 assert(moduleOutputDir.ends_with(sep));
46 fs::make_absolute(outputDir, moduleOutputDir);
47 path::remove_dots(moduleOutputDir,
true);
48 moduleOutputDir += sep;
54 SmallString<64> &moduleOutputDir) {
55 if (moduleOutputDir.starts_with(outputDir))
56 moduleOutputDir.erase(moduleOutputDir.begin(),
57 moduleOutputDir.begin() + outputDir.size());
61 OutputFileAttr attr) {
63 SmallString<64> b(attr.getDirectory());
72 return op->getAttrOfType<hw::OutputFileAttr>(
"output_file");
76 struct AssignOutputDirsPass
77 :
public circt::firrtl::impl::AssignOutputDirsBase<AssignOutputDirsPass> {
78 AssignOutputDirsPass(StringRef outputDir) {
79 if (!outputDir.empty())
80 outputDirOption = std::string(outputDir);
83 void runOnOperation()
override;
87 void AssignOutputDirsPass::runOnOperation() {
89 SmallString<64> outputDir(outputDirOption);
90 if (fs::make_absolute(outputDir)) {
92 "failed to convert the output directory to an absolute path");
96 path::remove_dots(outputDir,
true);
97 auto sep = path::get_separator();
98 if (!outputDir.ends_with(sep))
99 outputDir.append(sep);
101 bool changed =
false;
103 LLVM_DEBUG(llvm::dbgs() <<
"Updating modules:\n");
104 DenseSet<InstanceGraphNode *> visited;
105 for (
auto *root : getAnalysis<InstanceGraph>()) {
106 for (
auto *node : llvm::inverse_post_order_ext(root, visited)) {
107 FModuleLike moduleLike =
108 dyn_cast<FModuleLike>(node->getModule().getOperation());
109 if (!moduleLike || !isa<FModuleOp, FExtModuleOp>(moduleLike))
111 if (moduleLike->getAttrOfType<hw::OutputFileAttr>(
"output_file") ||
112 moduleLike.isPublic())
118 SmallString<64> moduleOutputDir;
119 auto i = node->usesBegin();
120 auto e = node->usesEnd();
121 for (; i != e; ++i) {
122 auto parent = (*i)->getParent()->getModule();
125 moduleOutputDir = file.getDirectory();
128 moduleOutputDir = outputDir;
133 for (; i != e; ++i) {
134 auto parent = (*i)->getParent()->getModule();
139 if (!moduleOutputDir.empty()) {
141 hw::OutputFileAttr::getAsDirectory(&getContext(), moduleOutputDir);
142 moduleLike->setAttr(
"output_file", f);
145 llvm::dbgs() <<
" - name: " << moduleLike.getName() <<
"\n"
146 <<
" directory: " << f.getFilename() <<
"\n";
153 markAllAnalysesPreserved();
157 std::unique_ptr<mlir::Pass>
159 return std::make_unique<AssignOutputDirsPass>(outputDir);
static void makeAbsolute(StringRef outputDir, SmallString< 64 > &moduleOutputDir)
static void tryMakeRelative(StringRef outputDir, SmallString< 64 > &moduleOutputDir)
static OutputFileAttr getOutputFile(igraph::ModuleOpInterface op)
assert(baseType &&"element must be base type")
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
std::unique_ptr< mlir::Pass > createAssignOutputDirsPass(mlir::StringRef outputDir="")
void makeCommonPrefix(SmallString< 64 > &a, StringRef b)
Truncate a to the common prefix of a and b.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
llvm::raw_ostream & debugPassHeader(const mlir::Pass *pass, int width=80)
Write a boilerplate header for a pass to the debug stream.
llvm::raw_ostream & debugFooter(int width=80)
Write a boilerplate footer to the debug stream to indicate that a pass has ended.