[ImportVerilog] Add Slang frontend dependency (#6620)

This is the first PR in a longer chain that adds basic SV support to
CIRCT.

Add the Slang Verilog frontend as a CIRCT dependency. This will be the
foundation for CIRCT's Verilog parsing, elaboration, type checking, and
lowering to the core dialects. By default, Slang is built as a static
library from scratch, which is then linked into the new `ImportVerilog`
conversion. Alternatively, CIRCT can also be linked against a local
Slang installation provided by the system.

Add the `ImportVerilog` conversion library. This library statically
links in the Slang dependency and wraps it in an exception-safe,
LLVM-style API. Currently this only consists of the `getSlangVersion`
function and the necessary linking flags to get it to link statically
against Slang.

Add the `circt-verilog` tool, which will provide a fully-flegded
interface to the new `ImportVerilog` library. Later on we'll also add an
MLIR translation library for single-file SV import. But in general, SV
builds take a lot of command line options (macros, search paths, etc.)
and multiple input files, which is why we have a dedicated tool. All the
tool does at the moment is print the linked Slang version. More to come.

Note that this intentionally links against **version 3** of Slang. Newer
versions are available -- 4 and 5 as of this commit -- but they rely on
fairly new C++ compiler features that didn't work out of the box in our
CI images. We'll eventually want to upgrade, but for now Slang 3 is
sufficient to get the ball rolling.

See https://github.com/MikePopoloski/slang for details on Slang.

Co-authored-by: ShiZuoye <albertethon@163.com>
Co-authored-by: hunterzju <hunter_ht@zju.edu.cn>
Co-authored-by: 孙海龙 <hailong.sun@terapines.com>
This commit is contained in:
Fabian Schuiki 2024-01-30 13:22:00 -08:00 committed by GitHub
parent 962fddb9ba
commit 3d8b7d08d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 254 additions and 4 deletions

View File

@ -220,7 +220,8 @@ jobs:
-DCMAKE_CXX_COMPILER=${{ matrix.compiler.cxx }} \
-DLLVM_EXTERNAL_LIT=`pwd`/../llvm/build/bin/llvm-lit \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DLLVM_LIT_ARGS="-v"
-DLLVM_LIT_ARGS="-v" \
-DCIRCT_SLANG_FRONTEND_ENABLED=ON
ninja check-circt check-circt-unit -j$(nproc)
ninja circt-doc

View File

@ -96,7 +96,8 @@ jobs:
-DMLIR_ENABLE_BINDINGS_PYTHON=ON \
-DCIRCT_BINDINGS_PYTHON_ENABLED=ON \
-DESI_RUNTIME=ON \
-DLLVM_LIT_ARGS="-v --show-unsupported ${{ matrix.lit-flags }}"
-DLLVM_LIT_ARGS="-v --show-unsupported ${{ matrix.lit-flags }}" \
-DCIRCT_SLANG_FRONTEND_ENABLED=ON
- name: Test CIRCT
run: |
ninja -C build check-circt -j$(nproc)

View File

@ -89,7 +89,8 @@ jobs:
-DMLIR_ENABLE_BINDINGS_PYTHON=ON \
-DCIRCT_BINDINGS_PYTHON_ENABLED=ON \
-DESI_RUNTIME=ON \
-DLLVM_LIT_ARGS="-v --show-unsupported"
-DLLVM_LIT_ARGS="-v --show-unsupported" \
-DCIRCT_SLANG_FRONTEND_ENABLED=ON
- name: Test CIRCT
run: |
ninja -C build check-circt -j$(nproc)

View File

@ -177,7 +177,7 @@ jobs:
${{ steps.setup-windows.outputs.setup }}
mkdir build
cd build
cmake -G Ninja -S "$(pwd)/../llvm/llvm" $EXTRA_CMAKE_ARGS -DCMAKE_BUILD_TYPE=${{ inputs.cmake_build_type }} -DBUILD_SHARED_LIBS=${{ inputs.build_shared_libs }} -DLLVM_BUILD_TOOLS=ON -DLLVM_BUILD_EXAMPLES=OFF -DLLVM_ENABLE_ASSERTIONS=${{ inputs.llvm_enable_assertions }} -DLLVM_ENABLE_PROJECTS=mlir -DLLVM_EXTERNAL_PROJECTS=circt -DLLVM_EXTERNAL_CIRCT_SOURCE_DIR=".." -DLLVM_STATIC_LINK_CXX_STDLIB=ON -DLLVM_ENABLE_TERMINFO=OFF -DLLVM_PARALLEL_LINK_JOBS=1 -DLLVM_TARGETS_TO_BUILD="host" -DLLVM_FORCE_ENABLE_STATS=${{ inputs.llvm_force_enable_stats }} -DLLVM_ENABLE_ZSTD=OFF -DVERILATOR_DISABLE=ON -DLLVM_PARALLEL_LINK_JOBS=1 -DCIRCT_RELEASE_TAG_ENABLED=ON -DCIRCT_RELEASE_TAG=firtool -DCMAKE_EXPORT_COMPILE_COMMANDS=OFF -DCMAKE_C_COMPILER=${{ inputs.cmake_c_compiler }} -DCMAKE_CXX_COMPILER=${{ inputs.cmake_cxx_compiler }} ${{ steps.configure-sccache.outputs.enable_sccache }} -DCMAKE_INSTALL_PREFIX="$(pwd)/../install" -DLLVM_INSTALL_UTILS=ON
cmake -G Ninja -S "$(pwd)/../llvm/llvm" $EXTRA_CMAKE_ARGS -DCMAKE_BUILD_TYPE=${{ inputs.cmake_build_type }} -DBUILD_SHARED_LIBS=${{ inputs.build_shared_libs }} -DLLVM_BUILD_TOOLS=ON -DLLVM_BUILD_EXAMPLES=OFF -DLLVM_ENABLE_ASSERTIONS=${{ inputs.llvm_enable_assertions }} -DLLVM_ENABLE_PROJECTS=mlir -DLLVM_EXTERNAL_PROJECTS=circt -DLLVM_EXTERNAL_CIRCT_SOURCE_DIR=".." -DLLVM_STATIC_LINK_CXX_STDLIB=ON -DLLVM_ENABLE_TERMINFO=OFF -DLLVM_PARALLEL_LINK_JOBS=1 -DLLVM_TARGETS_TO_BUILD="host" -DLLVM_FORCE_ENABLE_STATS=${{ inputs.llvm_force_enable_stats }} -DLLVM_ENABLE_ZSTD=OFF -DVERILATOR_DISABLE=ON -DLLVM_PARALLEL_LINK_JOBS=1 -DCIRCT_RELEASE_TAG_ENABLED=ON -DCIRCT_RELEASE_TAG=firtool -DCMAKE_EXPORT_COMPILE_COMMANDS=OFF -DCMAKE_C_COMPILER=${{ inputs.cmake_c_compiler }} -DCMAKE_CXX_COMPILER=${{ inputs.cmake_cxx_compiler }} ${{ steps.configure-sccache.outputs.enable_sccache }} -DCMAKE_INSTALL_PREFIX="$(pwd)/../install" -DLLVM_INSTALL_UTILS=ON -DCIRCT_SLANG_FRONTEND_ENABLED=ON
# Optionally test
- name: Test CIRCT
if: inputs.runTests

View File

@ -25,6 +25,10 @@ if(POLICY CMP0116)
cmake_policy(SET CMP0116 OLD)
endif()
if(POLICY CMP0135)
cmake_policy(SET CMP0135 NEW)
endif()
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
@ -523,6 +527,62 @@ if(CIRCT_BINDINGS_TCL_ENABLED)
message(STATUS "Found TCL executable: ${TCL_TCLSH}")
endif()
#-------------------------------------------------------------------------------
# slang Verilog Frontend
#-------------------------------------------------------------------------------
option(CIRCT_SLANG_FRONTEND_ENABLED "Enables the slang Verilog frontend." OFF)
option(CIRCT_SLANG_BUILD_FROM_SOURCE
"Build slang from source instead of finding an installed package" ON)
llvm_canonicalize_cmake_booleans(CIRCT_SLANG_FRONTEND_ENABLED)
llvm_canonicalize_cmake_booleans(CIRCT_SLANG_BUILD_FROM_SOURCE)
if(CIRCT_SLANG_FRONTEND_ENABLED)
message(STATUS "slang Verilog frontend is enabled")
if(CIRCT_SLANG_BUILD_FROM_SOURCE)
# Build slang as part of CIRCT (see https://sv-lang.com/building.html)
message(STATUS "Building slang from source")
include(FetchContent)
FetchContent_Declare(
slang
URL https://github.com/MikePopoloski/slang/archive/refs/tags/v3.0.tar.gz
URL_HASH SHA256=02d184133525f6330a32bef492761b8ff52d0a33caed08eb51733f63cddb08e3
)
set(FETCHCONTENT_TRY_FIND_PACKAGE_MODE "NEVER")
# Force Slang to be built as a static library to avoid messing around with
# RPATHs and installing a slang dylib alongside CIRCT. The static library
# will embed Slang into ImportVerilog.
set(ORIGINAL_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
set(ORIGINAL_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS})
set(CMAKE_CXX_FLAGS "")
set(BUILD_SHARED_LIBS OFF)
FetchContent_MakeAvailable(slang)
set(CMAKE_CXX_FLAGS ${ORIGINAL_CMAKE_CXX_FLAGS})
set(BUILD_SHARED_LIBS ${ORIGINAL_BUILD_SHARED_LIBS})
if(BUILD_SHARED_LIBS)
set_target_properties(slang_slang PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_target_properties(fmt PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_target_properties(unordered_dense PROPERTIES POSITION_INDEPENDENT_CODE ON)
endif()
# The following feels *very* hacky, but CMake complains about the
# CIRCTImportVerilog target linking against slang_slang (even with PRIVATE
# linking) without the latter being in an export set. I think we'd want to
# statically link slang into the CIRCTImportVerilog library, but seems to be
# harder than it ought to be.
set_property(
GLOBAL APPEND PROPERTY CIRCT_EXPORTS slang_slang unordered_dense fmt)
install(TARGETS slang_slang unordered_dense fmt EXPORT CIRCTTargets)
else()
find_package(slang 3.0 REQUIRED)
endif()
endif()
#-------------------------------------------------------------------------------
# Directory setup
#-------------------------------------------------------------------------------

View File

@ -0,0 +1,26 @@
//===- ImportVerilog.h - Slang Verilog frontend integration ---------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Defines the interface to the Verilog frontend.
//
//===----------------------------------------------------------------------===//
#ifndef CIRCT_CONVERSION_IMPORTVERILOG_H
#define CIRCT_CONVERSION_IMPORTVERILOG_H
#include <string>
namespace circt {
/// Return a human-readable string describing the slang frontend version linked
/// into CIRCT.
std::string getSlangVersion();
} // namespace circt
#endif // CIRCT_CONVERSION_IMPORTVERILOG_H

View File

@ -28,3 +28,7 @@ add_subdirectory(SimToSV)
add_subdirectory(CFToHandshake)
add_subdirectory(VerifToSV)
add_subdirectory(CalyxNative)
if(CIRCT_SLANG_FRONTEND_ENABLED)
add_subdirectory(ImportVerilog)
endif()

View File

@ -0,0 +1,38 @@
# slang uses exceptions
set(LLVM_REQUIRES_EH ON)
set(LLVM_REQUIRES_RTTI ON)
# For ABI compatibility, define the DEBUG macro in debug builds. Slang sets this
# internally. If we don't set this here as well, header-defined things like the
# destructor of `Driver`, which is generated in ImportVerilog's compilation
# unit, will destroy a different set of fields than what was potentially built
# or modified by code compiled in the Slang compilation unit.
add_compile_definitions($<$<CONFIG:Debug>:DEBUG>)
# Disable some compiler warnings caused by slang headers such that the
# `ImportVerilog` build doesn't spew out a ton of warnings that are not related
# to CIRCT.
if (MSVC)
# No idea what to put here
else ()
# slang uses exceptions; we intercept these in ImportVerilog
add_compile_options(-fexceptions)
add_compile_options(-frtti)
# slang has some classes with virtual funcs but non-virtual destructor.
add_compile_options(-Wno-non-virtual-dtor)
# some other warnings we've seen
add_compile_options(-Wno-c++98-compat-extra-semi)
add_compile_options(-Wno-ctad-maybe-unsupported)
add_compile_options(-Wno-cast-qual)
# visitor switch statements cover all cases but have default
add_compile_options(-Wno-covered-switch-default)
endif ()
add_circt_translation_library(CIRCTImportVerilog
ImportVerilog.cpp
LINK_LIBS PUBLIC
MLIRTranslateLib
PRIVATE
slang_slang
)

View File

@ -0,0 +1,27 @@
//===- ImportVerilog.cpp - Slang Verilog frontend integration -------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This implements bridging from the slang Verilog frontend to CIRCT dialects.
//
//===----------------------------------------------------------------------===//
#include "circt/Conversion/ImportVerilog.h"
#include "llvm/Support/raw_ostream.h"
#include "slang/util/Version.h"
std::string circt::getSlangVersion() {
std::string buffer;
llvm::raw_string_ostream os(buffer);
os << "slang version ";
os << slang::VersionInfo::getMajor() << ".";
os << slang::VersionInfo::getMinor() << ".";
os << slang::VersionInfo::getPatch() << "+";
os << slang::VersionInfo::getHash();
return buffer;
}

View File

@ -43,6 +43,10 @@ if(CIRCT_LLHD_SIM_ENABLED)
list(APPEND CIRCT_TEST_DEPENDS circt-llhd-signals-runtime-wrappers)
endif()
if(CIRCT_SLANG_FRONTEND_ENABLED)
list(APPEND CIRCT_TEST_DEPENDS circt-verilog)
endif()
add_lit_testsuite(check-circt "Running the CIRCT regression tests"
${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${CIRCT_TEST_DEPENDS}

View File

@ -0,0 +1,6 @@
// RUN: circt-verilog -h | FileCheck %s --check-prefix=CHECK-HELP
// RUN: circt-verilog --version | FileCheck %s --check-prefix=CHECK-VERSION
// REQUIRES: slang
// CHECK-HELP: OVERVIEW: Verilog and SystemVerilog frontend
// CHECK-VERSION: slang version 3.

View File

@ -84,4 +84,9 @@ if config.llhd_sim_enabled:
config.available_features.add('llhd-sim')
tools.append('llhd-sim')
# Add circt-verilog if the Slang frontend is enabled.
if config.slang_frontend_enabled:
config.available_features.add('slang')
tools.append('circt-verilog')
llvm_config.add_tool_substitutions(tools, tool_dirs)

View File

@ -40,6 +40,7 @@ config.esi_capnp = "@ESI_CAPNP@"
config.zlib = "@HAVE_ZLIB@"
config.scheduling_or_tools = "@SCHEDULING_OR_TOOLS@"
config.llhd_sim_enabled = @CIRCT_LLHD_SIM_ENABLED@
config.slang_frontend_enabled = @CIRCT_SLANG_FRONTEND_ENABLED@
# Support substitution of the tools_dir with user parameters. This is
# used when we can't determine the tool dir at configuration time.

View File

@ -16,3 +16,7 @@ add_subdirectory(om-linker)
add_subdirectory(py-split-input-file)
add_subdirectory(hlstool)
add_subdirectory(ibistool)
if(CIRCT_SLANG_FRONTEND_ENABLED)
add_subdirectory(circt-verilog)
endif()

View File

@ -0,0 +1,11 @@
add_circt_tool(circt-verilog
circt-verilog.cpp
)
llvm_update_compile_flags(circt-verilog)
target_link_libraries(circt-verilog PRIVATE
CIRCTImportVerilog
CIRCTSupport
MLIRIR
)

View File

@ -0,0 +1,61 @@
//===- circt-verilog.cpp - Getting Verilog into CIRCT ---------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements a utility to parse Verilog and SystemVerilog input
// files. This builds on CIRCT's ImportVerilog library, which ultimately relies
// on slang to do the heavy lifting.
//
//===----------------------------------------------------------------------===//
#include "circt/Conversion/ImportVerilog.h"
#include "circt/Support/Version.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/Pass/PassManager.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/InitLLVM.h"
using namespace llvm;
using namespace mlir;
using namespace circt;
//===----------------------------------------------------------------------===//
// Implementation
//===----------------------------------------------------------------------===//
static LogicalResult execute(MLIRContext *context) {
// This is where we would call out to ImportVerilog to parse the input.
return success();
}
int main(int argc, char **argv) {
InitLLVM y(argc, argv);
// Set the bug report message to indicate users should file issues on
// llvm/circt and not llvm/llvm-project.
setBugReportMsg(circtBugReportMsg);
// Print the CIRCT and Slang versions when requested.
cl::AddExtraVersionPrinter([](raw_ostream &os) {
os << getCirctVersion() << '\n';
os << getSlangVersion() << '\n';
});
// Register any pass manager command line options.
registerMLIRContextCLOptions();
registerPassManagerCLOptions();
registerDefaultTimingManagerCLOptions();
registerAsmPrinterCLOptions();
// Parse pass names in main to ensure static initialization completed.
cl::ParseCommandLineOptions(argc, argv,
"Verilog and SystemVerilog frontend\n");
// Perform the actual work and use "exit" to avoid slow context teardown.
MLIRContext context;
exit(failed(execute(&context)));
}