Loading [MathJax]/extensions/tex2jax.js
CIRCT 22.0.0git
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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 "llvm/ADT/PostOrderIterator.h"
17#include "llvm/Support/FileSystem.h"
18#include "llvm/Support/Path.h"
19
20#define DEBUG_TYPE "firrtl-assign-output-dirs"
21
22namespace circt {
23namespace firrtl {
24#define GEN_PASS_DEF_ASSIGNOUTPUTDIRS
25#include "circt/Dialect/FIRRTL/Passes.h.inc"
26} // namespace firrtl
27} // namespace circt
28
29using namespace circt;
30using namespace firrtl;
31namespace path = llvm::sys::path;
32namespace fs = llvm::sys::fs;
33
34using hw::OutputFileAttr;
35
36// If moduleOutputDir is a relative path, convert it to an absolute path, by
37// interpreting moduleOutputDir as relative to the outputDir.
38static void makeAbsolute(StringRef outputDir,
39 SmallString<64> &moduleOutputDir) {
40 auto sep = llvm::sys::path::get_separator();
41 if (!moduleOutputDir.empty())
42 assert(moduleOutputDir.ends_with(sep));
43 fs::make_absolute(outputDir, moduleOutputDir);
44 path::remove_dots(moduleOutputDir, true);
45 moduleOutputDir += sep;
46}
47
48// If outputDir is a prefix of moduleOutputDir, then make moduleOutputDir
49// relative to outputDir. Otherwise, leave moduleOutputDir as absolute.
50static void tryMakeRelative(StringRef outputDir,
51 SmallString<64> &moduleOutputDir) {
52 if (moduleOutputDir.starts_with(outputDir))
53 moduleOutputDir.erase(moduleOutputDir.begin(),
54 moduleOutputDir.begin() + outputDir.size());
55}
56
57static void makeCommonPrefix(StringRef outputDir, SmallString<64> &a,
58 OutputFileAttr attr) {
59 if (attr) {
60 SmallString<64> b(attr.getDirectory());
61 makeAbsolute(outputDir, b);
62 makeCommonPrefix(a, b);
63 } else {
64 makeCommonPrefix(a, outputDir);
65 }
66}
67
68static OutputFileAttr getOutputFile(igraph::ModuleOpInterface op) {
69 return op->getAttrOfType<hw::OutputFileAttr>("output_file");
70}
71
72namespace {
73struct AssignOutputDirsPass
74 : public circt::firrtl::impl::AssignOutputDirsBase<AssignOutputDirsPass> {
75 using Base::Base;
76
77 AssignOutputDirsPass(StringRef outputDir) {
78 if (!outputDir.empty())
79 outputDirOption = std::string(outputDir);
80 }
81
82 void runOnOperation() override;
83};
84} // namespace
85
86void AssignOutputDirsPass::runOnOperation() {
87 LLVM_DEBUG(debugPassHeader(this) << "\n");
88 SmallString<64> outputDir(outputDirOption);
89 if (fs::make_absolute(outputDir)) {
90 emitError(mlir::UnknownLoc::get(&getContext()),
91 "failed to convert the output directory to an absolute path");
92 signalPassFailure();
93 return;
94 }
95 path::remove_dots(outputDir, true);
96 auto sep = path::get_separator();
97 if (!outputDir.ends_with(sep))
98 outputDir.append(sep);
99
100 bool changed = false;
101
102 LLVM_DEBUG(llvm::dbgs() << "Updating modules:\n");
103 DenseSet<InstanceGraphNode *> visited;
104 for (auto *root : getAnalysis<InstanceGraph>()) {
105 for (auto *node : llvm::inverse_post_order_ext(root, visited)) {
106 FModuleLike moduleLike =
107 dyn_cast<FModuleLike>(node->getModule().getOperation());
108 if (!moduleLike || !isa<FModuleOp, FExtModuleOp>(moduleLike))
109 continue;
110 if (moduleLike->getAttrOfType<hw::OutputFileAttr>("output_file") ||
111 moduleLike.isPublic())
112 continue;
113
114 // Get the output directory of the first parent, and then fold the current
115 // output directory with the LCA of all other discovered output
116 // directories.
117 SmallString<64> moduleOutputDir;
118 auto i = node->usesBegin();
119 auto e = node->usesEnd();
120 for (; i != e; ++i) {
121 auto parent = (*i)->getParent()->getModule();
122 auto file = getOutputFile(parent);
123 if (file) {
124 moduleOutputDir = file.getDirectory();
125 makeAbsolute(outputDir, moduleOutputDir);
126 } else {
127 moduleOutputDir = outputDir;
128 }
129 ++i;
130 break;
131 }
132 for (; i != e; ++i) {
133 auto parent = (*i)->getParent()->getModule();
134 makeCommonPrefix(outputDir, moduleOutputDir, getOutputFile(parent));
135 }
136
137 tryMakeRelative(outputDir, moduleOutputDir);
138 if (!moduleOutputDir.empty()) {
139 auto f =
140 hw::OutputFileAttr::getAsDirectory(&getContext(), moduleOutputDir);
141 moduleLike->setAttr("output_file", f);
142 changed = true;
143 LLVM_DEBUG({
144 llvm::dbgs() << " - name: " << moduleLike.getName() << "\n"
145 << " directory: " << f.getFilename() << "\n";
146 });
147 }
148 }
149 }
150
151 if (!changed)
152 markAllAnalysesPreserved();
153 LLVM_DEBUG(debugFooter() << "\n");
154}
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")
This graph tracks modules and where they are instantiated.
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.
Definition Debug.cpp:31
llvm::raw_ostream & debugFooter(int width=80)
Write a boilerplate footer to the debug stream to indicate that a pass has ended.
Definition Debug.cpp:35