14 #include "mlir/IR/BuiltinTypes.h"
15 #include "mlir/IR/Diagnostics.h"
16 #include "mlir/IR/Verifier.h"
17 #include "mlir/Support/Timing.h"
18 #include "mlir/Tools/mlir-translate/Translation.h"
19 #include "llvm/ADT/Hashing.h"
20 #include "llvm/Support/SourceMgr.h"
22 #include "slang/diagnostics/DiagnosticClient.h"
23 #include "slang/driver/Driver.h"
24 #include "slang/parsing/Preprocessor.h"
25 #include "slang/syntax/SyntaxPrinter.h"
26 #include "slang/util/Version.h"
29 using namespace circt;
30 using namespace ImportVerilog;
32 using llvm::SourceMgr;
36 llvm::raw_string_ostream os(buffer);
37 os <<
"slang version ";
38 os << slang::VersionInfo::getMajor() <<
".";
39 os << slang::VersionInfo::getMinor() <<
".";
40 os << slang::VersionInfo::getPatch() <<
"+";
41 os << slang::VersionInfo::getHash();
53 slang::SourceLocation loc) {
54 if (loc && loc.buffer() != slang::SourceLocation::NoLocation.buffer()) {
55 auto fileName = bufferFilePaths.lookup(loc.buffer());
56 auto line = sourceManager.getLineNumber(loc);
57 auto column = sourceManager.getColumnNumber(loc);
74 class MlirDiagnosticClient :
public slang::DiagnosticClient {
79 : context(context), bufferFilePaths(bufferFilePaths) {}
81 void report(
const slang::ReportedDiagnostic &diag)
override {
83 auto &diagEngine = context->getDiagEngine();
85 getSeverity(diag.severity));
86 mlirDiag << diag.formattedMessage;
90 auto optionName = engine->getOptionName(diag.originalDiagnostic.code);
91 if (!optionName.empty())
92 mlirDiag <<
" [-W" << optionName <<
"]";
95 for (
auto it = diag.expansionLocs.rbegin(); it != diag.expansionLocs.rend();
97 auto ¬e = mlirDiag.attachNote(
99 auto macroName = sourceManager->getMacroName(*it);
100 if (macroName.empty())
101 note <<
"expanded from here";
103 note <<
"expanded from macro '" << macroName <<
"'";
112 static DiagnosticSeverity getSeverity(slang::DiagnosticSeverity severity) {
114 case slang::DiagnosticSeverity::Fatal:
115 case slang::DiagnosticSeverity::Error:
116 return DiagnosticSeverity::Error;
117 case slang::DiagnosticSeverity::Warning:
118 return DiagnosticSeverity::Warning;
119 case slang::DiagnosticSeverity::Ignored:
120 case slang::DiagnosticSeverity::Note:
121 return DiagnosticSeverity::Remark;
123 llvm_unreachable(
"all slang diagnostic severities should be handled");
124 return DiagnosticSeverity::Error;
128 MLIRContext *context;
137 static slang::BufferID
getEmptyKey() {
return slang::BufferID(); }
139 return slang::BufferID(UINT32_MAX - 1,
""sv);
145 static bool isEqual(slang::BufferID a, slang::BufferID b) {
return a == b; }
156 struct ImportDriver {
157 ImportDriver(MLIRContext *mlirContext, TimingScope &ts,
159 : mlirContext(mlirContext), ts(ts),
160 options(options ? *options : defaultOptions) {}
162 LogicalResult prepareDriver(SourceMgr &sourceMgr);
166 MLIRContext *mlirContext;
172 slang::driver::Driver driver;
189 LogicalResult ImportDriver::prepareDriver(SourceMgr &sourceMgr) {
193 std::make_shared<MlirDiagnosticClient>(mlirContext, bufferFilePaths);
194 driver.diagEngine.addClient(diagClient);
201 for (
unsigned i = 0, e = sourceMgr.getNumBuffers(); i < e; ++i) {
202 const llvm::MemoryBuffer *mlirBuffer = sourceMgr.getMemoryBuffer(i + 1);
203 auto slangBuffer = driver.sourceManager.assignText(
204 mlirBuffer->getBufferIdentifier(), mlirBuffer->getBuffer());
205 driver.buffers.push_back(slangBuffer);
206 bufferFilePaths.insert({slangBuffer.id, mlirBuffer->getBufferIdentifier()});
210 driver.options.includeDirs = options.includeDirs;
211 driver.options.includeSystemDirs = options.includeSystemDirs;
212 driver.options.libDirs = options.libDirs;
213 driver.options.libExts = options.libExts;
214 driver.options.excludeExts.insert(options.excludeExts.begin(),
215 options.excludeExts.end());
216 driver.options.ignoreDirectives = options.ignoreDirectives;
218 driver.options.maxIncludeDepth = options.maxIncludeDepth;
219 driver.options.defines = options.defines;
220 driver.options.undefines = options.undefines;
221 driver.options.librariesInheritMacros = options.librariesInheritMacros;
223 driver.options.timeScale = options.timeScale;
224 driver.options.allowUseBeforeDeclare = options.allowUseBeforeDeclare;
225 driver.options.ignoreUnknownModules = options.ignoreUnknownModules;
226 driver.options.onlyLint =
227 options.mode == ImportVerilogOptions::Mode::OnlyLint;
228 driver.options.topModules = options.topModules;
229 driver.options.paramOverrides = options.paramOverrides;
231 driver.options.errorLimit = options.errorLimit;
232 driver.options.warningOptions = options.warningOptions;
233 driver.options.suppressWarningsPaths = options.suppressWarningsPaths;
235 driver.options.singleUnit = options.singleUnit;
236 driver.options.libraryFiles = options.libraryFiles;
238 for (
auto &dir : sourceMgr.getIncludeDirs())
239 driver.options.includeDirs.push_back(dir);
241 return success(driver.processOptions());
248 auto parseTimer = ts.nest(
"Verilog parser");
249 bool parseSuccess = driver.parseAllSources();
253 auto compileTimer = ts.nest(
"Verilog elaboration");
254 auto compilation = driver.createCompilation();
255 for (
auto &diag : compilation->getAllDiagnostics())
256 driver.diagEngine.issue(diag);
257 if (!parseSuccess || driver.diagEngine.getNumErrors() > 0)
263 if (options.mode == ImportVerilogOptions::Mode::OnlyLint)
268 ->loadDialect<moore::MooreDialect, hw::HWDialect, cf::ControlFlowDialect,
269 func::FuncDialect, debug::DebugDialect>();
270 auto conversionTimer = ts.nest(
"Verilog to dialect mapping");
271 Context context(options, *compilation, module, driver.sourceManager,
273 if (failed(context.convertCompilation()))
275 conversionTimer.stop();
278 auto verifierTimer = ts.nest(
"Post-parse verification");
285 auto parseTimer = ts.nest(
"Verilog preprocessing");
289 auto preprocessAndPrint = [&](slang::parsing::Preprocessor &preprocessor) {
290 slang::syntax::SyntaxPrinter output;
291 output.setIncludeComments(
false);
293 slang::parsing::Token token = preprocessor.next();
295 if (token.kind == slang::parsing::TokenKind::EndOfFile)
299 for (
auto &diag : preprocessor.getDiagnostics()) {
300 if (diag.isError()) {
301 driver.diagEngine.issue(diag);
313 auto optionBag = driver.createOptionBag();
314 if (driver.options.singleUnit ==
true) {
315 slang::BumpAllocator alloc;
316 slang::Diagnostics diagnostics;
317 slang::parsing::Preprocessor preprocessor(driver.sourceManager, alloc,
318 diagnostics, optionBag);
321 for (
auto &buffer : slang::make_reverse_range(driver.buffers))
322 preprocessor.pushSource(buffer);
323 if (failed(preprocessAndPrint(preprocessor)))
326 for (
auto &buffer : driver.buffers) {
327 slang::BumpAllocator alloc;
328 slang::Diagnostics diagnostics;
329 slang::parsing::Preprocessor preprocessor(driver.sourceManager, alloc,
330 diagnostics, optionBag);
331 preprocessor.pushSource(buffer);
332 if (failed(preprocessAndPrint(preprocessor)))
350 }
catch (
const std::exception &e) {
351 return emitError(UnknownLoc(),
"internal slang error: ") << e.what();
357 MLIRContext *mlirContext, TimingScope &ts,
361 ImportDriver importDriver(mlirContext, ts, options);
362 if (failed(importDriver.prepareDriver(sourceMgr)))
364 return importDriver.importVerilog(module);
371 MLIRContext *mlirContext,
372 TimingScope &ts, llvm::raw_ostream &os,
375 ImportDriver importDriver(mlirContext, ts, options);
376 if (failed(importDriver.prepareDriver(sourceMgr)))
378 return importDriver.preprocessVerilog(os);
384 static TranslateToMLIRRegistration fromVerilog(
385 "import-verilog",
"import Verilog or SystemVerilog",
386 [](llvm::SourceMgr &sourceMgr, MLIRContext *context) {
393 importVerilog(sourceMgr, context, ts, module.get(), &options)))
static llvm::hash_code hash_value(const ElaboratorValue &val)
static LogicalResult catchExceptions(llvm::function_ref< LogicalResult()> callback)
Execute a callback and report any thrown exceptions as "internal slang error" MLIR diagnostics.
static Location convertLocation(MLIRContext *context, const slang::SourceManager &sourceManager, SmallDenseMap< slang::BufferID, StringRef > &bufferFilePaths, slang::SourceLocation loc)
Convert a slang SourceLocation to an MLIR Location.
static LogicalResult verify(Value clock, bool eventExists, mlir::Location loc)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
std::string getSlangVersion()
Return a human-readable string describing the slang frontend version linked into CIRCT.
mlir::LogicalResult importVerilog(llvm::SourceMgr &sourceMgr, mlir::MLIRContext *context, mlir::TimingScope &ts, mlir::ModuleOp module, const ImportVerilogOptions *options=nullptr)
Parse files in a source manager as Verilog source code and populate the given MLIR module with corres...
mlir::LogicalResult preprocessVerilog(llvm::SourceMgr &sourceMgr, mlir::MLIRContext *context, mlir::TimingScope &ts, llvm::raw_ostream &os, const ImportVerilogOptions *options=nullptr)
Run the files in a source manager through Slang's Verilog preprocessor and emit the result to the giv...
void registerFromVerilogTranslation()
Register the import-verilog MLIR translation.
Options that control how Verilog input files are parsed and processed.
bool debugInfo
Generate debug information in the form of debug dialect ops in the IR.
A helper class to facilitate the conversion from a Slang AST to MLIR operations.
static bool isEqual(slang::BufferID a, slang::BufferID b)
static slang::BufferID getEmptyKey()
static slang::BufferID getTombstoneKey()
static unsigned getHashValue(slang::BufferID id)