14#include "mlir/IR/Diagnostics.h"
15#include "mlir/IR/Verifier.h"
16#include "mlir/Support/Timing.h"
17#include "mlir/Tools/mlir-translate/Translation.h"
18#include "llvm/ADT/Hashing.h"
19#include "llvm/Support/SourceMgr.h"
21#include "slang/diagnostics/DiagnosticClient.h"
22#include "slang/driver/Driver.h"
23#include "slang/parsing/Preprocessor.h"
24#include "slang/syntax/SyntaxPrinter.h"
25#include "slang/util/VersionInfo.h"
29using namespace ImportVerilog;
35 llvm::raw_string_ostream os(buffer);
36 os <<
"slang version ";
37 os << slang::VersionInfo::getMajor() <<
".";
38 os << slang::VersionInfo::getMinor() <<
".";
39 os << slang::VersionInfo::getPatch() <<
"+";
40 os << slang::VersionInfo::getHash();
50 const slang::SourceManager &sourceManager,
51 slang::SourceLocation loc) {
52 if (loc && loc.buffer() != slang::SourceLocation::NoLocation.buffer()) {
53 auto fileName = sourceManager.getFileName(loc);
54 auto line = sourceManager.getLineNumber(loc);
55 auto column = sourceManager.getColumnNumber(loc);
56 return FileLineColLoc::get(context, fileName, line, column);
58 return UnknownLoc::get(context);
61Location Context::convertLocation(slang::SourceLocation loc) {
72class MlirDiagnosticClient :
public slang::DiagnosticClient {
74 MlirDiagnosticClient(MLIRContext *context) : context(context) {}
76 void report(
const slang::ReportedDiagnostic &diag)
override {
78 auto &diagEngine = context->getDiagEngine();
81 mlirDiag << diag.formattedMessage;
85 auto optionName = engine->getOptionName(diag.originalDiagnostic.code);
86 if (!optionName.empty())
87 mlirDiag <<
" [-W" << optionName <<
"]";
90 for (
auto loc : std::views::reverse(diag.expansionLocs)) {
91 auto ¬e = mlirDiag.attachNote(
93 auto macroName = sourceManager->getMacroName(loc);
94 if (macroName.empty())
95 note <<
"expanded from here";
97 note <<
"expanded from macro '" << macroName <<
"'";
101 slang::SmallVector<slang::SourceLocation> includeStack;
102 getIncludeStack(diag.location.buffer(), includeStack);
103 for (
auto &loc : std::views::reverse(includeStack))
109 return ::convertLocation(context, *sourceManager, loc);
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;
136 static slang::BufferID
getEmptyKey() {
return slang::BufferID(); }
138 return slang::BufferID(UINT32_MAX - 1,
""sv);
142 return llvm::hash_value(
id.getId());
144 static bool isEqual(slang::BufferID a, slang::BufferID b) {
return a == b; }
156 ImportDriver(MLIRContext *mlirContext, TimingScope &ts,
158 : mlirContext(mlirContext), ts(ts),
159 options(options ? *options : defaultOptions) {}
161 LogicalResult prepareDriver(SourceMgr &sourceMgr);
165 MLIRContext *mlirContext;
171 slang::driver::Driver driver;
178LogicalResult ImportDriver::prepareDriver(SourceMgr &sourceMgr) {
181 auto diagClient = std::make_shared<MlirDiagnosticClient>(mlirContext);
182 driver.diagEngine.addClient(diagClient);
189 DenseSet<StringRef> seenBuffers;
190 for (
unsigned i = 0, e = sourceMgr.getNumBuffers(); i < e; ++i) {
191 const llvm::MemoryBuffer *mlirBuffer = sourceMgr.getMemoryBuffer(i + 1);
192 auto name = mlirBuffer->getBufferIdentifier();
193 if (!name.empty() && !seenBuffers.insert(name).second)
196 driver.sourceManager.assignText(name, mlirBuffer->getBuffer());
197 driver.sourceLoader.addBuffer(slangBuffer);
200 for (
const auto &libDir : options.libDirs)
201 driver.sourceLoader.addSearchDirectories(libDir);
203 for (
const auto &libExt : options.libExts)
204 driver.sourceLoader.addSearchExtension(libExt);
206 for (
const auto &includeDir : options.includeDirs)
207 if (driver.sourceManager.addUserDirectories(includeDir))
210 for (
const auto &includeSystemDir : options.includeSystemDirs)
211 if (driver.sourceManager.addSystemDirectories(includeSystemDir))
215 driver.options.excludeExts.insert(options.excludeExts.begin(),
216 options.excludeExts.end());
217 driver.options.ignoreDirectives = options.ignoreDirectives;
219 driver.options.maxIncludeDepth = options.maxIncludeDepth;
220 driver.options.defines = options.defines;
221 driver.options.undefines = options.undefines;
222 driver.options.librariesInheritMacros = options.librariesInheritMacros;
224 driver.options.timeScale = options.timeScale;
225 driver.options.compilationFlags.emplace(
226 slang::ast::CompilationFlags::AllowUseBeforeDeclare,
227 options.allowUseBeforeDeclare);
228 driver.options.compilationFlags.emplace(
229 slang::ast::CompilationFlags::IgnoreUnknownModules,
230 options.ignoreUnknownModules);
231 driver.options.compilationFlags.emplace(
232 slang::ast::CompilationFlags::LintMode,
234 driver.options.compilationFlags.emplace(
235 slang::ast::CompilationFlags::DisableInstanceCaching,
false);
236 driver.options.topModules = options.topModules;
237 driver.options.paramOverrides = options.paramOverrides;
239 driver.options.errorLimit = options.errorLimit;
240 driver.options.warningOptions = options.warningOptions;
242 driver.options.singleUnit = options.singleUnit;
244 return success(driver.processOptions());
249LogicalResult ImportDriver::importVerilog(ModuleOp module) {
251 auto parseTimer = ts.nest(
"Verilog parser");
252 bool parseSuccess = driver.parseAllSources();
256 auto compileTimer = ts.nest(
"Verilog elaboration");
257 auto compilation = driver.createCompilation();
258 for (
auto &diag : compilation->getAllDiagnostics())
259 driver.diagEngine.issue(diag);
260 if (!parseSuccess || driver.diagEngine.getNumErrors() > 0)
271 ->loadDialect<moore::MooreDialect, hw::HWDialect, cf::ControlFlowDialect,
272 func::FuncDialect, verif::VerifDialect, ltl::LTLDialect,
273 debug::DebugDialect>();
274 auto conversionTimer = ts.nest(
"Verilog to dialect mapping");
275 Context context(options, *compilation, module, driver.sourceManager);
276 if (failed(context.convertCompilation()))
278 conversionTimer.stop();
281 auto verifierTimer = ts.nest(
"Post-parse verification");
282 return verify(module);
287LogicalResult ImportDriver::preprocessVerilog(llvm::raw_ostream &os) {
288 auto parseTimer = ts.nest(
"Verilog preprocessing");
292 auto preprocessAndPrint = [&](slang::parsing::Preprocessor &preprocessor) {
293 slang::syntax::SyntaxPrinter output;
294 output.setIncludeComments(
false);
296 slang::parsing::Token token = preprocessor.next();
298 if (token.kind == slang::parsing::TokenKind::EndOfFile)
302 for (
auto &diag : preprocessor.getDiagnostics()) {
303 if (diag.isError()) {
304 driver.diagEngine.issue(diag);
316 auto optionBag = driver.createOptionBag();
317 if (driver.options.singleUnit ==
true) {
318 slang::BumpAllocator alloc;
319 slang::Diagnostics diagnostics;
320 slang::parsing::Preprocessor preprocessor(driver.sourceManager, alloc,
321 diagnostics, optionBag);
324 auto sources = driver.sourceLoader.loadSources();
325 for (
auto &buffer : std::views::reverse(sources))
326 preprocessor.pushSource(buffer);
327 if (failed(preprocessAndPrint(preprocessor)))
330 for (
auto &buffer : driver.sourceLoader.loadSources()) {
331 slang::BumpAllocator alloc;
332 slang::Diagnostics diagnostics;
333 slang::parsing::Preprocessor preprocessor(driver.sourceManager, alloc,
334 diagnostics, optionBag);
335 preprocessor.pushSource(buffer);
336 if (failed(preprocessAndPrint(preprocessor)))
350 MLIRContext *mlirContext, TimingScope &ts,
353 ImportDriver importDriver(mlirContext, ts, options);
354 if (failed(importDriver.prepareDriver(sourceMgr)))
356 return importDriver.importVerilog(module);
362 MLIRContext *mlirContext,
363 TimingScope &ts, llvm::raw_ostream &os,
365 ImportDriver importDriver(mlirContext, ts, options);
366 if (failed(importDriver.prepareDriver(sourceMgr)))
368 return importDriver.preprocessVerilog(os);
373 static TranslateToMLIRRegistration fromVerilog(
374 "import-verilog",
"import Verilog or SystemVerilog",
375 [](llvm::SourceMgr &sourceMgr, MLIRContext *context) {
378 ModuleOp::create(UnknownLoc::get(context)));
383 importVerilog(sourceMgr, context, ts, module.get(), &options)))
static Location convertLocation(MLIRContext *context, const slang::SourceManager &sourceManager, slang::SourceLocation loc)
Convert a slang SourceLocation to an MLIR Location.
static mlir::lsp::DiagnosticSeverity getSeverity(slang::DiagnosticSeverity severity)
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.
std::vector< std::string > warningOptions
A list of warning options that will be passed to the DiagnosticEngine.
@ OnlyLint
Only lint the input, without elaboration and lowering to CIRCT IR.
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.
const slang::SourceManager & sourceManager
MLIRContext * getContext()
Return the MLIR context.
Location convertLocation(slang::SourceLocation loc)
Convert a slang SourceLocation into an MLIR Location.
static bool isEqual(slang::BufferID a, slang::BufferID b)
static slang::BufferID getEmptyKey()
static slang::BufferID getTombstoneKey()
static unsigned getHashValue(slang::BufferID id)