CIRCT 20.0.0git
Loading...
Searching...
No Matches
GeneratorCallout.cpp
Go to the documentation of this file.
1//===- GeneratorCallout.cpp - Generator Callout Pass ----------------------===//
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//
9// Call arbitrary programs and pass them the attributes attached to external
10// modules.
11//
12//===----------------------------------------------------------------------===//
13
17#include "mlir/IR/Builders.h"
18#include "mlir/Pass/Pass.h"
19#include "llvm/Support/MemoryBuffer.h"
20#include "llvm/Support/Path.h"
21#include "llvm/Support/Process.h"
22
23namespace circt {
24namespace sv {
25#define GEN_PASS_DEF_HWGENERATORCALLOUTPASS
26#include "circt/Dialect/SV/SVPasses.h.inc"
27} // namespace sv
28} // namespace circt
29
30using namespace circt;
31using namespace sv;
32using namespace hw;
33
34//===----------------------------------------------------------------------===//
35// GeneratorCalloutPass
36//===----------------------------------------------------------------------===//
37
38namespace {
39
40struct HWGeneratorCalloutPass
41 : public circt::sv::impl::HWGeneratorCalloutPassBase<
42 HWGeneratorCalloutPass> {
43 void runOnOperation() override;
44
45 void processGenerator(HWModuleGeneratedOp generatedModuleOp,
46 StringRef generatorExe,
47 ArrayRef<StringRef> extraGeneratorArgs);
48};
49} // end anonymous namespace
50
51void HWGeneratorCalloutPass::runOnOperation() {
52 ModuleOp root = getOperation();
53 SmallVector<StringRef> genOptions;
54 StringRef extraGeneratorArgs(genExecArgs);
55 extraGeneratorArgs.split(genOptions, ';');
56
57 SmallString<32> execName = llvm::sys::path::filename(genExecutable);
58 SmallString<32> execPath = llvm::sys::path::parent_path(genExecutable);
59
60 auto generatorExe = llvm::sys::findProgramByName(execName, {execPath});
61 // If program not found, search it in $PATH.
62 if (!generatorExe)
63 generatorExe = llvm::sys::findProgramByName(execName);
64 // If cannot find the executable, then nothing to do, return.
65 if (!generatorExe) {
66 root.emitError("cannot find executable '" + execName + "' in path '" +
67 execPath + "'");
68 return;
69 }
70 for (auto &op : llvm::make_early_inc_range(root.getBody()->getOperations())) {
71 if (auto generator = dyn_cast<HWModuleGeneratedOp>(op))
72 processGenerator(generator, *generatorExe, extraGeneratorArgs);
73 }
74}
75
76void HWGeneratorCalloutPass::processGenerator(
77 HWModuleGeneratedOp generatedModuleOp, StringRef generatorExe,
78 ArrayRef<StringRef> extraGeneratorArgs) {
79 // Get the corresponding schema associated with this generated op.
80 auto genSchema =
81 dyn_cast<HWGeneratorSchemaOp>(generatedModuleOp.getGeneratorKindOp());
82 if (!genSchema)
83 return;
84
85 // Ignore the generator op if the schema does not match the user specified
86 // schema name from command line "-schema-name"
87 if (genSchema.getDescriptor().str() != schemaName)
88 return;
89
90 SmallVector<std::string> generatorArgs;
91 // First argument should be the executable name.
92 generatorArgs.push_back(generatorExe.str());
93 for (auto o : extraGeneratorArgs)
94 generatorArgs.push_back(o.str());
95
96 auto moduleName =
97 generatedModuleOp.getVerilogModuleNameAttr().getValue().str();
98 // The moduleName option is not present in the schema, so add it
99 // explicitly.
100 generatorArgs.push_back("--moduleName");
101 generatorArgs.push_back(moduleName);
102 // Iterate over all the attributes in the schema.
103 // Assumption: All the options required by the generator program must be
104 // present in the schema.
105 for (auto attr : genSchema.getRequiredAttrs()) {
106 auto sAttr = cast<StringAttr>(attr);
107 // Get the port name from schema.
108 StringRef portName = sAttr.getValue();
109 generatorArgs.push_back("--" + portName.str());
110 // Get the value for the corresponding port name.
111 auto v = generatedModuleOp->getAttr(portName);
112 if (auto intV = dyn_cast<IntegerAttr>(v))
113 generatorArgs.push_back(std::to_string(intV.getValue().getZExtValue()));
114 else if (auto strV = dyn_cast<StringAttr>(v))
115 generatorArgs.push_back(strV.getValue().str());
116 else {
117 generatedModuleOp.emitError(
118 "portname attribute " + portName +
119 " value specified on the rtl.module.generated operation is not "
120 "handled, "
121 "only integer and string types supported.");
122 return;
123 }
124 }
125 SmallVector<StringRef> generatorArgStrRef;
126 for (const std::string &a : generatorArgs)
127 generatorArgStrRef.push_back(a);
128
129 std::string errMsg;
130 SmallString<32> genExecOutFileName;
131 auto errCode = llvm::sys::fs::getPotentiallyUniqueTempFileName(
132 "generatorCalloutTemp", StringRef(""), genExecOutFileName);
133 // Default error code is 0.
134 std::error_code ok;
135 if (errCode != ok) {
136 generatedModuleOp.emitError("cannot generate a unique temporary file name");
137 return;
138 }
139 std::optional<StringRef> redirects[] = {
140 std::nullopt, StringRef(genExecOutFileName), std::nullopt};
141 int result = llvm::sys::ExecuteAndWait(
142 generatorExe, generatorArgStrRef, /*Env=*/std::nullopt,
143 /*Redirects=*/redirects,
144 /*SecondsToWait=*/0, /*MemoryLimit=*/0, &errMsg);
145
146 if (result != 0) {
147 generatedModuleOp.emitError("execution of '" + generatorExe + "' failed");
148 return;
149 }
150
151 auto bufferRead = llvm::MemoryBuffer::getFile(genExecOutFileName);
152 if (!bufferRead || !*bufferRead) {
153 generatedModuleOp.emitError("execution of '" + generatorExe +
154 "' did not produce any output file named '" +
155 genExecOutFileName + "'");
156 return;
157 }
158
159 // Only extract the first line from the output.
160 auto fileContent = (*bufferRead)->getBuffer().split('\n').first.str();
161 OpBuilder builder(generatedModuleOp);
162 auto extMod = builder.create<hw::HWModuleExternOp>(
163 generatedModuleOp.getLoc(), generatedModuleOp.getVerilogModuleNameAttr(),
164 generatedModuleOp.getPortList());
165 // Attach an attribute to which file the definition of the external
166 // module exists in.
167 extMod->setAttr("filenames", builder.getStringAttr(fileContent));
168 generatedModuleOp.erase();
169}
170
172 return std::make_unique<HWGeneratorCalloutPass>();
173}
std::unique_ptr< mlir::Pass > createHWGeneratorCalloutPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition hw.py:1
Definition sv.py:1