Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/bench-hyperfine.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ jobs:
LLVM_SYS_191_PREFIX: /usr/lib/llvm-19/
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: check and free hdd space left
run: |
echo "Listing 20 largest packages"
Expand Down Expand Up @@ -129,6 +131,7 @@ jobs:
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request[matrix.branch].sha }}
submodules: true

- name: Fetch Rust cache
uses: Swatinem/rust-cache@v2
Expand Down Expand Up @@ -162,6 +165,7 @@ jobs:
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request[matrix.branch].sha }}
submodules: true

- name: Install Hyperfine
uses: taiki-e/install-action@v2
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ jobs:
TABLEGEN_190_PREFIX: /usr/lib/llvm-19/
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: dtolnay/rust-toolchain@1.84.1
with:
components: clippy, rustfmt
Expand Down Expand Up @@ -116,6 +118,8 @@ jobs:
RUST_LOG: cairo_native=debug,cairo_native_test=debug
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Install testing tools
uses: taiki-e/install-action@v2
with:
Expand Down Expand Up @@ -171,6 +175,8 @@ jobs:
RUST_LOG: cairo_native=debug,cairo_native_test=debug
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Install testing tools
uses: taiki-e/install-action@v2
with:
Expand All @@ -194,6 +200,8 @@ jobs:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: check and free hdd space left
run: |
echo "Listing 20 largest packages"
Expand Down Expand Up @@ -222,6 +230,8 @@ jobs:

steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Retreive cached dependecies
uses: Swatinem/rust-cache@v2
- name: Install dependencies
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Set env
run: |
echo "MLIR_SYS_190_PREFIX=${{ matrix.dep_base_dir }}" >> $GITHUB_ENV
Expand Down
11 changes: 5 additions & 6 deletions .github/workflows/starknet-blocks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ on:

jobs:
run-blocks:
if: false
name: Run Blocks
runs-on: ubuntu-latest
env:
Expand All @@ -33,7 +32,7 @@ jobs:
with:
repository: starkware-libs/starknet-replay
path: starknet-replay
ref: 5e75e33d67de77fe68aba06e05571175c0976733
ref: 4b896e523bd33da66b95c8b2afdb7423785e99d4

# We need native to use the linux deps ci action
- name: Checkout Native
Expand All @@ -46,8 +45,8 @@ jobs:
repository: starkware-libs/sequencer
path: sequencer
# branch main-v0.14.2
ref: 77a1a32b7b2c52edd9b634276e3bb28f5fbd750c
ref: efa9bd7d9e33e44d0cea08bf67c7b413fb20c7cb

- name: Restore RPC Calls
id: restore-rpc-calls
uses: actions/cache/restore@v4.2.0
Expand Down Expand Up @@ -108,14 +107,14 @@ jobs:
with:
name: dump-${{matrix.block}}-${{matrix.runner}}
path: starknet-replay/state_dumps/${{matrix.runner}}

- name: Save RPC Calls
uses: actions/cache/save@v4.2.0
if: ${{ always() && matrix.runner == 'vm' }}
with:
path: starknet-replay/cache
key: ${{ steps.restore-rpc-calls.outputs.cache-primary-key }}

compare-dumps:
name: Compare Dumps
needs: [run-blocks]
Expand Down
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,12 @@ cairo-*.tar

*.ipynb
cairo-native-stress-logs.jsonl

.DS_Store
bench_starknet_compilation_data
cairo
/cairo

test_data/e2e_sierra/
test_data_artifacts/programs
test_data_artifacts/contracts
test_data_artifacts/tests
Expand Down
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[submodule "vendor/cairo"]
path = vendor/cairo
url = https://github.com/starkware-libs/cairo.git
branch = v2.16.0
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ description = "A compiler to convert Cairo's IR Sierra code to MLIR and execute
readme = "README.md"
keywords = ["starknet", "cairo", "compiler", "mlir"]
categories = ["compilers"]
exclude = ["vendor/"]
version.workspace = true
edition.workspace = true
license.workspace = true
Expand Down
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ install-scarb-macos:
pull-external-projects:
python3 ./scripts/pull_external_projects.py v${CAIRO_2_VERSION}

