mirror of https://github.com/llvm/circt.git
[Moore] Add SystemVerilog types (#2699)
Add an implementation of the SystemVerilog type system to the Moore dialect, modeled after the one in Moore's Rust codebase: https://github.com/fabianschuiki/moore/blob/master/src/svlog/ty.rs This is the first step towards migrating a larger chunk of the Moore codebase into CIRCT, as it allows Moore's codegen to start emitting higher-level operations (e.g., `moore.mir.concat`, to be added later) instead of directly dropping to LLHD/HW. Doing so will allow us to eventually move the codegen over into CIRCT, and start work on implementing the type checking and type inference on the higher-level operations. My hope is that we might eventually be able to reconcile the Moore types and some of the higher-level operations with the SV dialect, since both work with SystemVerilog, albeit for two diametrically opposed purposes. The types are designed to very clearly distinguish between packed and unpacked types, and provide a certain level of guarantees about the structure of nested types through C++ types. For example, struct aggregate types and typedefs/decltype constructs come in a packed and unpacked flavor to enforce proper nesting of these types. Where user-defined types are involved, for example through structs and typedefs/decltype, the MLIR types aim to capture enough information to faithfully reconstruct the type as it was originally formulated by the user. This helps provide good and understandable diagnostics. As a concrete example, integer types capture whether their sign was provided explicitly by the user, in order to distinguish `int` and `int signed`, despite those two types being semantically identical. This commit also adds a `unittests` directory as seen in LLVM and MLIR, to test the human-readable serialization of the Moore types and other type attributes.
This commit is contained in:
parent
ff4e615642
commit
4c74e87023
|
@ -74,6 +74,46 @@ endif ()
|
|||
|
||||
set(CIRCT_BUILT_STANDALONE 1)
|
||||
set(BACKEND_PACKAGE_STRING "LLVM ${LLVM_PACKAGE_VERSION}")
|
||||
|
||||
# Handle unittests when building out-of-tree against an installed version of
|
||||
# LLVM/MLIR (not a build tree). Adapted from `llvm/flang/CMakeLists.txt`.
|
||||
set(CIRCT_GTEST_AVAILABLE 0)
|
||||
set(UNITTEST_DIR ${LLVM_BUILD_MAIN_SRC_DIR}/utils/unittest)
|
||||
if (NOT EXISTS ${UNITTEST_DIR}/googletest/include/gtest/gtest.h)
|
||||
set(UNITTEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/llvm/llvm/utils/unittest)
|
||||
endif()
|
||||
if (EXISTS ${UNITTEST_DIR}/googletest/include/gtest/gtest.h)
|
||||
if (NOT TARGET gtest)
|
||||
find_package(Threads)
|
||||
add_llvm_library(gtest
|
||||
${UNITTEST_DIR}/googletest/src/gtest-all.cc
|
||||
${UNITTEST_DIR}/googlemock/src/gmock-all.cc
|
||||
LINK_LIBS pthread
|
||||
LINK_COMPONENTS Support # llvm::raw_ostream
|
||||
BUILDTREE_ONLY
|
||||
)
|
||||
target_include_directories(gtest
|
||||
PUBLIC
|
||||
"${UNITTEST_DIR}/googletest/include"
|
||||
"${UNITTEST_DIR}/googlemock/include"
|
||||
PRIVATE
|
||||
"${UNITTEST_DIR}/googletest"
|
||||
"${UNITTEST_DIR}/googlemock"
|
||||
)
|
||||
add_llvm_library(gtest_main
|
||||
${UNITTEST_DIR}/UnitTestMain/TestMain.cpp
|
||||
LINK_LIBS gtest
|
||||
LINK_COMPONENTS Support # llvm::cl
|
||||
BUILDTREE_ONLY
|
||||
)
|
||||
endif()
|
||||
set(CIRCT_GTEST_AVAILABLE 1)
|
||||
else()
|
||||
message(WARNING "Skipping unittests since LLVM install does not include \
|
||||
gtest headers and libraries")
|
||||
set(CIRCT_GTEST_AVAILABLE 0)
|
||||
endif()
|
||||
|
||||
else()
|
||||
# CMake library generation settings.
|
||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Default to building a static mondo-lib")
|
||||
|
@ -369,7 +409,9 @@ endif()
|
|||
add_subdirectory(include/circt)
|
||||
add_subdirectory(lib)
|
||||
add_subdirectory(tools)
|
||||
#add_subdirectory(unittests)
|
||||
if (CIRCT_GTEST_AVAILABLE)
|
||||
add_subdirectory(unittests)
|
||||
endif()
|
||||
add_subdirectory(test)
|
||||
add_subdirectory(integration_test)
|
||||
add_subdirectory(frontends)
|
||||
|
|
|
@ -26,7 +26,12 @@ def MooreDialect : Dialect {
|
|||
let extraClassDeclaration = [{
|
||||
/// Register all Moore types.
|
||||
void registerTypes();
|
||||
|
||||
/// Type parsing and printing.
|
||||
Type parseType(DialectAsmParser &parser) const override;
|
||||
void printType(Type, DialectAsmPrinter &) const override;
|
||||
}];
|
||||
let useDefaultTypePrinterParser = 0;
|
||||
}
|
||||
|
||||
#endif // CIRCT_DIALECT_MOORE_MOOREDIALECT
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -30,12 +30,3 @@ class WrapperTypeBase<string name, string mnemo> : MooreType<name> {
|
|||
|
||||
def LValueTypeImpl : WrapperTypeBase<"LValue", "lvalue">;
|
||||
def RValueTypeImpl : WrapperTypeBase<"RValue", "rvalue">;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Integer atom types
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def IntTypeImpl : MooreType<"Int"> {
|
||||
let summary = "System-Verilog int type";
|
||||
let mnemonic = "sv.int";
|
||||
}
|
||||
|
|
|
@ -44,8 +44,8 @@ struct AssignOpConv;
|
|||
|
||||
static Type convertMooreType(Type type) {
|
||||
return TypeSwitch<Type, Type>(type)
|
||||
.Case<moore::IntType>([](moore::IntType ty) {
|
||||
return IntegerType::get(ty.getContext(), 32);
|
||||
.Case<moore::IntType>([](auto type) {
|
||||
return IntegerType::get(type.getContext(), type.getBitSize());
|
||||
})
|
||||
.Case<moore::RValueType>(
|
||||
[](auto type) { return convertMooreType(type.getNestedType()); })
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -8,6 +8,12 @@ configure_lit_site_cfg(
|
|||
MAIN_CONFIG
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py
|
||||
)
|
||||
configure_lit_site_cfg(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg.py
|
||||
MAIN_CONFIG
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.cfg.py
|
||||
)
|
||||
|
||||
set(CIRCT_TEST_DEPENDS
|
||||
FileCheck count not
|
||||
|
@ -22,6 +28,10 @@ set(CIRCT_TEST_DEPENDS
|
|||
mlir-cpu-runner
|
||||
)
|
||||
|
||||
if (CIRCT_GTEST_AVAILABLE)
|
||||
list(APPEND CIRCT_TEST_DEPENDS CIRCTUnitTests)
|
||||
endif()
|
||||
|
||||
if(CIRCT_LLHD_SIM_ENABLED)
|
||||
list(APPEND CIRCT_TEST_DEPENDS llhd-sim)
|
||||
list(APPEND CIRCT_TEST_DEPENDS circt-llhd-signals-runtime-wrappers)
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
// CHECK-LABEL: llhd.entity @test1
|
||||
llhd.entity @test1() -> () {
|
||||
// CHECK-NEXT: %c5_i32 = hw.constant 5 : i32
|
||||
%0 = moore.mir.constant 5 : !moore.rvalue<!moore.sv.int>
|
||||
// CHECK-NEXT: %c3_i32 = hw.constant 3 : i32
|
||||
// CHECK-NEXT: [[SIG:%.*]] = llhd.sig "varname" %c3_i32 : i32
|
||||
%1 = moore.mir.vardecl "varname" = 3 : !moore.lvalue<!moore.sv.int>
|
||||
// CHECK-NEXT: [[TIME:%.*]] = llhd.constant_time <0s, 0d, 1e>
|
||||
// CHECK-NEXT: llhd.drv [[SIG]], %c5_i32 after [[TIME]] : !llhd.sig<i32>
|
||||
moore.mir.assign %1, %0 : !moore.lvalue<!moore.sv.int>, !moore.rvalue<!moore.sv.int>
|
||||
// CHECK-NEXT: %c5_i32 = hw.constant 5 : i32
|
||||
%0 = moore.mir.constant 5 : !moore.rvalue<!moore.int>
|
||||
// CHECK-NEXT: %c3_i32 = hw.constant 3 : i32
|
||||
// CHECK-NEXT: [[SIG:%.*]] = llhd.sig "varname" %c3_i32 : i32
|
||||
%1 = moore.mir.vardecl "varname" = 3 : !moore.lvalue<!moore.int>
|
||||
// CHECK-NEXT: [[TIME:%.*]] = llhd.constant_time <0s, 0d, 1e>
|
||||
// CHECK-NEXT: llhd.drv [[SIG]], %c5_i32 after [[TIME]] : !llhd.sig<i32>
|
||||
moore.mir.assign %1, %0 : !moore.lvalue<!moore.int>, !moore.rvalue<!moore.int>
|
||||
}
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
// CHECK-LABEL: llhd.entity @test1
|
||||
llhd.entity @test1() -> () {
|
||||
// CHECK-NEXT: [[CONST:%.*]] = moore.mir.constant 5 : !moore.rvalue<!moore.sv.int>
|
||||
// CHECK-NEXT: [[VAR:%.*]] = moore.mir.vardecl "varname" = 3 : !moore.lvalue<!moore.sv.int>
|
||||
// CHECK-NEXT: moore.mir.assign [[VAR]], [[CONST]] : !moore.lvalue<!moore.sv.int>, !moore.rvalue<!moore.sv.int>
|
||||
%0 = moore.mir.constant 5 : !moore.rvalue<!moore.sv.int>
|
||||
%1 = moore.mir.vardecl "varname" = 3 : !moore.lvalue<!moore.sv.int>
|
||||
moore.mir.assign %1, %0 : !moore.lvalue<!moore.sv.int>, !moore.rvalue<!moore.sv.int>
|
||||
// CHECK-NEXT: [[CONST:%.*]] = moore.mir.constant 5 : !moore.rvalue<!moore.int>
|
||||
// CHECK-NEXT: [[VAR:%.*]] = moore.mir.vardecl "varname" = 3 : !moore.lvalue<!moore.int>
|
||||
// CHECK-NEXT: moore.mir.assign [[VAR]], [[CONST]] : !moore.lvalue<!moore.int>, !moore.rvalue<!moore.int>
|
||||
%0 = moore.mir.constant 5 : !moore.rvalue<!moore.int>
|
||||
%1 = moore.mir.vardecl "varname" = 3 : !moore.lvalue<!moore.int>
|
||||
moore.mir.assign %1, %0 : !moore.lvalue<!moore.int>, !moore.rvalue<!moore.int>
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
// RUN: circt-opt --verify-diagnostics --split-input-file %s
|
||||
|
||||
// expected-error @+1 {{ambiguous packing; wrap `named` in `packed<...>` or `unpacked<...>` to disambiguate}}
|
||||
func @Foo(%arg0: !moore.named<"foo", bit, loc(unknown)>) { return }
|
||||
|
||||
// -----
|
||||
// expected-error @+1 {{ambiguous packing; wrap `ref` in `packed<...>` or `unpacked<...>` to disambiguate}}
|
||||
func @Foo(%arg0: !moore.ref<bit, loc(unknown)>) { return }
|
||||
|
||||
// -----
|
||||
// expected-error @+1 {{ambiguous packing; wrap `unsized` in `packed<...>` or `unpacked<...>` to disambiguate}}
|
||||
func @Foo(%arg0: !moore.unsized<bit>) { return }
|
||||
|
||||
// -----
|
||||
// expected-error @+1 {{ambiguous packing; wrap `range` in `packed<...>` or `unpacked<...>` to disambiguate}}
|
||||
func @Foo(%arg0: !moore.range<bit, 3:0>) { return }
|
||||
|
||||
// -----
|
||||
// expected-error @+1 {{ambiguous packing; wrap `struct` in `packed<...>` or `unpacked<...>` to disambiguate}}
|
||||
func @Foo(%arg0: !moore.struct<{}, loc(unknown)>) { return }
|
||||
|
||||
// -----
|
||||
// expected-error @+1 {{unpacked struct cannot have a sign}}
|
||||
func @Foo(%arg0: !moore.unpacked<struct<unsigned, {}, loc(unknown)>>) { return }
|
||||
func @Bar(%arg0: !moore.packed<struct<unsigned, {}, loc(unknown)>>) { return }
|
||||
|
||||
// -----
|
||||
// expected-error @+1 {{unpacked type '!moore.string' where only packed types are allowed}}
|
||||
func @Foo(%arg0: !moore.packed<struct<{a: string}, loc(unknown)>>) { return }
|
||||
|
||||
// -----
|
||||
// expected-error @+1 {{unpacked type '!moore.string' where only packed types are allowed}}
|
||||
func @Foo(%arg0: !moore.packed<unsized<string>>) { return }
|
|
@ -0,0 +1,153 @@
|
|||
// RUN: circt-opt %s | circt-opt | FileCheck %s
|
||||
|
||||
// CHECK-LABEL: func @UnitTypes(
|
||||
func @UnitTypes(
|
||||
// CHECK-SAME: %arg0: !moore.void
|
||||
// CHECK-SAME: %arg1: !moore.string
|
||||
// CHECK-SAME: %arg2: !moore.chandle
|
||||
// CHECK-SAME: %arg3: !moore.event
|
||||
%arg0: !moore.void,
|
||||
%arg1: !moore.string,
|
||||
%arg2: !moore.chandle,
|
||||
%arg3: !moore.event
|
||||
) { return }
|
||||
|
||||
// CHECK-LABEL: func @IntTypes(
|
||||
func @IntTypes(
|
||||
// CHECK-SAME: %arg0: !moore.bit
|
||||
// CHECK-SAME: %arg1: !moore.logic
|
||||
// CHECK-SAME: %arg2: !moore.reg
|
||||
// CHECK-SAME: %arg3: !moore.byte
|
||||
// CHECK-SAME: %arg4: !moore.shortint
|
||||
// CHECK-SAME: %arg5: !moore.int
|
||||
// CHECK-SAME: %arg6: !moore.longint
|
||||
// CHECK-SAME: %arg7: !moore.integer
|
||||
// CHECK-SAME: %arg8: !moore.time
|
||||
%arg0: !moore.bit,
|
||||
%arg1: !moore.logic,
|
||||
%arg2: !moore.reg,
|
||||
%arg3: !moore.byte,
|
||||
%arg4: !moore.shortint,
|
||||
%arg5: !moore.int,
|
||||
%arg6: !moore.longint,
|
||||
%arg7: !moore.integer,
|
||||
%arg8: !moore.time,
|
||||
// CHECK-SAME: %arg9: !moore.bit<unsigned>
|
||||
// CHECK-SAME: %arg10: !moore.logic<unsigned>
|
||||
// CHECK-SAME: %arg11: !moore.reg<unsigned>
|
||||
// CHECK-SAME: %arg12: !moore.byte<unsigned>
|
||||
// CHECK-SAME: %arg13: !moore.shortint<unsigned>
|
||||
// CHECK-SAME: %arg14: !moore.int<unsigned>
|
||||
// CHECK-SAME: %arg15: !moore.longint<unsigned>
|
||||
// CHECK-SAME: %arg16: !moore.integer<unsigned>
|
||||
// CHECK-SAME: %arg17: !moore.time<unsigned>
|
||||
%arg9: !moore.bit<unsigned>,
|
||||
%arg10: !moore.logic<unsigned>,
|
||||
%arg11: !moore.reg<unsigned>,
|
||||
%arg12: !moore.byte<unsigned>,
|
||||
%arg13: !moore.shortint<unsigned>,
|
||||
%arg14: !moore.int<unsigned>,
|
||||
%arg15: !moore.longint<unsigned>,
|
||||
%arg16: !moore.integer<unsigned>,
|
||||
%arg17: !moore.time<unsigned>,
|
||||
// CHECK-SAME: %arg18: !moore.bit<signed>
|
||||
// CHECK-SAME: %arg19: !moore.logic<signed>
|
||||
// CHECK-SAME: %arg20: !moore.reg<signed>
|
||||
// CHECK-SAME: %arg21: !moore.byte<signed>
|
||||
// CHECK-SAME: %arg22: !moore.shortint<signed>
|
||||
// CHECK-SAME: %arg23: !moore.int<signed>
|
||||
// CHECK-SAME: %arg24: !moore.longint<signed>
|
||||
// CHECK-SAME: %arg25: !moore.integer<signed>
|
||||
// CHECK-SAME: %arg26: !moore.time<signed>
|
||||
%arg18: !moore.bit<signed>,
|
||||
%arg19: !moore.logic<signed>,
|
||||
%arg20: !moore.reg<signed>,
|
||||
%arg21: !moore.byte<signed>,
|
||||
%arg22: !moore.shortint<signed>,
|
||||
%arg23: !moore.int<signed>,
|
||||
%arg24: !moore.longint<signed>,
|
||||
%arg25: !moore.integer<signed>,
|
||||
%arg26: !moore.time<signed>
|
||||
) { return }
|
||||
|
||||
// CHECK-LABEL: func @RealTypes(
|
||||
func @RealTypes(
|
||||
// CHECK-SAME: %arg0: !moore.shortreal
|
||||
// CHECK-SAME: %arg1: !moore.real
|
||||
// CHECK-SAME: %arg2: !moore.realtime
|
||||
%arg0: !moore.shortreal,
|
||||
%arg1: !moore.real,
|
||||
%arg2: !moore.realtime
|
||||
) { return }
|
||||
|
||||
// CHECK-LABEL: func @EnumType(
|
||||
func @EnumType(
|
||||
// CHECK-SAME: %arg0: !moore.enum<loc("foo.sv":42:9001)>
|
||||
// CHECK-SAME: %arg1: !moore.enum<int, loc("foo.sv":42:9001)>
|
||||
// CHECK-SAME: %arg2: !moore.enum<"Foo", loc("foo.sv":42:9001)>
|
||||
// CHECK-SAME: %arg3: !moore.enum<"Foo", int, loc("foo.sv":42:9001)>
|
||||
%arg0: !moore.enum<loc("foo.sv":42:9001)>,
|
||||
%arg1: !moore.enum<int, loc("foo.sv":42:9001)>,
|
||||
%arg2: !moore.enum<"Foo", loc("foo.sv":42:9001)>,
|
||||
%arg3: !moore.enum<"Foo", int, loc("foo.sv":42:9001)>
|
||||
) { return }
|
||||
|
||||
// CHECK-LABEL: func @IndirectTypes(
|
||||
func @IndirectTypes(
|
||||
// CHECK-SAME: %arg0: !moore.packed<named<"Foo", bit, loc("foo.sv":42:9001)>>
|
||||
// CHECK-SAME: %arg1: !moore.packed<ref<bit, loc("foo.sv":42:9001)>>
|
||||
%arg0: !moore.packed<named<"Foo", bit, loc("foo.sv":42:9001)>>,
|
||||
%arg1: !moore.packed<ref<bit, loc("foo.sv":42:9001)>>,
|
||||
// CHECK-SAME: %arg2: !moore.unpacked<named<"Foo", bit, loc("foo.sv":42:9001)>>
|
||||
// CHECK-SAME: %arg3: !moore.unpacked<named<"Foo", string, loc("foo.sv":42:9001)>>
|
||||
// CHECK-SAME: %arg4: !moore.unpacked<ref<bit, loc("foo.sv":42:9001)>>
|
||||
// CHECK-SAME: %arg5: !moore.unpacked<ref<string, loc("foo.sv":42:9001)>>
|
||||
%arg2: !moore.unpacked<named<"Foo", bit, loc("foo.sv":42:9001)>>,
|
||||
%arg3: !moore.unpacked<named<"Foo", string, loc("foo.sv":42:9001)>>,
|
||||
%arg4: !moore.unpacked<ref<bit, loc("foo.sv":42:9001)>>,
|
||||
%arg5: !moore.unpacked<ref<string, loc("foo.sv":42:9001)>>
|
||||
) { return }
|
||||
|
||||
// CHECK-LABEL: func @DimTypes(
|
||||
func @DimTypes(
|
||||
// CHECK-SAME: %arg0: !moore.packed<unsized<bit>>,
|
||||
// CHECK-SAME: %arg1: !moore.packed<range<bit, 4:-5>>,
|
||||
%arg0: !moore.packed<unsized<bit>>,
|
||||
%arg1: !moore.packed<range<bit, 4:-5>>,
|
||||
// CHECK-SAME: %arg2: !moore.unpacked<unsized<bit>>,
|
||||
// CHECK-SAME: %arg3: !moore.unpacked<array<bit, 42>>,
|
||||
// CHECK-SAME: %arg4: !moore.unpacked<range<bit, 4:-5>>,
|
||||
// CHECK-SAME: %arg5: !moore.unpacked<assoc<bit>>,
|
||||
// CHECK-SAME: %arg6: !moore.unpacked<assoc<bit, string>>,
|
||||
// CHECK-SAME: %arg7: !moore.unpacked<queue<bit>>,
|
||||
// CHECK-SAME: %arg8: !moore.unpacked<queue<bit, 9001>>
|
||||
%arg2: !moore.unpacked<unsized<bit>>,
|
||||
%arg3: !moore.unpacked<array<bit, 42>>,
|
||||
%arg4: !moore.unpacked<range<bit, 4:-5>>,
|
||||
%arg5: !moore.unpacked<assoc<bit>>,
|
||||
%arg6: !moore.unpacked<assoc<bit, string>>,
|
||||
%arg7: !moore.unpacked<queue<bit>>,
|
||||
%arg8: !moore.unpacked<queue<bit, 9001>>
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
// CHECK-LABEL: func @StructTypes(
|
||||
func @StructTypes(
|
||||
// CHECK-SAME: %arg0: !moore.packed<struct<{}, loc("foo.sv":42:9001)>>
|
||||
// CHECK-SAME: %arg1: !moore.packed<struct<"Foo", {}, loc("foo.sv":42:9001)>>
|
||||
// CHECK-SAME: %arg2: !moore.packed<struct<unsigned, {}, loc("foo.sv":42:9001)>>
|
||||
// CHECK-SAME: %arg3: !moore.packed<struct<"Foo", signed, {}, loc("foo.sv":42:9001)>>
|
||||
// CHECK-SAME: %arg4: !moore.packed<struct<{foo: bit loc("foo.sv":1:2), bar: int loc("foo.sv":3:4)}, loc("foo.sv":42:9001)>>
|
||||
%arg0: !moore.packed<struct<{}, loc("foo.sv":42:9001)>>,
|
||||
%arg1: !moore.packed<struct<"Foo", {}, loc("foo.sv":42:9001)>>,
|
||||
%arg2: !moore.packed<struct<unsigned, {}, loc("foo.sv":42:9001)>>,
|
||||
%arg3: !moore.packed<struct<"Foo", signed, {}, loc("foo.sv":42:9001)>>,
|
||||
%arg4: !moore.packed<struct<{foo: bit loc("foo.sv":1:2), bar: int loc("foo.sv":3:4)}, loc("foo.sv":42:9001)>>,
|
||||
// CHECK-SAME: %arg5: !moore.unpacked<struct<{}, loc("foo.sv":42:9001)>>
|
||||
// CHECK-SAME: %arg6: !moore.unpacked<struct<"Foo", {}, loc("foo.sv":42:9001)>>
|
||||
// CHECK-SAME: %arg7: !moore.unpacked<struct<{foo: string loc("foo.sv":1:2), bar: event loc("foo.sv":3:4)}, loc("foo.sv":42:9001)>>
|
||||
%arg5: !moore.unpacked<struct<{}, loc("foo.sv":42:9001)>>,
|
||||
%arg6: !moore.unpacked<struct<"Foo", {}, loc("foo.sv":42:9001)>>,
|
||||
%arg7: !moore.unpacked<struct<{foo: string loc("foo.sv":1:2), bar: event loc("foo.sv":3:4)}, loc("foo.sv":42:9001)>>
|
||||
) { return }
|
|
@ -0,0 +1,39 @@
|
|||
# -*- Python -*-
|
||||
|
||||
# Configuration file for the 'lit' test runner.
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
import lit.formats
|
||||
|
||||
# name: The name of this test suite.
|
||||
config.name = 'CIRCT-Unit'
|
||||
|
||||
# suffixes: A list of file extensions to treat as test files.
|
||||
config.suffixes = []
|
||||
|
||||
# test_source_root: The root path where tests are located.
|
||||
# test_exec_root: The root path where tests should be run.
|
||||
config.test_exec_root = os.path.join(config.circt_obj_root, 'unittests')
|
||||
config.test_source_root = config.test_exec_root
|
||||
|
||||
# testFormat: The test format to use to interpret tests.
|
||||
config.test_format = lit.formats.GoogleTest(config.llvm_build_mode, 'Tests')
|
||||
|
||||
# Propagate the temp directory. Windows requires this because it uses \Windows\
|
||||
# if none of these are present.
|
||||
if 'TMP' in os.environ:
|
||||
config.environment['TMP'] = os.environ['TMP']
|
||||
if 'TEMP' in os.environ:
|
||||
config.environment['TEMP'] = os.environ['TEMP']
|
||||
|
||||
# Propagate HOME as it can be used to override incorrect homedir in passwd
|
||||
# that causes the tests to fail.
|
||||
if 'HOME' in os.environ:
|
||||
config.environment['HOME'] = os.environ['HOME']
|
||||
|
||||
# Propagate path to symbolizer for ASan/MSan.
|
||||
for symbolizer in ['ASAN_SYMBOLIZER_PATH', 'MSAN_SYMBOLIZER_PATH']:
|
||||
if symbolizer in os.environ:
|
||||
config.environment[symbolizer] = os.environ[symbolizer]
|
|
@ -0,0 +1,27 @@
|
|||
@LIT_SITE_CFG_IN_HEADER@
|
||||
|
||||
import sys
|
||||
|
||||
config.llvm_src_root = "@LLVM_SOURCE_DIR@"
|
||||
config.llvm_obj_root = "@LLVM_BINARY_DIR@"
|
||||
config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
|
||||
config.llvm_build_mode = "@LLVM_BUILD_MODE@"
|
||||
config.enable_shared = @ENABLE_SHARED@
|
||||
config.shlibdir = "@SHLIBDIR@"
|
||||
config.circt_src_root = "@CIRCT_SOURCE_DIR@"
|
||||
config.circt_obj_root = "@CIRCT_BINARY_DIR@"
|
||||
config.circt_tools_dir = "@CIRCT_TOOLS_DIR@"
|
||||
|
||||
# Support substitution of the tools_dir and build_mode with user parameters.
|
||||
# This is used when we can't determine the tool dir at configuration time.
|
||||
try:
|
||||
config.llvm_tools_dir = config.llvm_tools_dir % lit_config.params
|
||||
config.llvm_build_mode = config.llvm_build_mode % lit_config.params
|
||||
config.shlibdir = config.shlibdir % lit_config.params
|
||||
except KeyError:
|
||||
e = sys.exc_info()[1]
|
||||
key, = e.args
|
||||
lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
|
||||
|
||||
# Let the main config do the real work.
|
||||
lit_config.load_config(config, "@CIRCT_SOURCE_DIR@/test/Unit/lit.cfg.py")
|
|
@ -0,0 +1,8 @@
|
|||
add_custom_target(CIRCTUnitTests)
|
||||
set_target_properties(CIRCTUnitTests PROPERTIES FOLDER "CIRCT Tests")
|
||||
|
||||
function(add_circt_unittest test_dirname)
|
||||
add_unittest(CIRCTUnitTests ${test_dirname} ${ARGN})
|
||||
endfunction()
|
||||
|
||||
add_subdirectory(Dialect)
|
|
@ -0,0 +1 @@
|
|||
add_subdirectory(Moore)
|
|
@ -0,0 +1,8 @@
|
|||
add_circt_unittest(CIRCTMooreTests
|
||||
TypesTest.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(CIRCTMooreTests
|
||||
PRIVATE
|
||||
CIRCTMoore
|
||||
)
|
|
@ -0,0 +1,402 @@
|
|||
//===- TypesTest.cpp - Moore type unit tests ------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "circt/Dialect/Moore/MooreDialect.h"
|
||||
#include "circt/Dialect/Moore/MooreTypes.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace mlir;
|
||||
using namespace circt;
|
||||
using namespace moore;
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(TypesTest, UnitTypes) {
|
||||
MLIRContext context;
|
||||
context.loadDialect<MooreDialect>();
|
||||
|
||||
auto voidType = VoidType::get(&context);
|
||||
auto stringType = StringType::get(&context);
|
||||
auto chandleType = ChandleType::get(&context);
|
||||
auto eventType = EventType::get(&context);
|
||||
|
||||
ASSERT_EQ(voidType.toString(), "void");
|
||||
ASSERT_EQ(stringType.toString(), "string");
|
||||
ASSERT_EQ(chandleType.toString(), "chandle");
|
||||
ASSERT_EQ(eventType.toString(), "event");
|
||||
|
||||
ASSERT_EQ(voidType.getBitSize(), 0u);
|
||||
ASSERT_EQ(stringType.getBitSize(), llvm::None);
|
||||
ASSERT_EQ(chandleType.getBitSize(), llvm::None);
|
||||
ASSERT_EQ(eventType.getBitSize(), llvm::None);
|
||||
|
||||
ASSERT_EQ(voidType.getDomain(), Domain::TwoValued);
|
||||
ASSERT_EQ(stringType.getDomain(), Domain::TwoValued);
|
||||
ASSERT_EQ(chandleType.getDomain(), Domain::TwoValued);
|
||||
ASSERT_EQ(eventType.getDomain(), Domain::TwoValued);
|
||||
|
||||
ASSERT_EQ(voidType.getSign(), Sign::Unsigned);
|
||||
ASSERT_EQ(stringType.getSign(), Sign::Unsigned);
|
||||
ASSERT_EQ(chandleType.getSign(), Sign::Unsigned);
|
||||
ASSERT_EQ(eventType.getSign(), Sign::Unsigned);
|
||||
}
|
||||
|
||||
TEST(TypesTest, Ranges) {
|
||||
Range a(42);
|
||||
Range b(32, RangeDir::Down, -5);
|
||||
Range c(16, RangeDir::Up, -3);
|
||||
|
||||
ASSERT_EQ(a.toString(), "41:0");
|
||||
ASSERT_EQ(b.toString(), "26:-5");
|
||||
ASSERT_EQ(c.toString(), "-3:12");
|
||||
|
||||
ASSERT_EQ(a.left(), 41);
|
||||
ASSERT_EQ(a.right(), 0);
|
||||
ASSERT_EQ(a.low(), 0);
|
||||
ASSERT_EQ(a.high(), 41);
|
||||
ASSERT_EQ(a.increment(), -1);
|
||||
|
||||
ASSERT_EQ(b.left(), 26);
|
||||
ASSERT_EQ(b.right(), -5);
|
||||
ASSERT_EQ(b.low(), -5);
|
||||
ASSERT_EQ(b.high(), 26);
|
||||
ASSERT_EQ(b.increment(), -1);
|
||||
|
||||
ASSERT_EQ(c.left(), -3);
|
||||
ASSERT_EQ(c.right(), 12);
|
||||
ASSERT_EQ(c.low(), -3);
|
||||
ASSERT_EQ(c.high(), 12);
|
||||
ASSERT_EQ(c.increment(), 1);
|
||||
}
|
||||
|
||||
TEST(TypesTest, PackedInt) {
|
||||
MLIRContext context;
|
||||
context.loadDialect<MooreDialect>();
|
||||
|
||||
std::tuple<IntType::Kind, StringRef, Domain, Sign> pairs[] = {
|
||||
{IntType::Bit, "bit", Domain::TwoValued, Sign::Unsigned},
|
||||
{IntType::Logic, "logic", Domain::FourValued, Sign::Unsigned},
|
||||
{IntType::Reg, "reg", Domain::FourValued, Sign::Unsigned},
|
||||
{IntType::Byte, "byte", Domain::TwoValued, Sign::Signed},
|
||||
{IntType::ShortInt, "shortint", Domain::TwoValued, Sign::Signed},
|
||||
{IntType::Int, "int", Domain::TwoValued, Sign::Signed},
|
||||
{IntType::LongInt, "longint", Domain::TwoValued, Sign::Signed},
|
||||
{IntType::Integer, "integer", Domain::FourValued, Sign::Signed},
|
||||
{IntType::Time, "time", Domain::TwoValued, Sign::Unsigned},
|
||||
};
|
||||
|
||||
for (auto pair : pairs) {
|
||||
auto kind = std::get<0>(pair);
|
||||
auto keyword = std::get<1>(pair);
|
||||
auto type = IntType::get(&context, kind);
|
||||
auto unsignedType = IntType::get(&context, kind, Sign::Unsigned);
|
||||
auto signedType = IntType::get(&context, kind, Sign::Signed);
|
||||
|
||||
// Check the formatting.
|
||||
ASSERT_EQ(type.toString(), keyword);
|
||||
ASSERT_EQ(unsignedType.toString(), std::string(keyword) + " unsigned");
|
||||
ASSERT_EQ(signedType.toString(), std::string(keyword) + " signed");
|
||||
|
||||
// Check the domain.
|
||||
ASSERT_EQ(type.getDomain(), std::get<2>(pair));
|
||||
ASSERT_EQ(unsignedType.getDomain(), std::get<2>(pair));
|
||||
ASSERT_EQ(signedType.getDomain(), std::get<2>(pair));
|
||||
|
||||
// Check the sign.
|
||||
ASSERT_EQ(type.getSign(), std::get<3>(pair));
|
||||
ASSERT_EQ(unsignedType.getSign(), Sign::Unsigned);
|
||||
ASSERT_EQ(signedType.getSign(), Sign::Signed);
|
||||
ASSERT_FALSE(type.isSignExplicit());
|
||||
ASSERT_TRUE(unsignedType.isSignExplicit());
|
||||
ASSERT_TRUE(signedType.isSignExplicit());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TypesTest, Reals) {
|
||||
MLIRContext context;
|
||||
context.loadDialect<MooreDialect>();
|
||||
|
||||
auto t0 = RealType::get(&context, RealType::ShortReal);
|
||||
auto t1 = RealType::get(&context, RealType::Real);
|
||||
auto t2 = RealType::get(&context, RealType::RealTime);
|
||||
|
||||
ASSERT_EQ(t0.toString(), "shortreal");
|
||||
ASSERT_EQ(t1.toString(), "real");
|
||||
ASSERT_EQ(t2.toString(), "realtime");
|
||||
|
||||
ASSERT_EQ(t0.getDomain(), Domain::TwoValued);
|
||||
ASSERT_EQ(t1.getDomain(), Domain::TwoValued);
|
||||
ASSERT_EQ(t2.getDomain(), Domain::TwoValued);
|
||||
|
||||
ASSERT_EQ(t0.getBitSize(), 32u);
|
||||
ASSERT_EQ(t1.getBitSize(), 64u);
|
||||
ASSERT_EQ(t2.getBitSize(), 64u);
|
||||
|
||||
ASSERT_EQ(t0.getSign(), Sign::Unsigned);
|
||||
ASSERT_EQ(t1.getSign(), Sign::Unsigned);
|
||||
ASSERT_EQ(t2.getSign(), Sign::Unsigned);
|
||||
}
|
||||
|
||||
TEST(TypesTest, PackedDim) {
|
||||
MLIRContext context;
|
||||
context.loadDialect<MooreDialect>();
|
||||
|
||||
auto bitType = IntType::get(&context, IntType::Bit);
|
||||
auto arrayType1 = PackedRangeDim::get(bitType, 3);
|
||||
auto arrayType2 = PackedRangeDim::get(arrayType1, 2);
|
||||
auto arrayType3 = PackedUnsizedDim::get(arrayType2);
|
||||
|
||||
ASSERT_EQ(arrayType1.toString(), "bit [2:0]");
|
||||
ASSERT_EQ(arrayType2.toString(), "bit [1:0][2:0]");
|
||||
ASSERT_EQ(arrayType3.toString(), "bit [][1:0][2:0]");
|
||||
|
||||
ASSERT_EQ(arrayType1.getRange(), Range(3));
|
||||
ASSERT_EQ(arrayType3.getRange(), llvm::None);
|
||||
ASSERT_EQ(arrayType1.getSize(), 3u);
|
||||
ASSERT_EQ(arrayType3.getSize(), llvm::None);
|
||||
}
|
||||
|
||||
TEST(TypesTest, UnpackedDim) {
|
||||
MLIRContext context;
|
||||
context.loadDialect<MooreDialect>();
|
||||
|
||||
auto stringType = StringType::get(&context);
|
||||
auto arrayType1 = UnpackedUnsizedDim::get(stringType);
|
||||
auto arrayType2 = UnpackedArrayDim::get(arrayType1, 42);
|
||||
auto arrayType3 = UnpackedRangeDim::get(arrayType2, 2);
|
||||
auto arrayType4 = UnpackedAssocDim::get(arrayType3);
|
||||
auto arrayType5 = UnpackedAssocDim::get(arrayType4, stringType);
|
||||
auto arrayType6 = UnpackedQueueDim::get(arrayType5);
|
||||
auto arrayType7 = UnpackedQueueDim::get(arrayType6, 9);
|
||||
|
||||
ASSERT_EQ(arrayType1.toString(), "string $ []");
|
||||
ASSERT_EQ(arrayType2.toString(), "string $ [42][]");
|
||||
ASSERT_EQ(arrayType3.toString(), "string $ [1:0][42][]");
|
||||
ASSERT_EQ(arrayType4.toString(), "string $ [*][1:0][42][]");
|
||||
ASSERT_EQ(arrayType5.toString(), "string $ [string][*][1:0][42][]");
|
||||
ASSERT_EQ(arrayType6.toString(), "string $ [$][string][*][1:0][42][]");
|
||||
ASSERT_EQ(arrayType7.toString(), "string $ [$:9][$][string][*][1:0][42][]");
|
||||
|
||||
ASSERT_EQ(arrayType2.getSize(), 42);
|
||||
ASSERT_EQ(arrayType3.getRange(), Range(2));
|
||||
ASSERT_EQ(arrayType4.getIndexType(), UnpackedType{});
|
||||
ASSERT_EQ(arrayType5.getIndexType(), stringType);
|
||||
ASSERT_EQ(arrayType6.getBound(), llvm::None);
|
||||
ASSERT_EQ(arrayType7.getBound(), 9u);
|
||||
}
|
||||
|
||||
TEST(TypesTest, UnpackedFormattingAroundStuff) {
|
||||
MLIRContext context;
|
||||
context.loadDialect<MooreDialect>();
|
||||
|
||||
auto bitType = IntType::get(&context, IntType::Bit);
|
||||
auto arrayType1 = PackedRangeDim::get(bitType, 3);
|
||||
auto arrayType2 = UnpackedArrayDim::get(arrayType1, 42);
|
||||
|
||||
// Packed type formatting with custom separator.
|
||||
ASSERT_EQ(arrayType1.toString(), "bit [2:0]");
|
||||
ASSERT_EQ(arrayType1.toString("foo"), "bit [2:0] foo");
|
||||
ASSERT_EQ(arrayType1.toString([](auto &os) { os << "bar"; }),
|
||||
"bit [2:0] bar");
|
||||
|
||||
// Unpacked type formatting with custom separator.
|
||||
ASSERT_EQ(arrayType2.toString(), "bit [2:0] $ [42]");
|
||||
ASSERT_EQ(arrayType2.toString("foo"), "bit [2:0] foo [42]");
|
||||
ASSERT_EQ(arrayType2.toString([](auto &os) { os << "bar"; }),
|
||||
"bit [2:0] bar [42]");
|
||||
}
|
||||
|
||||
TEST(TypesTest, Resolution) {
|
||||
MLIRContext context;
|
||||
context.loadDialect<MooreDialect>();
|
||||
|
||||
auto loc = UnknownLoc::get(&context);
|
||||
auto t0 = IntType::get(&context, IntType::Bit);
|
||||
auto t1 = PackedRangeDim::get(t0, 3);
|
||||
auto t2 = PackedNamedType::get(t1, "foo", loc);
|
||||
|
||||
ASSERT_EQ(t2.toString(), "foo");
|
||||
ASSERT_EQ(t2.resolved().toString(), "bit [2:0]");
|
||||
ASSERT_EQ(t2.fullyResolved().toString(), "bit [2:0]");
|
||||
|
||||
auto t3 = PackedRangeDim::get(t2, 2);
|
||||
auto t4 = PackedNamedType::get(t3, "bar", loc);
|
||||
|
||||
ASSERT_EQ(t4.toString(), "bar");
|
||||
ASSERT_EQ(t4.resolved().toString(), "foo [1:0]");
|
||||
ASSERT_EQ(t4.fullyResolved().toString(), "bit [1:0][2:0]");
|
||||
|
||||
auto t5 = UnpackedArrayDim::get(t4, 4);
|
||||
auto t6 = UnpackedNamedType::get(t5, "tony", loc);
|
||||
|
||||
ASSERT_EQ(t6.toString(), "tony");
|
||||
ASSERT_EQ(t6.resolved().toString(), "bar $ [4]");
|
||||
ASSERT_EQ(t6.fullyResolved().toString(), "bit [1:0][2:0] $ [4]");
|
||||
|
||||
auto t7 = UnpackedAssocDim::get(t6);
|
||||
auto t8 = UnpackedNamedType::get(t7, "ada", loc);
|
||||
|
||||
ASSERT_EQ(t8.toString(), "ada");
|
||||
ASSERT_EQ(t8.resolved().toString(), "tony $ [*]");
|
||||
ASSERT_EQ(t8.fullyResolved().toString(), "bit [1:0][2:0] $ [*][4]");
|
||||
|
||||
// Type references
|
||||
auto r0 = PackedRefType::get(t2, loc);
|
||||
|
||||
ASSERT_EQ(r0.toString(), "type(foo)");
|
||||
ASSERT_EQ(r0.resolved().toString(), "foo");
|
||||
ASSERT_EQ(r0.fullyResolved().toString(), "bit [2:0]");
|
||||
|
||||
auto r1 = UnpackedRefType::get(t8, loc);
|
||||
|
||||
ASSERT_EQ(r1.toString(), "type(ada)");
|
||||
ASSERT_EQ(r1.resolved().toString(), "ada");
|
||||
ASSERT_EQ(r1.fullyResolved().toString(), "bit [1:0][2:0] $ [*][4]");
|
||||
}
|
||||
|
||||
TEST(TypesTest, NamedStructFormatting) {
|
||||
MLIRContext context;
|
||||
context.loadDialect<MooreDialect>();
|
||||
auto loc = UnknownLoc::get(&context);
|
||||
auto foo = StringAttr::get(&context, "Foo");
|
||||
|
||||
auto s0 = UnpackedStructType::get(StructKind::Struct, {}, foo, loc);
|
||||
auto s1 = UnpackedStructType::get(StructKind::Union, {}, foo, loc);
|
||||
auto s2 = UnpackedStructType::get(StructKind::TaggedUnion, {}, foo, loc);
|
||||
auto s3 = PackedStructType::get(StructKind::Struct, {}, foo, loc);
|
||||
auto s4 = PackedStructType::get(StructKind::Union, {}, foo, loc);
|
||||
auto s5 = PackedStructType::get(StructKind::TaggedUnion, {}, foo, loc);
|
||||
auto s6 =
|
||||
PackedStructType::get(StructKind::Struct, {}, foo, loc, Sign::Unsigned);
|
||||
auto s7 =
|
||||
PackedStructType::get(StructKind::Union, {}, foo, loc, Sign::Unsigned);
|
||||
auto s8 = PackedStructType::get(StructKind::TaggedUnion, {}, foo, loc,
|
||||
Sign::Unsigned);
|
||||
auto s9 =
|
||||
PackedStructType::get(StructKind::Struct, {}, foo, loc, Sign::Signed);
|
||||
auto s10 =
|
||||
PackedStructType::get(StructKind::Union, {}, foo, loc, Sign::Signed);
|
||||
auto s11 = PackedStructType::get(StructKind::TaggedUnion, {}, foo, loc,
|
||||
Sign::Signed);
|
||||
|
||||
ASSERT_EQ(s0.toString(), "struct Foo");
|
||||
ASSERT_EQ(s1.toString(), "union Foo");
|
||||
ASSERT_EQ(s2.toString(), "union tagged Foo");
|
||||
ASSERT_EQ(s3.toString(), "struct packed Foo");
|
||||
ASSERT_EQ(s4.toString(), "union packed Foo");
|
||||
ASSERT_EQ(s5.toString(), "union tagged packed Foo");
|
||||
ASSERT_EQ(s6.toString(), "struct packed unsigned Foo");
|
||||
ASSERT_EQ(s7.toString(), "union packed unsigned Foo");
|
||||
ASSERT_EQ(s8.toString(), "union tagged packed unsigned Foo");
|
||||
ASSERT_EQ(s9.toString(), "struct packed signed Foo");
|
||||
ASSERT_EQ(s10.toString(), "union packed signed Foo");
|
||||
ASSERT_EQ(s11.toString(), "union tagged packed signed Foo");
|
||||
}
|
||||
|
||||
TEST(TypesTest, Structs) {
|
||||
MLIRContext context;
|
||||
context.loadDialect<MooreDialect>();
|
||||
auto loc = UnknownLoc::get(&context);
|
||||
auto foo = StringAttr::get(&context, "foo");
|
||||
auto bar = StringAttr::get(&context, "bar");
|
||||
|
||||
auto bitType = IntType::get(&context, IntType::Bit);
|
||||
auto logicType = IntType::get(&context, IntType::Logic);
|
||||
auto bit8Type = PackedRangeDim::get(bitType, 8);
|
||||
auto bitDynArrayType = PackedUnsizedDim::get(bitType);
|
||||
|
||||
auto s0 = UnpackedStructType::get(StructKind::Struct,
|
||||
{StructMember{foo, loc, bitType}}, {}, loc);
|
||||
auto s1 = UnpackedStructType::get(
|
||||
StructKind::Struct,
|
||||
{StructMember{foo, loc, bitType}, StructMember{bar, loc, bit8Type}}, {},
|
||||
loc);
|
||||
auto s2 = UnpackedStructType::get(
|
||||
StructKind::Struct,
|
||||
{StructMember{foo, loc, bitType}, StructMember{bar, loc, logicType}}, {},
|
||||
loc);
|
||||
auto s3 = UnpackedStructType::get(StructKind::Struct,
|
||||
{StructMember{foo, loc, bitType},
|
||||
StructMember{bar, loc, bitDynArrayType}},
|
||||
{}, loc);
|
||||
|
||||
// Member formatting
|
||||
ASSERT_EQ(s0.toString(), "struct { bit foo; }");
|
||||
ASSERT_EQ(s1.toString(), "struct { bit foo; bit [7:0] bar; }");
|
||||
|
||||
// Value domain
|
||||
ASSERT_EQ(s1.getDomain(), Domain::TwoValued);
|
||||
ASSERT_EQ(s2.getDomain(), Domain::FourValued);
|
||||
|
||||
// Bit size
|
||||
ASSERT_EQ(s0.getBitSize(), 1u);
|
||||
ASSERT_EQ(s1.getBitSize(), 9u);
|
||||
ASSERT_EQ(s2.getBitSize(), 2u);
|
||||
ASSERT_EQ(s3.getBitSize(), llvm::None);
|
||||
}
|
||||
|
||||
TEST(TypesTest, Enums) {
|
||||
MLIRContext context;
|
||||
context.loadDialect<MooreDialect>();
|
||||
auto loc = UnknownLoc::get(&context);
|
||||
auto foo = StringAttr::get(&context, "Foo");
|
||||
auto intType = IntType::getInt(&context);
|
||||
auto bitType = IntType::get(&context, IntType::Bit);
|
||||
auto bit8Type = PackedRangeDim::get(bitType, 8);
|
||||
auto slogicType = IntType::get(&context, IntType::Logic, Sign::Signed);
|
||||
auto slogic8Type = PackedRangeDim::get(slogicType, 8);
|
||||
|
||||
auto e0 = EnumType::get({}, loc);
|
||||
auto e1 = EnumType::get(foo, loc);
|
||||
auto e2 = EnumType::get({}, loc, bit8Type);
|
||||
auto e3 = EnumType::get(foo, loc, bit8Type);
|
||||
auto e4 = EnumType::get({}, loc, slogic8Type);
|
||||
auto e5 = EnumType::get(foo, loc, slogic8Type);
|
||||
|
||||
// Formatting
|
||||
ASSERT_EQ(e0.toString(), "enum");
|
||||
ASSERT_EQ(e1.toString(), "enum Foo");
|
||||
ASSERT_EQ(e2.toString(), "enum bit [7:0]");
|
||||
ASSERT_EQ(e3.toString(), "enum Foo");
|
||||
ASSERT_EQ(e4.toString(), "enum logic signed [7:0]");
|
||||
ASSERT_EQ(e5.toString(), "enum Foo");
|
||||
|
||||
// Base types
|
||||
ASSERT_EQ(e0.getBase(), intType);
|
||||
ASSERT_EQ(e1.getBase(), intType);
|
||||
ASSERT_EQ(e2.getBase(), bit8Type);
|
||||
ASSERT_EQ(e3.getBase(), bit8Type);
|
||||
ASSERT_EQ(e4.getBase(), slogic8Type);
|
||||
ASSERT_EQ(e5.getBase(), slogic8Type);
|
||||
|
||||
// Sign
|
||||
ASSERT_EQ(e0.getSign(), Sign::Signed); // implicit int
|
||||
ASSERT_EQ(e1.getSign(), Sign::Signed); // implicit int
|
||||
ASSERT_EQ(e2.getSign(), Sign::Unsigned);
|
||||
ASSERT_EQ(e3.getSign(), Sign::Unsigned);
|
||||
ASSERT_EQ(e4.getSign(), Sign::Signed);
|
||||
ASSERT_EQ(e5.getSign(), Sign::Signed);
|
||||
|
||||
// Value domain
|
||||
ASSERT_EQ(e0.getDomain(), Domain::TwoValued);
|
||||
ASSERT_EQ(e1.getDomain(), Domain::TwoValued);
|
||||
ASSERT_EQ(e2.getDomain(), Domain::TwoValued);
|
||||
ASSERT_EQ(e3.getDomain(), Domain::TwoValued);
|
||||
ASSERT_EQ(e4.getDomain(), Domain::FourValued);
|
||||
ASSERT_EQ(e5.getDomain(), Domain::FourValued);
|
||||
|
||||
// Bit size
|
||||
ASSERT_EQ(e0.getBitSize(), 32u);
|
||||
ASSERT_EQ(e1.getBitSize(), 32u);
|
||||
ASSERT_EQ(e2.getBitSize(), 8u);
|
||||
ASSERT_EQ(e3.getBitSize(), 8u);
|
||||
ASSERT_EQ(e4.getBitSize(), 8u);
|
||||
ASSERT_EQ(e5.getBitSize(), 8u);
|
||||
}
|
||||
|
||||
} // namespace
|
Loading…
Reference in New Issue