28#include "mlir/IR/Attributes.h"
29#include "mlir/Pass/Pass.h"
30#include "mlir/Support/FileUtilities.h"
31#include "llvm/ADT/MapVector.h"
32#include "llvm/Support/Debug.h"
33#include "llvm/Support/FormatAdapters.h"
34#include "llvm/Support/FormatVariadic.h"
35#include "llvm/Support/MemoryBuffer.h"
36#include "llvm/Support/Path.h"
38#define DEBUG_TYPE "firrtl-blackbox-reader"
42#define GEN_PASS_DEF_BLACKBOXREADER
43#include "circt/Dialect/FIRRTL/Passes.h.inc"
48using namespace firrtl;
57struct AnnotationInfo {
61 hw::OutputFileAttr outputFileAttr;
63 StringAttr inlineText;
67 void print(raw_ostream &os,
unsigned indent = 0)
const {
68 os << llvm::formatv(
"name: {1}\n"
69 "{0}outputFile: {2}\n"
71 llvm::fmt_pad(
"", indent, 0), name,
72 outputFileAttr.getFilename(),
73 outputFileAttr.getExcludeFromFilelist().getValue());
78struct BlackBoxReaderPass
79 :
public circt::firrtl::impl::BlackBoxReaderBase<BlackBoxReaderPass> {
82 void runOnOperation()
override;
83 bool runOnAnnotation(Operation *op,
Annotation anno, OpBuilder &builder,
84 bool isCover, AnnotationInfo &annotationInfo);
85 StringAttr loadFile(Operation *op, StringRef inputPath, OpBuilder &builder);
86 hw::OutputFileAttr
getOutputFile(Operation *origOp, StringAttr fileNameAttr,
87 bool isCover =
false);
98 StringRef testBenchDir;
112 llvm::MapVector<StringAttr, AnnotationInfo> filenameToAnnotationInfo;
117void BlackBoxReaderPass::runOnOperation() {
119 CircuitOp circuitOp = getOperation();
122 instanceGraph = &getAnalysis<InstanceGraph>();
123 instanceInfo = &getAnalysis<InstanceInfo>();
124 auto context = &getContext();
127 bool anythingChanged =
false;
137 SmallVector<Attribute, 4> filteredAnnos;
139 filteredAnnos.push_back(annot.getDict());
143 if (
auto dir = annot.getMember<StringAttr>(
"directory")) {
144 coverDir = dir.getValue();
149 if (
auto dir = annot.getMember<StringAttr>(
"dirname")) {
150 testBenchDir = dir.getValue();
156 if (
auto target = annot.getMember<StringAttr>(
"targetDir")) {
157 targetDir = target.getValue();
161 <<
" annotation missing \"targetDir\" attribute";
171 LLVM_DEBUG(llvm::dbgs() <<
"Black box target directory: " << targetDir
175 auto builder = circuitOp.getBodyBuilder();
177 LLVM_DEBUG(llvm::dbgs() <<
"Visiting extmodules:\n");
179 builder.getDictionaryAttr({{builder.getStringAttr(
"class"),
182 llvm::MapVector<Operation *, SmallVector<StringAttr>>
183 verbatimExtmoduleToFiles;
185 for (
auto extmoduleOp : circuitOp.
getBodyBlock()->getOps<FExtModuleOp>()) {
187 llvm::dbgs().indent(2)
188 <<
"- name: " << extmoduleOp.getModuleNameAttr() <<
"\n";
189 llvm::dbgs().indent(4) <<
"annotations:\n";
194 bool foundBBoxAnno =
false;
195 annotations.removeAnnotations([&](
Annotation anno) {
196 AnnotationInfo annotationInfo;
197 if (!runOnAnnotation(extmoduleOp, anno, builder, isCover, annotationInfo))
200 LLVM_DEBUG(annotationInfo.print(llvm::dbgs().indent(6) <<
"- ", 8));
203 verbatimExtmoduleToFiles[extmoduleOp].push_back(annotationInfo.name);
210 auto [ptr, inserted] = filenameToAnnotationInfo.try_emplace(
211 annotationInfo.name, annotationInfo);
213 filenameToAnnotationInfo[annotationInfo.name] = annotationInfo;
215 auto &fileAttr = ptr->second.outputFileAttr;
216 SmallString<64> directory(fileAttr.getDirectory());
218 annotationInfo.outputFileAttr.getDirectory());
219 fileAttr = hw::OutputFileAttr::getFromDirectoryAndFilename(
220 context, directory, annotationInfo.name.getValue(),
222 fileAttr.getExcludeFromFilelist().getValue());
226 foundBBoxAnno =
true;
231 annotations.addAnnotations({bboxAnno});
232 anythingChanged =
true;
234 annotations.applyToOperation(extmoduleOp);
238 for (
auto &[moduleOp, fileNames] : verbatimExtmoduleToFiles) {
240 SmallVector<Attribute> verbatimFiles;
241 llvm::SmallPtrSet<StringAttr, 4> seenFiles;
243 for (StringAttr fileName : fileNames) {
244 if (!seenFiles.insert(fileName).second)
248 auto &annotationInfo = filenameToAnnotationInfo[fileName];
249 auto fileDict = builder.getDictionaryAttr(
250 {{builder.getStringAttr(
"content"), annotationInfo.inlineText},
251 {builder.getStringAttr(
"output_file"),
252 builder.getStringAttr(
253 annotationInfo.outputFileAttr.getFilename().getValue())}});
254 verbatimFiles.push_back(fileDict);
257 if (!verbatimFiles.empty()) {
258 annotations.addAnnotations({builder.getDictionaryAttr(
259 {{builder.getStringAttr(
"class"),
261 {builder.getStringAttr(
"files"),
262 builder.getArrayAttr(verbatimFiles)}})});
263 annotations.applyToOperation(moduleOp);
264 anythingChanged =
true;
269 if (!anythingChanged)
270 markAllAnalysesPreserved();
271 markAnalysesPreserved<InstanceGraph, InstanceInfo>();
274 filenameToAnnotationInfo.clear();
275 verbatimExtmoduleToFiles.clear();
281bool BlackBoxReaderPass::runOnAnnotation(Operation *op,
Annotation anno,
282 OpBuilder &builder,
bool isCover,
283 AnnotationInfo &annotationInfo) {
286 auto name = anno.
getMember<StringAttr>(
"name");
287 auto text = anno.
getMember<StringAttr>(
"text");
288 if (!name || !text) {
290 <<
" annotation missing \"name\" or \"text\" attribute";
295 annotationInfo.outputFileAttr =
getOutputFile(op, name, isCover);
296 annotationInfo.name = name;
297 annotationInfo.inlineText = text;
303 auto path = anno.
getMember<StringAttr>(
"path");
306 <<
" annotation missing \"path\" attribute";
310 SmallString<128> inputPath(inputPrefix);
312 auto text = loadFile(op, inputPath, builder);
314 op->emitError(
"Cannot find file ") << inputPath;
318 auto name = builder.getStringAttr(llvm::sys::path::filename(path));
319 annotationInfo.outputFileAttr =
getOutputFile(op, name, isCover);
320 annotationInfo.name = name;
321 annotationInfo.inlineText = text;
331StringAttr BlackBoxReaderPass::loadFile(Operation *op, StringRef inputPath,
332 OpBuilder &builder) {
333 LLVM_DEBUG(llvm::dbgs() <<
"Add black box source `"
334 << llvm::sys::path::filename(inputPath) <<
"` from `"
335 << inputPath <<
"`\n");
338 std::string errorMessage;
339 auto input = mlir::openInputFile(inputPath, &errorMessage);
344 return builder.getStringAttr(input->getBuffer());
348hw::OutputFileAttr BlackBoxReaderPass::getOutputFile(Operation *origOp,
349 StringAttr fileNameAttr,
353 auto outputFile = origOp->getAttrOfType<hw::OutputFileAttr>(
"output_file");
354 if (outputFile && !outputFile.isDirectory()) {
360 auto *context = &getContext();
361 auto fileName = fileNameAttr.getValue();
362 auto ext = llvm::sys::path::extension(fileName);
363 bool exclude = (ext ==
".h" || ext ==
".vh" || ext ==
".svh");
364 auto outDir = targetDir;
368 outDir = outputFile.getFilename();
373 else if (!testBenchDir.empty() && targetDir ==
"." &&
374 !instanceInfo->anyInstanceInEffectiveDesign(
375 cast<igraph::ModuleOpInterface>(origOp)))
376 outDir = testBenchDir;
382 SmallString<128> outputFilePath(outDir);
383 llvm::sys::path::append(outputFilePath, fileName);
384 return hw::OutputFileAttr::getFromFilename(context, outputFilePath, exclude);
static OutputFileAttr getOutputFile(igraph::ModuleOpInterface op)
static void print(TypedAttr val, llvm::raw_ostream &os)
static Block * getBodyBlock(FModuleLike mod)
#define CIRCT_DEBUG_SCOPED_PASS_LOGGER(PASS)
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
bool applyToOperation(Operation *op) const
Store the annotations in this set in an operation's annotations attribute, overwriting any existing a...
This class provides a read-only projection of an annotation.
AttrClass getMember(StringAttr name) const
Return a member of the annotation.
bool isClass(Args... names) const
Return true if this annotation matches any of the specified class names.
This graph tracks modules and where they are instantiated.
constexpr const char * extractCoverageAnnoClass
constexpr const char * blackBoxAnnoClass
constexpr const char * testBenchDirAnnoClass
constexpr const char * verifBlackBoxAnnoClass
constexpr const char * blackBoxPathAnnoClass
constexpr const char * blackBoxTargetDirAnnoClass
constexpr const char * blackBoxInlineAnnoClass
constexpr const char * verbatimBlackBoxAnnoClass
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.
void appendPossiblyAbsolutePath(llvm::SmallVectorImpl< char > &base, const llvm::Twine &suffix)
Append a path to an existing path, replacing it if the other path is absolute.
The namespace of a CircuitOp, generally inhabited by modules.