diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..8a5def09 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +# General Code +* @reilabs/starkware diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..2fd219dc --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,24 @@ +--- +name: Bug report +about: Found something wrong? Let us know. +title: "[BUG] " +labels: bug +assignees: '' +--- + +# Describe the Bug + +A clear and concise description of what the bug is. + +# To Reproduce + +Steps to reproduce the behavior: + +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +# Expected Behaviour + +A clear and concise description of what you expected to happen. diff --git a/.github/ISSUE_TEMPLATE/feature.md b/.github/ISSUE_TEMPLATE/feature.md new file mode 100644 index 00000000..cf73ab1b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature.md @@ -0,0 +1,15 @@ +--- +name: Feature +about: A new feature to be added. +title: "[FEAT] " +labels: enhancement +assignees: '' +--- + +# Description + +What is this about? + +# Spec + +Give details. diff --git a/.github/ISSUE_TEMPLATE/performance.md b/.github/ISSUE_TEMPLATE/performance.md new file mode 100644 index 00000000..5a5657e1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/performance.md @@ -0,0 +1,15 @@ +--- +name: Performance +about: An opportunity for performance improvement or other performance-related work. +title: "[PERF] " +labels: enhancement +assignees: '' +--- + +# Description + +What is this about? + +# Spec + +Give details. diff --git a/.github/ISSUE_TEMPLATE/task.md b/.github/ISSUE_TEMPLATE/task.md new file mode 100644 index 00000000..37b39945 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/task.md @@ -0,0 +1,15 @@ +--- +name: Task +about: A development task to be done. +title: "[TASK] " +labels: enhancement +assignees: '' +--- + +# Description + +What is this about? + +# Spec + +Give details. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..03583ac6 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,12 @@ +# Summary + + + +# Details + + + +# Checklist + +- [ ] Code is formatted by Rustfmt. +- [ ] Documentation has been updated if necessary. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..98fde593 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,136 @@ +# Metadata for the actions workflow +name: CI +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "*" ] + +# Environment variables that will be set on all runners +env: + CI_DEV_SHELL: "nix --store ~/nix_store develop '.#ci'" + CARGO_TERM_COLOR: always # Always colour Cargo's output. + CARGO_INCREMENTAL: 0 # Always run without incremental builds on CI. + CARGO_PROFILE_DEV_DEBUG: 0 # Don't embed debug info even though the build is a dev build. + +# Configuration for individual jobs +jobs: + + # This job is responsible for running the unit and integration tests. +# test: +# name: "Test" +# strategy: +# fail-fast: false +# matrix: +# os: [ "ubuntu-latest", "macos-latest" ] +# runs-on: ${{ matrix.os }} +# steps: +# - name: Checkout Code +# uses: actions/checkout@v3 +# - name: Install Lix +# shell: "bash" +# run: | +# curl -sSf -L https://install.lix.systems/lix | sh -s -- install --no-confirm +# - name: Restore Nix Cache +# uses: actions/cache@v3 +# continue-on-error: true +# with: +# path: | +# /nix/store +# key: nix-${{ hashFiles('**/flake.lock') }}-${{ matrix.os }} +# - name: Restore Rust Cache +# uses: actions/cache@v3 +# continue-on-error: true +# with: +# path: | +# target/ +# key: rust-${{ hashFiles('**/Cargo.lock') }}-${{ matrix.os }} +# - name: Build Lix Dependencies +# shell: "bash" +# run: | +# nix build +# - name: Build Tests +# shell: "bash" +# run: | +# ${{ env.CI_DEV_SHELL }} --command cargo test --all-targets --no-run +# - name: Run Tests +# shell: "bash" +# run: | +# ${{ env.CI_DEV_SHELL }} --command cargo test --all-targets -- --nocapture + + # This job runs the linter. + lint: + name: "Lint" + runs-on: "ubuntu-latest" + steps: + - name: Checkout Code + uses: actions/checkout@v3 + - name: Install Lix + shell: "bash" + run: | + curl -sSf -L https://install.lix.systems/lix | sh -s -- install --no-confirm + sudo chown -R $USER: /nix + - name: Restore Nix Cache + uses: actions/cache@v3 + continue-on-error: true + with: + path: | + ~/nix_store + key: nix-${{ hashFiles('**/flake.lock') }}-ubuntu-latest + - name: Restore Rust Cache + uses: actions/cache@v3 + continue-on-error: true + with: + path: | + target/ + key: rust-${{ hashFiles('**/Cargo.lock') }}-ubuntu-latest + - name: Build Lix Dependencies + shell: "bash" + run: | + nix build + - name: Install Lix + shell: "bash" + run: | + curl -sSf -L https://install.lix.systems/lix | sh -s -- install --no-confirm + - name: Lint Code + shell: "bash" + run: | + ${{ env.CI_DEV_SHELL }} --command cargo clippy --all-targets + + # This job checks the code formatting. +# formatting: +# name: "Check Formatting" +# runs-on: "ubuntu-latest" +# steps: +# - name: Checkout Code +# uses: actions/checkout@v3 +# - name: Install Lix +# shell: "bash" +# run: | +# curl -sSf -L https://install.lix.systems/lix | sh -s -- install --no-confirm +# - name: Restore Nix Cache +# uses: actions/cache@v3 +# continue-on-error: true +# with: +# path: | +# /nix/store +# key: nix-${{ hashFiles('**/flake.lock') }}-ubuntu-latest +# - name: Restore Rust Cache +# uses: actions/cache@v3 +# continue-on-error: true +# with: +# path: | +# target/ +# key: rust-${{ hashFiles('**/Cargo.lock') }}-ubuntu-latest +# - name: Build Lix Dependencies +# shell: "bash" +# run: | +# nix build +# - name: Install Lix +# shell: "bash" +# run: | +# curl -sSf -L https://install.lix.systems/lix | sh -s -- install --no-confirm +# - name: Check Formatting +# shell: "bash" +# run: | +# ${{ env.CI_DEV_SHELL }} --command cargo fmt --all -- --check diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..84607523 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +# Rust +/target + +# Tooling +.idea/ +result diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..a4e6426b --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,428 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "ariadne" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44055e597c674aef7cb903b2b9f6e4cba1277ed0d2d61dae7cd52d7ffa81f8e2" +dependencies = [ + "unicode-width", + "yansi", +] + +[[package]] +name = "cc" +version = "1.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.5.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "inkwell" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40fb405537710d51f6bdbc8471365ddd4cd6d3a3c3ad6e0c8291691031ba94b2" +dependencies = [ + "either", + "inkwell_internals", + "libc", + "llvm-sys", + "once_cell", + "thiserror", +] + +[[package]] +name = "inkwell_internals" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd28cfd4cfba665d47d31c08a6ba637eed16770abca2eccbbc3ca831fef1e44" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" + +[[package]] +name = "llvm-sys" +version = "180.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "778fa5fa02e32728e718f11eec147e6f134137399ab02fd2c13d32476337affa" +dependencies = [ + "anyhow", + "cc", + "lazy_static", + "libc", + "regex-lite", + "semver", +] + +[[package]] +name = "llvm-to-cairo" +version = "0.1.0" +dependencies = [ + "anyhow", + "ariadne", + "clap", + "inkwell", + "miette", + "thiserror", + "tracing", +] + +[[package]] +name = "miette" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4edc8853320c2a0dab800fbda86253c8938f6ea88510dc92c5f1ed20e794afc1" +dependencies = [ + "cfg-if", + "miette-derive", + "thiserror", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex-lite" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-width" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..15c4425f --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "llvm-to-cairo" +version = "0.1.0" +homepage = "https://github.com/reilabs/llvm-to-cairo" +repository = "https://github.com/reilabs/llvm-to-cairo" +license-file = "LICENSE" + +authors = ["Reilabs"] +description = "A compiler to allow LLVM bytecode to run on the Starknet ecosystem in a provable fashion." +keywords = ["compiler", "starknet", "starkware"] +categories = ["compilers", "virtualization", "cryptography::cryptocurrencies"] + +edition = "2021" +rust-version = "1.80.1" + +[dependencies] +ariadne = "0.4.1" +clap = "4.5.16" +inkwell = { version = "0.5.0", features = ["llvm18-0"] } +miette = "7.2.0" +thiserror = "1.0.63" +tracing = "0.1.40" + +[dev-dependencies] +anyhow = "1.0.86" + +[profile.release] +debug = true # Include full debug information in release builds. +overflow-checks = true # Keep overflow checks in production builds. +lto = "thin" # Thin LTO performs cross-crate LTO while not bloating the build time too much. diff --git a/README.md b/README.md new file mode 100644 index 00000000..f64b4532 --- /dev/null +++ b/README.md @@ -0,0 +1,49 @@ +# LLVM on CairoVM + +This repository contains the efforts to enable compilation of LLVM bytecode to run on top of the +[CairoVM](https://github.com/lambdaclass/cairo-vm) and [Starknet](https://www.starknet.io). The +goals of this project are threefold: + +1. **Provable Rust Execution:** To provide the ability to prove the execution of LLVM bytecode using + Starknet's proving infrastructure, thereby allowing verification of said execution. +2. **Writing Contracts in LLVM Languages:** To provide the ability to write contracts for execution + on Starknet using any language that compiles to LLVM (while recognizing that this will require a + small per-language effort). +3. **Using Foreign Libraries from Cairo:** There exist a wealth of useful cryptographic libraries in + languages such as Rust that compile to LLVM. Rather than requiring users to reimplement them in + [Cairo](https://www.cairo-lang.org), this effort would allow them to be exposed directly. + +The initial efforts for this project are focusing on using [Rust](https://rust-lang.org) as the +source of the LLVM bytecode, and will see support libraries implemented for this language. +Nevertheless, this project aims to be agnostic to the actual source language of the bytecode besides +the language-specific libraries. + +## Architectural Overview + +As there is a significant mismatch between the computational model expected by LLVM, and the Cairo +model of execution, we take a multi-layered approach. + +- **Compilation:** Where there is a direct correspondence between LLVM and Cairo's semantics, we can + perform direct compilation, generating Cairo's `FlatLowered` IR from LLVM IR. +- **Polyfills:** Where there is a mismatch, we have to implement the mismatched operation as an + _emulation_ or a _polyfill_. These will implement the expected semantics (often given by + [compiler-rt](https://compiler-rt.llvm.org)) as Cairo code that can then be called into by the + compilation process. + +As Cairo is not an operating system, we restrict our source code to be `#[no_std]` or the equivalent +for other languages. This is necessary as we cannot provide useful primitives for things like the +filesystem, network, or even threading. + +In the future, we intend to move many of our polyfilled operations into native operations as part of +the CASM instruction set, or as Cairo +[builtins](https://book.cairo-lang.org/ch204-00-builtins.html#builtins) to improve performance. +Starting with the emulation or polyfill layer, however, lets us determine which operations are going +to be most effective to transfer first, and help us arrive to the final design of such operations +before moving them to AIR. + +## Contributing + +If you want to contribute code or documentation (non-code contributions are always welcome) to this +project, please take a look at our [contributing](./docs/CONTRIBUTING.md) documentation. It provides +an overview of how to get up and running, as well as what the contribution process looks like for +this repository. diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100644 index 00000000..6598be76 --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,97 @@ +# Contributing + +This document exists as a brief introduction to how you can contribute to the LLVM to Cairo +project. It includes a guide to [getting started](#setting-up-for-development) and +[contributing to `main`](#getting-your-work-on-main). + +This repository is written in [Rust](https://www.rust-lang.org), a high-performance and +low-level language with a smart compiler that helps to write reliable and fast software. If you +haven't worked with Rust before, take a look at the ["New to Rust?"](#new-to-rust) section below! + +## Setting Up for Development + +Unfortunately the complexity of having LLVM available for building this project means that we have +to be a bit careful with our environment setup. We recommend using [lix](https://lix.systems) to +work with the flake configuration included in the repository. + +We assume that you are either running on linux or macOS at this stage. + +1. Install [lix](https://lix.systems/install/) using the lix installer—you will want to say "yes" + when asked if you want to enable flakes—and make sure that you can successfully run the `nix` + command. + + ```shell + curl -sSf -L https://install.lix.systems/lix | sh -s -- install + # Follow the instructions + nix --version + ``` + +2. Clone the repository. If you don't want to contribute directly you can use HTTPS clones: + + ```shell + git clone https://github.com/reilabs/llvm-to-cairo + ``` + + If you _do_ want to contribute directly to the tree, we recommend cloning over SSH: + + ```shell + git clone git@github.com:reilabs/llvm-to-cairo.git + ``` + +3. Enter the cloned directory (`cd llvm-to-cairo`) and launch a development shell using + `nix develop`. This will launch into your default shell, but you can override this by running + `nix develop ".#ci" --command ` to use the CI dev shell instead. + +4. Within this shell you are able to run Cargo commands such as `cargo build`, which will build the + project, or `cargo test` which will run the tests. + +### Setting Up Your IDE + +Due to the complexities of getting some IDEs to work with nix-based Rust projects, we recommend +using a system-wide installation of the correct toolchain (as specified in +[`Cargo.toml`](../Cargo.toml)). Then, we recommend launching your IDE from the development shell +provided by `nix develop`, as this will give it the correct environment variables to find the LLVM +install. + +We cannot provide instructions for _all_ IDEs, but for those using RustRover you will need to go to +the top-level "Rust" section in settings, and point both "Toolchain location" and "Standard library" +to a system-level install of both. For example: + +```text +Toolchain Location = /Users//.rustup/toolchains/stable-platform-here/bin +Standard library = /Users//.rustup/toolchains/stable-platform-here/lib/rustlib/src/rust +``` + +## Getting Your Work on `main` + +For contributions this repository works on a +[Pull Request](https://github.com/reilabs/llvm-to-cairo/pulls) and subsequent review +model, supported by CI to check that things avoid being broken. The process works as follows: + +1. If necessary, you fork the repository, but if you have access please create a branch. +2. You make your changes on that branch. +3. Pull-request that branch against `main`. +4. The pull request will be reviewed, and CI will run on it. +5. Once reviewers accept the code, and CI has passed, it will be merged to main! + +## New to Rust? + +If you are new to working with Rust, a great place to start is the official +[Rust Book](https://doc.rust-lang.org/book/). It gives a great overview of the language and +general style. It's also worth getting familiar with the following tools: + +- [Rustup](https://rustup.rs), the Rust toolchain installer. +- [Cargo](https://doc.rust-lang.org/cargo/), the Rust build tool and package manager. +- [docs.rs](https://docs.rs), a site providing up-to-date crate (package) documentation for all + packages published to [crates.io](https://crates.io), the official package registry. +- [Rustdoc](https://doc.rust-lang.org/rustdoc/index.html), the ecosystem's official + documentation tool. + +In terms of development tooling, there are two major options in this space. + +- [Rust Analyzer](https://rust-analyzer.github.io) is the official implementation of the + [Language Server Protocol](https://microsoft.github.io/language-server-protocol/) for Rust, + and will work with any LSP compatible host. +- [RustRover](https://www.jetbrains.com/rust/) is the fully-featured JetBrains IDE for working with + Rust in single- and multi-language projects. The Rust support plugin can also run in other + JetBrains IDEs if needed. diff --git a/flake.lock b/flake.lock new file mode 100644 index 00000000..d85597f8 --- /dev/null +++ b/flake.lock @@ -0,0 +1,116 @@ +{ + "nodes": { + "crane": { + "locked": { + "lastModified": 1725125250, + "narHash": "sha256-CB20rDD5eHikF6mMTTJdwPP1qvyoiyyw1RDUzwIaIF8=", + "owner": "ipetkov", + "repo": "crane", + "rev": "96fd12c7100e9e05fa1a0a5bd108525600ce282f", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "fenix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "rust-analyzer-src": "rust-analyzer-src" + }, + "locked": { + "lastModified": 1725345102, + "narHash": "sha256-VO8GFsFlvV9OJKxXM86Y141fAIoDlbqgbZ4EqqZ5vb8=", + "owner": "nix-community", + "repo": "fenix", + "rev": "a13cbbf5407a16a60fcf82cdceb301cf87a65b41", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "fenix", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1725103162, + "narHash": "sha256-Ym04C5+qovuQDYL/rKWSR+WESseQBbNAe5DsXNx5trY=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "12228ff1752d7b7624a54e9c1af4b222b3c1073b", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "crane": "crane", + "fenix": "fenix", + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "rust-analyzer-src": { + "flake": false, + "locked": { + "lastModified": 1725296863, + "narHash": "sha256-48BG4uhr6uj4yRPOWyeb9k1btmaGTV2Q3JoOs1Db/Cc=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "304e5f58cdcdaeb6f005198e5e07f9ead0e03d34", + "type": "github" + }, + "original": { + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000..1a8bf817 --- /dev/null +++ b/flake.nix @@ -0,0 +1,85 @@ +# A flake that sets up the necessary development environment for things. +{ + description = "LLVM to CairoVM"; + + # The things that we want to pin to. + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + crane.url = "github:ipetkov/crane"; + fenix = { + url = "github:nix-community/fenix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + # The results of our flake. + outputs = { self, nixpkgs, flake-utils, crane, fenix }: + flake-utils.lib.eachDefaultSystem (system: + let + # We grab our expected rust version from the Cargo.toml. + rustVersion = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).package.rust-version; + + # Then we set up our libraries for building this thing. + pkgs = nixpkgs.legacyPackages.${system}; + fenixLib = fenix.packages.${system}; + fenixStable = fenixLib.fromToolchainName { + name = rustVersion; + sha256 = "sha256-3jVIIf5XPnUU1CRaTyAiO0XHVbJl12MSx3eucTXCjtE="; + }; + + # As we want nightly Rustfmt, we have to build a custom toolchain. + fenixToolchain = fenixLib.combine [ + fenixLib.latest.rustfmt # `fenixLib.latest` is specifically the latest nightly + (fenixStable.withComponents [ + "cargo" + "clippy" + "rust-docs" + "rust-src" + "rust-std" + "rustc" + ]) + ]; + + # The crane library configures the Rust toolchain, along with the components we expect it + # to have. + craneLib = (crane.mkLib pkgs).overrideToolchain fenixToolchain; + + # Then we build our actual package, which is our application. + llvmToCairo = pkgs.callPackage ./package.nix { + inherit craneLib; + }; + + # We get your default shell to make sure things feel familiar in the dev shell. + getUserShellCommand = if pkgs.stdenv.hostPlatform.isDarwin then + "dscl . -read ~ UserShell | cut -d ' ' -f2" + else + "getent passwd $USER | cut -d ':' -f7"; + in { + packages = { + inherit llvmToCairo; + default = llvmToCairo; + }; + + # The default dev shell puts you in your native shell to make things feel happy. + devShells.default = craneLib.devShell { + LLVM_SYS_180_PREFIX = "${pkgs.lib.getDev pkgs.llvmPackages_18.libllvm}"; + inputsFrom = [ + llvmToCairo + ]; + + shellHook = '' + exec $(${getUserShellCommand}) + ''; + }; + + # The dev shell for CI allows it to interpret commands properly. + devShells.ci = craneLib.devShell { + LLVM_SYS_180_PREFIX = "${pkgs.lib.getDev pkgs.llvmPackages_18.libllvm}"; + inputsFrom = [ + llvmToCairo + ]; + }; + } + ); +} diff --git a/package.nix b/package.nix new file mode 100644 index 00000000..ba836c4f --- /dev/null +++ b/package.nix @@ -0,0 +1,27 @@ +# This file defines the actual package. +# +# We want to be able to run commands from a nix shell using this package +# definition. +{ craneLib, lib, llvmPackages_18, libiconv, stdenv }: let + src = craneLib.cleanCargoSource ./.; +in craneLib.buildPackage { + inherit src; + + # Disallow confusing buildInputs and nativeBuildInputs for sanity. + strictDeps = true; + + # Things that are needed at build time on the system doing building. + nativeBuildInputs = [ + llvmPackages_18.llvm + ]; + + # The things that we need available at build and runtime on the target system. + buildInputs = [ + llvmPackages_18.llvm + ] ++ lib.optionals stdenv.hostPlatform.isDarwin [ + libiconv + ]; + + # We name this so we can quickly `nix-run` + meta.mainProgram = "llvm-to-cairo"; +} diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 00000000..8bd3e7d1 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,56 @@ +# This file contains the configuration for the ecosystem's formatting tool, `rustfmt`. It only contains entries where +# they differ from the default or for unstable attributes whose default may change. +# +# For more information on the configuration see here: https://github.com/rust-lang/rustfmt/blob/master/Configurations.md + +# High-level configuration, telling rustfmt which featureset to use. +edition = "2021" +version = "Two" + +# Configuration controlling general code style. +brace_style = "SameLineWhere" +chain_width = 70 +combine_control_expr = true +condense_wildcard_suffixes = true +control_brace_style = "AlwaysSameLine" +empty_item_single_line = true +enum_discrim_align_threshold = 20 +fn_single_line = false +force_multiline_blocks = false +format_strings = true +hex_literal_case = "Lower" +indent_style = "Block" +inline_attribute_width = 0 +match_arm_blocks = true +reorder_impl_items = true +single_line_let_else_max_width = 70 +space_after_colon = true +spaces_around_ranges = false +struct_field_align_threshold = 20 +struct_lit_single_line = true +struct_variant_width = 70 +trailing_comma = "Vertical" +trailing_semicolon = true +type_punctuation_density = "Wide" +use_field_init_shorthand = true +where_single_line = false + +# Configuration controlling the formatting of macros. +format_macro_bodies = true +format_macro_matchers = true + +# Configuration controlling how imports are formatted. +group_imports = "StdExternalCrate" +imports_granularity = "Crate" +imports_layout = "HorizontalVertical" + +# Configuration controlling how spacing is formatted. +blank_lines_lower_bound = 0 +blank_lines_upper_bound = 1 + +# Configuration controlling the formatting of comments. +comment_width = 80 +format_code_in_doc_comments = true +normalize_comments = true +normalize_doc_attributes = true +wrap_comments = true diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 00000000..013f2909 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,6 @@ +#![warn(clippy::all, clippy::cargo, clippy::pedantic)] +#![allow(clippy::module_name_repetitions)] // Allows for better API naming + +fn main() { + println!("Hello, world!"); +}