CIRCT 23.0.0git
Loading...
Searching...
No Matches
AssignOutputDirs.cpp
Go to the documentation of this file.
1//===- AssignOutputDirs.cpp - Assign Output Directories ---------*- C++ -*-===//
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
15#include "circt/Support/Debug.h"
16#include "circt/Support/Path.h"
17#include "llvm/ADT/PostOrderIterator.h"
18#include "llvm/Support/FileSystem.h"
19#include "llvm/Support/Path.h"
20
21#define DEBUG_TYPE "firrtl-assign-output-dirs"
22
23namespace circt {
24namespace firrtl {
25#define GEN_PASS_DEF_ASSIGNOUTPUTDIRS
26#include "circt/Dialect/FIRRTL/Passes.h.inc"
27} // namespace firrtl
28} // namespace circt
29
30using namespace circt;
31using namespace firrtl;
32namespace path = llvm::sys::path;
33namespace fs = llvm::sys::fs;
34
35using hw::OutputFileAttr;
36
37// If moduleOutputDir is a relative path, convert it to an absolute path, by
38// interpreting moduleOutputDir as relative to the outputDir.
39static void makeAbsolute(StringRef outputDir,
40 SmallString<64> &moduleOutputDir) {
41 auto sep = llvm::sys::path::get_separator();
42 if (!moduleOutputDir.empty())
43 assert(moduleOutputDir.ends_with(sep));
44 path::make_absolute(outputDir, moduleOutputDir);
45 path::remove_dots(moduleOutputDir, true);
46 moduleOutputDir += sep;
47}
48
49// If outputDir is a prefix of moduleOutputDir, then make moduleOutputDir
50// relative to outputDir. Otherwise, leave moduleOutputDir as absolute.
51static void tryMakeRelative(StringRef outputDir,
52 SmallString<64> &moduleOutputDir) {
53 if (moduleOutputDir.starts_with(outputDir))
54 moduleOutputDir.erase(moduleOutputDir.begin(),
55 moduleOutputDir.begin() + outputDir.size());
56}
57
58static void makeCommonPrefix(StringRef outputDir, SmallString<64> &a,
59 OutputFileAttr attr) {
60 if (attr) {
61 SmallString<64> b(attr.getDirectory());
62 makeAbsolute(outputDir, b);
64 } else {
65 makeCommonDirectoryPrefix(a, outputDir);
66 }
67}
68
69static OutputFileAttr getOutputFile(igraph::ModuleOpInterface op) {
70 return op->getAttrOfType<hw::OutputFileAttr>("output_file");
71}
72
73namespace {
74struct AssignOutputDirsPass
75 : public circt::firrtl::impl::AssignOutputDirsBase<AssignOutputDirsPass> {
76 using Base::Base;
77
78 AssignOutputDirsPass(StringRef outputDir) {
79 if (!outputDir.empty())
80 outputDirOption = std::string(outputDir);
81 }
82
83 void runOnOperation() override;
84};
85} // namespace
86
87void AssignOutputDirsPass::runOnOperation() {
89 SmallString<64> outputDir(outputDirOption);
90 if (fs::make_absolute(outputDir)) {
91 emitError(mlir::UnknownLoc::get(&getContext()),
92 "failed to convert the output directory to an absolute path");
93 signalPassFailure();
94 return;
95 }
96 path::remove_dots(outputDir, true);
97 auto sep = path::get_separator();
98 if (!outputDir.ends_with(sep))
99 outputDir.append(sep);
100
101 bool changed = false;
102
103 LLVM_DEBUG(llvm::dbgs() << "Updating modules:\n");
104 getAnalysis<InstanceGraph>().walkInversePostOrder([&](auto &node) {
105 FModuleLike moduleLike =
106 dyn_cast<FModuleLike>(node.getModule().getOperation());
107 if (!moduleLike || !isa<FModuleOp, FExtModuleOp>(moduleLike))
108 return;
109 if (moduleLike->getAttrOfType<hw::OutputFileAttr>("output_file") ||
110 moduleLike.isPublic())
111 return;
112
113 // Get the output directory of the first parent, and then fold the current
114 // output directory with the LCA of all other discovered output
115 // directories.
116 SmallString<64> moduleOutputDir;
117 auto i = node.usesBegin();
118 auto e = node.usesEnd();
119 for (; i != e; ++i) {
120 auto parent = (*i)->getParent()->getModule();
121 auto file = getOutputFile(parent);
122 if (file) {
123 moduleOutputDir = file.getDirectory();
124 makeAbsolute(outputDir, moduleOutputDir);
125 } else {
126 moduleOutputDir = outputDir;
127 }
128 ++i;
129 break;
130 }
131 for (; i != e; ++i) {
132 auto parent = (*i)->getParent()->getModule();
133 makeCommonPrefix(outputDir, moduleOutputDir, getOutputFile(parent));
134 }
135
136 tryMakeRelative(outputDir, moduleOutputDir);
137 if (!moduleOutputDir.empty()) {
138 auto f =
139 hw::OutputFileAttr::getAsDirectory(&getContext(), moduleOutputDir);
140 moduleLike->setAttr("output_file", f);
141 changed = true;
142 LLVM_DEBUG({
143 llvm::dbgs() << " - name: " << moduleLike.getName() << "\n"
144 << " directory: " << f.getFilename() << "\n";
145 });
146 }
147 });
148
149 if (!changed)
150 markAllAnalysesPreserved();
151}
static void makeAbsolute(StringRef outputDir, SmallString< 64 > &moduleOutputDir)
static void tryMakeRelative(StringRef outputDir, SmallString< 64 > &moduleOutputDir)
static void makeCommonPrefix(StringRef outputDir, SmallString< 64 > &a, OutputFileAttr attr)
static OutputFileAttr getOutputFile(igraph::ModuleOpInterface op)
assert(baseType &&"element must be base type")
#define CIRCT_DEBUG_SCOPED_PASS_LOGGER(PASS)
Definition Debug.h:70
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void makeCommonDirectoryPrefix(llvm::SmallVectorImpl< char > &a, StringRef b)
Truncate a in place to the longest common directory prefix of a and b, ensuring that the result ends ...
Definition Path.cpp:36