17#include "llvm/ADT/PostOrderIterator.h"
18#include "llvm/Support/FileSystem.h"
19#include "llvm/Support/Path.h"
21#define DEBUG_TYPE "firrtl-assign-output-dirs"
25#define GEN_PASS_DEF_ASSIGNOUTPUTDIRS
26#include "circt/Dialect/FIRRTL/Passes.h.inc"
31using namespace firrtl;
32namespace path = llvm::sys::path;
33namespace fs = llvm::sys::fs;
35using hw::OutputFileAttr;
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;
52 SmallString<64> &moduleOutputDir) {
53 if (moduleOutputDir.starts_with(outputDir))
54 moduleOutputDir.erase(moduleOutputDir.begin(),
55 moduleOutputDir.begin() + outputDir.size());
59 OutputFileAttr attr) {
61 SmallString<64> b(attr.getDirectory());
70 return op->getAttrOfType<hw::OutputFileAttr>(
"output_file");
74struct AssignOutputDirsPass
75 :
public circt::firrtl::impl::AssignOutputDirsBase<AssignOutputDirsPass> {
78 AssignOutputDirsPass(StringRef outputDir) {
79 if (!outputDir.empty())
80 outputDirOption = std::string(outputDir);
83 void runOnOperation()
override;
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");
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 getAnalysis<InstanceGraph>().walkInversePostOrder([&](
auto &node) {
105 FModuleLike moduleLike =
106 dyn_cast<FModuleLike>(node.getModule().getOperation());
107 if (!moduleLike || !isa<FModuleOp, FExtModuleOp>(moduleLike))
109 if (moduleLike->getAttrOfType<hw::OutputFileAttr>(
"output_file") ||
110 moduleLike.isPublic())
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();
123 moduleOutputDir = file.getDirectory();
126 moduleOutputDir = outputDir;
131 for (; i != e; ++i) {
132 auto parent = (*i)->getParent()->getModule();
137 if (!moduleOutputDir.empty()) {
139 hw::OutputFileAttr::getAsDirectory(&getContext(), moduleOutputDir);
140 moduleLike->setAttr(
"output_file", f);
143 llvm::dbgs() <<
" - name: " << moduleLike.getName() <<
"\n"
144 <<
" directory: " << f.getFilename() <<
"\n";
150 markAllAnalysesPreserved();
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)
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 ...