Add support for the simulation control system tasks `$stop`, `$finish`,
and `$exit`. Also add corresponding ops to the Moore dialect that handle
the orthogonal pieces of functionality represented by these tasks.
Factor the materialization of Slang `SVInt`s and `ConstantValue`s out
into a helper function on the import context. This will allow for easier
access to constant materialization from outside the expression
conversion code.
Rework the `moore.wait_event` op to be able to accurately model the
semantics of SystemVerilog's `@...` event control statements. The op now
has a body region which is executed to detect a relevant change in one
or more interesting values. A new `moore.detect_event` op serves as the
mechanism to encode whether a posedge, negedge, both, or any change at
all on a value should be detected as an event.
Based on this new `moore.wait_event` op we can properly convert most of
the event control statements in `ImportVerilog` to a corresponding MLIR
op. Delay control like `#1ns` is not handled yet.
In the MooreToCore conversion this new op allows us to properly generate
`llhd.wait` operations at the right place that suspend process execution
until an interesting event has occurred. This now also allows us to
support almost all SystemVerilog processes in the lowering. The only
missing ones are `always_comb` and `always_latch` which require an
implicit `llhd.wait` to be inserted. @maerhart has a version of that
lowering almost ready though.
This commit also adds an `llhd.final` op in order to be able to lower
`final` procedures.
Fixes#7482.
Co-authored-by: Martin Erhart <maerhart@outlook.com>
Add a lowering pattern from `moore.conditional` to `scf.if`. This
currently relies on the condition being a two-valued integer after
lowering. Once we support four-valued integers at the core dialect
level, the lowering of `moore.conditional` will become a lot more
complicated.
Bump LLVM [1] to include an upstream verifier performance fix [2].
This required two minor fixes to CIRCT:
* [HW] Qualify types for safer use in other dialects.
* [ImportVerilog] Fix ternary with diff types, both become Value.
[1]: 5689cccead...c69b8c445a
[2]: 7a98071da2
Extend Moore's `ConstantOp` to use the new `FVIntegerAttr`, which now
allows us to materialize four-valued integer constants in the IR. Also
adjust ImportVerilog to finally properly captured integer literals with
X and Z bits.
With this change, `circt-verilog` is now capable of fully parsing the
Snitch RISC-V core used as a benchmark in the original LLHD paper at
PLDI 2020, and to produce a corresponding blob of IR.
Examples of the extended op:
moore.constant 0 : i32
moore.constant 2 : i2
moore.constant -2 : i2
moore.constant h123456789ABCDEF0 : i64
moore.constant h123456789ABCDEF0XZ : l72
moore.constant b1010 : i8
moore.constant b1010XZ : l8
Fix an issue in the mapping of the logical `&&`, `||`, `->`, and `<->`
operators, where the left and right-hand side could have different value
domains in the AST (one `logic`, one `bit`).
Similarly, fix an issue with the `?:` ternary operator where the true
and false expressions could have different but cast-compatible types.
Add support for assignment patterns like `'{42, 9001}` in rvalue
position. These are roughly SystemVerilog's equivalent of
`struct_create` and `array_create`. This commit also adds an
`array_create` op to support assignment patterns for arrays.
Add missing conversions for cases where the Slang AST has expressions
operating directly on packed structs/arrays, but the Moore IR expects
a conversion to a simple bit vector type.
Also clean up a few things and remove an invalid `struct_inject`
conversion.
Rework the Moore dialect operations that manipulate struct values. These
are intended to operate on `StructType` and `UnpackedStructType` values
directly, but were defined in ODS as operating on references to structs.
This was likely a hold-over from early development where we were still
figuring out the distinction between ref types and value types in SV.
This commit adjusts the struct ops such that they actually operate on
struct values instead of references to structs. It also moves more
operand constraints into ODS and simplifies the op verifiers by
factoring out some common code into helper functions.
Enhance the `struct_inject` canonicalizer to also consider
`struct_create` operations as part of the inject chain. This allows an
initial `struct_create` that is modified by a subsequent inject to be
canonicalized into a new `struct_create` with updated values.
Add missing basic and error tests for the struct-related ops, and
simplify the variable destructuring test by removing unrelated
operations.
Also fixes an issue in variable op destructuring where a variable with
initial value would have its initial value discarded during
destructuring. Initial values now prevent destructuring. Alternatively,
we may choose to insert appropriate `struct_extract` ops to destructure
the initial value in the future.
Divide the extract into a dynamic extract named moore.dyn_extract and a constant extract named moore.extract, the former has a variable as its low bit like arr[x], but the latter has a constant value as its low bit like arr[1].
Co-authored-by: Fabian Schuiki <fabian@schuiki.ch>
Add basic support for function definitions and calls to such functions.
Input function arguments are currently passed into the function by
value, while output, inout, ref, and const ref arguments are passed by
reference at the moment. Later on we may want to be more faithful to the
SV spec and make output and inout arguments also pass by value.
Calls to void functions are slightly strange in that they don't really
have a result value, but the `convertExpression` function really wants
a valid `Value` to return. To work around this, these calls generate an
additional `!moore.void` value using `unrealized_conversion_cast`, which
gets deleted again by the statement conversion code.
Add support for enum variants in expressions. Until now, ImportVerilog
would emit a "unknown name" diagnostic when an enum variant is used in
an expression. This is due to the lowering of named value expressions
simply checking whether an MLIR value is present in the `valueSymbols`
table for the referenced symbol name. This works for variables which
create dedicated declarations, but not for enum variants which
potentially live outside the current module's scope.
Instead, ImportVerilog will now check if the named value is a constant,
for example a parameter or an enum variant, and materialize that
constant directly as a `moore.constant` op. This will also be able to
deal with parameters declared inside of packages, for which the table of
value symbols of the current module does not contain any value. (Local
parameters inside the module generate a `moore.named_constant` op that
is present in the table.)
Handle calls to the `$signed` and `$unsigned` system tasks by simply
passing through the argument. The casting is handled by Slang during
type checking and is materialized as a type conversion node in the AST.
The call itself has no function after that.
The `visitCall` function is going to be the place to add handling for
other system calls in the future. IEEE 1800-2017 section 20 defines a
fairly substantial list of builtin system tasks. Most of these will want
to have a dedicated `moore.builtin.*` op in the future.
For the new concept of Moore dialect, some operations will be defined as memory-related operations. Modeling memref Dialect and LLVM dialect, the operation relationship is as follows:
ReadOp and blockingAssignOp are related to loadOp and storeOp.
VariableOp is related to allocaOp.
However, the operations mentioned below are for basic types. This PR will support nested types in the following way:
VariableOp with nested types is still related to allocaOp (will be replaced with structCreateOp and UnionCreateOp).
structExtractRefOp is related to storeOp.
structExtractOp is related to loadOp.
To implement this:
Since these operations will be lowered to the hw dialect, the design largely refers to the hw dialect.
Add the trait DestructurableAllocationOpInterface for VariableOp.
Add the trait DestructurableAccessorOpInterface for structExtractOp and structExtractRefOp.
Implement the DestructurableTypeInterface for structLikeType and the reftype of structLikeType.
For local variables:
Use the SROA (Scalar Replacement of Aggregates) Pass to destructure all nested-type variables into basic-type variables.
Use the Mem2Reg (Memory to Register) Pass to replace variables imported by SROA with constants.
For global/module-level variables:
When importing Verilog, use structInjectOp rather than blockingAssignOp, because structExtractRefOp has the Destructurable trait, but global variables should not be destructured.
structInjectOp means creating a new struct with new values and other old values.
Use the canonicalizer Pass to fold duplicate injecting same field operations.
Use the canonicalizer Pass to explicitly show new struct creation.
Use the canonicalizer Pass to send source values directly and remove structExtractOp.
Also, remove some unnecessary spaces in other code.
What's more:
Verify that the input of nested-type-related operations should match the field type defined.
To do:
Update the use of struct SSA values referring to the latest structInjectOp SSA values.
Design the method for union types.
Add and support the dbg dialect to keep local variables visible after SROA & Mem2Reg.
Co-authored-by: Théo Degioanni <degiotheo@gmail.com>
Co-authored-by: Fabian Schuiki <fabian@schuiki.ch>
Fix an issue where ImportVerilog would currently crash if an unbased,
unsized literal like `'0` is used to initialize or assign to a packed
struct. Instead, the integer literal should be constructed and then
converted to the packed aggregate type. In a later pass, this conversion
can be lowered to a more careful `moore.struct_create`.
[Moore] Modify the tests related to the RefType.
Add a wrapper type(moore::RefType) to work for VariableOp/NetOp, ReadOp, and AssignOpBase, and it can wrap any SystemVerilog types. We added RefType in order to introduce Mem2Reg into moore to eliminate the local temporary variables. Meanwhile, we added a new op named moore.extract_ref which is the copy of moore.extract that explicitly works on the ref type. And moore.concat_ref is the copy of moore.concat. Later, we will tweak union/struct ops like moore.struct_create in order to support the ref type.
moore.variable/moore.net will return a result with ref<T>, it's similar to memref.alloca.
Change moore::ReadLValueOp to moore::ReadOp, it's similar to memref.load. Initially, we need moore.read_lvalue only to service for assigmen operations(like +=, *=, etc). However, moore. read is not only for assignment operations but also to take a value with RefType(ref) and return the current value with the nested type(T). For example, a = b + c, moore.read will take b and c(both are ref<T>), and then return a value with the nested type(T).
We think the MooreLValueType and VariableDeclOp(52a71a6) that had been removed eventually found their proper site.
We also divide convertExpression() into convertLvalueExpression() for the LHS of assignments and convertRvalueExpression() for the RHS of assignments. The former will return a value with RefType like ref<i32>, but the latter returns a value without RefType like i32.
Co-authored-by: Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
* [ImportVerilog]Support union types.
* [ImportVerilog]Rename structMember with structLikeMember
* [ImportVerilog] check the type of new Expressions.
* [ImportVerilog]Add value check for new Expressions.
* clang-format modify recommand
* [importVerilog]Remove useless inlcludes
* [ImportVerilog]Add union size and domain
* [ImportVerilog]Give more specefic errors
* [ImportVerilog] Support member-access expression
Support member-access expression.
Add container multiSymbolValue for multi-symbols pointing one value.
Signed-off-by: mingzheTerapines <mingzhe.zhang@terapines.com>
* [ImportVerilog] Support member-access expression
Separate two containers and their annotations.
* [ImportVerilog] Support member-access expression3
use auto instead of const slang::ast::Expression *
declare concatName with expr.member.name
* [ImportVerilog] Support member-access expression4
Simplfy string allocation.
* [ImportVerilog] Support member-access expression
The signing of unpacked structures is not allowed.- IEEE Standard
* [ImportVerilog] Support member-access expression6
Add packed unsigned struct occasion for testing.
* [ImportVerilog] Support Union Type
Support Union Type
Modify uniont tyep to event type as error type example.
* [ImportVerilog]Add errors example
Add error example for unpacked union.
* [ImportVerilog] Add strucfield op
Define a struct field access op that can represent accesses into struct fields.
* [ImportVerilog] Add struct inject and extract op
Add struct inject and extract op.
Remove union support.
* [ImportVerilog] Support memberaccess
* Removed some useless include.
* fix test error
* Fix errors.sv
* remove space.
---------
Signed-off-by: mingzheTerapines <mingzhe.zhang@terapines.com>
The core type most SystemVerilog expressions are interested in and
operate on is a "simple bit vector type". These are individual integer
atoms like `bit` or `logic`, integral types like `int`, or packed arrays
with a single dimension and an integer atom inner type, like
`bit [42:0]`. So in a nutshell, simple bit vector types are MLIR's `i42`
in the two-valued (`bit`) case, or the four-valued equivalent (`logic`).
Up until this point, the Moore dialect reflected this pattern by
providing and `IntType` for the integer atoms like `bit` and `int`, and
using the `PackedRangeDim` for single dimension vectors of `bit`. A
`SimpleBitVectorType` helper struct would then summarize the _actual_
bit vector that was expressed by the packed range and integer atom. This
makes working with the types in TableGen files very annoying, since the
thing you are actually interested in -- the simple bit vector -- is not
a propery MLIR type, but more like a helper struct on the side.
This commit rips out the existing `IntType` and its composition with a
packed array dimension, and replaces it with a proper simple bit vector
type that is actually an MLIR type. As a result, SystemVerilog types
like `int unsigned`, `bit [42:0]`, `reg`, `logic signed [31:0]`, or
`integer` are all translated into the same MLIR type. This new simple
bit vector MLIR type retains the `IntType` name, and prints as
`!moore.i42` or `!moore.l42`, depending on whether it is a two-valued or
four-valued integer. Single `bit` and `logic` atoms become `i1` and `l1`
respectively.
This makes the Moore type system a lot easier to work with and removes
a lot of unnecessary noise. Operations can now simply use
`llvm::isa<IntType>` to check if a value is a simple bit vector.
Instead of annotating types as signed or unsigned, make Moore dialect
types signless and move the signedness into operations. This affects
division, modulus/remainder, and comparison operations. These now come
in a signed and unsigned flavor. ImportVerilog consults the Slang AST
type to determine signedness when creating Moore dialect ops. The Moore
types themselves now no longer carry any sign information. This
significantly simplifies the dialect and takes the type system one step
closer towards having just a basic two- and four-valued bit vector type.
Add support for pre and post increment and decrement expressions, like
`x++` and `--x`, as well as assign expressions, like `a += 5`. Slang
represents these assignments as `Assign(a, Add(LValueRef, 5))` in the
AST. The `LValueRef` node contextually refers to the parent assignment's
left-hand side. To deal with this, also add a corresponding lvalue stack
to the conversion context. Assignments push and pop their lvalues onto
and off of this stack.
These expressions require a mechanism in the IR to express _when_ a
variable is read. To capture this, add a new `moore.read_lvalue` op.
It currently looks like an identity operation with a `MemRead` side
effect. Further down the road, we may want to introduce a proper
reference type for variables, ports, nets, and other things, and have
`read_lvalue` and the various assigns operate on that type instead. This
sets the foundation for that.
Co-authored-by: Hailong Sun <hailong.sun@terapines.com>
Co-authored-by: ShiZuoye <albertethon@163.com>
Co-authored-by: hunterzju <hunter_ht@zju.edu.cn>
Co-authored-by: Anqi Yu <anqi.yu@terapines.com>
Extend the `ImportVerilog` conversion to support most of the basic
expressions that commonly appear in SystemVerilog input files. Also add
the correpsonding expression ops to the Moore dialect, and finally get
rid of the old MIR expressions file which is now obsolete.
Thanks @hailongSun2000 and @albertethon for doing a lot of the leg work
to get expression support in!
Co-authored-by: Hailong Sun <hailong.sun@terapines.com>
Co-authored-by: ShiZuoye <albertethon@163.com>
Co-authored-by: Martin Erhart <maerhart@outlook.com>
Add continuous, blocking, and non-blocking assignments to the Moore
dialect. These represent the corresponding constructs in SystemVerilog.
Add a `ScopedHashTable` to the ImportVerilog conversion context and add
variable declarations to it. This allows expression conversion to
resolve name expressions to the MLIR value that was generated for the
corresponding declaration. The Slang AST node pointer itself is used as
a lookup key, since the AST already has all names resolved.
Add a basic expression handling mechanism to the ImportVerilog
conversion. A new `convertExpression` entry point calls an `ExprVisitor`
to convert expression nodes in the Slang AST to the corresponding MLIR
operations. This currently only supports name expressions, which simply
looks up the converted MLIR value for whatever the name was resolved to,
and blocking and non-blocking assignments.
Extend the module conversion to properly handle continuous assignments
at the module level.
Thanks @albertethon, @hailongSun2000, and @angelzzzzz for the help to
get this started.
Co-authored-by: ShiZuoye <albertethon@163.com>
Co-authored-by: Hailong Sun <hailong.sun@terapines.com>
Co-authored-by: Anqi Yu <anqi.yu@terapines.com>