-
Notifications
You must be signed in to change notification settings - Fork 31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Link against CIRCT and use it for codegen #234
Conversation
Add a first bindgen-based `circt-sys` crate that allows Rust code to use the CIRCT and, by extension, MLIR project code.
Add a `circt` crate that contains a lightweight wrapper to make `circt-sys` more comfortable to use from the Rust world. Add this crate as a dependency of `svlog`, for later use in module emission.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent work! This is a big step forward in terms of merging Moore with CIRCT.
I see you even incorporated FileCheck tests.
Just a few comments, mostly on index bitwidth and unique name checking.
Additionally, it could be useful to add some instructions to the README on how to build moore as it got quite a bit more complicated with CIRCT as a submodule (or did I miss some automation?).
E.g.,
git submodule update --init --recursive
mkdir -p circt/build
mkdir -p circt/llvm/build
cd circt/llvm/build
cmake ../llvm \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=../install \
-DLLVM_BUILD_EXAMPLES=OFF \
-DLLVM_ENABLE_ASSERTIONS=ON \
-DLLVM_ENABLE_BINDINGS=OFF \
-DLLVM_ENABLE_OCAMLDOC=OFF \
-DLLVM_ENABLE_PROJECTS=mlir \
-DLLVM_INSTALL_UTILS=ON \
-DLLVM_OPTIMIZED_TABLEGEN=ON \
-DLLVM_TARGETS_TO_BUILD=""
cmake --build . --target install
cd ../../build
cmake .. -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=../install \
-DMLIR_DIR=$PWD/../llvm/install/lib/cmake/mlir \
-DLLVM_DIR=$PWD/../llvm/install/lib/cmake/llvm \
-DLLVM_ENABLE_ASSERTIONS=ON
cmake --build . --target install
cd ../..
export CIRCT_SYS_CIRCT_DIR=`pwd`/circt
export CIRCT_SYS_CIRCT_BUILD_DIR=`pwd`/circt/install
export CIRCT_SYS_LLVM_DIR=`pwd`/circt/llvm
export CIRCT_SYS_LLVM_BUILD_DIR=`pwd`/circt/llvm/install
cargo build
offset: usize, | ||
length: usize, | ||
) -> Self { | ||
let offset = crate::hw::ConstantOp::new(builder, 64, &offset.into()).into(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The IR emitted here will fail during the CIRCT verification pass because ArraySliceOp expects the bitwidth of offset
to be llvm::Log2_64_Ceil(type_cast<ArrayType>($_self).getSize())
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's an excellent catch! I should have added a run of the verifier into Moore directly, just after codegen. Let me do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's a good idea!
src/svlog/codegen.rs
Outdated
self.builder.ins().sig(v) | ||
( | ||
self.builder.ins().sig(v.0), | ||
circt::llhd::SignalOp::new(self.mlir_builder, "", v.1).into(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above.
src/svlog/codegen.rs
Outdated
circt::llhd::VariableOp::new(self.mlir_builder, inner).into() | ||
} else if circt::llhd::is_signal_type(ty) { | ||
let inner = self.emit_zero_for_type_mlir(circt::llhd::signal_type_element(ty)); | ||
circt::llhd::SignalOp::new(self.mlir_builder, "", inner).into() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above.
src/svlog/codegen.rs
Outdated
let init = self.emit_zero_for_type_both(ty); | ||
let sig = ( | ||
self.builder.ins().sig(init.0), | ||
circt::llhd::SignalOp::new(self.mlir_builder, "", init.1).into(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above.
self.builder.ins().br_cond(event_cond, init_blk, event_blk); | ||
self.builder.append_to(event_blk); | ||
let event_blk = self.mk_block(Some("event")); | ||
self.mk_cond_br(event_cond, init_blk, event_blk); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the only call to mk_cond_br
where the successors are not transposed. Are you sure that init_blk
and event_blk
shouldn't be transposed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ufff that would have been annoying to debug. Thanks a lot! 😬
Thanks a lot for the extremely detailed review @maerhart! This is awesome, and you caught quite a few bugs 😬.
Yeah that is a good idea. I'll add the snippet to the README. I was considering making the |
I'd say good instructions are good enough for now. Automatic fetch and build is certainly more convenient from a user perspective (provided it always succeeds), but it should definitely print in the CLI when it does so and report the progress, otherwise one might think it ran into an infinite loop or so 😆 |
Some tools like `llvm-lit` rely on the build directory and project source tree to be available, so it makes sense to make the CI look like it was a regular development build that you would do on your own machine.
This PR makes Moore link against the circt library and uses that to generate code.
More specifically, this adds a
circt-sys
crate with the low-level bindings against the MLIR C library (generated by thebindgen
crate), and acirct
crate which contains some higher-level wrapper code that makes CIRCT and MLIR easier to use from Rust code. Note that we do not establish any kind of safety in Rust terms, but the API is "safe enough" for what we're trying to use it for.Currently
codegen.rs
calls the original LLHD crate and the new CIRCT bindings in parallel to generate code. This was useful as a sanity check and to make sure the CIRCT-based emission is up to par with the LLHD crate. At a later point we should strip codegen down to use only CIRCT.This PR also adds a
--format=mlir-native
output option which uses MLIR's dialect printer to emit the assembly.