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"
25 #define GEN_PASS_DEF_HWGENERATORCALLOUTPASS
26 #include "circt/Dialect/SV/SVPasses.h.inc"
30 using namespace circt;
40 struct HWGeneratorCalloutPass
41 :
public circt::sv::impl::HWGeneratorCalloutPassBase<
42 HWGeneratorCalloutPass> {
43 void runOnOperation()
override;
45 void processGenerator(HWModuleGeneratedOp generatedModuleOp,
46 StringRef generatorExe,
47 ArrayRef<StringRef> extraGeneratorArgs);
51 void HWGeneratorCalloutPass::runOnOperation() {
52 ModuleOp root = getOperation();
53 SmallVector<StringRef> genOptions;
54 StringRef extraGeneratorArgs(genExecArgs);
55 extraGeneratorArgs.split(genOptions,
';');
57 SmallString<32> execName = llvm::sys::path::filename(genExecutable);
58 SmallString<32> execPath = llvm::sys::path::parent_path(genExecutable);
60 auto generatorExe = llvm::sys::findProgramByName(execName, {execPath});
63 generatorExe = llvm::sys::findProgramByName(execName);
66 root.emitError(
"cannot find executable '" + execName +
"' in path '" +
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);
76 void HWGeneratorCalloutPass::processGenerator(
77 HWModuleGeneratedOp generatedModuleOp, StringRef generatorExe,
78 ArrayRef<StringRef> extraGeneratorArgs) {
81 dyn_cast<HWGeneratorSchemaOp>(generatedModuleOp.getGeneratorKindOp());
87 if (genSchema.getDescriptor().str() != schemaName)
90 SmallVector<std::string> generatorArgs;
92 generatorArgs.push_back(generatorExe.str());
93 for (
auto o : extraGeneratorArgs)
94 generatorArgs.push_back(o.str());
97 generatedModuleOp.getVerilogModuleNameAttr().getValue().str();
100 generatorArgs.push_back(
"--moduleName");
101 generatorArgs.push_back(moduleName);
105 for (
auto attr : genSchema.getRequiredAttrs()) {
106 auto sAttr = cast<StringAttr>(attr);
108 StringRef portName = sAttr.getValue();
109 generatorArgs.push_back(
"--" + portName.str());
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());
117 generatedModuleOp.emitError(
118 "portname attribute " + portName +
119 " value specified on the rtl.module.generated operation is not "
121 "only integer and string types supported.");
125 SmallVector<StringRef> generatorArgStrRef;
126 for (
const std::string &a : generatorArgs)
127 generatorArgStrRef.push_back(a);
130 SmallString<32> genExecOutFileName;
131 auto errCode = llvm::sys::fs::getPotentiallyUniqueTempFileName(
132 "generatorCalloutTemp", StringRef(
""), genExecOutFileName);
136 generatedModuleOp.emitError(
"cannot generate a unique temporary file name");
139 std::optional<StringRef> redirects[] = {
140 std::nullopt, StringRef(genExecOutFileName), std::nullopt};
141 int result = llvm::sys::ExecuteAndWait(
142 generatorExe, generatorArgStrRef, std::nullopt,
147 generatedModuleOp.emitError(
"execution of '" + generatorExe +
"' failed");
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 +
"'");
160 auto fileContent = (*bufferRead)->getBuffer().split(
'\n').first.str();
161 OpBuilder builder(generatedModuleOp);
163 generatedModuleOp.getLoc(), generatedModuleOp.getVerilogModuleNameAttr(),
164 generatedModuleOp.getPortList());
167 extMod->setAttr(
"filenames", builder.getStringAttr(fileContent));
168 generatedModuleOp.erase();
172 return std::make_unique<HWGeneratorCalloutPass>();
std::unique_ptr< mlir::Pass > createHWGeneratorCalloutPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.