Skip to content

Commit

Permalink
Netlist: add option to control unrolling of procedural for loops (#1134)
Browse files Browse the repository at this point in the history
  • Loading branch information
jameshanlon authored Sep 26, 2024
1 parent 6e18236 commit 6ad50f1
Show file tree
Hide file tree
Showing 13 changed files with 91 additions and 76 deletions.
17 changes: 17 additions & 0 deletions tools/netlist/include/NetlistVisitorOptions.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//------------------------------------------------------------------------------
//! @file NetlistVisitorOptions.h
//! @brief Options controlling the way the netlist is created.
//
// SPDX-FileCopyrightText: Michael Popoloski
// SPDX-License-Identifier: MIT
//------------------------------------------------------------------------------
#pragma once

#include <optional>

/// Hold various options controlling the way the netlist is created.
struct NetlistVisitorOptions {

/// If enabled, unroll for loops in procedural blocks.
bool unrollForLoops{false};
};
9 changes: 6 additions & 3 deletions tools/netlist/include/visitors/GenerateBlockVisitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//------------------------------------------------------------------------------
#pragma once

#include "visitors/ContinuousAssignVisitor.hpp"
#include "visitors/ProceduralBlockVisitor.hpp"

using namespace slang;
Expand All @@ -18,8 +19,9 @@ namespace netlist {
/// marked as uninstantiated, and are therefore not visited.
class GenerateBlockVisitor : public ast::ASTVisitor<GenerateBlockVisitor, true, false> {
public:
explicit GenerateBlockVisitor(ast::Compilation& compilation, Netlist& netlist) :
compilation(compilation), netlist(netlist) {}
explicit GenerateBlockVisitor(ast::Compilation& compilation, Netlist& netlist,
NetlistVisitorOptions const& options) :
compilation(compilation), netlist(netlist), options(options) {}

/// Variable declaration.
void handle(const ast::VariableSymbol& symbol) { netlist.addVariableDeclaration(symbol); }
Expand All @@ -29,7 +31,7 @@ class GenerateBlockVisitor : public ast::ASTVisitor<GenerateBlockVisitor, true,

/// Procedural block.
void handle(const ast::ProceduralBlockSymbol& symbol) {
ProceduralBlockVisitor visitor(compilation, netlist, ast::EdgeKind::None);
ProceduralBlockVisitor visitor(compilation, netlist, options, ast::EdgeKind::None);
symbol.visit(visitor);
}

Expand All @@ -43,6 +45,7 @@ class GenerateBlockVisitor : public ast::ASTVisitor<GenerateBlockVisitor, true,

private:
Netlist& netlist;
NetlistVisitorOptions const& options;
ast::Compilation& compilation;
};

Expand Down
10 changes: 6 additions & 4 deletions tools/netlist/include/visitors/InstanceVisitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ namespace netlist {
/// variables mirroring the ports.
class InstanceVisitor : public ast::ASTVisitor<InstanceVisitor, true, false> {
public:
explicit InstanceVisitor(ast::Compilation& compilation, Netlist& netlist) :
compilation(compilation), netlist(netlist) {}
explicit InstanceVisitor(ast::Compilation& compilation, Netlist& netlist,
NetlistVisitorOptions const& options) :
compilation(compilation), netlist(netlist), options(options) {}

private:
void connectDeclToVar(NetlistNode& declNode, const ast::Symbol& variable) {
Expand Down Expand Up @@ -207,15 +208,15 @@ class InstanceVisitor : public ast::ASTVisitor<InstanceVisitor, true, false> {

/// Procedural block.
void handle(const ast::ProceduralBlockSymbol& symbol) {
ProceduralBlockVisitor visitor(compilation, netlist,
ProceduralBlockVisitor visitor(compilation, netlist, options,
ProceduralBlockVisitor::determineEdgeKind(symbol));
symbol.visit(visitor);
}

/// Generate block.
void handle(const ast::GenerateBlockSymbol& symbol) {
if (!symbol.isUninstantiated) {
GenerateBlockVisitor visitor(compilation, netlist);
GenerateBlockVisitor visitor(compilation, netlist, options);
symbol.visit(visitor);
}
}
Expand All @@ -231,6 +232,7 @@ class InstanceVisitor : public ast::ASTVisitor<InstanceVisitor, true, false> {
private:
ast::Compilation& compilation;
Netlist& netlist;
NetlistVisitorOptions const& options;
};

} // namespace netlist
23 changes: 6 additions & 17 deletions tools/netlist/include/visitors/NetlistVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,13 @@
//------------------------------------------------------------------------------
#pragma once

#include "Config.h"
#include "Debug.h"
#include "Netlist.h"
#include "fmt/color.h"
#include "fmt/format.h"
#include "NetlistVisitorOptions.hpp"
#include "visitors/InstanceVisitor.hpp"
#include <algorithm>
#include <iostream>

#include "slang/ast/ASTContext.h"
#include "slang/ast/ASTVisitor.h"
#include "slang/ast/Compilation.h"
#include "slang/ast/SemanticFacts.h"
#include "slang/ast/Symbol.h"
#include "slang/ast/expressions/AssignmentExpressions.h"
#include "slang/ast/symbols/BlockSymbols.h"
#include "slang/ast/symbols/CompilationUnitSymbols.h"
#include "slang/ast/symbols/ValueSymbol.h"
#include "slang/diagnostics/TextDiagnosticClient.h"
#include "slang/util/Util.h"

using namespace slang;

Expand All @@ -35,17 +22,19 @@ namespace netlist {
/// The top-level visitor that traverses the AST and builds a netlist connectivity graph.
class NetlistVisitor : public ast::ASTVisitor<NetlistVisitor, true, false> {
public:
explicit NetlistVisitor(ast::Compilation& compilation, Netlist& netlist) :
compilation(compilation), netlist(netlist) {}
explicit NetlistVisitor(ast::Compilation& compilation, Netlist& netlist,
NetlistVisitorOptions const& options) :
compilation(compilation), netlist(netlist), options(options) {}

void handle(const ast::InstanceSymbol& symbol) {
InstanceVisitor visitor(compilation, netlist);
InstanceVisitor visitor(compilation, netlist, options);
symbol.visit(visitor);
}

private:
ast::Compilation& compilation;
Netlist& netlist;
NetlistVisitorOptions const& options;
};

} // namespace netlist
42 changes: 10 additions & 32 deletions tools/netlist/include/visitors/ProceduralBlockVisitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,27 @@

#include "Debug.h"
#include "Netlist.h"
#include <memory>
#include "NetlistVisitorOptions.hpp"
#include "visitors/VariableReferenceVisitor.hpp"

#include "slang/ast/EvalContext.h"
#include "slang/ast/symbols/BlockSymbols.h"
#include "slang/util/IntervalMap.h"

using namespace slang;

namespace netlist {

/// Visit a proceural block. This visitor performs unrolling of loops and
/// evaluation of conditionals where the controlloing conditions can be
/// evaluation of conditionals where the controlling conditions can be
/// determined statically.
class ProceduralBlockVisitor : public ast::ASTVisitor<ProceduralBlockVisitor, true, false> {
public:
bool anyErrors = false;

explicit ProceduralBlockVisitor(ast::Compilation& compilation, Netlist& netlist,
ast::EdgeKind edgeKind) :
NetlistVisitorOptions const& options, ast::EdgeKind edgeKind) :
netlist(netlist), evalCtx(ast::ASTContext(compilation.getRoot(), ast::LookupLocation::max)),
edgeKind(edgeKind) {
options(options), edgeKind(edgeKind) {
evalCtx.pushEmptyFrame();
DEBUG_PRINT("Procedural block\n");
}
Expand Down Expand Up @@ -68,7 +68,7 @@ class ProceduralBlockVisitor : public ast::ASTVisitor<ProceduralBlockVisitor, tr
if (result == ast::EdgeKind::None)
break;
}
// if we got here, edgeKind is not "None" which is all we care about
// If we got here, edgeKind is not "None" which is all we care about.
}
}
return result;
Expand All @@ -84,8 +84,9 @@ class ProceduralBlockVisitor : public ast::ASTVisitor<ProceduralBlockVisitor, tr

void handle(const ast::ForLoopStatement& loop) {

// Conditions this loop cannot be unrolled.
if (loop.loopVars.empty() || !loop.stopExpr || loop.steps.empty() || anyErrors) {
// Conditions that mean this loop cannot be unrolled.
if (!options.unrollForLoops || loop.loopVars.empty() || !loop.stopExpr ||
loop.steps.empty() || anyErrors) {
loop.body.visit(*this);
return;
}
Expand Down Expand Up @@ -174,22 +175,12 @@ class ProceduralBlockVisitor : public ast::ASTVisitor<ProceduralBlockVisitor, tr
cond.expr->visit(varRefVisitor);
}

// Push the condition variables.
for (auto& varRef : varRefVisitor.getVars()) {
condVarsStack.push_back(varRef);
}

// Visit the 'then' and 'else' statements, whose execution is
// under the control of the condition variables.
stmt.ifTrue.visit(*this);
if (stmt.ifFalse) {
stmt.ifFalse->visit(*this);
}

// Pop the condition variables.
for (auto& varRef : varRefVisitor.getVars()) {
condVarsStack.pop_back();
}
};

for (auto& cond : stmt.conditions) {
Expand Down Expand Up @@ -251,19 +242,6 @@ class ProceduralBlockVisitor : public ast::ASTVisitor<ProceduralBlockVisitor, tr
connectVarToVar(RHSVarRef, LHSVarRef);
}
}

// Add edges to the LHS target variables from declarations that
// correspond to conditions controlling the assignment.
for (auto* condNode : condVarsStack) {
auto& condVarRef = condNode->as<NetlistVariableReference>();

connectDeclToVar(condVarRef, condVarRef.symbol);
for (auto* leftNode : visitorLHS.getVars()) {

// Add edge from conditional variable to the LHS variable.
connectVarToVar(*condNode, *leftNode);
}
}
}

private:
Expand Down Expand Up @@ -303,7 +281,7 @@ class ProceduralBlockVisitor : public ast::ASTVisitor<ProceduralBlockVisitor, tr

Netlist& netlist;
ast::EvalContext evalCtx;
SmallVector<NetlistNode*> condVarsStack;
NetlistVisitorOptions const& options;
ast::EdgeKind edgeKind;
};

Expand Down
4 changes: 4 additions & 0 deletions tools/netlist/include/visitors/VariableReferenceVisitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
//------------------------------------------------------------------------------
#pragma once

#include "Netlist.h"

#include "slang/ast/ASTVisitor.h"

using namespace slang;

namespace netlist {
Expand Down
11 changes: 5 additions & 6 deletions tools/netlist/netlist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,8 @@
#include "fmt/color.h"
#include "fmt/format.h"
#include "visitors/NetlistVisitor.h"
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <unordered_set>
#include <utility>
#include <vector>

#include "slang/ast/ASTSerializer.h"
Expand All @@ -27,8 +24,6 @@
#include "slang/driver/Driver.h"
#include "slang/text/FormatBuffer.h"
#include "slang/text/Json.h"
#include "slang/util/String.h"
#include "slang/util/TimeTrace.h"
#include "slang/util/Util.h"
#include "slang/util/VersionInfo.h"

Expand Down Expand Up @@ -212,11 +207,13 @@ int main(int argc, char** argv) {
std::optional<bool> quiet;
std::optional<bool> debug;
std::optional<bool> combLoops;
std::optional<bool> unrollForLoops;
driver.cmdLine.add("-h,--help", showHelp, "Display available options");
driver.cmdLine.add("--version", showVersion, "Display version information and exit");
driver.cmdLine.add("-q,--quiet", quiet, "Suppress non-essential output");
driver.cmdLine.add("-d,--debug", debug, "Output debugging information");
driver.cmdLine.add("-c,--comb-loops", combLoops, "Detect combinatorial loops");
driver.cmdLine.add("--unroll-for-loops", unrollForLoops, "Unroll procedural for loops");

std::optional<std::string> astJsonFile;
driver.cmdLine.add(
Expand Down Expand Up @@ -289,7 +286,9 @@ int main(int argc, char** argv) {

// Create the netlist by traversing the AST.
Netlist netlist;
NetlistVisitor visitor(*compilation, netlist);
NetlistVisitorOptions options;
options.unrollForLoops = unrollForLoops.value_or(false);
NetlistVisitor visitor(*compilation, netlist, options);
compilation->getRoot().visit(visitor);
netlist.split();
DEBUG_PRINT("Netlist has {} nodes and {} edges\n", netlist.numNodes(), netlist.numEdges());
Expand Down
1 change: 1 addition & 0 deletions tools/netlist/tests/CombLoopsTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "CombLoops.h"
#include "NetlistTest.h"
#include "Test.h"

//===---------------------------------------------------------------------===//
// Basic tests
Expand Down
1 change: 1 addition & 0 deletions tools/netlist/tests/NameTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//------------------------------------------------------------------------------

#include "NetlistTest.h"
#include "Test.h"

//===---------------------------------------------------------------------===//
// Tests for name resolution.
Expand Down
16 changes: 13 additions & 3 deletions tools/netlist/tests/NetlistTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,25 @@

#include "Netlist.h"
#include "PathFinder.h"
#include "Test.h"
#include "visitors/NetlistVisitor.h"
#include <string>

#include "slang/ast/Compilation.h"

using namespace netlist;

inline Netlist createNetlist(Compilation& compilation) {
inline Netlist createNetlist(ast::Compilation& compilation) {
Netlist netlist;
NetlistVisitorOptions options;
NetlistVisitor visitor(compilation, netlist, options);
compilation.getRoot().visit(visitor);
netlist.split();
return netlist;
}

inline Netlist createNetlist(ast::Compilation& compilation, NetlistVisitorOptions const& options) {
Netlist netlist;
NetlistVisitor visitor(compilation, netlist);
NetlistVisitor visitor(compilation, netlist, options);
compilation.getRoot().visit(visitor);
netlist.split();
return netlist;
Expand Down
Loading

0 comments on commit 6ad50f1

Please sign in to comment.