CIRCT 23.0.0git
Loading...
Searching...
No Matches
ImportVerilog.cpp
Go to the documentation of this file.
1//===- ImportVerilog.cpp - Slang Verilog frontend integration -------------===//
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// This implements bridging from the slang Verilog frontend to CIRCT dialects.
10//
11//===----------------------------------------------------------------------===//
12
19#include "mlir/Conversion/SCFToControlFlow/SCFToControlFlow.h"
20#include "mlir/IR/Diagnostics.h"
21#include "mlir/IR/Verifier.h"
22#include "mlir/Pass/PassManager.h"
23#include "mlir/Support/Timing.h"
24#include "mlir/Tools/mlir-translate/Translation.h"
25#include "mlir/Transforms/Passes.h"
26#include "llvm/ADT/Hashing.h"
27#include "llvm/Support/SourceMgr.h"
28
29#include "slang/analysis/AnalysisManager.h"
30#include "slang/diagnostics/DiagnosticClient.h"
31#include "slang/diagnostics/Diagnostics.h"
32#include "slang/driver/Driver.h"
33#include "slang/parsing/Preprocessor.h"
34#include "slang/syntax/SyntaxPrinter.h"
35#include "slang/syntax/SyntaxTree.h"
36#include "slang/util/VersionInfo.h"
37
38using namespace mlir;
39using namespace circt;
40using namespace ImportVerilog;
41
42using llvm::SourceMgr;
43
45 std::string buffer;
46 llvm::raw_string_ostream os(buffer);
47 os << "slang version ";
48 os << slang::VersionInfo::getMajor() << ".";
49 os << slang::VersionInfo::getMinor() << ".";
50 os << slang::VersionInfo::getPatch() << "+";
51 os << slang::VersionInfo::getHash();
52 return buffer;
53}
54
55//===----------------------------------------------------------------------===//
56// Diagnostics
57//===----------------------------------------------------------------------===//
58
59/// Convert a slang `SourceLocation` to an MLIR `Location`.
60static Location convertLocation(MLIRContext *context,
61 const slang::SourceManager &sourceManager,
62 slang::SourceLocation loc) {
63 if (loc && loc.buffer() != slang::SourceLocation::NoLocation.buffer()) {
64 auto fileName = sourceManager.getFileName(loc);
65 auto line = sourceManager.getLineNumber(loc);
66 auto column = sourceManager.getColumnNumber(loc);
67 return FileLineColLoc::get(context, fileName, line, column);
68 }
69 return UnknownLoc::get(context);
70}
71
72/// Convert a slang `SourceRange` to an MLIR `Location`.
73static Location convertLocation(MLIRContext *context,
74 const slang::SourceManager &sourceManager,
75 slang::SourceRange range) {
76 auto start = range.start();
77 auto end = range.end();
78 if (start && start.buffer() != slang::SourceLocation::NoLocation.buffer()) {
79 auto fileName = sourceManager.getFileName(start);
80 auto startLine = sourceManager.getLineNumber(start);
81 auto startColumn = sourceManager.getColumnNumber(start);
82 if (end && end.buffer() == start.buffer()) {
83 auto endLine = sourceManager.getLineNumber(end);
84 auto endColumn = sourceManager.getColumnNumber(end);
85 return FileLineColRange::get(context, fileName, startLine, startColumn,
86 endLine, endColumn);
87 }
88 return FileLineColLoc::get(context, fileName, startLine, startColumn);
89 }
90 return UnknownLoc::get(context);
91}
92
93Location Context::convertLocation(slang::SourceLocation loc) {
94 return ::convertLocation(getContext(), sourceManager, loc);
95}
96
97Location Context::convertLocation(slang::SourceRange range) {
98 return ::convertLocation(getContext(), sourceManager, range);
99}
100
101namespace {
102/// A converter that can be plugged into a slang `DiagnosticEngine` as a client
103/// that will map slang diagnostics to their MLIR counterpart and emit them.
104class MlirDiagnosticClient : public slang::DiagnosticClient {
105public:
106 MlirDiagnosticClient(MLIRContext *context) : context(context) {}
107
108 void report(const slang::ReportedDiagnostic &diag) override {
109 // Generate the primary MLIR diagnostic.
110 auto &diagEngine = context->getDiagEngine();
111 Location loc = !diag.ranges.empty() ? convertLocation(diag.ranges[0])
112 : convertLocation(diag.location);
113
114 auto mlirDiag = diagEngine.emit(loc, getSeverity(diag.severity));
115 mlirDiag << diag.formattedMessage;
116
117 // Append the name of the option that can be used to control this
118 // diagnostic.
119 auto optionName = engine->getOptionName(diag.originalDiagnostic.code);
120 if (!optionName.empty())
121 mlirDiag << " [-W" << optionName << "]";
122
123 // Write out macro expansions, if we have any, in reverse order.
124 for (auto loc : std::views::reverse(diag.expansionLocs)) {
125 auto &note = mlirDiag.attachNote(
126 convertLocation(sourceManager->getFullyOriginalLoc(loc)));
127 auto macroName = sourceManager->getMacroName(loc);
128 if (macroName.empty())
129 note << "expanded from here";
130 else
131 note << "expanded from macro '" << macroName << "'";
132 }
133
134 // Write out the include stack.
135 slang::SmallVector<slang::SourceLocation> includeStack;
136 getIncludeStack(diag.location.buffer(), includeStack);
137 for (auto &loc : std::views::reverse(includeStack))
138 mlirDiag.attachNote(convertLocation(loc)) << "included from here";
139 }
140
141 /// Convert a slang `SourceLocation` to an MLIR `Location`.
142 Location convertLocation(slang::SourceLocation loc) const {
143 return ::convertLocation(context, *sourceManager, loc);
144 }
145
146 /// Convert a slang `SourceRange` to an MLIR `Location`.
147 Location convertLocation(slang::SourceRange range) const {
148 return ::convertLocation(context, *sourceManager, range);
149 }
150
151 static DiagnosticSeverity getSeverity(slang::DiagnosticSeverity severity) {
152 switch (severity) {
153 case slang::DiagnosticSeverity::Fatal:
154 case slang::DiagnosticSeverity::Error:
155 return DiagnosticSeverity::Error;
156 case slang::DiagnosticSeverity::Warning:
157 return DiagnosticSeverity::Warning;
158 case slang::DiagnosticSeverity::Ignored:
159 case slang::DiagnosticSeverity::Note:
160 return DiagnosticSeverity::Remark;
161 }
162 llvm_unreachable("all slang diagnostic severities should be handled");
163 return DiagnosticSeverity::Error;
164 }
165
166private:
167 MLIRContext *context;
168};
169} // namespace
170
171// Allow for `slang::BufferID` to be used as hash map keys.
172namespace llvm {
173template <>
174struct DenseMapInfo<slang::BufferID> {
175 static unsigned getHashValue(slang::BufferID id) {
176 return llvm::hash_value(id.getId());
177 }
178 static bool isEqual(slang::BufferID a, slang::BufferID b) { return a == b; }
179};
180} // namespace llvm
181
182//===----------------------------------------------------------------------===//
183// Driver
184//===----------------------------------------------------------------------===//
185
186namespace {
187const static ImportVerilogOptions defaultOptions;
188
189struct ImportDriver {
190 ImportDriver(MLIRContext *mlirContext, TimingScope &ts,
191 const ImportVerilogOptions *options)
192 : mlirContext(mlirContext), ts(ts),
193 options(options ? *options : defaultOptions) {}
194
195 LogicalResult prepareDriver(SourceMgr &sourceMgr);
196 LogicalResult importVerilog(ModuleOp module);
197 LogicalResult preprocessVerilog(llvm::raw_ostream &os);
198
199 MLIRContext *mlirContext;
200 TimingScope &ts;
201 const ImportVerilogOptions &options;
202
203 // Use slang's driver which conveniently packages a lot of the things we
204 // need for compilation.
205 slang::driver::Driver driver;
206};
207} // namespace
208
209/// Populate the Slang driver with source files from the given `sourceMgr`, and
210/// configure driver options based on the `ImportVerilogOptions` passed to the
211/// `ImportDriver` constructor.
212LogicalResult ImportDriver::prepareDriver(SourceMgr &sourceMgr) {
213 // Use slang's driver which conveniently packages a lot of the things we
214 // need for compilation.
215 auto diagClient = std::make_shared<MlirDiagnosticClient>(mlirContext);
216 driver.diagEngine.addClient(diagClient);
217
218 for (const auto &value : options.commandFiles)
219 if (!driver.processCommandFiles(value, /*makeRelative=*/true,
220 /*separateUnit=*/true))
221 return failure();
222
223 // Populate the source manager with the source files.
224 // NOTE: This is a bit ugly since we're essentially copying the Verilog
225 // source text in memory. At a later stage we'll want to extend slang's
226 // SourceManager such that it can contain non-owned buffers. This will do
227 // for now.
228 driver.sourceManager.setDisableProximatePaths(
229 !options.makeLocationPathsProximate);
230 DenseSet<StringRef> seenBuffers;
231 for (unsigned i = 0, e = sourceMgr.getNumBuffers(); i < e; ++i) {
232 const llvm::MemoryBuffer *mlirBuffer = sourceMgr.getMemoryBuffer(i + 1);
233 auto name = mlirBuffer->getBufferIdentifier();
234 if (!name.empty() && !seenBuffers.insert(name).second)
235 continue; // Slang doesn't like listing the same buffer twice
236 auto slangBuffer =
237 driver.sourceManager.assignText(name, mlirBuffer->getBuffer());
238 driver.sourceLoader.addBuffer(slangBuffer);
239 }
240
241 for (const auto &libDir : options.libDirs)
242 driver.sourceLoader.addSearchDirectories(libDir);
243
244 for (const auto &libExt : options.libExts)
245 driver.sourceLoader.addSearchExtension(libExt);
246
247 for (const auto &[i, f] : llvm::enumerate(options.libraryFiles)) {
248 // Include a space to avoid conflicts with explicitly-specified names.
249 auto libName = "library " + std::to_string(i);
250 driver.sourceLoader.addLibraryFiles(libName, f);
251 }
252
253 for (const auto &includeDir : options.includeDirs)
254 if (driver.sourceManager.addUserDirectories(includeDir))
255 return failure();
256
257 for (const auto &includeSystemDir : options.includeSystemDirs)
258 if (driver.sourceManager.addSystemDirectories(includeSystemDir))
259 return failure();
260
261 // Populate the driver options.
262 driver.addStandardArgs();
263
264 driver.options.excludeExts.insert(options.excludeExts.begin(),
265 options.excludeExts.end());
266 driver.options.ignoreDirectives = options.ignoreDirectives;
267
268 driver.options.maxIncludeDepth = options.maxIncludeDepth;
269 driver.options.defines = options.defines;
270 driver.options.undefines = options.undefines;
271 driver.options.librariesInheritMacros = options.librariesInheritMacros;
272
273 driver.options.timeScale = options.timeScale;
274 driver.options
275 .compilationFlags[slang::ast::CompilationFlags::AllowUseBeforeDeclare] =
276 options.allowUseBeforeDeclare;
277 driver.options
278 .compilationFlags[slang::ast::CompilationFlags::IgnoreUnknownModules] =
279 options.ignoreUnknownModules;
280 driver.options.compilationFlags[slang::ast::CompilationFlags::LintMode] =
282 driver.options
283 .compilationFlags[slang::ast::CompilationFlags::DisableInstanceCaching] =
284 false;
285 driver.options.topModules = options.topModules;
286 driver.options.paramOverrides = options.paramOverrides;
287
288 driver.options.errorLimit = options.errorLimit;
289 driver.options.warningOptions = options.warningOptions;
290
291 driver.options.singleUnit = options.singleUnit;
292
293 // Parse pass through options.
294 if (!options.slangArgs.empty()) {
295 SmallVector<const char *> slangArgs;
296 slangArgs.push_back("slang"); // dummy program name
297 for (const auto &arg : options.slangArgs)
298 slangArgs.push_back(arg.c_str());
299 if (!driver.parseCommandLine(slangArgs.size(), slangArgs.data()))
300 return failure();
301 }
302
303 return success(driver.processOptions());
304}
305
306/// Parse and elaborate the prepared source files, and populate the given MLIR
307/// `module` with corresponding operations.
308LogicalResult ImportDriver::importVerilog(ModuleOp module) {
309 // Parse the input.
310 auto parseTimer = ts.nest("Verilog parser");
311 bool parseSuccess = driver.parseAllSources();
312 parseTimer.stop();
313
314 // If we were only supposed to parse the input, gather the parse diagnostics
315 // and report them here, then return without elaborating. This mirrors
316 // slang-driver's `--parse-only`: errors that only surface during elaboration
317 // or IR conversion (unknown modules, constraint blocks, ...) don't run, so
318 // this succeeds on such inputs while still flagging genuine syntax errors.
319 // The module is left empty.
320 if (options.mode == ImportVerilogOptions::Mode::OnlyParse) {
321 slang::Diagnostics parseDiags;
322 for (const auto &tree : driver.sourceLoader.getLibraryMaps())
323 parseDiags.append_range(tree->diagnostics());
324 for (const auto &tree : driver.syntaxTrees)
325 parseDiags.append_range(tree->diagnostics());
326 parseDiags.sort(driver.sourceManager);
327 driver.diagEngine.issue(parseDiags);
328 return success(parseSuccess && driver.diagEngine.getNumErrors() == 0);
329 }
330
331 // Elaborate the input.
332 auto compileTimer = ts.nest("Verilog elaboration");
333 auto compilation = driver.createCompilation();
334
335 // Semantic analysis
336 auto analysisTimer = ts.nest("Semantic analysis");
337 driver.runAnalysis(*compilation);
338
339 for (auto &diag : compilation->getAllDiagnostics())
340 driver.diagEngine.issue(diag);
341 if (!parseSuccess || driver.diagEngine.getNumErrors() > 0)
342 return failure();
343 compileTimer.stop();
344
345 // If we were only supposed to lint the input, return here. This leaves the
346 // module empty, but any Slang linting messages got reported as diagnostics.
347 if (options.mode == ImportVerilogOptions::Mode::OnlyLint)
348 return success();
349
350 // Traverse the parsed Verilog AST and map it to the equivalent CIRCT ops.
351 mlirContext
352 ->loadDialect<moore::MooreDialect, hw::HWDialect, cf::ControlFlowDialect,
353 func::FuncDialect, verif::VerifDialect, ltl::LTLDialect,
354 debug::DebugDialect>();
355 auto conversionTimer = ts.nest("Verilog to dialect mapping");
356 Context context(options, *compilation, module, driver.sourceManager);
357 if (failed(context.convertCompilation()))
358 return failure();
359 conversionTimer.stop();
360
361 // Run the verifier on the constructed module to ensure it is clean.
362 auto verifierTimer = ts.nest("Post-parse verification");
363 return verify(module);
364}
365
366/// Preprocess the prepared source files and print them to the given output
367/// stream.
368LogicalResult ImportDriver::preprocessVerilog(llvm::raw_ostream &os) {
369 auto parseTimer = ts.nest("Verilog preprocessing");
370
371 // Run the preprocessor to completion across all sources previously added with
372 // `pushSource`, report diagnostics, and print the output.
373 auto preprocessAndPrint = [&](slang::parsing::Preprocessor &preprocessor) {
374 slang::syntax::SyntaxPrinter output;
375 output.setIncludeComments(false);
376 while (true) {
377 slang::parsing::Token token = preprocessor.next();
378 output.print(token);
379 if (token.kind == slang::parsing::TokenKind::EndOfFile)
380 break;
381 }
382
383 for (auto &diag : preprocessor.getDiagnostics()) {
384 if (diag.isError()) {
385 driver.diagEngine.issue(diag);
386 return failure();
387 }
388 }
389 os << output.str();
390 return success();
391 };
392
393 // Depending on whether the single-unit option is set, either add all source
394 // files to a single preprocessor such that they share define macros and
395 // directives, or create a separate preprocessor for each, such that each
396 // source file is in its own compilation unit.
397 auto optionBag = driver.createOptionBag();
398 if (driver.options.singleUnit == true) {
399 slang::BumpAllocator alloc;
400 slang::Diagnostics diagnostics;
401 slang::parsing::Preprocessor preprocessor(driver.sourceManager, alloc,
402 diagnostics, optionBag);
403 // Sources have to be pushed in reverse, as they form a stack in the
404 // preprocessor. Last pushed source is processed first.
405 auto sources = driver.sourceLoader.loadSources();
406 for (auto &buffer : std::views::reverse(sources))
407 preprocessor.pushSource(buffer);
408 if (failed(preprocessAndPrint(preprocessor)))
409 return failure();
410 } else {
411 for (auto &buffer : driver.sourceLoader.loadSources()) {
412 slang::BumpAllocator alloc;
413 slang::Diagnostics diagnostics;
414 slang::parsing::Preprocessor preprocessor(driver.sourceManager, alloc,
415 diagnostics, optionBag);
416 preprocessor.pushSource(buffer);
417 if (failed(preprocessAndPrint(preprocessor)))
418 return failure();
419 }
420 }
421
422 return success();
423}
424
425//===----------------------------------------------------------------------===//
426// Entry Points
427//===----------------------------------------------------------------------===//
428
429/// Parse the specified Verilog inputs into the specified MLIR context.
430LogicalResult circt::importVerilog(SourceMgr &sourceMgr,
431 MLIRContext *mlirContext, TimingScope &ts,
432 ModuleOp module,
433 const ImportVerilogOptions *options) {
434 ImportDriver importDriver(mlirContext, ts, options);
435 if (failed(importDriver.prepareDriver(sourceMgr)))
436 return failure();
437 return importDriver.importVerilog(module);
438}
439
440/// Run the files in a source manager through Slang's Verilog preprocessor and
441/// emit the result to the given output stream.
442LogicalResult circt::preprocessVerilog(SourceMgr &sourceMgr,
443 MLIRContext *mlirContext,
444 TimingScope &ts, llvm::raw_ostream &os,
445 const ImportVerilogOptions *options) {
446 ImportDriver importDriver(mlirContext, ts, options);
447 if (failed(importDriver.prepareDriver(sourceMgr)))
448 return failure();
449 return importDriver.preprocessVerilog(os);
450}
451
452/// Entry point as an MLIR translation.
454 static TranslateToMLIRRegistration fromVerilog(
455 "import-verilog", "import Verilog or SystemVerilog",
456 [](llvm::SourceMgr &sourceMgr, MLIRContext *context) {
457 TimingScope ts;
459 ModuleOp::create(UnknownLoc::get(context)));
460 ImportVerilogOptions options;
461 options.debugInfo = true;
462 options.warningOptions.push_back("no-missing-top");
463 if (failed(
464 importVerilog(sourceMgr, context, ts, module.get(), &options)))
465 module = {};
466 return module;
467 });
468}
469
470//===----------------------------------------------------------------------===//
471// Pass Pipeline
472//===----------------------------------------------------------------------===//
473
474/// Optimize and simplify the Moore dialect IR.
475void circt::populateVerilogToMoorePipeline(OpPassManager &pm) {
476 {
477 // Perform an initial cleanup and preprocessing across all
478 // modules/functions.
479 auto &anyPM = pm.nestAny();
480 anyPM.addPass(mlir::createCSEPass());
481 anyPM.addPass(mlir::createCanonicalizerPass());
482 }
483
484 pm.addPass(moore::createVTablesPass());
485
486 // Remove unused symbols.
487 pm.addPass(mlir::createSymbolDCEPass());
488
489 {
490 auto &anyPM = pm.nestAny();
491 anyPM.addPass(moore::createSimplifyRefsPass());
492 }
493
494 {
495 // Perform module-specific transformations.
496 auto &modulePM = pm.nest<moore::SVModuleOp>();
497 // TODO: Enable the following once it not longer interferes with @(...)
498 // event control checks. The introduced dummy variables make the event
499 // control observe a static local variable that never changes, instead of
500 // observing a module-wide signal.
501 // modulePM.addPass(moore::createSimplifyProceduresPass());
502 modulePM.addPass(mlir::createSROA());
503 }
504
505 {
506 // Perform a final cleanup across all modules/functions.
507 auto &anyPM = pm.nestAny();
508 anyPM.addPass(mlir::createMem2Reg());
509 anyPM.addPass(mlir::createCSEPass());
510 anyPM.addPass(mlir::createCanonicalizerPass());
511 }
512}
513
514/// Convert Moore dialect IR into core dialect IR
515void circt::populateMooreToCorePipeline(OpPassManager &pm) {
516 // Perform the conversion.
517 pm.addPass(createConvertMooreToCorePass());
518
519 {
520 // Conversion to the core dialects likely uncovers new canonicalization
521 // opportunities.
522 auto &anyPM = pm.nestAny();
523 anyPM.addPass(mlir::createCSEPass());
524 anyPM.addPass(mlir::createCanonicalizerPass());
525 }
526}
527
528/// Convert LLHD dialect IR into core dialect IR
530 OpPassManager &pm, const LlhdToCorePipelineOptions &options) {
531 // Inline function calls and lower SCF to CF.
532 pm.addNestedPass<hw::HWModuleOp>(llhd::createWrapProceduralOpsPass());
533 pm.addPass(mlir::createSCFToControlFlowPass());
534 pm.addPass(llhd::createInlineCallsPass());
535 pm.addPass(mlir::createSymbolDCEPass());
536
537 // Simplify processes, replace signals with process results, and detect
538 // registers.
539 auto &modulePM = pm.nest<hw::HWModuleOp>();
540 // See https://github.com/llvm/circt/issues/8804.
541 if (options.sroa) {
542 modulePM.addPass(mlir::createSROA());
543 }
544 modulePM.addPass(llhd::createMem2RegPass());
545 modulePM.addPass(llhd::createHoistSignalsPass());
546 modulePM.addPass(llhd::createDeseqPass());
547 modulePM.addPass(llhd::createLowerProcessesPass());
548 modulePM.addPass(mlir::createCSEPass());
549 modulePM.addPass(mlir::createCanonicalizerPass());
550
551 // Unroll loops and remove control flow.
552 modulePM.addPass(llhd::createUnrollLoopsPass());
553 modulePM.addPass(mlir::createCSEPass());
554 modulePM.addPass(mlir::createCanonicalizerPass());
555 modulePM.addPass(llhd::createRemoveControlFlowPass());
556 modulePM.addPass(mlir::createCSEPass());
557 modulePM.addPass(mlir::createCanonicalizerPass());
558
559 // Convert `arith.select` generated by some of the control flow canonicalizers
560 // to `comb.mux`.
561 modulePM.addPass(createMapArithToCombPass(true));
562
563 // Simplify module-level signals.
564 modulePM.addPass(llhd::createCombineDrivesPass());
565 modulePM.addPass(llhd::createSig2Reg());
566 modulePM.addPass(mlir::createCSEPass());
567 modulePM.addPass(mlir::createCanonicalizerPass());
568
569 // Map `seq.firreg` with array type and `hw.array_inject` self-feedback to
570 // `seq.firmem` ops.
571 if (options.detectMemories) {
572 modulePM.addPass(seq::createRegOfVecToMem());
573 modulePM.addPass(mlir::createCSEPass());
574 modulePM.addPass(mlir::createCanonicalizerPass());
575 }
576}
static std::unique_ptr< Context > context
static Location convertLocation(MLIRContext *context, const slang::SourceManager &sourceManager, slang::SourceLocation loc)
Convert a slang SourceLocation to an MLIR Location.
static llvm::lsp::DiagnosticSeverity getSeverity(slang::DiagnosticSeverity severity)
std::unique_ptr< mlir::Pass > createSimplifyRefsPass()
std::unique_ptr< mlir::Pass > createVTablesPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
std::unique_ptr< mlir::Pass > createMapArithToCombPass(bool enableBestEffortLowering=false)
void populateVerilogToMoorePipeline(mlir::OpPassManager &pm)
Optimize and simplify the Moore dialect IR.
void populateMooreToCorePipeline(mlir::OpPassManager &pm)
Convert Moore dialect IR into core dialect IR.
void populateLlhdToCorePipeline(mlir::OpPassManager &pm, const LlhdToCorePipelineOptions &options)
std::string getSlangVersion()
Return a human-readable string describing the slang frontend version linked into CIRCT.
std::unique_ptr< OperationPass< ModuleOp > > createConvertMooreToCorePass()
Create an Moore to Comb/HW/LLHD conversion pass.
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.
llvm::hash_code hash_value(const DenseSet< T > &set)
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.
@ OnlyParse
Only parse the input syntax and report parse diagnostics.
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.
Convert LLHD dialect IR into core dialect IR.
static bool isEqual(slang::BufferID a, slang::BufferID b)
static unsigned getHashValue(slang::BufferID id)