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"
29#include "slang/analysis/AnalysisManager.h"
30#include "slang/diagnostics/DiagnosticClient.h"
31#include "slang/driver/Driver.h"
32#include "slang/parsing/Preprocessor.h"
33#include "slang/syntax/SyntaxPrinter.h"
34#include "slang/util/VersionInfo.h"
38using namespace ImportVerilog;
44 llvm::raw_string_ostream os(buffer);
45 os <<
"slang version ";
46 os << slang::VersionInfo::getMajor() <<
".";
47 os << slang::VersionInfo::getMinor() <<
".";
48 os << slang::VersionInfo::getPatch() <<
"+";
49 os << slang::VersionInfo::getHash();
59 const slang::SourceManager &sourceManager,
60 slang::SourceLocation loc) {
61 if (loc && loc.buffer() != slang::SourceLocation::NoLocation.buffer()) {
62 auto fileName = sourceManager.getFileName(loc);
63 auto line = sourceManager.getLineNumber(loc);
64 auto column = sourceManager.getColumnNumber(loc);
65 return FileLineColLoc::get(
context, fileName, line, column);
67 return UnknownLoc::get(
context);
72 const slang::SourceManager &sourceManager,
73 slang::SourceRange range) {
74 auto start = range.start();
75 auto end = range.end();
76 if (start && start.buffer() != slang::SourceLocation::NoLocation.buffer()) {
77 auto fileName = sourceManager.getFileName(start);
78 auto startLine = sourceManager.getLineNumber(start);
79 auto startColumn = sourceManager.getColumnNumber(start);
80 if (end && end.buffer() == start.buffer()) {
81 auto endLine = sourceManager.getLineNumber(end);
82 auto endColumn = sourceManager.getColumnNumber(end);
83 return FileLineColRange::get(
context, fileName, startLine, startColumn,
86 return FileLineColLoc::get(
context, fileName, startLine, startColumn);
88 return UnknownLoc::get(
context);
91Location Context::convertLocation(slang::SourceLocation loc) {
102class MlirDiagnosticClient :
public slang::DiagnosticClient {
106 void report(
const slang::ReportedDiagnostic &diag)
override {
108 auto &diagEngine =
context->getDiagEngine();
112 auto mlirDiag = diagEngine.emit(loc,
getSeverity(diag.severity));
113 mlirDiag << diag.formattedMessage;
117 auto optionName = engine->getOptionName(diag.originalDiagnostic.code);
118 if (!optionName.empty())
119 mlirDiag <<
" [-W" << optionName <<
"]";
122 for (
auto loc : std::views::reverse(diag.expansionLocs)) {
123 auto ¬e = mlirDiag.attachNote(
125 auto macroName = sourceManager->getMacroName(loc);
126 if (macroName.empty())
127 note <<
"expanded from here";
129 note <<
"expanded from macro '" << macroName <<
"'";
133 slang::SmallVector<slang::SourceLocation> includeStack;
134 getIncludeStack(diag.location.buffer(), includeStack);
135 for (
auto &loc : std::views::reverse(includeStack))
141 return ::convertLocation(
context, *sourceManager, loc);
146 return ::convertLocation(
context, *sourceManager, range);
149 static DiagnosticSeverity
getSeverity(slang::DiagnosticSeverity severity) {
151 case slang::DiagnosticSeverity::Fatal:
152 case slang::DiagnosticSeverity::Error:
153 return DiagnosticSeverity::Error;
154 case slang::DiagnosticSeverity::Warning:
155 return DiagnosticSeverity::Warning;
156 case slang::DiagnosticSeverity::Ignored:
157 case slang::DiagnosticSeverity::Note:
158 return DiagnosticSeverity::Remark;
160 llvm_unreachable(
"all slang diagnostic severities should be handled");
161 return DiagnosticSeverity::Error;
176 static bool isEqual(slang::BufferID a, slang::BufferID b) {
return a == b; }
188 ImportDriver(MLIRContext *mlirContext, TimingScope &ts,
190 : mlirContext(mlirContext), ts(ts),
191 options(options ? *options : defaultOptions) {}
193 LogicalResult prepareDriver(SourceMgr &sourceMgr);
197 MLIRContext *mlirContext;
203 slang::driver::Driver driver;
210LogicalResult ImportDriver::prepareDriver(SourceMgr &sourceMgr) {
213 auto diagClient = std::make_shared<MlirDiagnosticClient>(mlirContext);
214 driver.diagEngine.addClient(diagClient);
216 for (
const auto &value : options.commandFiles)
217 if (!driver.processCommandFiles(value, true,
226 DenseSet<StringRef> seenBuffers;
227 for (
unsigned i = 0, e = sourceMgr.getNumBuffers(); i < e; ++i) {
228 const llvm::MemoryBuffer *mlirBuffer = sourceMgr.getMemoryBuffer(i + 1);
229 auto name = mlirBuffer->getBufferIdentifier();
230 if (!name.empty() && !seenBuffers.insert(name).second)
233 driver.sourceManager.assignText(name, mlirBuffer->getBuffer());
234 driver.sourceLoader.addBuffer(slangBuffer);
237 for (
const auto &libDir : options.libDirs)
238 driver.sourceLoader.addSearchDirectories(libDir);
240 for (
const auto &libExt : options.libExts)
241 driver.sourceLoader.addSearchExtension(libExt);
243 for (
const auto &[i, f] :
llvm::enumerate(options.libraryFiles)) {
245 auto libName =
"library " + std::to_string(i);
246 driver.sourceLoader.addLibraryFiles(libName, f);
249 for (
const auto &includeDir : options.includeDirs)
250 if (driver.sourceManager.addUserDirectories(includeDir))
253 for (
const auto &includeSystemDir : options.includeSystemDirs)
254 if (driver.sourceManager.addSystemDirectories(includeSystemDir))
258 driver.addStandardArgs();
260 driver.options.excludeExts.insert(options.excludeExts.begin(),
261 options.excludeExts.end());
262 driver.options.ignoreDirectives = options.ignoreDirectives;
264 driver.options.maxIncludeDepth = options.maxIncludeDepth;
265 driver.options.defines = options.defines;
266 driver.options.undefines = options.undefines;
267 driver.options.librariesInheritMacros = options.librariesInheritMacros;
269 driver.options.timeScale = options.timeScale;
271 .compilationFlags[slang::ast::CompilationFlags::AllowUseBeforeDeclare] =
272 options.allowUseBeforeDeclare;
274 .compilationFlags[slang::ast::CompilationFlags::IgnoreUnknownModules] =
275 options.ignoreUnknownModules;
276 driver.options.compilationFlags[slang::ast::CompilationFlags::LintMode] =
279 .compilationFlags[slang::ast::CompilationFlags::DisableInstanceCaching] =
281 driver.options.topModules = options.topModules;
282 driver.options.paramOverrides = options.paramOverrides;
284 driver.options.errorLimit = options.errorLimit;
285 driver.options.warningOptions = options.warningOptions;
287 driver.options.singleUnit = options.singleUnit;
290 if (!options.slangArgs.empty()) {
291 SmallVector<const char *> slangArgs;
292 slangArgs.push_back(
"slang");
293 for (
const auto &arg : options.slangArgs)
294 slangArgs.push_back(arg.c_str());
295 if (!driver.parseCommandLine(slangArgs.size(), slangArgs.data()))
299 return success(driver.processOptions());
304LogicalResult ImportDriver::importVerilog(ModuleOp module) {
306 auto parseTimer = ts.nest(
"Verilog parser");
307 bool parseSuccess = driver.parseAllSources();
311 auto compileTimer = ts.nest(
"Verilog elaboration");
312 auto compilation = driver.createCompilation();
315 auto analysisTimer = ts.nest(
"Semantic analysis");
316 driver.runAnalysis(*compilation);
318 for (
auto &diag : compilation->getAllDiagnostics())
319 driver.diagEngine.issue(diag);
320 if (!parseSuccess || driver.diagEngine.getNumErrors() > 0)
331 ->loadDialect<moore::MooreDialect, hw::HWDialect, cf::ControlFlowDialect,
332 func::FuncDialect, verif::VerifDialect, ltl::LTLDialect,
333 debug::DebugDialect>();
334 auto conversionTimer = ts.nest(
"Verilog to dialect mapping");
335 Context context(options, *compilation, module, driver.sourceManager);
336 if (failed(
context.convertCompilation()))
338 conversionTimer.stop();
341 auto verifierTimer = ts.nest(
"Post-parse verification");
342 return verify(module);
347LogicalResult ImportDriver::preprocessVerilog(llvm::raw_ostream &os) {
348 auto parseTimer = ts.nest(
"Verilog preprocessing");
352 auto preprocessAndPrint = [&](slang::parsing::Preprocessor &preprocessor) {
353 slang::syntax::SyntaxPrinter output;
354 output.setIncludeComments(
false);
356 slang::parsing::Token token = preprocessor.next();
358 if (token.kind == slang::parsing::TokenKind::EndOfFile)
362 for (
auto &diag : preprocessor.getDiagnostics()) {
363 if (diag.isError()) {
364 driver.diagEngine.issue(diag);
376 auto optionBag = driver.createOptionBag();
377 if (driver.options.singleUnit ==
true) {
378 slang::BumpAllocator alloc;
379 slang::Diagnostics diagnostics;
380 slang::parsing::Preprocessor preprocessor(driver.sourceManager, alloc,
381 diagnostics, optionBag);
384 auto sources = driver.sourceLoader.loadSources();
385 for (
auto &buffer : std::views::reverse(sources))
386 preprocessor.pushSource(buffer);
387 if (failed(preprocessAndPrint(preprocessor)))
390 for (
auto &buffer : driver.sourceLoader.loadSources()) {
391 slang::BumpAllocator alloc;
392 slang::Diagnostics diagnostics;
393 slang::parsing::Preprocessor preprocessor(driver.sourceManager, alloc,
394 diagnostics, optionBag);
395 preprocessor.pushSource(buffer);
396 if (failed(preprocessAndPrint(preprocessor)))
410 MLIRContext *mlirContext, TimingScope &ts,
413 ImportDriver importDriver(mlirContext, ts, options);
414 if (failed(importDriver.prepareDriver(sourceMgr)))
416 return importDriver.importVerilog(module);
422 MLIRContext *mlirContext,
423 TimingScope &ts, llvm::raw_ostream &os,
425 ImportDriver importDriver(mlirContext, ts, options);
426 if (failed(importDriver.prepareDriver(sourceMgr)))
428 return importDriver.preprocessVerilog(os);
433 static TranslateToMLIRRegistration fromVerilog(
434 "import-verilog",
"import Verilog or SystemVerilog",
435 [](llvm::SourceMgr &sourceMgr, MLIRContext *
context) {
438 ModuleOp::create(UnknownLoc::get(
context)));
458 auto &anyPM = pm.nestAny();
459 anyPM.addPass(mlir::createCSEPass());
460 anyPM.addPass(mlir::createCanonicalizerPass());
466 pm.addPass(mlir::createSymbolDCEPass());
470 auto &modulePM = pm.nest<moore::SVModuleOp>();
477 modulePM.addPass(mlir::createSROA());
482 auto &anyPM = pm.nestAny();
483 anyPM.addPass(mlir::createMem2Reg());
484 anyPM.addPass(mlir::createCSEPass());
485 anyPM.addPass(mlir::createCanonicalizerPass());
497 auto &anyPM = pm.nestAny();
498 anyPM.addPass(mlir::createCSEPass());
499 anyPM.addPass(mlir::createCanonicalizerPass());
507 pm.addNestedPass<
hw::HWModuleOp>(llhd::createWrapProceduralOpsPass());
508 pm.addPass(mlir::createSCFToControlFlowPass());
509 pm.addPass(llhd::createInlineCallsPass());
510 pm.addPass(mlir::createSymbolDCEPass());
517 modulePM.addPass(mlir::createSROA());
519 modulePM.addPass(llhd::createMem2RegPass());
520 modulePM.addPass(llhd::createHoistSignalsPass());
521 modulePM.addPass(llhd::createDeseqPass());
522 modulePM.addPass(llhd::createLowerProcessesPass());
523 modulePM.addPass(mlir::createCSEPass());
524 modulePM.addPass(mlir::createCanonicalizerPass());
527 modulePM.addPass(llhd::createUnrollLoopsPass());
528 modulePM.addPass(mlir::createCSEPass());
529 modulePM.addPass(mlir::createCanonicalizerPass());
530 modulePM.addPass(llhd::createRemoveControlFlowPass());
531 modulePM.addPass(mlir::createCSEPass());
532 modulePM.addPass(mlir::createCanonicalizerPass());
539 modulePM.addPass(llhd::createCombineDrivesPass());
540 modulePM.addPass(llhd::createSig2Reg());
541 modulePM.addPass(mlir::createCSEPass());
542 modulePM.addPass(mlir::createCanonicalizerPass());
547 modulePM.addPass(seq::createRegOfVecToMem());
548 modulePM.addPass(mlir::createCSEPass());
549 modulePM.addPass(mlir::createCanonicalizerPass());
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, 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.
Convert LLHD dialect IR into core dialect IR.
Option< bool > detectMemories
static bool isEqual(slang::BufferID a, slang::BufferID b)
static unsigned getHashValue(slang::BufferID id)