Implement Yul to LLVM IR compilation benchmarks (#407)

# Description

Closes [#404](https://github.com/paritytech/revive/issues/404)

Adds compilation time benchmarks for:

* Parsing of Yul source code -> AST Object
* Lowering of AST Object -> LLVM IR (unoptimized)

The benchmarks can be run from the root via:

```sh
# Run all benchmarks in the revive-yul crate (parsing + lowering)
make bench-yul
```

HTML reports will be generated under `target/criterion`, and a summary
of the results at
[crates/yul/BENCHMARKS_PARSE_M4PRO.md](https://github.com/paritytech/revive/blob/lj/compilation-benchmarks-yul/crates/yul/BENCHMARKS_PARSE_M4PRO.md)
and
[crates/yul/BENCHMARKS_LOWER_M4PRO.md](https://github.com/paritytech/revive/blob/lj/compilation-benchmarks-yul/crates/yul/BENCHMARKS_LOWER_M4PRO.md)
(currently from running on a Mac M4 Pro).

---------

Co-authored-by: xermicus <cyrill@parity.io>
This commit is contained in:
LJ
2025-11-25 12:00:06 +01:00
committed by GitHub
parent 1e0cce0fa8
commit 0742227c5a
12 changed files with 425 additions and 24 deletions
@@ -256,6 +256,22 @@ impl<'ctx> Context<'ctx> {
}
}
/// Initializes a new dummy LLVM context.
///
/// Omits the LLVM module initialization; use this only in tests and benchmarks.
pub fn new_dummy(
llvm: &'ctx inkwell::context::Context,
optimizer_settings: OptimizerSettings,
) -> Self {
Self::new(
llvm,
llvm.create_module("dummy"),
Optimizer::new(optimizer_settings),
Default::default(),
Default::default(),
)
}
/// Builds the LLVM IR module, returning the build artifacts.
pub fn build(
self,
@@ -1,33 +1,21 @@
//! The LLVM IR generator context tests.
use crate::optimizer::settings::Settings as OptimizerSettings;
use crate::optimizer::Optimizer;
use crate::polkavm::context::attribute::Attribute;
use crate::polkavm::context::Context;
use crate::PolkaVMTarget;
pub fn create_context(
llvm: &inkwell::context::Context,
optimizer_settings: OptimizerSettings,
) -> Context<'_> {
/// Initializes the LLVM compiler backend.
fn initialize_llvm() {
crate::initialize_llvm(PolkaVMTarget::PVM, "resolc", Default::default());
let module = llvm.create_module("test");
let optimizer = Optimizer::new(optimizer_settings);
Context::new(
llvm,
module,
optimizer,
Default::default(),
Default::default(),
)
}
#[test]
pub fn check_attribute_null_pointer_is_invalid() {
initialize_llvm();
let llvm = inkwell::context::Context::create();
let mut context = create_context(&llvm, OptimizerSettings::cycles());
let mut context = Context::new_dummy(&llvm, OptimizerSettings::cycles());
let function = context
.add_function(
@@ -51,8 +39,10 @@ pub fn check_attribute_null_pointer_is_invalid() {
#[test]
pub fn check_attribute_optimize_for_size_mode_3() {
initialize_llvm();
let llvm = inkwell::context::Context::create();
let mut context = create_context(&llvm, OptimizerSettings::cycles());
let mut context = Context::new_dummy(&llvm, OptimizerSettings::cycles());
let function = context
.add_function(
@@ -76,8 +66,10 @@ pub fn check_attribute_optimize_for_size_mode_3() {
#[test]
pub fn check_attribute_optimize_for_size_mode_z() {
initialize_llvm();
let llvm = inkwell::context::Context::create();
let mut context = create_context(&llvm, OptimizerSettings::size());
let mut context = Context::new_dummy(&llvm, OptimizerSettings::size());
let function = context
.add_function(
@@ -101,8 +93,10 @@ pub fn check_attribute_optimize_for_size_mode_z() {
#[test]
pub fn check_attribute_min_size_mode_3() {
initialize_llvm();
let llvm = inkwell::context::Context::create();
let mut context = create_context(&llvm, OptimizerSettings::cycles());
let mut context = Context::new_dummy(&llvm, OptimizerSettings::cycles());
let function = context
.add_function(
@@ -126,8 +120,10 @@ pub fn check_attribute_min_size_mode_3() {
#[test]
pub fn check_attribute_min_size_mode_z() {
initialize_llvm();
let llvm = inkwell::context::Context::create();
let mut context = create_context(&llvm, OptimizerSettings::size());
let mut context = Context::new_dummy(&llvm, OptimizerSettings::size());
let function = context
.add_function(