99#include " ImportVerilogInternals.h"
1010#include " slang/ast/Compilation.h"
1111#include " slang/ast/symbols/ClassSymbols.h"
12+ #include " llvm/ADT/STLFunctionalExtras.h"
1213#include " llvm/ADT/ScopeExit.h"
1314
1415using namespace circt ;
@@ -407,11 +408,19 @@ struct ModuleVisitor : public BaseVisitor {
407408 using slang::ast::MultiPortSymbol;
408409 using slang::ast::PortSymbol;
409410
411+ if (context.options .allowUseBeforeDeclare .value_or (false ))
412+ if (context.predeclaredInstances .contains (&instNode))
413+ return success ();
414+
410415 // Interface instances are expanded inline into individual variable/net ops
411416 // rather than creating a moore.instance op.
412417 auto defKind = instNode.body .getDefinition ().definitionKind ;
413- if (defKind == slang::ast::DefinitionKind::Interface)
418+ if (defKind == slang::ast::DefinitionKind::Interface) {
419+ if (context.options .allowUseBeforeDeclare .value_or (false ))
420+ if (context.interfaceInstances .lookup (&instNode))
421+ return success ();
414422 return expandInterfaceInstance (instNode);
423+ }
415424
416425 auto *moduleLowering = context.convertModuleHeader (&instNode.body );
417426 if (!moduleLowering)
@@ -700,6 +709,10 @@ struct ModuleVisitor : public BaseVisitor {
700709
701710 // Handle variables.
702711 LogicalResult visit (const slang::ast::VariableSymbol &varNode) {
712+ if (context.options .allowUseBeforeDeclare .value_or (false ))
713+ if (context.valueSymbols .lookup (&varNode))
714+ return success ();
715+
703716 auto loweredType = context.convertType (*varNode.getDeclaredType ());
704717 if (!loweredType)
705718 return failure ();
@@ -725,6 +738,10 @@ struct ModuleVisitor : public BaseVisitor {
725738
726739 // Handle nets.
727740 LogicalResult visit (const slang::ast::NetSymbol &netNode) {
741+ if (context.options .allowUseBeforeDeclare .value_or (false ))
742+ if (context.valueSymbols .lookup (&netNode))
743+ return success ();
744+
728745 auto loweredType = context.convertType (*netNode.getDeclaredType ());
729746 if (!loweredType)
730747 return failure ();
@@ -1356,8 +1373,280 @@ Context::convertModuleBody(const slang::ast::InstanceBodySymbol *module) {
13561373 }
13571374 }
13581375
1376+ const bool allowUseBeforeDeclare =
1377+ options.allowUseBeforeDeclare .value_or (false );
1378+ SmallVector<std::pair<moore::VariableOp, const slang::ast::Expression *>>
1379+ pendingVariableInitializers;
1380+ SmallVector<std::pair<moore::NetOp, const slang::ast::Expression *>>
1381+ pendingNetDeclarationAssignments;
1382+
1383+ struct ModulePredeclaration {
1384+ Context &context;
1385+ OpBuilder &builder;
1386+ SmallVector<std::pair<moore::VariableOp, const slang::ast::Expression *>>
1387+ &pendingVariableInitializers;
1388+ SmallVector<std::pair<moore::NetOp, const slang::ast::Expression *>>
1389+ &pendingNetDeclarationAssignments;
1390+
1391+ LogicalResult declareVariable (const slang::ast::VariableSymbol &varNode,
1392+ Location loc, StringRef blockNamePrefix) {
1393+ auto loweredType = context.convertType (*varNode.getDeclaredType ());
1394+ if (!loweredType)
1395+ return failure ();
1396+
1397+ auto varOp = moore::VariableOp::create (
1398+ builder, loc,
1399+ moore::RefType::get (cast<moore::UnpackedType>(loweredType)),
1400+ builder.getStringAttr (Twine (blockNamePrefix) + varNode.name ),
1401+ Value{});
1402+ context.valueSymbols .insert (&varNode, varOp);
1403+
1404+ const auto &canonTy = varNode.getType ().getCanonicalType ();
1405+ if (const auto *vi = canonTy.as_if <slang::ast::VirtualInterfaceType>())
1406+ if (failed (context.registerVirtualInterfaceMembers (varNode, *vi, loc)))
1407+ return failure ();
1408+
1409+ if (const auto *init = varNode.getInitializer ())
1410+ pendingVariableInitializers.push_back ({varOp, init});
1411+ return success ();
1412+ }
1413+
1414+ LogicalResult declareNet (const slang::ast::NetSymbol &netNode, Location loc,
1415+ StringRef blockNamePrefix) {
1416+ auto loweredType = context.convertType (*netNode.getDeclaredType ());
1417+ if (!loweredType)
1418+ return failure ();
1419+
1420+ auto netkind = convertNetKind (netNode.netType .netKind );
1421+ if (netkind == moore::NetKind::Interconnect ||
1422+ netkind == moore::NetKind::UserDefined ||
1423+ netkind == moore::NetKind::Unknown)
1424+ return mlir::emitError (loc, " unsupported net kind `" )
1425+ << netNode.netType .name << " `" ;
1426+
1427+ auto netOp = moore::NetOp::create (
1428+ builder, loc,
1429+ moore::RefType::get (cast<moore::UnpackedType>(loweredType)),
1430+ builder.getStringAttr (Twine (blockNamePrefix) + netNode.name ), netkind,
1431+ Value{});
1432+ context.valueSymbols .insert (&netNode, netOp);
1433+
1434+ if (const auto *init = netNode.getInitializer ())
1435+ pendingNetDeclarationAssignments.push_back ({netOp, init});
1436+ return success ();
1437+ }
1438+
1439+ SmallString<64 >
1440+ getGenerateBlockPrefix (const slang::ast::GenerateBlockSymbol &genNode,
1441+ StringRef blockNamePrefix) {
1442+ SmallString<64 > prefix = blockNamePrefix;
1443+ if (!genNode.name .empty () ||
1444+ genNode.getParentScope ()->asSymbol ().kind !=
1445+ slang::ast::SymbolKind::GenerateBlockArray) {
1446+ prefix += genNode.getExternalName ();
1447+ prefix += ' .' ;
1448+ }
1449+ return prefix;
1450+ }
1451+
1452+ LogicalResult predeclareStorageGenerateBlock (
1453+ const slang::ast::GenerateBlockSymbol &genNode,
1454+ StringRef blockNamePrefix) {
1455+ if (genNode.isUninstantiated )
1456+ return success ();
1457+ return predeclareStorageScope (
1458+ genNode, getGenerateBlockPrefix (genNode, blockNamePrefix));
1459+ }
1460+
1461+ LogicalResult predeclareInterfaceGenerateBlock (
1462+ const slang::ast::GenerateBlockSymbol &genNode,
1463+ StringRef blockNamePrefix) {
1464+ if (genNode.isUninstantiated )
1465+ return success ();
1466+ return predeclareInterfaceScope (
1467+ genNode, getGenerateBlockPrefix (genNode, blockNamePrefix));
1468+ }
1469+
1470+ LogicalResult predeclareModuleInstanceGenerateBlock (
1471+ const slang::ast::GenerateBlockSymbol &genNode,
1472+ StringRef blockNamePrefix) {
1473+ if (genNode.isUninstantiated )
1474+ return success ();
1475+ return predeclareModuleInstanceScope (
1476+ genNode, getGenerateBlockPrefix (genNode, blockNamePrefix));
1477+ }
1478+
1479+ LogicalResult predeclareGenerateBlockArray (
1480+ const slang::ast::GenerateBlockArraySymbol &genArrNode,
1481+ StringRef blockNamePrefix,
1482+ llvm::function_ref<
1483+ LogicalResult (const slang::ast::GenerateBlockSymbol &, StringRef)>
1484+ predeclareBlock) {
1485+ SmallString<64 > prefix = blockNamePrefix;
1486+ prefix += genArrNode.getExternalName ();
1487+ prefix += ' _' ;
1488+ auto prefixBaseLen = prefix.size ();
1489+
1490+ for (const auto *entry : genArrNode.entries ) {
1491+ prefix.resize (prefixBaseLen);
1492+ if (entry->arrayIndex )
1493+ prefix += entry->arrayIndex ->toString ();
1494+ else
1495+ Twine (entry->constructIndex ).toVector (prefix);
1496+ prefix += ' .' ;
1497+
1498+ if (failed (predeclareBlock (*entry, prefix)))
1499+ return failure ();
1500+ }
1501+ return success ();
1502+ }
1503+
1504+ LogicalResult predeclareStorageMember (const slang::ast::Symbol &member,
1505+ StringRef blockNamePrefix) {
1506+ auto loc = context.convertLocation (member.location );
1507+ if (const auto *varNode = member.as_if <slang::ast::VariableSymbol>())
1508+ return declareVariable (*varNode, loc, blockNamePrefix);
1509+
1510+ if (const auto *netNode = member.as_if <slang::ast::NetSymbol>())
1511+ return declareNet (*netNode, loc, blockNamePrefix);
1512+
1513+ if (const auto *genNode = member.as_if <slang::ast::GenerateBlockSymbol>())
1514+ return predeclareStorageGenerateBlock (*genNode, blockNamePrefix);
1515+
1516+ if (const auto *genArrNode =
1517+ member.as_if <slang::ast::GenerateBlockArraySymbol>())
1518+ return predeclareGenerateBlockArray (
1519+ *genArrNode, blockNamePrefix,
1520+ [&](const slang::ast::GenerateBlockSymbol &gen, StringRef prefix) {
1521+ return predeclareStorageGenerateBlock (gen, prefix);
1522+ });
1523+
1524+ return success ();
1525+ }
1526+
1527+ LogicalResult predeclareInterfaceMember (const slang::ast::Symbol &member,
1528+ StringRef blockNamePrefix) {
1529+ auto loc = context.convertLocation (member.location );
1530+ if (const auto *instNode = member.as_if <slang::ast::InstanceSymbol>()) {
1531+ if (instNode->body .getDefinition ().definitionKind ==
1532+ slang::ast::DefinitionKind::Interface)
1533+ return ModuleVisitor (context, loc, blockNamePrefix)
1534+ .expandInterfaceInstance (*instNode);
1535+ return success ();
1536+ }
1537+
1538+ if (const auto *genNode = member.as_if <slang::ast::GenerateBlockSymbol>())
1539+ return predeclareInterfaceGenerateBlock (*genNode, blockNamePrefix);
1540+
1541+ if (const auto *genArrNode =
1542+ member.as_if <slang::ast::GenerateBlockArraySymbol>())
1543+ return predeclareGenerateBlockArray (
1544+ *genArrNode, blockNamePrefix,
1545+ [&](const slang::ast::GenerateBlockSymbol &gen, StringRef prefix) {
1546+ return predeclareInterfaceGenerateBlock (gen, prefix);
1547+ });
1548+
1549+ return success ();
1550+ }
1551+
1552+ LogicalResult
1553+ predeclareModuleInstanceMember (const slang::ast::Symbol &member,
1554+ StringRef blockNamePrefix) {
1555+ auto loc = context.convertLocation (member.location );
1556+ if (const auto *instNode = member.as_if <slang::ast::InstanceSymbol>()) {
1557+ if (instNode->body .getDefinition ().definitionKind !=
1558+ slang::ast::DefinitionKind::Interface) {
1559+ if (failed (ModuleVisitor (context, loc, blockNamePrefix)
1560+ .visit (*instNode)))
1561+ return failure ();
1562+ context.predeclaredInstances .insert (instNode);
1563+ }
1564+ return success ();
1565+ }
1566+
1567+ if (const auto *genNode = member.as_if <slang::ast::GenerateBlockSymbol>())
1568+ return predeclareModuleInstanceGenerateBlock (*genNode, blockNamePrefix);
1569+
1570+ if (const auto *genArrNode =
1571+ member.as_if <slang::ast::GenerateBlockArraySymbol>())
1572+ return predeclareGenerateBlockArray (
1573+ *genArrNode, blockNamePrefix,
1574+ [&](const slang::ast::GenerateBlockSymbol &gen, StringRef prefix) {
1575+ return predeclareModuleInstanceGenerateBlock (gen, prefix);
1576+ });
1577+
1578+ return success ();
1579+ }
1580+
1581+ LogicalResult predeclareStorageScope (const slang::ast::Scope &scope,
1582+ StringRef blockNamePrefix) {
1583+ for (auto &member : scope.members ())
1584+ if (failed (predeclareStorageMember (member, blockNamePrefix)))
1585+ return failure ();
1586+ return success ();
1587+ }
1588+
1589+ LogicalResult predeclareInterfaceScope (const slang::ast::Scope &scope,
1590+ StringRef blockNamePrefix) {
1591+ for (auto &member : scope.members ())
1592+ if (failed (predeclareInterfaceMember (member, blockNamePrefix)))
1593+ return failure ();
1594+ return success ();
1595+ }
1596+
1597+ LogicalResult predeclareModuleInstanceScope (const slang::ast::Scope &scope,
1598+ StringRef blockNamePrefix) {
1599+ for (auto &member : scope.members ())
1600+ if (failed (predeclareModuleInstanceMember (member, blockNamePrefix)))
1601+ return failure ();
1602+ return success ();
1603+ }
1604+
1605+ LogicalResult predeclareScope (const slang::ast::Scope &scope,
1606+ StringRef blockNamePrefix) {
1607+ // First create variables and nets for the whole generated scope tree so
1608+ // later phases can bind port connections or hierarchical references to
1609+ // declarations that appear later in source.
1610+ if (failed (predeclareStorageScope (scope, blockNamePrefix)))
1611+ return failure ();
1612+
1613+ // Then expand interface instances. Interface expansion may lower
1614+ // continuous assignments or procedures from the interface body, so all
1615+ // storage symbols must already be available.
1616+ if (failed (predeclareInterfaceScope (scope, blockNamePrefix)))
1617+ return failure ();
1618+
1619+ // Finally instantiate modules. This makes later hierarchical references
1620+ // to instance internals available before earlier procedural blocks lower.
1621+ return predeclareModuleInstanceScope (scope, blockNamePrefix);
1622+ }
1623+ };
1624+
1625+ // Slang can resolve module-scope references to declarations that appear later
1626+ // in the source when `--allow-use-before-declare` is enabled. ImportVerilog
1627+ // still has to create Moore declarations before lowering any expression that
1628+ // may refer to them. Walk generated scopes as well as the direct module body,
1629+ // and pre-expand interface instances so earlier hierarchical references like
1630+ // `bus.sig` can find the expanded member values. Since Moore modules are
1631+ // graph regions, initializer operands can be attached after all declarations
1632+ // have been registered.
1633+ if (allowUseBeforeDeclare) {
1634+ ModulePredeclaration predecl{*this , builder, pendingVariableInitializers,
1635+ pendingNetDeclarationAssignments};
1636+ if (failed (predecl.predeclareScope (*module , " " )))
1637+ return failure ();
1638+ }
1639+
1640+ auto isPredeclaredMember = [&](const slang::ast::Symbol &member) {
1641+ return allowUseBeforeDeclare &&
1642+ (member.kind == slang::ast::SymbolKind::Variable ||
1643+ member.kind == slang::ast::SymbolKind::Net);
1644+ };
1645+
13591646 // Convert the body of the module.
13601647 for (auto &member : module ->members ()) {
1648+ if (isPredeclaredMember (member))
1649+ continue ;
13611650 auto loc = convertLocation (member.location );
13621651 if (failed (member.visit (ModuleVisitor (*this , loc))))
13631652 return failure ();
@@ -1367,6 +1656,26 @@ Context::convertModuleBody(const slang::ast::InstanceBodySymbol *module) {
13671656 return failure ();
13681657 }
13691658
1659+ // Lower deferred declaration assignments after the full module body has had a
1660+ // chance to create any additional symbols, such as generated block members.
1661+ if (allowUseBeforeDeclare) {
1662+ for (auto [netOp, init] : pendingNetDeclarationAssignments) {
1663+ auto dstType = cast<moore::RefType>(netOp.getType ()).getNestedType ();
1664+ auto rvalue = convertRvalueExpression (*init, dstType);
1665+ if (!rvalue)
1666+ return failure ();
1667+ netOp.getAssignmentMutable ().assign (rvalue);
1668+ }
1669+
1670+ for (auto [varOp, init] : pendingVariableInitializers) {
1671+ auto dstType = cast<moore::RefType>(varOp.getType ()).getNestedType ();
1672+ auto rvalue = convertRvalueExpression (*init, dstType);
1673+ if (!rvalue)
1674+ return failure ();
1675+ varOp.getInitialMutable ().assign (rvalue);
1676+ }
1677+ }
1678+
13701679 // Create additional ops to drive input port values onto the corresponding
13711680 // internal variables and nets, and to collect output port values for the
13721681 // terminator.
0 commit comments