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