test_data/e2e_sierra: vendor/cairo
python3 ./scripts/extract_e2e_sierra.py


.PHONY: compile-test-data
compile-test-data:
compile-test-data: test_data/e2e_sierra
python3 ./scripts/compile_test_data.py
98 changes: 98 additions & 0 deletions scripts/extract_e2e_sierra.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#!/usr/bin/env python3
"""
Extract sierra_code sections from cairo e2e test data files.

Input: test_data/e2e_libfuncs_raw/ (files in //! > format)
Output: test_data/e2e_sierra/ (individual .sierra files)
"""

import os
import re
import shutil
import sys

SRC_DIR = "vendor/cairo/tests/e2e_test_data/libfuncs"
DST_DIR = "test_data/e2e_sierra"


def sanitize_name(name):
"""Convert test name to a safe filename."""
return re.sub(r"[^\w\-]", "_", name.strip()).strip("_")


def parse_test_cases(text):
"""Parse //! > format into list of test-case dicts mapping section_key -> content."""
cases = re.split(r"^//! > =+\s*$", text, flags=re.MULTILINE)
results = []
for case in cases:
sections = {}
section_order = []
current_section = None
lines = []
for line in case.splitlines():
m = re.match(r"^//! > (.+)$", line)
if m:
if current_section is not None:
sections[current_section] = "\n".join(lines).strip()
current_section = m.group(1).strip()
section_order.append(current_section)
lines = []
else:
lines.append(line)
if current_section is not None:
sections[current_section] = "\n".join(lines).strip()
if sections:
sections["_order"] = section_order
results.append(sections)
return results


def main():
if not os.path.isdir(SRC_DIR):
print(
f"Source directory {SRC_DIR} not found. "
"Run 'git submodule update --init' first."
)
sys.exit(1)

shutil.rmtree(DST_DIR, ignore_errors=True)

count = 0
for dirpath, _, filenames in sorted(os.walk(SRC_DIR)):
for filename in sorted(filenames):
filepath = os.path.join(dirpath, filename)

with open(filepath, "r") as f:
content = f.read()

# Preserve subdirectory structure (e.g. starknet/syscalls)
rel_dir = os.path.relpath(dirpath, SRC_DIR)
test_cases = parse_test_cases(content)
for case in test_cases:
sierra = case.get("sierra_code", "").strip()
if not sierra:
continue

# The test name is the first section key (not a section called "test_name")
order = case.get("_order", [])
if not order:
continue
test_name = order[0]

safe_name = sanitize_name(test_name)
if not safe_name:
continue

out_dir = os.path.join(DST_DIR, rel_dir, filename)
os.makedirs(out_dir, exist_ok=True)
out_path = os.path.join(out_dir, f"{safe_name}.sierra")

with open(out_path, "w") as f:
f.write(sierra + "\n")
count += 1

print(f"Extracted {count} sierra files into {DST_DIR}/")


