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/diagnostics/DiagnosticClient.h"
30#include "slang/driver/Driver.h"
31#include "slang/parsing/Preprocessor.h"
32#include "slang/syntax/SyntaxPrinter.h"
33#include "slang/util/VersionInfo.h"
37using namespace ImportVerilog;
43 llvm::raw_string_ostream os(buffer);
44 os <<
"slang version ";
45 os << slang::VersionInfo::getMajor() <<
".";
46 os << slang::VersionInfo::getMinor() <<
".";
47 os << slang::VersionInfo::getPatch() <<
"+";
48 os << slang::VersionInfo::getHash();
58 const slang::SourceManager &sourceManager,
59 slang::SourceLocation loc) {
60 if (loc && loc.buffer() != slang::SourceLocation::NoLocation.buffer()) {
61 auto fileName = sourceManager.getFileName(loc);
62 auto line = sourceManager.getLineNumber(loc);
63 auto column = sourceManager.getColumnNumber(loc);
64 return FileLineColLoc::get(context, fileName, line, column);
66 return UnknownLoc::get(context);
69Location Context::convertLocation(slang::SourceLocation loc) {
80class MlirDiagnosticClient :
public slang::DiagnosticClient {
82 MlirDiagnosticClient(MLIRContext *context) : context(context) {}
84 void report(
const slang::ReportedDiagnostic &diag)
override {
86 auto &diagEngine = context->getDiagEngine();
89 mlirDiag << diag.formattedMessage;
93 auto optionName = engine->getOptionName(diag.originalDiagnostic.code);
94 if (!optionName.empty())
95 mlirDiag <<
" [-W" << optionName <<
"]";
98 for (
auto loc : std::views::reverse(diag.expansionLocs)) {
99 auto ¬e = mlirDiag.attachNote(
101 auto macroName = sourceManager->getMacroName(loc);
102 if (macroName.empty())
103 note <<
"expanded from here";
105 note <<
"expanded from macro '" << macroName <<
"'";
109 slang::SmallVector<slang::SourceLocation> includeStack;
110 getIncludeStack(diag.location.buffer(), includeStack);
111 for (
auto &loc : std::views::reverse(includeStack))
117 return ::convertLocation(context, *sourceManager, loc);
120 static DiagnosticSeverity
getSeverity(slang::DiagnosticSeverity severity) {
122 case slang::DiagnosticSeverity::Fatal:
123 case slang::DiagnosticSeverity::Error:
124 return DiagnosticSeverity::Error;
125 case slang::DiagnosticSeverity::Warning:
126 return DiagnosticSeverity::Warning;
127 case slang::DiagnosticSeverity::Ignored:
128 case slang::DiagnosticSeverity::Note:
129 return DiagnosticSeverity::Remark;
131 llvm_unreachable(
"all slang diagnostic severities should be handled");
132 return DiagnosticSeverity::Error;
136 MLIRContext *context;
144 static slang::BufferID
getEmptyKey() {
return slang::BufferID(); }
146 return slang::BufferID(UINT32_MAX - 1,
""sv);
152 static bool isEqual(slang::BufferID a, slang::BufferID b) {
return a == b; }
164 ImportDriver(MLIRContext *mlirContext, TimingScope &ts,
166 : mlirContext(mlirContext), ts(ts),
167 options(options ? *options : defaultOptions) {}
169 LogicalResult prepareDriver(SourceMgr &sourceMgr);
173 MLIRContext *mlirContext;
179 slang::driver::Driver driver;
186LogicalResult ImportDriver::prepareDriver(SourceMgr &sourceMgr) {
189 auto diagClient = std::make_shared<MlirDiagnosticClient>(mlirContext);
190 driver.diagEngine.addClient(diagClient);
192 for (
const auto &value : options.commandFiles)
193 if (!driver.processCommandFiles(value, true,
202 DenseSet<StringRef> seenBuffers;
203 for (
unsigned i = 0, e = sourceMgr.getNumBuffers(); i < e; ++i) {
204 const llvm::MemoryBuffer *mlirBuffer = sourceMgr.getMemoryBuffer(i + 1);
205 auto name = mlirBuffer->getBufferIdentifier();
206 if (!name.empty() && !seenBuffers.insert(name).second)
209 driver.sourceManager.assignText(name, mlirBuffer->getBuffer());
210 driver.sourceLoader.addBuffer(slangBuffer);
213 for (
const auto &libDir : options.libDirs)
214 driver.sourceLoader.addSearchDirectories(libDir);
216 for (
const auto &libExt : options.libExts)
217 driver.sourceLoader.addSearchExtension(libExt);
219 for (
const auto &includeDir : options.includeDirs)
220 if (driver.sourceManager.addUserDirectories(includeDir))
223 for (
const auto &includeSystemDir : options.includeSystemDirs)
224 if (driver.sourceManager.addSystemDirectories(includeSystemDir))
228 driver.options.excludeExts.insert(options.excludeExts.begin(),
229 options.excludeExts.end());
230 driver.options.ignoreDirectives = options.ignoreDirectives;
232 driver.options.maxIncludeDepth = options.maxIncludeDepth;
233 driver.options.defines = options.defines;
234 driver.options.undefines = options.undefines;
235 driver.options.librariesInheritMacros = options.librariesInheritMacros;
237 driver.options.timeScale = options.timeScale;
238 driver.options.compilationFlags.emplace(
239 slang::ast::CompilationFlags::AllowUseBeforeDeclare,
240 options.allowUseBeforeDeclare);
241 driver.options.compilationFlags.emplace(
242 slang::ast::CompilationFlags::IgnoreUnknownModules,
243 options.ignoreUnknownModules);
244 driver.options.compilationFlags.emplace(
245 slang::ast::CompilationFlags::LintMode,
247 driver.options.compilationFlags.emplace(
248 slang::ast::CompilationFlags::DisableInstanceCaching,
false);
249 driver.options.topModules = options.topModules;
250 driver.options.paramOverrides = options.paramOverrides;
252 driver.options.errorLimit = options.errorLimit;
253 driver.options.warningOptions = options.warningOptions;
255 driver.options.singleUnit = options.singleUnit;
257 return success(driver.processOptions());
262LogicalResult ImportDriver::importVerilog(ModuleOp module) {
264 auto parseTimer = ts.nest(
"Verilog parser");
265 bool parseSuccess = driver.parseAllSources();
269 auto compileTimer = ts.nest(
"Verilog elaboration");
270 auto compilation = driver.createCompilation();
271 for (
auto &diag : compilation->getAllDiagnostics())
272 driver.diagEngine.issue(diag);
273 if (!parseSuccess || driver.diagEngine.getNumErrors() > 0)
284 ->loadDialect<moore::MooreDialect, hw::HWDialect, cf::ControlFlowDialect,
285 func::FuncDialect, verif::VerifDialect, ltl::LTLDialect,
286 debug::DebugDialect>();
287 auto conversionTimer = ts.nest(
"Verilog to dialect mapping");
288 Context context(options, *compilation, module, driver.sourceManager);
289 if (failed(context.convertCompilation()))
291 conversionTimer.stop();
294 auto verifierTimer = ts.nest(
"Post-parse verification");
295 return verify(module);
300LogicalResult ImportDriver::preprocessVerilog(llvm::raw_ostream &os) {
301 auto parseTimer = ts.nest(
"Verilog preprocessing");
305 auto preprocessAndPrint = [&](slang::parsing::Preprocessor &preprocessor) {
306 slang::syntax::SyntaxPrinter output;
307 output.setIncludeComments(
false);
309 slang::parsing::Token token = preprocessor.next();
311 if (token.kind == slang::parsing::TokenKind::EndOfFile)
315 for (
auto &diag : preprocessor.getDiagnostics()) {
316 if (diag.isError()) {
317 driver.diagEngine.issue(diag);
329 auto optionBag = driver.createOptionBag();
330 if (driver.options.singleUnit ==
true) {
331 slang::BumpAllocator alloc;
332 slang::Diagnostics diagnostics;
333 slang::parsing::Preprocessor preprocessor(driver.sourceManager, alloc,
334 diagnostics, optionBag);
337 auto sources = driver.sourceLoader.loadSources();
338 for (
auto &buffer : std::views::reverse(sources))
339 preprocessor.pushSource(buffer);
340 if (failed(preprocessAndPrint(preprocessor)))
343 for (
auto &buffer : driver.sourceLoader.loadSources()) {
344 slang::BumpAllocator alloc;
345 slang::Diagnostics diagnostics;
346 slang::parsing::Preprocessor preprocessor(driver.sourceManager, alloc,
347 diagnostics, optionBag);
348 preprocessor.pushSource(buffer);
349 if (failed(preprocessAndPrint(preprocessor)))
363 MLIRContext *mlirContext, TimingScope &ts,
366 ImportDriver importDriver(mlirContext, ts, options);
367 if (failed(importDriver.prepareDriver(sourceMgr)))
369 return importDriver.importVerilog(module);
375 MLIRContext *mlirContext,
376 TimingScope &ts, llvm::raw_ostream &os,
378 ImportDriver importDriver(mlirContext, ts, options);
379 if (failed(importDriver.prepareDriver(sourceMgr)))
381 return importDriver.preprocessVerilog(os);
386 static TranslateToMLIRRegistration fromVerilog(
387 "import-verilog",
"import Verilog or SystemVerilog",
388 [](llvm::SourceMgr &sourceMgr, MLIRContext *context) {
391 ModuleOp::create(UnknownLoc::get(context)));
396 importVerilog(sourceMgr, context, ts, module.get(), &options)))
411 auto &anyPM = pm.nestAny();
412 anyPM.addPass(mlir::createCSEPass());
413 anyPM.addPass(mlir::createCanonicalizerPass());
419 pm.addPass(mlir::createSymbolDCEPass());
423 auto &modulePM = pm.nest<moore::SVModuleOp>();
430 modulePM.addPass(mlir::createSROA());
435 auto &anyPM = pm.nestAny();
436 anyPM.addPass(mlir::createMem2Reg());
437 anyPM.addPass(mlir::createCSEPass());
438 anyPM.addPass(mlir::createCanonicalizerPass());
450 auto &anyPM = pm.nestAny();
451 anyPM.addPass(mlir::createCSEPass());
452 anyPM.addPass(mlir::createCanonicalizerPass());
460 pm.addNestedPass<
hw::HWModuleOp>(llhd::createWrapProceduralOpsPass());
461 pm.addPass(mlir::createSCFToControlFlowPass());
462 pm.addPass(llhd::createInlineCallsPass());
463 pm.addPass(mlir::createSymbolDCEPass());
470 modulePM.addPass(llhd::createMem2RegPass());
471 modulePM.addPass(llhd::createHoistSignalsPass());
472 modulePM.addPass(llhd::createDeseqPass());
473 modulePM.addPass(llhd::createLowerProcessesPass());
474 modulePM.addPass(mlir::createCSEPass());
475 modulePM.addPass(mlir::createCanonicalizerPass());
478 modulePM.addPass(llhd::createUnrollLoopsPass());
479 modulePM.addPass(mlir::createCSEPass());
480 modulePM.addPass(mlir::createCanonicalizerPass());
481 modulePM.addPass(llhd::createRemoveControlFlowPass());
482 modulePM.addPass(mlir::createCSEPass());
483 modulePM.addPass(mlir::createCanonicalizerPass());
490 modulePM.addPass(llhd::createCombineDrivesPass());
491 modulePM.addPass(llhd::createSig2Reg());
492 modulePM.addPass(mlir::createCSEPass());
493 modulePM.addPass(mlir::createCanonicalizerPass());
499 modulePM.addPass(mlir::createCSEPass());
500 modulePM.addPass(mlir::createCanonicalizerPass());
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 > createLowerConcatRefPass()
std::unique_ptr< mlir::Pass > createVTablesPass()
std::unique_ptr< mlir::Pass > createRegOfVecToMem()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void populateVerilogToMoorePipeline(mlir::OpPassManager &pm)
Optimize and simplify the Moore dialect IR.
std::unique_ptr< mlir::Pass > createMapArithToCombPass()
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 slang::BufferID getEmptyKey()
static slang::BufferID getTombstoneKey()
static unsigned getHashValue(slang::BufferID id)