if __name__ == "__main__":
main()
4 changes: 4 additions & 0 deletions src/libfuncs/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ fn build_init_circuit_data<'ctx, 'this>(
metadata: &mut MetadataStorage,
info: &SignatureAndTypeConcreteLibfunc,
) -> Result<()> {
metadata.get_or_insert_with(|| ReallocBindingsMeta::new(context, helper));

let circuit_info = match registry.get_type(&info.ty)? {
CoreTypeConcrete::Circuit(CircuitTypeConcrete::Circuit(info)) => &info.circuit_info,
_ => return Err(SierraAssertError::BadTypeInfo.into()),
Expand Down Expand Up @@ -307,6 +309,8 @@ fn build_eval<'ctx, 'this>(
metadata: &mut MetadataStorage,
info: &SignatureAndTypeConcreteLibfunc,
) -> Result<()> {
metadata.get_or_insert_with(|| ReallocBindingsMeta::new(context, helper));

let circuit_info = match registry.get_type(&info.ty)? {
CoreTypeConcrete::Circuit(CircuitTypeConcrete::Circuit(info)) => &info.circuit_info,
_ => return Err(SierraAssertError::BadTypeInfo.into()),
Expand Down
6 changes: 6 additions & 0 deletions src/types/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ pub fn build_circuit_accumulator<'ctx>(
metadata: &mut MetadataStorage,
info: WithSelf<InfoOnlyConcreteType>,
) -> Result<Type<'ctx>> {
metadata.get_or_insert_with(|| ReallocBindingsMeta::new(context, module));

let Some(GenericArg::Type(circuit_type_id)) = info.info.long_id.generic_args.first() else {
return Err(SierraAssertError::BadTypeInfo.into());
};
Expand Down Expand Up @@ -211,6 +213,8 @@ pub fn build_circuit_data<'ctx>(
metadata: &mut MetadataStorage,
info: WithSelf<InfoOnlyConcreteType>,
) -> Result<Type<'ctx>> {
metadata.get_or_insert_with(|| ReallocBindingsMeta::new(context, module));

let Some(GenericArg::Type(circuit_type_id)) = info.info.long_id.generic_args.first() else {
return Err(SierraAssertError::BadTypeInfo.into());
};
Expand Down Expand Up @@ -302,6 +306,8 @@ pub fn build_circuit_outputs<'ctx>(
metadata: &mut MetadataStorage,
info: WithSelf<InfoOnlyConcreteType>,
) -> Result<Type<'ctx>> {
metadata.get_or_insert_with(|| ReallocBindingsMeta::new(context, module));

let Some(GenericArg::Type(circuit_type_id)) = info.info.long_id.generic_args.first() else {
return Err(SierraAssertError::BadTypeInfo.into());
};
Expand Down
60 changes: 60 additions & 0 deletions tests/tests/e2e_libfuncs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use cairo_lang_sierra::ProgramParser;
use cairo_native::context::NativeContext;
use std::fs;
use std::path::Path;

/// Collects all `.sierra` files under the e2e_sierra directory and compiles each
/// through cairo-native (Sierra → LLVM) to verify they compile without errors.
#[test]
fn compile_e2e_libfunc_sierra() {
let sierra_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("test_data/e2e_sierra");
assert!(
sierra_dir.exists(),
"{} not found. Run 'git submodule update --init && make test_data/e2e_sierra' first.",
sierra_dir.display()
);

let context = NativeContext::new();
let parser = ProgramParser::new();

let mut total = 0;
let mut failures = Vec::new();

for entry in walkdir::WalkDir::new(&sierra_dir) {
let entry = entry.unwrap();
let path = entry.path();
if path.extension().is_some_and(|e| e == "sierra") {
total += 1;
let source = fs::read_to_string(path).unwrap();
let rel_path = path.strip_prefix(&sierra_dir).unwrap();

let program = match parser.parse(&source) {
Ok(p) => p,
Err(e) => {
failures.push(format!("{}: parse error: {e}", rel_path.display()));
continue;
}
};

eprintln!("compiling {}", rel_path.display());
if let Err(e) = context.compile(&program, false, Some(Default::default()), None) {
failures.push(format!("{}: compile error: {e}", rel_path.display()));
}
}
}

assert!(
total > 0,
"No .sierra files found in {}",
sierra_dir.display()
);

if !failures.is_empty() {
panic!(
"{}/{} e2e libfunc sierra files failed to compile:\n{}",
failures.len(),
total,
failures.join("\n")
);
}
}
1 change: 1 addition & 0 deletions tests/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod cases;
pub mod circuit;
pub mod compile_library;
pub mod dict;
pub mod e2e_libfuncs;
pub mod ec;
pub mod felt252;
pub mod libfuncs;
Expand Down
1 change: 1 addition & 0 deletions vendor/cairo
Submodule cairo added at 6a43d7
Loading