├── .codecov.yml ├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── bug-report.md │ └── feature-request.md ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml └── workflows │ └── test.yml ├── .gitignore ├── .rustfmt.toml ├── Cargo.toml ├── LICENSE ├── README.md ├── _typos.toml ├── build.rs ├── examples ├── jit.rs └── kaleidoscope │ ├── README.md │ ├── implementation_typed_pointers.rs │ └── main.rs ├── internal_macros ├── Cargo.toml ├── README.md └── src │ ├── cfg.rs │ ├── enum.rs │ └── lib.rs ├── src ├── attributes.rs ├── basic_block.rs ├── builder.rs ├── comdat.rs ├── context.rs ├── data_layout.rs ├── debug_info.rs ├── execution_engine.rs ├── intrinsics.rs ├── lib.rs ├── memory_buffer.rs ├── memory_manager.rs ├── module.rs ├── object_file.rs ├── passes.rs ├── support │ ├── error_handling.rs │ └── mod.rs ├── targets.rs ├── types │ ├── array_type.rs │ ├── enums.rs │ ├── float_type.rs │ ├── fn_type.rs │ ├── int_type.rs │ ├── metadata_type.rs │ ├── mod.rs │ ├── ptr_type.rs │ ├── scalable_vec_type.rs │ ├── struct_type.rs │ ├── traits.rs │ ├── vec_type.rs │ └── void_type.rs └── values │ ├── array_value.rs │ ├── basic_value_use.rs │ ├── call_site_value.rs │ ├── callable_value.rs │ ├── enums.rs │ ├── float_value.rs │ ├── fn_value.rs │ ├── generic_value.rs │ ├── global_value.rs │ ├── instruction_value.rs │ ├── int_value.rs │ ├── metadata_value.rs │ ├── mod.rs │ ├── operand_bundle.rs │ ├── phi_value.rs │ ├── ptr_value.rs │ ├── scalable_vec_value.rs │ ├── struct_value.rs │ ├── traits.rs │ └── vec_value.rs └── tests └── all ├── main.rs ├── test_attributes.rs ├── test_basic_block.rs ├── test_builder.rs ├── test_context.rs ├── test_debug_info.rs ├── test_execution_engine.rs ├── test_instruction_conversion.rs ├── test_instruction_values.rs ├── test_intrinsics.rs ├── test_module.rs ├── test_object_file.rs ├── test_passes.rs ├── test_targets.rs ├── test_tari_example.rs ├── test_types.rs └── test_values.rs /.codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "internal_macros" 3 | - "tests" 4 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Inkwell Code of Conduct 2 | 3 | *Note: This is not a legal document.* 4 | 5 | The Inkwell team is committed to the following rules: 6 | 7 | * Treat everyone fairly. 8 | * Be kind and respectful to others. 9 | * Judge technical problems and solutions, not people. 10 | * Use polite language. 11 | * In case of disagreement use arbitrage of position of authority and responsibility (eg. project owner). 12 | 13 | We expect others to follow these rules as well. 14 | 15 | This COC is based on [dpc's](https://github.com/dpc/public/blob/master/COC.md). 16 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Inkwell 2 | 3 | Hello there! Thank you for taking interest in Inkwell! 4 | 5 | ## Found a Bug? 6 | 7 | * Please ensure the bug was not already reported by searching our [issue tracker](https://github.com/TheDan64/inkwell/issues). 8 | * If you're unable to find an open issue relating to the problem, please file an [issue](https://github.com/TheDan64/inkwell/issues/new). 9 | 10 | 11 | 12 | ## Want to Submit a Pull Request? 13 | 14 | * Please ensure your PR follows these guidelines: 15 | 16 | ### Required 17 | 18 | * My code follows the code style of this project 19 | * I have added documentation and doc tests to any new functions or types 20 | * I have updated documentation and doc tests to any modified functions or types as applicable 21 | * I have added tests to cover my changes 22 | * All new and existing tests passed 23 | * I am basing my changes off master, instead of one of the llvm version branches (they're deprecated and no longer necessary) 24 | 25 | ### Desired 26 | 27 | * I have ran `cargo clippy` and updated portions of code pertaining to my changes 28 | * I will keep my code reasonably up to date via rebasing over merging whenever possible (This helps avoid unnecessary merge commits) 29 | 30 | ## Got Questions? 31 | 32 | Please attempt to ask your question at our [Gitter Chat Room](https://gitter.im/inkwell-rs/Lobby). If no one gets back to you in a day or so, feel free to open up an issue. 33 | 34 | Thanks!! 35 | 36 | Inkwell Team 37 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the Bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Please provide a simple sample of code which reproduces the issue on your machine. 12 | 13 | **Expected Behavior** 14 | A clear and concise description of what you expected to happen. 15 | 16 | **LLVM Version (please complete the following information):** 17 | - LLVM Version: [e.g. 6.0] 18 | - Inkwell Branch Used: [e.g. llvm6-0] 19 | 20 | **Desktop (please complete the following information):** 21 | - OS: [e.g. Ubuntu 16.04, Windows 10] 22 | 23 | **Additional Context** 24 | Add any other context about the problem here. 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe possible drawbacks to your solution** 14 | How might this solution hinder other components or users if implemented? 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ## Description 5 | 6 | 7 | 8 | ## Related Issue 9 | 10 | 11 | 12 | 13 | 14 | 15 | ## How This Has Been Tested 16 | 17 | 18 | 19 | 20 | 21 | ## Option\ 22 | 23 | 24 | 25 | 26 | ## Checklist 27 | 28 | 29 | 30 | 31 | - [ ] I have read the [Contributing Guide](https://github.com/TheDan64/inkwell/blob/master/.github/CONTRIBUTING.md) 32 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "10:00" 8 | open-pull-requests-limit: 10 9 | ignore: 10 | - dependency-name: llvm-sys 11 | versions: 12 | - "> 60" 13 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test Suite and Doc 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | CARGO_TERM_COLOR: always 7 | DOC_LLVM_FEATURE: llvm18-1 8 | DOC_LLVM_VERSION: "18.1" 9 | DOC_PATH: target/doc 10 | 11 | jobs: 12 | lint: 13 | name: Linting 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout Repo 17 | uses: actions/checkout@v4 18 | - name: Install Rust Stable 19 | uses: dtolnay/rust-toolchain@stable 20 | - name: Install typos 21 | uses: taiki-e/install-action@typos 22 | - name: Check typos 23 | run: typos . 24 | - name: Check code formatting 25 | run: cargo fmt --check 26 | tests: 27 | name: "LLVM ${{ matrix.llvm-version[0] }}: ${{ matrix.os }}" 28 | runs-on: ${{ matrix.os }} 29 | strategy: 30 | matrix: 31 | llvm-version: 32 | - ["8.0", "8-0"] 33 | - ["9.0", "9-0"] 34 | - ["10.0", "10-0"] 35 | - ["11.0", "11-0"] 36 | - ["12.0", "12-0"] 37 | - ["13.0", "13-0"] 38 | - ["14.0", "14-0"] 39 | - ["15.0", "15-0"] 40 | - ["16.0", "16-0"] 41 | - ["17.0", "17-0"] 42 | - ["18.1", "18-1"] 43 | include: 44 | - os: ubuntu-22.04 45 | steps: 46 | - name: Checkout Repo 47 | uses: actions/checkout@v4 48 | - name: Install Dependencies 49 | run: sudo apt update && sudo apt install -y libtinfo5 50 | - name: Install LLVM and Clang (LLVM >= 7.1) 51 | uses: KyleMayes/install-llvm-action@v2 52 | with: 53 | version: ${{ matrix.llvm-version[0] }} 54 | - name: llvm-config 55 | run: llvm-config --version --bindir --libdir 56 | - name: Install Rust Stable 57 | uses: dtolnay/rust-toolchain@stable 58 | - name: cargo clippy 59 | run: cargo clippy --tests --features llvm${{ matrix.llvm-version[1] }} -- -D warnings 60 | - name: Build 61 | run: cargo build --release --features llvm${{ matrix.llvm-version[1] }} --verbose 62 | - name: Run tests 63 | run: cargo test --release --features llvm${{ matrix.llvm-version[1] }} --verbose 64 | - name: Build example 65 | run: cargo build --example kaleidoscope --features llvm${{ matrix.llvm-version[1] }} --verbose 66 | doc: 67 | name: Documentation 68 | runs-on: ubuntu-22.04 69 | needs: [lint, tests] 70 | if: github.event_name == 'push' && github.ref == 'refs/heads/master' 71 | steps: 72 | - uses: actions/checkout@v4 73 | - uses: KyleMayes/install-llvm-action@v2 74 | with: 75 | version: ${{ env.DOC_LLVM_VERSION }} 76 | - name: Install Rust Nightly 77 | uses: dtolnay/rust-toolchain@nightly 78 | - name: Build Documentation 79 | run: cargo +nightly doc --features ${{ env.DOC_LLVM_FEATURE }},nightly --verbose 80 | - name: Doc Index Page Redirection 81 | run: echo '' > ${{ env.DOC_PATH }}/index.html 82 | - name: Deploy Documentation 83 | uses: peaceiris/actions-gh-pages@v3 84 | with: 85 | github_token: ${{ secrets.GITHUB_TOKEN }} 86 | publish_dir: ${{ env.DOC_PATH }} 87 | force_orphan: true 88 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | internal_macros/target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock 8 | Cargo.lock 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | # IDE project data 14 | /.idea/ 15 | /.vscode/ 16 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | # comment_width = 100 2 | # format_code_in_doc_comments = true 3 | # imports_granularity = "Module" 4 | # match_arm_blocks = false 5 | match_block_trailing_comma = true 6 | max_width = 120 7 | merge_derives = true 8 | newline_style = "Unix" 9 | use_field_init_shorthand = true 10 | use_try_shorthand = true 11 | # wrap_comments = true 12 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "inkwell" 3 | version = "0.6.0" 4 | authors = ["Daniel Kolsoi "] 5 | description = "Inkwell aims to help you pen your own programming languages by safely wrapping llvm-sys." 6 | documentation = "https://thedan64.github.io/inkwell/" 7 | repository = "https://github.com/TheDan64/inkwell" 8 | readme = "README.md" 9 | keywords = ["llvm", "safe", "wrapper"] 10 | license = "Apache-2.0" 11 | categories = ["development-tools::ffi"] 12 | edition = "2021" 13 | 14 | [features] 15 | default = ["target-all"] 16 | typed-pointers = [] 17 | 18 | # Please update internal_macros::FEATURE_VERSIONS when adding a new LLVM version 19 | llvm8-0 = ["llvm-sys-80", "typed-pointers"] 20 | llvm9-0 = ["llvm-sys-90", "typed-pointers"] 21 | llvm10-0 = ["llvm-sys-100", "typed-pointers"] 22 | llvm11-0 = ["llvm-sys-110", "typed-pointers"] 23 | llvm12-0 = ["llvm-sys-120", "typed-pointers"] 24 | llvm13-0 = ["llvm-sys-130", "typed-pointers"] 25 | llvm14-0 = ["llvm-sys-140", "typed-pointers"] 26 | llvm15-0 = ["llvm-sys-150"] 27 | llvm16-0 = ["llvm-sys-160"] 28 | llvm17-0 = ["llvm-sys-170"] 29 | llvm18-1 = ["llvm-sys-181"] 30 | 31 | # Don't link against LLVM libraries. This is useful if another dependency is 32 | # installing LLVM. See llvm-sys for more details. We can't enable a single 33 | # `no-llvm-linking` feature across the board of llvm versions, as it'll cause 34 | # cargo to try and download and compile them all. See 35 | # https://github.com/rust-lang/cargo/issues/3494 36 | llvm8-0-no-llvm-linking = ["llvm8-0", "llvm-sys-80/no-llvm-linking"] 37 | llvm9-0-no-llvm-linking = ["llvm9-0", "llvm-sys-90/no-llvm-linking"] 38 | llvm10-0-no-llvm-linking = ["llvm10-0", "llvm-sys-100/no-llvm-linking"] 39 | llvm11-0-no-llvm-linking = ["llvm11-0", "llvm-sys-110/no-llvm-linking"] 40 | llvm12-0-no-llvm-linking = ["llvm12-0", "llvm-sys-120/no-llvm-linking"] 41 | llvm13-0-no-llvm-linking = ["llvm13-0", "llvm-sys-130/no-llvm-linking"] 42 | llvm14-0-no-llvm-linking = ["llvm14-0", "llvm-sys-140/no-llvm-linking"] 43 | llvm15-0-no-llvm-linking = ["llvm15-0", "llvm-sys-150/no-llvm-linking"] 44 | llvm16-0-no-llvm-linking = ["llvm16-0", "llvm-sys-160/no-llvm-linking"] 45 | llvm17-0-no-llvm-linking = ["llvm17-0", "llvm-sys-170/no-llvm-linking"] 46 | llvm18-1-no-llvm-linking = ["llvm18-1", "llvm-sys-181/no-llvm-linking"] 47 | 48 | # Linking preference. 49 | # If none of these are enabled, it defaults to force static linking. 50 | # 51 | # Force dynamic linking against LLVM libraries. See llvm-sys for more details 52 | llvm12-0-force-dynamic = ["llvm12-0", "llvm-sys-120/force-dynamic"] 53 | llvm13-0-force-dynamic = ["llvm13-0", "llvm-sys-130/force-dynamic"] 54 | llvm14-0-force-dynamic = ["llvm14-0", "llvm-sys-140/force-dynamic"] 55 | llvm15-0-force-dynamic = ["llvm15-0", "llvm-sys-150/force-dynamic"] 56 | llvm16-0-force-dynamic = ["llvm16-0", "llvm-sys-160/force-dynamic"] 57 | llvm17-0-force-dynamic = ["llvm17-0", "llvm-sys-170/force-dynamic"] 58 | llvm18-1-force-dynamic = ["llvm18-1", "llvm-sys-181/force-dynamic"] 59 | 60 | # Prefer dynamic linking against LLVM libraries. See llvm-sys for more details 61 | llvm12-0-prefer-dynamic = ["llvm12-0", "llvm-sys-120/prefer-dynamic"] 62 | llvm13-0-prefer-dynamic = ["llvm13-0", "llvm-sys-130/prefer-dynamic"] 63 | llvm14-0-prefer-dynamic = ["llvm14-0", "llvm-sys-140/prefer-dynamic"] 64 | llvm15-0-prefer-dynamic = ["llvm15-0", "llvm-sys-150/prefer-dynamic"] 65 | llvm16-0-prefer-dynamic = ["llvm16-0", "llvm-sys-160/prefer-dynamic"] 66 | llvm17-0-prefer-dynamic = ["llvm17-0", "llvm-sys-170/prefer-dynamic"] 67 | llvm18-1-prefer-dynamic = ["llvm18-1", "llvm-sys-181/prefer-dynamic"] 68 | 69 | # Force static linking against LLVM libraries. See llvm-sys for more details 70 | llvm12-0-force-static = ["llvm12-0", "llvm-sys-120/force-static"] 71 | llvm13-0-force-static = ["llvm13-0", "llvm-sys-130/force-static"] 72 | llvm14-0-force-static = ["llvm14-0", "llvm-sys-140/force-static"] 73 | llvm15-0-force-static = ["llvm15-0", "llvm-sys-150/force-static"] 74 | llvm16-0-force-static = ["llvm16-0", "llvm-sys-160/force-static"] 75 | llvm17-0-force-static = ["llvm17-0", "llvm-sys-170/force-static"] 76 | llvm18-1-force-static = ["llvm18-1", "llvm-sys-181/force-static"] 77 | 78 | # Prefer static linking against LLVM libraries. See llvm-sys for more details 79 | llvm12-0-prefer-static = ["llvm12-0", "llvm-sys-120/prefer-static"] 80 | llvm13-0-prefer-static = ["llvm13-0", "llvm-sys-130/prefer-static"] 81 | llvm14-0-prefer-static = ["llvm14-0", "llvm-sys-140/prefer-static"] 82 | llvm15-0-prefer-static = ["llvm15-0", "llvm-sys-150/prefer-static"] 83 | llvm16-0-prefer-static = ["llvm16-0", "llvm-sys-160/prefer-static"] 84 | llvm17-0-prefer-static = ["llvm17-0", "llvm-sys-170/prefer-static"] 85 | llvm18-1-prefer-static = ["llvm18-1", "llvm-sys-181/prefer-static"] 86 | 87 | # Don't force linking to libffi on non-windows platforms. Without this feature 88 | # inkwell always links to libffi on non-windows platforms. 89 | no-libffi-linking = [] 90 | target-x86 = [] 91 | target-arm = [] 92 | target-mips = [] 93 | target-aarch64 = [] 94 | target-amdgpu = [] 95 | target-systemz = [] 96 | target-hexagon = [] 97 | target-nvptx = [] 98 | target-msp430 = [] 99 | target-xcore = [] 100 | target-powerpc = [] 101 | target-sparc = [] 102 | target-bpf = [] 103 | target-lanai = [] 104 | target-webassembly = [] 105 | target-riscv = [] 106 | target-loongarch = [] 107 | target-syncvm = [] 108 | target-all = [ 109 | "target-x86", 110 | "target-arm", 111 | "target-mips", 112 | "target-aarch64", 113 | "target-amdgpu", 114 | "target-systemz", 115 | "target-hexagon", 116 | "target-nvptx", 117 | "target-msp430", 118 | "target-xcore", 119 | "target-powerpc", 120 | "target-sparc", 121 | "target-bpf", 122 | "target-lanai", 123 | "target-webassembly", 124 | "target-riscv", 125 | "target-loongarch", 126 | ] 127 | experimental = ["static-alloc"] 128 | nightly = ["inkwell_internals/nightly"] 129 | 130 | [dependencies] 131 | inkwell_internals = { path = "./internal_macros", version = "0.11.0" } 132 | 133 | llvm-sys-80 = { package = "llvm-sys", version = "80.3", optional = true } 134 | llvm-sys-90 = { package = "llvm-sys", version = "90.2.2", optional = true } 135 | llvm-sys-100 = { package = "llvm-sys", version = "100.2.4", optional = true } 136 | llvm-sys-110 = { package = "llvm-sys", version = "110.0.4", optional = true } 137 | llvm-sys-120 = { package = "llvm-sys", version = "120.3.2", optional = true } 138 | llvm-sys-130 = { package = "llvm-sys", version = "130.1.2", optional = true } 139 | llvm-sys-140 = { package = "llvm-sys", version = "140.1.3", optional = true } 140 | llvm-sys-150 = { package = "llvm-sys", version = "150.2.1", optional = true } 141 | llvm-sys-160 = { package = "llvm-sys", version = "160.2.1", optional = true } 142 | llvm-sys-170 = { package = "llvm-sys", version = "170.2.0", optional = true } 143 | llvm-sys-181 = { package = "llvm-sys", version = "181.2.0", optional = true } 144 | 145 | either = "1.5" 146 | libc = "0.2" 147 | once_cell = "1.16" 148 | thiserror = "2.0.11" 149 | 150 | static-alloc = { version = "0.2", optional = true } 151 | serde = { version = "1.0", default-features = false, features = [ 152 | "derive", 153 | ], optional = true } 154 | 155 | [dev-dependencies] 156 | regex = "1" 157 | 158 | [badges] 159 | codecov = { repository = "TheDan64/inkwell" } 160 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Inkwell(s) 2 | 3 | [![Crates.io](https://img.shields.io/crates/v/inkwell.svg?style=plastic)](https://crates.io/crates/inkwell) 4 | [![Build Status](https://github.com/TheDan64/inkwell/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/TheDan64/inkwell/actions/workflows/test.yml?query=branch%3Amaster) 5 | [![codecov](https://codecov.io/gh/TheDan64/inkwell/branch/master/graph/badge.svg)](https://codecov.io/gh/TheDan64/inkwell) 6 | [![lines of code](https://tokei.rs/b1/github/TheDan64/inkwell)](https://github.com/Aaronepower/tokei) 7 | [![Join the chat at https://gitter.im/inkwell-rs/Lobby](https://badges.gitter.im/inkwell-rs/Lobby.svg)](https://gitter.im/inkwell-rs/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 8 | ![Minimum rustc 1.56](https://img.shields.io/badge/rustc-1.56+-brightgreen.svg) 9 | 10 | **I**t's a **N**ew **K**ind of **W**rapper for **E**xposing **LL**VM (*S*afely) 11 | 12 | Inkwell aims to help you pen your own programming languages by safely wrapping llvm-sys. It provides a more strongly typed interface than the underlying LLVM C API so that certain types of errors can be caught at compile time instead of at LLVM's runtime. This means we are trying to replicate LLVM IR's strong typing as closely as possible. The ultimate goal is to make LLVM safer from the rust end and a bit easier to learn (via documentation) and use. 13 | 14 | ## Requirements 15 | 16 | * Rust 1.56+ (Stable, Beta, or Nightly) 17 | * One of LLVM 8-18 18 | 19 | ## Usage 20 | 21 | You'll need to point your Cargo.toml to use a single LLVM version feature flag corresponding to your LLVM version as such: 22 | 23 | ```toml 24 | [dependencies] 25 | inkwell = { version = "0.6.0", features = ["llvm18-1"] } 26 | ``` 27 | 28 | Supported versions: 29 | LLVM 4-18 mapping to a cargo feature flag `llvmM-0` where `M` corresponds to the LLVM major version. 30 | 31 | Please be aware that we may make breaking changes on master from time to time since we are 32 | pre-v1.0.0, in compliance with semver. Please prefer a crates.io release whenever possible! 33 | 34 | ## Documentation 35 | 36 | Documentation is automatically [deployed here](https://thedan64.github.io/inkwell/) based on master. These docs are not yet 100% complete and only show the latest supported LLVM version due to a rustdoc issue. See [#2](https://github.com/TheDan64/inkwell/issues/2) for more info. 37 | 38 | ## Examples 39 | 40 | ### Tari's [llvm-sys example](https://gitlab.com/taricorp/llvm-sys.rs/blob/6411edb2fed1a805b7ec5029afc9c3ae1cf6c842/examples/jit-function.rs) written in safe code1 with Inkwell: 41 | 42 | ```rust 43 | use inkwell::builder::Builder; 44 | use inkwell::context::Context; 45 | use inkwell::execution_engine::{ExecutionEngine, JitFunction}; 46 | use inkwell::module::Module; 47 | use inkwell::OptimizationLevel; 48 | 49 | use std::error::Error; 50 | 51 | /// Convenience type alias for the `sum` function. 52 | /// 53 | /// Calling this is innately `unsafe` because there's no guarantee it doesn't 54 | /// do `unsafe` operations internally. 55 | type SumFunc = unsafe extern "C" fn(u64, u64, u64) -> u64; 56 | 57 | struct CodeGen<'ctx> { 58 | context: &'ctx Context, 59 | module: Module<'ctx>, 60 | builder: Builder<'ctx>, 61 | execution_engine: ExecutionEngine<'ctx>, 62 | } 63 | 64 | impl<'ctx> CodeGen<'ctx> { 65 | fn jit_compile_sum(&self) -> Option> { 66 | let i64_type = self.context.i64_type(); 67 | let fn_type = i64_type.fn_type(&[i64_type.into(), i64_type.into(), i64_type.into()], false); 68 | let function = self.module.add_function("sum", fn_type, None); 69 | let basic_block = self.context.append_basic_block(function, "entry"); 70 | 71 | self.builder.position_at_end(basic_block); 72 | 73 | let x = function.get_nth_param(0)?.into_int_value(); 74 | let y = function.get_nth_param(1)?.into_int_value(); 75 | let z = function.get_nth_param(2)?.into_int_value(); 76 | 77 | let sum = self.builder.build_int_add(x, y, "sum").unwrap(); 78 | let sum = self.builder.build_int_add(sum, z, "sum").unwrap(); 79 | 80 | self.builder.build_return(Some(&sum)).unwrap(); 81 | 82 | unsafe { self.execution_engine.get_function("sum").ok() } 83 | } 84 | } 85 | 86 | fn main() -> Result<(), Box> { 87 | let context = Context::create(); 88 | let module = context.create_module("sum"); 89 | let execution_engine = module.create_jit_execution_engine(OptimizationLevel::None)?; 90 | let codegen = CodeGen { 91 | context: &context, 92 | module, 93 | builder: context.create_builder(), 94 | execution_engine, 95 | }; 96 | 97 | let sum = codegen.jit_compile_sum().ok_or("Unable to JIT compile `sum`")?; 98 | 99 | let x = 1u64; 100 | let y = 2u64; 101 | let z = 3u64; 102 | 103 | unsafe { 104 | println!("{} + {} + {} = {}", x, y, z, sum.call(x, y, z)); 105 | assert_eq!(sum.call(x, y, z), x + y + z); 106 | } 107 | 108 | Ok(()) 109 | } 110 | ``` 111 | 112 | 1 There are two uses of `unsafe` in this example because the actual 113 | act of compiling and executing code on the fly is innately `unsafe`. For one, 114 | there is no way of verifying we are calling `get_function()` with the right function 115 | signature. It is also `unsafe` to *call* the function we get because there's no 116 | guarantee the code itself doesn't do `unsafe` things internally (the same reason 117 | you need `unsafe` when calling into C). 118 | 119 | ### LLVM's [Kaleidoscope Tutorial](https://llvm.org/docs/tutorial/index.html) 120 | 121 | Can be found in the examples directory. 122 | 123 | ## Alternative Crate(s) 124 | 125 | * [llvm-ir](https://github.com/cdisselkoen/llvm-ir) 126 | 127 | ## Contributing 128 | 129 | Check out our [Contributing Guide](.github/CONTRIBUTING.md) 130 | -------------------------------------------------------------------------------- /_typos.toml: -------------------------------------------------------------------------------- 1 | [default] 2 | extend-ignore-identifiers-re = [ 3 | "OLT", 4 | "toi", 5 | "isplay", 6 | "BVE", 7 | "olt", 8 | "TRE", 9 | ] -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | if cfg!(all(not(target_os = "windows"), not(feature = "no-libffi-linking"))) { 3 | println!("cargo:rustc-link-lib=dylib=ffi"); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /examples/jit.rs: -------------------------------------------------------------------------------- 1 | use inkwell::builder::Builder; 2 | use inkwell::context::Context; 3 | use inkwell::execution_engine::{ExecutionEngine, JitFunction}; 4 | use inkwell::module::Module; 5 | use inkwell::OptimizationLevel; 6 | 7 | use std::error::Error; 8 | 9 | /// Convenience type alias for the `sum` function. 10 | /// 11 | /// Calling this is innately `unsafe` because there's no guarantee it doesn't 12 | /// do `unsafe` operations internally. 13 | type SumFunc = unsafe extern "C" fn(u64, u64, u64) -> u64; 14 | 15 | struct CodeGen<'ctx> { 16 | context: &'ctx Context, 17 | module: Module<'ctx>, 18 | builder: Builder<'ctx>, 19 | execution_engine: ExecutionEngine<'ctx>, 20 | } 21 | 22 | impl<'ctx> CodeGen<'ctx> { 23 | fn jit_compile_sum(&self) -> Option> { 24 | let i64_type = self.context.i64_type(); 25 | let fn_type = i64_type.fn_type(&[i64_type.into(), i64_type.into(), i64_type.into()], false); 26 | let function = self.module.add_function("sum", fn_type, None); 27 | let basic_block = self.context.append_basic_block(function, "entry"); 28 | 29 | self.builder.position_at_end(basic_block); 30 | 31 | let x = function.get_nth_param(0)?.into_int_value(); 32 | let y = function.get_nth_param(1)?.into_int_value(); 33 | let z = function.get_nth_param(2)?.into_int_value(); 34 | 35 | let sum = self.builder.build_int_add(x, y, "sum").unwrap(); 36 | let sum = self.builder.build_int_add(sum, z, "sum").unwrap(); 37 | 38 | self.builder.build_return(Some(&sum)).unwrap(); 39 | 40 | unsafe { self.execution_engine.get_function("sum").ok() } 41 | } 42 | } 43 | 44 | fn main() -> Result<(), Box> { 45 | let context = Context::create(); 46 | let module = context.create_module("sum"); 47 | let execution_engine = module.create_jit_execution_engine(OptimizationLevel::None)?; 48 | let codegen = CodeGen { 49 | context: &context, 50 | module, 51 | builder: context.create_builder(), 52 | execution_engine, 53 | }; 54 | 55 | let sum = codegen.jit_compile_sum().ok_or("Unable to JIT compile `sum`")?; 56 | 57 | let x = 1u64; 58 | let y = 2u64; 59 | let z = 3u64; 60 | 61 | unsafe { 62 | println!("{} + {} + {} = {}", x, y, z, sum.call(x, y, z)); 63 | assert_eq!(sum.call(x, y, z), x + y + z); 64 | } 65 | 66 | Ok(()) 67 | } 68 | -------------------------------------------------------------------------------- /examples/kaleidoscope/README.md: -------------------------------------------------------------------------------- 1 | # Kaleidoscope 2 | 3 | This example shows how one can implement the [Kaleidoscope programming language](https://llvm.org/docs/tutorial/index.html) using Inkwell. 4 | It implements every feature up to the [7th chapter](https://llvm.org/docs/tutorial/MyFirstLanguageFrontend/LangImpl07.html). 5 | 6 | The [usage](../../README.md#usage) part doesn't fit the example as it shares the same `Cargo.toml` file with the whole project. 7 | 8 | To run the example, the LLVM version is required: 9 | 10 | ```sh 11 | cargo run --example kaleidoscope --features llvm$(llvm-config --version | sed 's/\./-/;s/\.[0-9]*//') 12 | ``` 13 | 14 | When running this command, a prompt will be displayed; for example: 15 | 16 | ``` 17 | ?> 1 + 1 18 | => 2 19 | 20 | ?> var a = 5, b = 10 in a * b 21 | => 50 22 | 23 | ?> def fib(n) if n < 2 then n else fib(n - 1) + fib(n - 2) 24 | 25 | ?> fib(40) 26 | => 102334155 27 | 28 | ?> 29 | ``` 30 | 31 | Additional arguments can be passed to the produced executable: 32 | 33 | - `--dc`: **D**isplay **C**ompiler output 34 | - `--dp`: **D**isplay **P**arser output 35 | - `--dl`: **D**isplay **L**exer output 36 | 37 | For example, running with all three switches may lead to the following output: 38 | 39 | ``` 40 | ?> 1 + 2 * 2 41 | -> Attempting to parse lexed input: 42 | [Number(1), Op('+'), Number(2), Op('*'), Number(2)] 43 | 44 | -> Expression parsed: 45 | Binary { op: '+', left: Number(1), right: Binary { op: '*', left: Number(2), right: Number(2) } } 46 | 47 | -> Expression compiled to IR: 48 | define double @anonymous() { 49 | entry: 50 | ret double 5.000000e+00 51 | } 52 | 53 | => 5 54 | ``` 55 | 56 | Finally, the prompt can be exited by entering "exit" or "quit". 57 | -------------------------------------------------------------------------------- /examples/kaleidoscope/main.rs: -------------------------------------------------------------------------------- 1 | //! This is an example of the [Kaleidoscope tutorial](https://llvm.org/docs/tutorial/) 2 | //! made in Rust, using Inkwell. 3 | //! Currently, all features up to the 4 | //! [7th chapter](https://llvm.org/docs/tutorial/MyFirstLanguageFrontend/LangImpl07.html) 5 | //! are available. 6 | //! This example is supposed to be ran as a executable, which launches a REPL. 7 | //! The source code is in the following order: 8 | //! - `implementation_typed_pointers.rs`: 9 | //! Lexer, 10 | //! Parser, 11 | //! Compiler. 12 | //! - `main.rs`: 13 | //! Program. 14 | //! 15 | //! Both the `Parser` and the `Compiler` may fail, in which case they would return 16 | //! an error represented by `Result`, for easier error reporting. 17 | 18 | use std::collections::HashMap; 19 | use std::io::{self, Write}; 20 | 21 | use inkwell::context::Context; 22 | use inkwell::module::Module; 23 | #[llvm_versions(..=15)] 24 | use inkwell::passes::PassManager; 25 | use inkwell::OptimizationLevel; 26 | #[llvm_versions(16..)] 27 | use inkwell::{ 28 | passes::PassBuilderOptions, 29 | targets::{CodeModel, InitializationConfig, RelocMode, Target, TargetMachine}, 30 | }; 31 | 32 | use inkwell_internals::llvm_versions; 33 | 34 | mod implementation_typed_pointers; 35 | pub use implementation_typed_pointers::*; 36 | 37 | // ====================================================================================== 38 | // PROGRAM ============================================================================== 39 | // ====================================================================================== 40 | 41 | // macro used to print & flush without printing a new line 42 | macro_rules! print_flush { 43 | ( $( $x:expr ),* ) => { 44 | print!( $($x, )* ); 45 | 46 | std::io::stdout().flush().expect("Could not flush to standard output."); 47 | }; 48 | } 49 | 50 | #[no_mangle] 51 | pub extern "C" fn putchard(x: f64) -> f64 { 52 | print_flush!("{}", x as u8 as char); 53 | x 54 | } 55 | 56 | #[no_mangle] 57 | pub extern "C" fn printd(x: f64) -> f64 { 58 | println!("{}", x); 59 | x 60 | } 61 | 62 | // Adding the functions above to a global array, 63 | // so Rust compiler won't remove them. 64 | #[used] 65 | static EXTERNAL_FNS: [extern "C" fn(f64) -> f64; 2] = [putchard, printd]; 66 | 67 | #[llvm_versions(..=15)] 68 | fn run_passes_on(module: &Module) { 69 | let fpm = PassManager::create(()); 70 | 71 | fpm.add_instruction_combining_pass(); 72 | fpm.add_reassociate_pass(); 73 | fpm.add_gvn_pass(); 74 | fpm.add_cfg_simplification_pass(); 75 | fpm.add_basic_alias_analysis_pass(); 76 | fpm.add_promote_memory_to_register_pass(); 77 | 78 | fpm.run_on(module); 79 | } 80 | 81 | #[llvm_versions(16..)] 82 | fn run_passes_on(module: &Module) { 83 | Target::initialize_all(&InitializationConfig::default()); 84 | let target_triple = TargetMachine::get_default_triple(); 85 | let target = Target::from_triple(&target_triple).unwrap(); 86 | let target_machine = target 87 | .create_target_machine( 88 | &target_triple, 89 | "generic", 90 | "", 91 | OptimizationLevel::None, 92 | RelocMode::PIC, 93 | CodeModel::Default, 94 | ) 95 | .unwrap(); 96 | 97 | let passes: &[&str] = &[ 98 | "instcombine", 99 | "reassociate", 100 | "gvn", 101 | "simplifycfg", 102 | // "basic-aa", 103 | "mem2reg", 104 | ]; 105 | 106 | module 107 | .run_passes(passes.join(",").as_str(), &target_machine, PassBuilderOptions::create()) 108 | .unwrap(); 109 | } 110 | 111 | /// Entry point of the program; acts as a REPL. 112 | pub fn main() { 113 | let mut display_lexer_output = false; 114 | let mut display_parser_output = false; 115 | let mut display_compiler_output = false; 116 | 117 | for arg in std::env::args() { 118 | match arg.as_str() { 119 | "--dl" => display_lexer_output = true, 120 | "--dp" => display_parser_output = true, 121 | "--dc" => display_compiler_output = true, 122 | _ => (), 123 | } 124 | } 125 | 126 | let context = Context::create(); 127 | let builder = context.create_builder(); 128 | 129 | let mut previous_exprs = Vec::new(); 130 | 131 | loop { 132 | println!(); 133 | print_flush!("?> "); 134 | 135 | // Read input from stdin 136 | let mut input = String::new(); 137 | io::stdin() 138 | .read_line(&mut input) 139 | .expect("Could not read from standard input."); 140 | 141 | if input.starts_with("exit") || input.starts_with("quit") { 142 | break; 143 | } else if input.chars().all(char::is_whitespace) { 144 | continue; 145 | } 146 | 147 | // Build precedence map 148 | let mut prec = HashMap::with_capacity(6); 149 | 150 | prec.insert('=', 2); 151 | prec.insert('<', 10); 152 | prec.insert('+', 20); 153 | prec.insert('-', 20); 154 | prec.insert('*', 40); 155 | prec.insert('/', 40); 156 | 157 | // Parse and (optionally) display input 158 | if display_lexer_output { 159 | println!( 160 | "-> Attempting to parse lexed input: \n{:?}\n", 161 | Lexer::new(input.as_str()).collect::>() 162 | ); 163 | } 164 | 165 | // make module 166 | let module = context.create_module("tmp"); 167 | 168 | // recompile every previously parsed function into the new module 169 | for prev in &previous_exprs { 170 | Compiler::compile(&context, &builder, &module, prev).expect("Cannot re-add previously compiled function."); 171 | } 172 | 173 | let (function, is_anonymous) = match Parser::new(input, &mut prec).parse() { 174 | Ok(fun) => { 175 | let is_anon = fun.is_anon; 176 | 177 | if display_parser_output { 178 | if is_anon { 179 | println!("-> Expression parsed: \n{:?}\n", fun.body); 180 | } else { 181 | println!("-> Function parsed: \n{:?}\n", fun); 182 | } 183 | } 184 | 185 | match Compiler::compile(&context, &builder, &module, &fun) { 186 | Ok(function) => { 187 | if !is_anon { 188 | // only add it now to ensure it is correct 189 | previous_exprs.push(fun); 190 | } 191 | 192 | (function, is_anon) 193 | }, 194 | Err(err) => { 195 | println!("!> Error compiling function: {}", err); 196 | continue; 197 | }, 198 | } 199 | }, 200 | Err(err) => { 201 | println!("!> Error parsing expression: {}", err); 202 | continue; 203 | }, 204 | }; 205 | 206 | run_passes_on(&module); 207 | 208 | if display_compiler_output { 209 | println!("-> Expression compiled to IR:"); 210 | function.print_to_stderr(); 211 | } 212 | 213 | if is_anonymous { 214 | let ee = module.create_jit_execution_engine(OptimizationLevel::None).unwrap(); 215 | 216 | let fn_name = function.get_name().to_str().unwrap(); 217 | let maybe_fn = unsafe { ee.get_function:: f64>(fn_name) }; 218 | let compiled_fn = match maybe_fn { 219 | Ok(f) => f, 220 | Err(err) => { 221 | println!("!> Error during execution: {:?}", err); 222 | continue; 223 | }, 224 | }; 225 | 226 | unsafe { 227 | println!("=> {}", compiled_fn.call()); 228 | } 229 | } 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /internal_macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Daniel Kolsoi "] 3 | description = "Internal macro crate for inkwell" 4 | edition = "2024" 5 | license = "Apache-2.0" 6 | name = "inkwell_internals" 7 | readme = "README.md" 8 | repository = "https://github.com/TheDan64/inkwell" 9 | version = "0.11.0" 10 | 11 | [dependencies] 12 | proc-macro2 = "1.0" 13 | quote = "1.0" 14 | syn = { version = "2.0", features = ["full", "fold"] } 15 | 16 | [lib] 17 | proc-macro = true 18 | 19 | [features] 20 | nightly = [] 21 | -------------------------------------------------------------------------------- /internal_macros/README.md: -------------------------------------------------------------------------------- 1 | # Inkwell-Internals 2 | 3 | This crate is used to generate proc macro(s) in [inkwell](https://github.com/TheDan64/inkwell) and should not be a direct dependency. 4 | -------------------------------------------------------------------------------- /internal_macros/src/enum.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::{Span, TokenStream}; 2 | use quote::quote; 3 | use syn::fold::Fold; 4 | use syn::parse::{Error, Parse, ParseStream, Result}; 5 | use syn::parse_quote; 6 | use syn::spanned::Spanned; 7 | use syn::{Arm, PatPath, Path}; 8 | use syn::{Attribute, Ident, Variant}; 9 | 10 | /// Used to track an enum variant and its corresponding mappings (LLVM <-> Rust), 11 | /// as well as attributes 12 | struct EnumVariant { 13 | llvm_variant: Ident, 14 | rust_variant: Ident, 15 | attrs: Vec, 16 | } 17 | 18 | impl EnumVariant { 19 | fn new(variant: &Variant) -> Self { 20 | let rust_variant = variant.ident.clone(); 21 | let llvm_variant = Ident::new(&format!("LLVM{}", rust_variant), variant.span()); 22 | let mut attrs = variant.attrs.clone(); 23 | attrs.retain(|attr| !attr.path().is_ident("llvm_variant")); 24 | Self { 25 | llvm_variant, 26 | rust_variant, 27 | attrs, 28 | } 29 | } 30 | 31 | fn with_name(variant: &Variant, mut llvm_variant: Ident) -> Self { 32 | let rust_variant = variant.ident.clone(); 33 | llvm_variant.set_span(rust_variant.span()); 34 | let mut attrs = variant.attrs.clone(); 35 | attrs.retain(|attr| !attr.path().is_ident("llvm_variant")); 36 | Self { 37 | llvm_variant, 38 | rust_variant, 39 | attrs, 40 | } 41 | } 42 | } 43 | 44 | /// Used when constructing the variants of an enum declaration. 45 | #[derive(Default)] 46 | struct EnumVariants { 47 | variants: Vec, 48 | error: Option, 49 | } 50 | 51 | impl EnumVariants { 52 | #[inline] 53 | fn len(&self) -> usize { 54 | self.variants.len() 55 | } 56 | 57 | #[inline] 58 | fn iter(&self) -> core::slice::Iter<'_, EnumVariant> { 59 | self.variants.iter() 60 | } 61 | 62 | #[inline] 63 | fn has_error(&self) -> bool { 64 | self.error.is_some() 65 | } 66 | 67 | #[inline] 68 | fn set_error(&mut self, err: &str, span: Span) { 69 | self.error = Some(Error::new(span, err)); 70 | } 71 | 72 | fn into_error(self) -> Error { 73 | self.error.unwrap() 74 | } 75 | } 76 | 77 | impl Fold for EnumVariants { 78 | fn fold_variant(&mut self, mut variant: Variant) -> Variant { 79 | use syn::Meta; 80 | 81 | if self.has_error() { 82 | return variant; 83 | } 84 | 85 | // Check for llvm_variant 86 | if let Some(attr) = variant.attrs.iter().find(|attr| attr.path().is_ident("llvm_variant")) { 87 | // Extract attribute meta 88 | if let Meta::List(meta) = &attr.meta { 89 | // We should only have one element 90 | 91 | if let Ok(Meta::Path(name)) = meta.parse_args() { 92 | self.variants 93 | .push(EnumVariant::with_name(&variant, name.get_ident().unwrap().clone())); 94 | // Strip the llvm_variant attribute from the final AST 95 | variant.attrs.retain(|attr| !attr.path().is_ident("llvm_variant")); 96 | return variant; 97 | } 98 | } 99 | 100 | // If at any point we fall through to here, it is the same basic issue, invalid format 101 | self.set_error("expected #[llvm_variant(VARIANT_NAME)]", attr.span()); 102 | return variant; 103 | } 104 | 105 | self.variants.push(EnumVariant::new(&variant)); 106 | variant 107 | } 108 | } 109 | 110 | /// Used to parse an enum declaration decorated with `#[llvm_enum(..)]` 111 | pub struct LLVMEnumType { 112 | name: Ident, 113 | decl: syn::ItemEnum, 114 | variants: EnumVariants, 115 | } 116 | 117 | impl Parse for LLVMEnumType { 118 | fn parse(input: ParseStream) -> Result { 119 | // Parse enum declaration 120 | let decl = input.parse::()?; 121 | let name = decl.ident.clone(); 122 | 123 | // Fold over variants and expand llvm_versions 124 | let decl = crate::cfg::VersionFolder::fold_any(Fold::fold_item_enum, decl)?; 125 | 126 | let mut variants = EnumVariants::default(); 127 | let decl = variants.fold_item_enum(decl); 128 | if variants.has_error() { 129 | return Err(variants.into_error()); 130 | } 131 | 132 | Ok(Self { name, decl, variants }) 133 | } 134 | } 135 | 136 | pub fn llvm_enum(llvm_ty: Path, llvm_enum_type: LLVMEnumType) -> TokenStream { 137 | // Construct match arms for LLVM -> Rust enum conversion 138 | let mut from_arms = Vec::with_capacity(llvm_enum_type.variants.len()); 139 | for variant in llvm_enum_type.variants.iter() { 140 | let src_variant = variant.llvm_variant.clone(); 141 | // Filter out doc comments or else rustc will warn about docs on match arms in newer versions. 142 | let src_attrs: Vec<_> = variant 143 | .attrs 144 | .iter() 145 | .filter(|&attr| !attr.meta.path().is_ident("doc")) 146 | .collect(); 147 | let src_ty = llvm_ty.clone(); 148 | let dst_variant = variant.rust_variant.clone(); 149 | let dst_ty = llvm_enum_type.name.clone(); 150 | 151 | let pat = PatPath { 152 | attrs: Vec::new(), 153 | qself: None, 154 | path: parse_quote!(#src_ty::#src_variant), 155 | }; 156 | 157 | let arm: Arm = parse_quote! { 158 | #(#src_attrs)* 159 | #pat => { #dst_ty::#dst_variant } 160 | }; 161 | from_arms.push(arm); 162 | } 163 | 164 | // Construct match arms for Rust -> LLVM enum conversion 165 | let mut to_arms = Vec::with_capacity(llvm_enum_type.variants.len()); 166 | for variant in llvm_enum_type.variants.iter() { 167 | let src_variant = variant.rust_variant.clone(); 168 | // Filter out doc comments or else rustc will warn about docs on match arms in newer versions. 169 | let src_attrs: Vec<_> = variant 170 | .attrs 171 | .iter() 172 | .filter(|&attr| !attr.meta.path().is_ident("doc")) 173 | .collect(); 174 | let src_ty = llvm_enum_type.name.clone(); 175 | let dst_variant = variant.llvm_variant.clone(); 176 | let dst_ty = llvm_ty.clone(); 177 | 178 | let pat = PatPath { 179 | attrs: Vec::new(), 180 | qself: None, 181 | path: parse_quote!(#src_ty::#src_variant), 182 | }; 183 | 184 | let arm: Arm = parse_quote! { 185 | #(#src_attrs)* 186 | #pat => { #dst_ty::#dst_variant } 187 | }; 188 | to_arms.push(arm); 189 | } 190 | 191 | let enum_ty = llvm_enum_type.name.clone(); 192 | let enum_decl = llvm_enum_type.decl; 193 | 194 | quote! { 195 | #enum_decl 196 | 197 | impl #enum_ty { 198 | fn new(src: #llvm_ty) -> Self { 199 | match src { 200 | #(#from_arms)* 201 | } 202 | } 203 | } 204 | impl From<#llvm_ty> for #enum_ty { 205 | fn from(src: #llvm_ty) -> Self { 206 | Self::new(src) 207 | } 208 | } 209 | impl Into<#llvm_ty> for #enum_ty { 210 | fn into(self) -> #llvm_ty { 211 | match self { 212 | #(#to_arms),* 213 | } 214 | } 215 | } 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /internal_macros/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! These macros are only intended to be used by inkwell internally 2 | //! and should not be expected to have public support nor stability. 3 | //! Here be dragons 🐉 4 | 5 | use proc_macro::TokenStream; 6 | use syn::parse_macro_input; 7 | 8 | mod cfg; 9 | mod r#enum; 10 | 11 | /// This macro can be used to specify version constraints for an enum/struct/union or 12 | /// other item which can be decorated with an attribute. 13 | /// 14 | /// It takes one argument which is any range of major or `major.minor` LLVM versions. 15 | /// 16 | /// To use with enum variants or struct fields, you need to decorate the parent item with 17 | /// the `#[llvm_versioned_item]` attribute, as this is the hook we need to modify the AST 18 | /// of those items. 19 | /// 20 | /// # Examples 21 | /// 22 | /// ```ignore 23 | /// // Inclusive range from 15 up to and including 18. 24 | /// #[llvm_versions(15..=18)] 25 | /// 26 | /// // Exclusive range from 15 up to but not including 18. 27 | /// #[llvm_versions(15..18)] 28 | /// 29 | /// // Inclusive range from 15.1 up to and including the latest release. 30 | /// #[llvm_versions(15.1..)] 31 | /// ``` 32 | #[proc_macro_attribute] 33 | pub fn llvm_versions(args: TokenStream, input: TokenStream) -> TokenStream { 34 | let args = parse_macro_input!(args as cfg::VersionRange); 35 | cfg::expand(Some(args), input) 36 | } 37 | 38 | /// This attribute is used to decorate enums, structs, or unions which may contain 39 | /// variants/fields which make use of `#[llvm_versions(..)]` 40 | /// 41 | /// # Examples 42 | /// 43 | /// ```ignore 44 | /// #[llvm_versioned_item] 45 | /// enum InstructionOpcode { 46 | /// Call, 47 | /// #[llvm_versions(3.8..=latest)] 48 | /// CatchPad, 49 | /// ... 50 | /// } 51 | /// ``` 52 | #[proc_macro_attribute] 53 | pub fn llvm_versioned_item(args: TokenStream, input: TokenStream) -> TokenStream { 54 | parse_macro_input!(args as syn::parse::Nothing); 55 | cfg::expand(None, input) 56 | } 57 | 58 | /// This attribute macro allows you to decorate an enum declaration which represents 59 | /// an LLVM enum with versioning constraints and/or custom variant names. There are 60 | /// a few expectations around the LLVM and Rust enums: 61 | /// 62 | /// - Both enums have the same number of variants 63 | /// - The name of the LLVM variant can be derived by appending 'LLVM' to the Rust variant 64 | /// 65 | /// The latter can be worked around manually with `#[llvm_variant]` if desired. 66 | /// 67 | /// # Examples 68 | /// 69 | /// ```ignore 70 | /// #[llvm_enum(LLVMOpcode)] 71 | /// enum InstructionOpcode { 72 | /// Call, 73 | /// #[llvm_versions(3.8..)] 74 | /// CatchPad, 75 | /// ..., 76 | /// #[llvm_variant(LLVMRet)] 77 | /// Return, 78 | /// ... 79 | /// } 80 | /// ``` 81 | /// 82 | /// The use of `#[llvm_variant(NAME)]` allows you to override the default 83 | /// naming scheme by providing the variant name which the source enum maps 84 | /// to. In the above example, `Ret` was deemed unnecessarily concise, so the 85 | /// source variant is named `Return` and mapped manually to `LLVMRet`. 86 | #[proc_macro_attribute] 87 | pub fn llvm_enum(args: TokenStream, input: TokenStream) -> TokenStream { 88 | // Expect something like #[llvm_enum(LLVMOpcode)] 89 | let llvm_ty = parse_macro_input!(args as syn::Path); 90 | let llvm_enum_type = parse_macro_input!(input as r#enum::LLVMEnumType); 91 | r#enum::llvm_enum(llvm_ty, llvm_enum_type).into() 92 | } 93 | -------------------------------------------------------------------------------- /src/comdat.rs: -------------------------------------------------------------------------------- 1 | //! A `Comdat` helps resolve linker errors for duplicate sections. 2 | // https://llvm.org/doxygen/IR_2Comdat_8h_source.html 3 | // https://stackoverflow.com/questions/1834597/what-is-the-comdat-section-used-for 4 | 5 | use llvm_sys::comdat::{LLVMComdatSelectionKind, LLVMGetComdatSelectionKind, LLVMSetComdatSelectionKind}; 6 | use llvm_sys::prelude::LLVMComdatRef; 7 | 8 | #[llvm_enum(LLVMComdatSelectionKind)] 9 | #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 10 | /// Determines how linker conflicts are to be resolved. 11 | pub enum ComdatSelectionKind { 12 | /// The linker may choose any COMDAT. 13 | #[llvm_variant(LLVMAnyComdatSelectionKind)] 14 | Any, 15 | /// The data referenced by the COMDAT must be the same. 16 | #[llvm_variant(LLVMExactMatchComdatSelectionKind)] 17 | ExactMatch, 18 | /// The linker will choose the largest COMDAT. 19 | #[llvm_variant(LLVMLargestComdatSelectionKind)] 20 | Largest, 21 | /// No other Module may specify this COMDAT. 22 | #[llvm_variant(LLVMNoDuplicatesComdatSelectionKind)] 23 | NoDuplicates, 24 | /// The data referenced by the COMDAT must be the same size. 25 | #[llvm_variant(LLVMSameSizeComdatSelectionKind)] 26 | SameSize, 27 | } 28 | 29 | /// A `Comdat` determines how to resolve duplicate sections when linking. 30 | #[derive(Debug, PartialEq, Eq, Copy, Clone)] 31 | pub struct Comdat(pub(crate) LLVMComdatRef); 32 | 33 | impl Comdat { 34 | /// Creates a new `Comdat` type from a raw pointer. 35 | pub unsafe fn new(comdat: LLVMComdatRef) -> Self { 36 | debug_assert!(!comdat.is_null()); 37 | 38 | Comdat(comdat) 39 | } 40 | 41 | /// Acquires the underlying raw pointer belonging to this `Comdat` type. 42 | pub fn as_mut_ptr(&self) -> LLVMComdatRef { 43 | self.0 44 | } 45 | 46 | /// Gets what kind of `Comdat` this is. 47 | pub fn get_selection_kind(self) -> ComdatSelectionKind { 48 | let kind_ptr = unsafe { LLVMGetComdatSelectionKind(self.0) }; 49 | 50 | ComdatSelectionKind::new(kind_ptr) 51 | } 52 | 53 | /// Sets what kind of `Comdat` this should be. 54 | pub fn set_selection_kind(self, kind: ComdatSelectionKind) { 55 | unsafe { LLVMSetComdatSelectionKind(self.0, kind.into()) } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/data_layout.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::CStr; 2 | use std::fmt; 3 | 4 | use crate::support::{LLVMString, LLVMStringOrRaw}; 5 | 6 | #[derive(Eq)] 7 | pub struct DataLayout { 8 | pub(crate) data_layout: LLVMStringOrRaw, 9 | } 10 | 11 | impl DataLayout { 12 | pub(crate) unsafe fn new_owned(data_layout: *const ::libc::c_char) -> DataLayout { 13 | debug_assert!(!data_layout.is_null()); 14 | 15 | DataLayout { 16 | data_layout: LLVMStringOrRaw::Owned(LLVMString::new(data_layout)), 17 | } 18 | } 19 | 20 | pub(crate) unsafe fn new_borrowed(data_layout: *const ::libc::c_char) -> DataLayout { 21 | debug_assert!(!data_layout.is_null()); 22 | 23 | DataLayout { 24 | data_layout: LLVMStringOrRaw::Borrowed(data_layout), 25 | } 26 | } 27 | 28 | pub fn as_str(&self) -> &CStr { 29 | self.data_layout.as_str() 30 | } 31 | 32 | pub fn as_ptr(&self) -> *const ::libc::c_char { 33 | match self.data_layout { 34 | LLVMStringOrRaw::Owned(ref llvm_string) => llvm_string.ptr, 35 | LLVMStringOrRaw::Borrowed(ptr) => ptr, 36 | } 37 | } 38 | } 39 | 40 | impl PartialEq for DataLayout { 41 | fn eq(&self, other: &DataLayout) -> bool { 42 | self.as_str() == other.as_str() 43 | } 44 | } 45 | 46 | impl fmt::Debug for DataLayout { 47 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 48 | f.debug_struct("DataLayout") 49 | .field("address", &self.as_ptr()) 50 | .field("repr", &self.as_str()) 51 | .finish() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/intrinsics.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMGetIntrinsicDeclaration, LLVMIntrinsicIsOverloaded, LLVMLookupIntrinsicID}; 2 | use llvm_sys::prelude::LLVMTypeRef; 3 | 4 | use crate::module::Module; 5 | use crate::types::{AsTypeRef, BasicTypeEnum}; 6 | use crate::values::FunctionValue; 7 | 8 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 9 | pub struct Intrinsic { 10 | id: u32, 11 | } 12 | 13 | /// A wrapper around LLVM intrinsic id 14 | /// 15 | /// To call it you would need to create a declaration inside a module using [`Self::get_declaration()`]. 16 | impl Intrinsic { 17 | /// Create an Intrinsic object from raw LLVM intrinsic id 18 | /// 19 | /// SAFETY: the id is a valid LLVM intrinsic ID 20 | pub(crate) unsafe fn new(id: u32) -> Self { 21 | Self { id } 22 | } 23 | 24 | /// Find llvm intrinsic id from name 25 | /// 26 | /// # Example 27 | /// ```no_run 28 | /// use inkwell::{intrinsics::Intrinsic, context::Context}; 29 | /// 30 | /// let trap_intrinsic = Intrinsic::find("llvm.trap").unwrap(); 31 | /// 32 | /// let context = Context::create(); 33 | /// let module = context.create_module("trap"); 34 | /// let builder = context.create_builder(); 35 | /// let void_type = context.void_type(); 36 | /// let fn_type = void_type.fn_type(&[], false); 37 | /// let fn_value = module.add_function("trap", fn_type, None); 38 | /// let entry = context.append_basic_block(fn_value, "entry"); 39 | /// 40 | /// let trap_function = trap_intrinsic.get_declaration(&module, &[]).unwrap(); 41 | /// 42 | /// builder.position_at_end(entry); 43 | /// builder.build_call(trap_function, &[], "trap_call"); 44 | /// ``` 45 | pub fn find(name: &str) -> Option { 46 | let id = unsafe { LLVMLookupIntrinsicID(name.as_ptr() as *const ::libc::c_char, name.len()) }; 47 | 48 | if id == 0 { 49 | return None; 50 | } 51 | 52 | Some(unsafe { Intrinsic::new(id) }) 53 | } 54 | 55 | /// Check if specified intrinsic is overloaded 56 | /// 57 | /// Overloaded intrinsics need some argument types to be specified to declare them 58 | pub fn is_overloaded(&self) -> bool { 59 | unsafe { LLVMIntrinsicIsOverloaded(self.id) != 0 } 60 | } 61 | 62 | /// Create or insert the declaration of an intrinsic. 63 | /// 64 | /// For overloaded intrinsics, parameter types must be provided to uniquely identify an overload. 65 | /// 66 | /// # Example 67 | /// ```no_run 68 | /// use inkwell::{intrinsics::Intrinsic, context::Context}; 69 | /// 70 | /// let trap_intrinsic = Intrinsic::find("llvm.trap").unwrap(); 71 | /// 72 | /// let context = Context::create(); 73 | /// let module = context.create_module("trap"); 74 | /// let builder = context.create_builder(); 75 | /// let void_type = context.void_type(); 76 | /// let fn_type = void_type.fn_type(&[], false); 77 | /// let fn_value = module.add_function("trap", fn_type, None); 78 | /// let entry = context.append_basic_block(fn_value, "entry"); 79 | /// 80 | /// let trap_function = trap_intrinsic.get_declaration(&module, &[]).unwrap(); 81 | /// 82 | /// builder.position_at_end(entry); 83 | /// builder.build_call(trap_function, &[], "trap_call"); 84 | /// ``` 85 | pub fn get_declaration<'ctx>( 86 | &self, 87 | module: &Module<'ctx>, 88 | param_types: &[BasicTypeEnum], 89 | ) -> Option> { 90 | let mut param_types: Vec = param_types.iter().map(|val| val.as_type_ref()).collect(); 91 | 92 | // param_types should be empty for non-overloaded intrinsics (I think?) 93 | // for overloaded intrinsics they determine the overload used 94 | 95 | if self.is_overloaded() && param_types.is_empty() { 96 | // LLVM crashes otherwise 97 | return None; 98 | } 99 | 100 | let res = unsafe { 101 | FunctionValue::new(LLVMGetIntrinsicDeclaration( 102 | module.module.get(), 103 | self.id, 104 | param_types.as_mut_ptr(), 105 | param_types.len(), 106 | )) 107 | }; 108 | 109 | res 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/memory_buffer.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{ 2 | LLVMCreateMemoryBufferWithContentsOfFile, LLVMCreateMemoryBufferWithMemoryRange, 3 | LLVMCreateMemoryBufferWithMemoryRangeCopy, LLVMCreateMemoryBufferWithSTDIN, LLVMDisposeMemoryBuffer, 4 | LLVMGetBufferSize, LLVMGetBufferStart, 5 | }; 6 | #[allow(deprecated)] 7 | use llvm_sys::object::LLVMCreateObjectFile; 8 | use llvm_sys::prelude::LLVMMemoryBufferRef; 9 | 10 | use crate::object_file::ObjectFile; 11 | use crate::support::{to_c_str, LLVMString}; 12 | 13 | use std::mem::{forget, MaybeUninit}; 14 | use std::path::Path; 15 | use std::ptr; 16 | use std::slice; 17 | 18 | #[derive(Debug)] 19 | pub struct MemoryBuffer { 20 | pub(crate) memory_buffer: LLVMMemoryBufferRef, 21 | } 22 | 23 | impl MemoryBuffer { 24 | pub unsafe fn new(memory_buffer: LLVMMemoryBufferRef) -> Self { 25 | assert!(!memory_buffer.is_null()); 26 | 27 | MemoryBuffer { memory_buffer } 28 | } 29 | 30 | pub fn as_mut_ptr(&self) -> LLVMMemoryBufferRef { 31 | self.memory_buffer 32 | } 33 | 34 | pub fn create_from_file(path: &Path) -> Result { 35 | let path = to_c_str(path.to_str().expect("Did not find a valid Unicode path string")); 36 | let mut memory_buffer = ptr::null_mut(); 37 | let mut err_string = MaybeUninit::uninit(); 38 | 39 | let return_code = unsafe { 40 | LLVMCreateMemoryBufferWithContentsOfFile( 41 | path.as_ptr() as *const ::libc::c_char, 42 | &mut memory_buffer, 43 | err_string.as_mut_ptr(), 44 | ) 45 | }; 46 | 47 | // TODO: Verify 1 is error code (LLVM can be inconsistent) 48 | if return_code == 1 { 49 | unsafe { 50 | return Err(LLVMString::new(err_string.assume_init())); 51 | } 52 | } 53 | 54 | unsafe { Ok(MemoryBuffer::new(memory_buffer)) } 55 | } 56 | 57 | pub fn create_from_stdin() -> Result { 58 | let mut memory_buffer = ptr::null_mut(); 59 | let mut err_string = MaybeUninit::uninit(); 60 | 61 | let return_code = unsafe { LLVMCreateMemoryBufferWithSTDIN(&mut memory_buffer, err_string.as_mut_ptr()) }; 62 | 63 | // TODO: Verify 1 is error code (LLVM can be inconsistent) 64 | if return_code == 1 { 65 | unsafe { 66 | return Err(LLVMString::new(err_string.assume_init())); 67 | } 68 | } 69 | 70 | unsafe { Ok(MemoryBuffer::new(memory_buffer)) } 71 | } 72 | 73 | /// This function is likely slightly cheaper than `create_from_memory_range_copy` since it intentionally 74 | /// leaks data to LLVM so that it doesn't have to reallocate. `create_from_memory_range_copy` may be removed 75 | /// in the future 76 | pub fn create_from_memory_range(input: &[u8], name: &str) -> Self { 77 | let name_c_string = to_c_str(name); 78 | 79 | let memory_buffer = unsafe { 80 | LLVMCreateMemoryBufferWithMemoryRange( 81 | input.as_ptr() as *const ::libc::c_char, 82 | input.len(), 83 | name_c_string.as_ptr(), 84 | false as i32, 85 | ) 86 | }; 87 | 88 | unsafe { MemoryBuffer::new(memory_buffer) } 89 | } 90 | 91 | /// This will create a new `MemoryBuffer` from the given input. 92 | /// 93 | /// This function is likely slightly more expensive than `create_from_memory_range` since it does not leak 94 | /// data to LLVM, forcing LLVM to make a copy. This function may be removed in the future in favor of 95 | /// `create_from_memory_range` 96 | pub fn create_from_memory_range_copy(input: &[u8], name: &str) -> Self { 97 | let name_c_string = to_c_str(name); 98 | 99 | let memory_buffer = unsafe { 100 | LLVMCreateMemoryBufferWithMemoryRangeCopy( 101 | input.as_ptr() as *const ::libc::c_char, 102 | input.len(), 103 | name_c_string.as_ptr(), 104 | ) 105 | }; 106 | 107 | unsafe { MemoryBuffer::new(memory_buffer) } 108 | } 109 | 110 | /// Gets a byte slice of this `MemoryBuffer`. 111 | pub fn as_slice(&self) -> &[u8] { 112 | unsafe { 113 | let start = LLVMGetBufferStart(self.memory_buffer); 114 | 115 | slice::from_raw_parts(start as *const _, self.get_size()) 116 | } 117 | } 118 | 119 | /// Gets the byte size of this `MemoryBuffer`. 120 | pub fn get_size(&self) -> usize { 121 | unsafe { LLVMGetBufferSize(self.memory_buffer) } 122 | } 123 | 124 | /// Convert this `MemoryBuffer` into an `ObjectFile`. LLVM does not currently 125 | /// provide any way to determine the cause of error if conversion fails. 126 | pub fn create_object_file(self) -> Result { 127 | #[allow(deprecated)] 128 | let object_file = unsafe { LLVMCreateObjectFile(self.memory_buffer) }; 129 | 130 | forget(self); 131 | 132 | if object_file.is_null() { 133 | return Err(()); 134 | } 135 | 136 | unsafe { Ok(ObjectFile::new(object_file)) } 137 | } 138 | } 139 | 140 | impl Drop for MemoryBuffer { 141 | fn drop(&mut self) { 142 | unsafe { 143 | LLVMDisposeMemoryBuffer(self.memory_buffer); 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/memory_manager.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::prelude::LLVMBool; 2 | 3 | /// A trait for user-defined memory management in MCJIT. 4 | /// 5 | /// Implementors can override how LLVM's MCJIT engine allocates memory for code 6 | /// and data sections. This is sometimes needed for: 7 | /// - custom allocators, 8 | /// - sandboxed or restricted environments, 9 | /// - capturing stack map sections (e.g., for garbage collection), 10 | /// - or other specialized JIT memory management requirements. 11 | /// 12 | /// # StackMap and GC Integration 13 | /// 14 | /// By examining the `section_name` argument in [`McjitMemoryManager::allocate_data_section`], 15 | /// you can detect sections such as `.llvm_stackmaps` (on ELF) or `__llvm_stackmaps` 16 | /// (on Mach-O). Recording the location of these sections may be useful for 17 | /// custom garbage collectors. For more information, refer to the [LLVM 18 | /// StackMaps documentation](https://llvm.org/docs/StackMaps.html#stack-map-section). 19 | /// 20 | /// Typically, on Darwin (Mach-O), the stack map section name is `__llvm_stackmaps`, 21 | /// and on Linux (ELF), it is `.llvm_stackmaps`. 22 | pub trait McjitMemoryManager: std::fmt::Debug { 23 | /// Allocates a block of memory for a code section. 24 | /// 25 | /// # Parameters 26 | /// 27 | /// * `size` - The size in bytes for the code section. 28 | /// * `alignment` - The required alignment in bytes. 29 | /// * `section_id` - A numeric ID that LLVM uses to identify this section. 30 | /// * `section_name` - A name for this section, if provided by LLVM. 31 | /// 32 | /// # Returns 33 | /// 34 | /// Returns a pointer to the allocated memory. Implementors must ensure it is 35 | /// at least `size` bytes long and meets `alignment` requirements. 36 | fn allocate_code_section( 37 | &mut self, 38 | size: libc::uintptr_t, 39 | alignment: libc::c_uint, 40 | section_id: libc::c_uint, 41 | section_name: &str, 42 | ) -> *mut u8; 43 | 44 | /// Allocates a block of memory for a data section. 45 | /// 46 | /// # Parameters 47 | /// 48 | /// * `size` - The size in bytes for the data section. 49 | /// * `alignment` - The required alignment in bytes. 50 | /// * `section_id` - A numeric ID that LLVM uses to identify this section. 51 | /// * `section_name` - A name for this section, if provided by LLVM. 52 | /// * `is_read_only` - Whether this data section should be read-only. 53 | /// 54 | /// # Returns 55 | /// 56 | /// Returns a pointer to the allocated memory. Implementors must ensure it is 57 | /// at least `size` bytes long and meets `alignment` requirements. 58 | fn allocate_data_section( 59 | &mut self, 60 | size: libc::uintptr_t, 61 | alignment: libc::c_uint, 62 | section_id: libc::c_uint, 63 | section_name: &str, 64 | is_read_only: bool, 65 | ) -> *mut u8; 66 | 67 | /// Finalizes memory permissions for all allocated sections. 68 | /// 69 | /// This is called once all sections have been allocated. Implementors can set 70 | /// permissions such as making code sections executable or data sections 71 | /// read-only. 72 | /// 73 | /// # Errors 74 | /// 75 | /// If any error occurs (for example, failing to set page permissions), 76 | /// return an `Err(String)`. This error is reported back to LLVM as a C string. 77 | fn finalize_memory(&mut self) -> Result<(), String>; 78 | 79 | /// Cleans up or deallocates resources before the memory manager is destroyed. 80 | /// 81 | /// This is called when LLVM has finished using the memory manager. Any 82 | /// additional allocations or references should be released here if needed. 83 | fn destroy(&mut self); 84 | } 85 | 86 | /// Holds a boxed `McjitMemoryManager` and passes it to LLVM as an opaque pointer. 87 | /// 88 | /// LLVM calls into the adapter using the extern "C" function pointers defined below. 89 | #[derive(Debug)] 90 | pub struct MemoryManagerAdapter { 91 | pub memory_manager: Box, 92 | } 93 | 94 | // ------ Extern "C" Adapters ------ 95 | 96 | /// Adapter for `allocate_code_section`. 97 | /// 98 | /// Called by LLVM with a raw pointer (`opaque`). Casts back to `MemoryManagerAdapter` 99 | /// and delegates to `allocate_code_section`. 100 | pub(crate) extern "C" fn allocate_code_section_adapter( 101 | opaque: *mut libc::c_void, 102 | size: libc::uintptr_t, 103 | alignment: libc::c_uint, 104 | section_id: libc::c_uint, 105 | section_name: *const libc::c_char, 106 | ) -> *mut u8 { 107 | let adapter = unsafe { &mut *(opaque as *mut MemoryManagerAdapter) }; 108 | let sname = unsafe { c_str_to_str(section_name) }; 109 | adapter 110 | .memory_manager 111 | .allocate_code_section(size, alignment, section_id, sname) 112 | } 113 | 114 | /// Adapter for `allocate_data_section`. 115 | /// 116 | /// Note that `LLVMBool` is `0` for false, and `1` for true. We check `!= 0` to 117 | /// interpret it as a bool. 118 | pub(crate) extern "C" fn allocate_data_section_adapter( 119 | opaque: *mut libc::c_void, 120 | size: libc::uintptr_t, 121 | alignment: libc::c_uint, 122 | section_id: libc::c_uint, 123 | section_name: *const libc::c_char, 124 | is_read_only: LLVMBool, 125 | ) -> *mut u8 { 126 | let adapter = unsafe { &mut *(opaque as *mut MemoryManagerAdapter) }; 127 | let sname = unsafe { c_str_to_str(section_name) }; 128 | adapter 129 | .memory_manager 130 | .allocate_data_section(size, alignment, section_id, sname, is_read_only != 0) 131 | } 132 | 133 | /// Adapter for `finalize_memory`. 134 | /// 135 | /// If an error is returned, the message is converted into a C string and set in `err_msg_out`. 136 | pub(crate) extern "C" fn finalize_memory_adapter( 137 | opaque: *mut libc::c_void, 138 | err_msg_out: *mut *mut libc::c_char, 139 | ) -> libc::c_int { 140 | let adapter = unsafe { &mut *(opaque as *mut MemoryManagerAdapter) }; 141 | match adapter.memory_manager.finalize_memory() { 142 | Ok(()) => 0, 143 | Err(e) => { 144 | let cstring = std::ffi::CString::new(e).unwrap_or_default(); 145 | unsafe { 146 | *err_msg_out = cstring.into_raw(); 147 | } 148 | 1 149 | }, 150 | } 151 | } 152 | 153 | /// Adapter for `destroy`. 154 | /// 155 | /// Called when LLVM is done with the memory manager. Calls `destroy` and drops 156 | /// the adapter to free resources. 157 | pub(crate) extern "C" fn destroy_adapter(opaque: *mut libc::c_void) { 158 | // Re-box to drop the adapter and its contents. 159 | // SAFETY: `opaque` must have been allocated by Box. 160 | let mut adapter = unsafe { Box::from_raw(opaque as *mut MemoryManagerAdapter) }; 161 | 162 | // Clean up user-defined resources 163 | adapter.memory_manager.destroy(); 164 | 165 | // Dropping `adapter` automatically frees the memory 166 | } 167 | 168 | /// Converts a raw C string pointer to a Rust `&str`. 169 | /// 170 | /// # Safety 171 | /// 172 | /// The caller must ensure `ptr` points to a valid, null-terminated UTF-8 string. 173 | /// If the string is invalid UTF-8 or `ptr` is null, an empty string is returned. 174 | unsafe fn c_str_to_str<'a>(ptr: *const libc::c_char) -> &'a str { 175 | if ptr.is_null() { 176 | "" 177 | } else { 178 | unsafe { std::ffi::CStr::from_ptr(ptr) }.to_str().unwrap_or("") 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /src/support/error_handling.rs: -------------------------------------------------------------------------------- 1 | //! This module contains some supplemental functions for dealing with errors. 2 | 3 | use libc::c_void; 4 | use llvm_sys::core::{LLVMGetDiagInfoDescription, LLVMGetDiagInfoSeverity}; 5 | use llvm_sys::error_handling::{LLVMInstallFatalErrorHandler, LLVMResetFatalErrorHandler}; 6 | use llvm_sys::prelude::LLVMDiagnosticInfoRef; 7 | use llvm_sys::LLVMDiagnosticSeverity; 8 | 9 | // REVIEW: Maybe it's possible to have a safe wrapper? If we can 10 | // wrap the provided function input ptr into a &CStr somehow 11 | // TODOC: Can be used like this: 12 | // extern "C" fn print_before_exit(msg: *const i8) { 13 | // let c_str = unsafe { std::ffi::CStr::from_ptr(msg) }; 14 | // 15 | // eprintln!("LLVM fatally errored: {:?}", c_str); 16 | // } 17 | // unsafe { 18 | // install_fatal_error_handler(print_before_exit); 19 | // } 20 | // and will be called before LLVM calls C exit() 21 | /// Installs an error handler to be called before LLVM exits. 22 | pub unsafe fn install_fatal_error_handler(handler: extern "C" fn(*const ::libc::c_char)) { 23 | LLVMInstallFatalErrorHandler(Some(handler)) 24 | } 25 | 26 | /// Resets LLVM's fatal error handler back to the default 27 | pub fn reset_fatal_error_handler() { 28 | unsafe { LLVMResetFatalErrorHandler() } 29 | } 30 | 31 | pub(crate) struct DiagnosticInfo { 32 | diagnostic_info: LLVMDiagnosticInfoRef, 33 | } 34 | 35 | impl DiagnosticInfo { 36 | pub unsafe fn new(diagnostic_info: LLVMDiagnosticInfoRef) -> Self { 37 | DiagnosticInfo { diagnostic_info } 38 | } 39 | 40 | pub(crate) fn get_description(&self) -> *mut ::libc::c_char { 41 | unsafe { LLVMGetDiagInfoDescription(self.diagnostic_info) } 42 | } 43 | 44 | pub(crate) fn severity_is_error(&self) -> bool { 45 | self.severity() == LLVMDiagnosticSeverity::LLVMDSError 46 | } 47 | 48 | fn severity(&self) -> LLVMDiagnosticSeverity { 49 | unsafe { LLVMGetDiagInfoSeverity(self.diagnostic_info) } 50 | } 51 | } 52 | 53 | // Assmuptions this handler makes: 54 | // * A valid *mut *mut i8 is provided as the void_ptr (via context.set_diagnostic_handler) 55 | // 56 | // https://github.com/llvm-mirror/llvm/blob/master/tools/llvm-c-test/diagnostic.c was super useful 57 | // for figuring out how to get this to work 58 | pub(crate) extern "C" fn get_error_str_diagnostic_handler( 59 | diagnostic_info: LLVMDiagnosticInfoRef, 60 | void_ptr: *mut c_void, 61 | ) { 62 | let diagnostic_info = unsafe { DiagnosticInfo::new(diagnostic_info) }; 63 | 64 | if diagnostic_info.severity_is_error() { 65 | let c_ptr_ptr = void_ptr as *mut *mut c_void as *mut *mut ::libc::c_char; 66 | 67 | unsafe { 68 | *c_ptr_ptr = diagnostic_info.get_description(); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/support/mod.rs: -------------------------------------------------------------------------------- 1 | #[deny(missing_docs)] 2 | pub mod error_handling; 3 | 4 | use libc::c_char; 5 | #[llvm_versions(16..)] 6 | use llvm_sys::core::LLVMGetVersion; 7 | use llvm_sys::core::{LLVMCreateMessage, LLVMDisposeMessage}; 8 | use llvm_sys::error_handling::LLVMEnablePrettyStackTrace; 9 | use llvm_sys::support::{LLVMLoadLibraryPermanently, LLVMSearchForAddressOfSymbol}; 10 | 11 | use std::borrow::Cow; 12 | use std::error::Error; 13 | use std::ffi::{CStr, CString}; 14 | use std::fmt::{self, Debug, Display, Formatter}; 15 | use std::ops::Deref; 16 | use std::path::Path; 17 | 18 | /// An owned LLVM String. Also known as a LLVM Message 19 | #[derive(Eq)] 20 | pub struct LLVMString { 21 | pub(crate) ptr: *const c_char, 22 | } 23 | 24 | impl LLVMString { 25 | pub(crate) unsafe fn new(ptr: *const c_char) -> Self { 26 | LLVMString { ptr } 27 | } 28 | 29 | /// This is a convenience method for creating a Rust `String`, 30 | /// however; it *will* reallocate. `LLVMString` should be used 31 | /// as much as possible to save memory since it is allocated by 32 | /// LLVM. It's essentially a `CString` with a custom LLVM 33 | /// deallocator 34 | #[allow(clippy::inherent_to_string_shadow_display)] 35 | pub fn to_string(&self) -> String { 36 | (*self).to_string_lossy().into_owned() 37 | } 38 | 39 | /// This method will allocate a c string through LLVM 40 | pub(crate) fn create_from_c_str(string: &CStr) -> LLVMString { 41 | unsafe { LLVMString::new(LLVMCreateMessage(string.as_ptr() as *const _)) } 42 | } 43 | 44 | /// This method will allocate a c string through LLVM 45 | pub(crate) fn create_from_str(string: &str) -> LLVMString { 46 | debug_assert_eq!(string.as_bytes()[string.len() - 1], 0); 47 | 48 | unsafe { LLVMString::new(LLVMCreateMessage(string.as_ptr() as *const _)) } 49 | } 50 | } 51 | 52 | impl Deref for LLVMString { 53 | type Target = CStr; 54 | 55 | fn deref(&self) -> &Self::Target { 56 | unsafe { CStr::from_ptr(self.ptr) } 57 | } 58 | } 59 | 60 | impl Debug for LLVMString { 61 | fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { 62 | write!(f, "{:?}", self.deref()) 63 | } 64 | } 65 | 66 | impl Display for LLVMString { 67 | fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { 68 | write!(f, "{:?}", self.deref()) 69 | } 70 | } 71 | 72 | impl PartialEq for LLVMString { 73 | fn eq(&self, other: &LLVMString) -> bool { 74 | **self == **other 75 | } 76 | } 77 | 78 | impl Error for LLVMString { 79 | fn description(&self) -> &str { 80 | self.to_str() 81 | .expect("Could not convert LLVMString to str (likely invalid unicode)") 82 | } 83 | 84 | fn cause(&self) -> Option<&dyn Error> { 85 | None 86 | } 87 | } 88 | 89 | impl Drop for LLVMString { 90 | fn drop(&mut self) { 91 | unsafe { 92 | LLVMDisposeMessage(self.ptr as *mut _); 93 | } 94 | } 95 | } 96 | 97 | // Similar to Cow; however does not provide ability to clone 98 | // since memory is allocated by LLVM. Could use a better name 99 | // too. This is meant to be an internal wrapper only. Maybe 100 | // belongs in a private utils module. 101 | #[derive(Eq)] 102 | pub(crate) enum LLVMStringOrRaw { 103 | Owned(LLVMString), 104 | Borrowed(*const c_char), 105 | } 106 | 107 | impl LLVMStringOrRaw { 108 | pub fn as_str(&self) -> &CStr { 109 | match self { 110 | LLVMStringOrRaw::Owned(llvm_string) => llvm_string.deref(), 111 | LLVMStringOrRaw::Borrowed(ptr) => unsafe { CStr::from_ptr(*ptr) }, 112 | } 113 | } 114 | } 115 | 116 | impl PartialEq for LLVMStringOrRaw { 117 | fn eq(&self, other: &LLVMStringOrRaw) -> bool { 118 | self.as_str() == other.as_str() 119 | } 120 | } 121 | 122 | /// This function is very unsafe. Any reference to LLVM data after this function is called will likely segfault. 123 | /// Probably only ever useful to call before your program ends. Might not even be absolutely necessary. 124 | pub unsafe fn shutdown_llvm() { 125 | use llvm_sys::core::LLVMShutdown; 126 | 127 | LLVMShutdown() 128 | } 129 | 130 | /// Returns the major, minor, and patch version of the LLVM in use 131 | #[llvm_versions(16..)] 132 | pub fn get_llvm_version() -> (u32, u32, u32) { 133 | let mut major: u32 = 0; 134 | let mut minor: u32 = 0; 135 | let mut patch: u32 = 0; 136 | 137 | unsafe { LLVMGetVersion(&mut major, &mut minor, &mut patch) }; 138 | 139 | (major, minor, patch) 140 | } 141 | 142 | /// Possible errors that can occur when loading a library 143 | #[derive(thiserror::Error, Debug, PartialEq, Eq, Clone, Copy)] 144 | pub enum LoadLibraryError { 145 | /// The given path could not be converted to a [`&str`] 146 | #[error("The given path could not be converted to a `&str`")] 147 | UnicodeError, 148 | /// The given path could not be loaded as a library 149 | #[error("The given path could not be loaded as a library")] 150 | LoadingError, 151 | } 152 | 153 | /// Permanently load the dynamic library at the given `path`. 154 | /// 155 | /// It is safe to call this function multiple times for the same library. 156 | pub fn load_library_permanently(path: &Path) -> Result<(), LoadLibraryError> { 157 | let filename = to_c_str(path.to_str().ok_or(LoadLibraryError::UnicodeError)?); 158 | 159 | let error = unsafe { LLVMLoadLibraryPermanently(filename.as_ptr()) == 1 }; 160 | if error { 161 | return Err(LoadLibraryError::LoadingError); 162 | } 163 | 164 | Ok(()) 165 | } 166 | 167 | #[test] 168 | fn test_load_library_permanently() { 169 | assert_eq!( 170 | load_library_permanently(Path::new("missing.dll")), 171 | Err(LoadLibraryError::LoadingError) 172 | ); 173 | } 174 | 175 | /// Permanently loads all the symbols visible inside the current program 176 | pub fn load_visible_symbols() { 177 | unsafe { LLVMLoadLibraryPermanently(std::ptr::null()) }; 178 | } 179 | 180 | /// Search through all previously loaded dynamic libraries for `symbol`. 181 | /// 182 | /// Returns an address of the symbol, if found 183 | pub fn search_for_address_of_symbol(symbol: &str) -> Option { 184 | let symbol = to_c_str(symbol); 185 | 186 | let address = unsafe { LLVMSearchForAddressOfSymbol(symbol.as_ptr()) }; 187 | if address.is_null() { 188 | return None; 189 | } 190 | Some(address as usize) 191 | } 192 | 193 | #[test] 194 | fn test_load_visible_symbols() { 195 | assert!(search_for_address_of_symbol("malloc").is_none()); 196 | load_visible_symbols(); 197 | assert!(search_for_address_of_symbol("malloc").is_some()); 198 | } 199 | 200 | /// Determines whether or not LLVM has been configured to run in multithreaded mode. (Inkwell currently does 201 | /// not officially support multithreaded mode) 202 | pub fn is_multithreaded() -> bool { 203 | use llvm_sys::core::LLVMIsMultithreaded; 204 | 205 | unsafe { LLVMIsMultithreaded() == 1 } 206 | } 207 | 208 | pub fn enable_llvm_pretty_stack_trace() { 209 | unsafe { LLVMEnablePrettyStackTrace() } 210 | } 211 | 212 | /// This function takes in a Rust string and either: 213 | /// 214 | /// A) Finds a terminating null byte in the Rust string and can reference it directly like a C string. 215 | /// 216 | /// B) Finds no null byte and allocates a new C string based on the input Rust string. 217 | pub(crate) fn to_c_str(mut s: &str) -> Cow<'_, CStr> { 218 | if s.is_empty() { 219 | s = "\0"; 220 | } 221 | 222 | // Start from the end of the string as it's the most likely place to find a null byte 223 | if !s.chars().rev().any(|ch| ch == '\0') { 224 | return Cow::from(CString::new(s).expect("unreachable since null bytes are checked")); 225 | } 226 | 227 | unsafe { Cow::from(CStr::from_ptr(s.as_ptr() as *const _)) } 228 | } 229 | 230 | #[test] 231 | fn test_to_c_str() { 232 | assert!(matches!(to_c_str("my string"), Cow::Owned(_))); 233 | assert!(matches!(to_c_str("my string\0"), Cow::Borrowed(_))); 234 | } 235 | -------------------------------------------------------------------------------- /src/types/fn_type.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{ 2 | LLVMCountParamTypes, LLVMGetParamTypes, LLVMGetReturnType, LLVMGetTypeKind, LLVMIsFunctionVarArg, 3 | }; 4 | use llvm_sys::prelude::LLVMTypeRef; 5 | use llvm_sys::LLVMTypeKind; 6 | 7 | use std::fmt::{self, Display}; 8 | use std::mem::forget; 9 | 10 | use crate::context::ContextRef; 11 | use crate::support::LLVMString; 12 | use crate::types::traits::AsTypeRef; 13 | use crate::types::{AnyType, BasicMetadataTypeEnum, BasicTypeEnum, PointerType, Type}; 14 | use crate::AddressSpace; 15 | 16 | /// A `FunctionType` is the type of a function variable. 17 | #[derive(PartialEq, Eq, Clone, Copy)] 18 | pub struct FunctionType<'ctx> { 19 | fn_type: Type<'ctx>, 20 | } 21 | 22 | impl<'ctx> FunctionType<'ctx> { 23 | /// Create `FunctionType` from [`LLVMTypeRef`] 24 | /// 25 | /// # Safety 26 | /// Undefined behavior, if referenced type isn't function type 27 | pub unsafe fn new(fn_type: LLVMTypeRef) -> Self { 28 | assert!(!fn_type.is_null()); 29 | 30 | FunctionType { 31 | fn_type: Type::new(fn_type), 32 | } 33 | } 34 | 35 | /// Creates a `PointerType` with this `FunctionType` for its element type. 36 | /// 37 | /// # Example 38 | /// 39 | /// ```no_run 40 | /// use inkwell::context::Context; 41 | /// use inkwell::AddressSpace; 42 | /// 43 | /// let context = Context::create(); 44 | /// let f32_type = context.f32_type(); 45 | /// let fn_type = f32_type.fn_type(&[], false); 46 | /// let fn_ptr_type = fn_type.ptr_type(AddressSpace::default()); 47 | /// 48 | /// #[cfg(feature = "typed-pointers")] 49 | /// assert_eq!(fn_ptr_type.get_element_type().into_function_type(), fn_type); 50 | /// ``` 51 | #[cfg_attr( 52 | any( 53 | all(feature = "llvm15-0", not(feature = "typed-pointers")), 54 | all(feature = "llvm16-0", not(feature = "typed-pointers")), 55 | feature = "llvm17-0", 56 | feature = "llvm18-1" 57 | ), 58 | deprecated( 59 | note = "Starting from version 15.0, LLVM doesn't differentiate between pointer types. Use Context::ptr_type instead." 60 | ) 61 | )] 62 | pub fn ptr_type(self, address_space: AddressSpace) -> PointerType<'ctx> { 63 | self.fn_type.ptr_type(address_space) 64 | } 65 | 66 | /// Determines whether or not a `FunctionType` is a variadic function. 67 | /// 68 | /// # Example 69 | /// 70 | /// ```no_run 71 | /// use inkwell::context::Context; 72 | /// 73 | /// let context = Context::create(); 74 | /// let f32_type = context.f32_type(); 75 | /// let fn_type = f32_type.fn_type(&[], true); 76 | /// 77 | /// assert!(fn_type.is_var_arg()); 78 | /// ``` 79 | pub fn is_var_arg(self) -> bool { 80 | unsafe { LLVMIsFunctionVarArg(self.as_type_ref()) != 0 } 81 | } 82 | 83 | /// Gets param types this `FunctionType` has. 84 | /// 85 | /// # Example 86 | /// 87 | /// ``` 88 | /// use inkwell::context::Context; 89 | /// 90 | /// let context = Context::create(); 91 | /// let f32_type = context.f32_type(); 92 | /// let fn_type = f32_type.fn_type(&[f32_type.into()], true); 93 | /// let param_types = fn_type.get_param_types(); 94 | /// 95 | /// assert_eq!(param_types.len(), 1); 96 | /// assert_eq!(param_types[0].into_float_type(), f32_type); 97 | /// ``` 98 | pub fn get_param_types(self) -> Vec> { 99 | let count = self.count_param_types(); 100 | let mut raw_vec: Vec = Vec::with_capacity(count as usize); 101 | let ptr = raw_vec.as_mut_ptr(); 102 | 103 | forget(raw_vec); 104 | 105 | let raw_vec = unsafe { 106 | LLVMGetParamTypes(self.as_type_ref(), ptr); 107 | 108 | Vec::from_raw_parts(ptr, count as usize, count as usize) 109 | }; 110 | 111 | raw_vec 112 | .iter() 113 | .map(|val| unsafe { BasicMetadataTypeEnum::new(*val) }) 114 | .collect() 115 | } 116 | 117 | /// Counts the number of param types this `FunctionType` has. 118 | /// 119 | /// # Example 120 | /// 121 | /// ```no_run 122 | /// use inkwell::context::Context; 123 | /// 124 | /// let context = Context::create(); 125 | /// let f32_type = context.f32_type(); 126 | /// let fn_type = f32_type.fn_type(&[f32_type.into()], true); 127 | /// 128 | /// assert_eq!(fn_type.count_param_types(), 1); 129 | /// ``` 130 | pub fn count_param_types(self) -> u32 { 131 | unsafe { LLVMCountParamTypes(self.as_type_ref()) } 132 | } 133 | 134 | // REVIEW: Always false -> const fn? 135 | /// Gets whether or not this `FunctionType` is sized or not. This is likely 136 | /// always false and may be removed in the future. 137 | /// 138 | /// # Example 139 | /// 140 | /// ```no_run 141 | /// use inkwell::context::Context; 142 | /// 143 | /// let context = Context::create(); 144 | /// let f32_type = context.f32_type(); 145 | /// let fn_type = f32_type.fn_type(&[], true); 146 | /// 147 | /// assert!(!fn_type.is_sized()); 148 | /// ``` 149 | pub fn is_sized(self) -> bool { 150 | self.fn_type.is_sized() 151 | } 152 | 153 | // REVIEW: Does this work on functions? 154 | // fn get_alignment(&self) -> IntValue { 155 | // self.fn_type.get_alignment() 156 | // } 157 | 158 | /// Gets a reference to the `Context` this `FunctionType` was created in. 159 | /// 160 | /// # Example 161 | /// 162 | /// ```no_run 163 | /// use inkwell::context::Context; 164 | /// 165 | /// let context = Context::create(); 166 | /// let f32_type = context.f32_type(); 167 | /// let fn_type = f32_type.fn_type(&[], true); 168 | /// 169 | /// assert_eq!(fn_type.get_context(), context); 170 | /// ``` 171 | pub fn get_context(self) -> ContextRef<'ctx> { 172 | self.fn_type.get_context() 173 | } 174 | 175 | /// Print the definition of a `FunctionType` to `LLVMString`. 176 | pub fn print_to_string(self) -> LLVMString { 177 | self.fn_type.print_to_string() 178 | } 179 | 180 | /// Gets the return type of this `FunctionType`. 181 | /// 182 | /// # Example 183 | /// 184 | /// ```no_run 185 | /// use inkwell::context::Context; 186 | /// 187 | /// let context = Context::create(); 188 | /// let f32_type = context.f32_type(); 189 | /// let fn_type = f32_type.fn_type(&[], true); 190 | /// 191 | /// assert_eq!(fn_type.get_return_type().unwrap().into_float_type(), f32_type); 192 | /// ``` 193 | pub fn get_return_type(self) -> Option> { 194 | let ty = unsafe { LLVMGetReturnType(self.as_type_ref()) }; 195 | 196 | let kind = unsafe { LLVMGetTypeKind(ty) }; 197 | 198 | if let LLVMTypeKind::LLVMVoidTypeKind = kind { 199 | return None; 200 | } 201 | 202 | unsafe { Some(BasicTypeEnum::new(ty)) } 203 | } 204 | 205 | // REVIEW: Can you do undef for functions? 206 | // Seems to "work" - no UB or SF so far but fails 207 | // LLVMIsAFunction() check. Commenting out for further research 208 | // pub fn get_undef(&self) -> FunctionValue { 209 | // FunctionValue::new(self.fn_type.get_undef()).expect("Should always get an undef value") 210 | // } 211 | } 212 | 213 | impl fmt::Debug for FunctionType<'_> { 214 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 215 | let llvm_type = self.print_to_string(); 216 | 217 | f.debug_struct("FunctionType") 218 | .field("address", &self.as_type_ref()) 219 | .field("is_var_args", &self.is_var_arg()) 220 | .field("llvm_type", &llvm_type) 221 | .finish() 222 | } 223 | } 224 | 225 | unsafe impl AsTypeRef for FunctionType<'_> { 226 | fn as_type_ref(&self) -> LLVMTypeRef { 227 | self.fn_type.ty 228 | } 229 | } 230 | 231 | impl Display for FunctionType<'_> { 232 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 233 | write!(f, "{}", self.print_to_string()) 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /src/types/metadata_type.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::prelude::LLVMTypeRef; 2 | 3 | use crate::context::ContextRef; 4 | use crate::support::LLVMString; 5 | use crate::types::enums::BasicMetadataTypeEnum; 6 | use crate::types::traits::AsTypeRef; 7 | use crate::types::{FunctionType, Type}; 8 | 9 | use std::fmt::{self, Display}; 10 | 11 | /// A `MetadataType` is the type of a metadata. 12 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] 13 | pub struct MetadataType<'ctx> { 14 | metadata_type: Type<'ctx>, 15 | } 16 | 17 | impl<'ctx> MetadataType<'ctx> { 18 | /// Create `MetadataType` from [`LLVMTypeRef`] 19 | /// 20 | /// # Safety 21 | /// Undefined behavior, if referenced type isn't metadata type 22 | pub unsafe fn new(metadata_type: LLVMTypeRef) -> Self { 23 | assert!(!metadata_type.is_null()); 24 | 25 | MetadataType { 26 | metadata_type: Type::new(metadata_type), 27 | } 28 | } 29 | 30 | /// Creates a `FunctionType` with this `MetadataType` for its return type. 31 | /// 32 | /// # Example 33 | /// 34 | /// ```no_run 35 | /// use inkwell::context::Context; 36 | /// 37 | /// let context = Context::create(); 38 | /// let md_type = context.metadata_type(); 39 | /// let fn_type = md_type.fn_type(&[], false); 40 | /// ``` 41 | pub fn fn_type(self, param_types: &[BasicMetadataTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { 42 | self.metadata_type.fn_type(param_types, is_var_args) 43 | } 44 | 45 | /// Gets a reference to the `Context` this `MetadataType` was created in. 46 | /// 47 | /// # Example 48 | /// 49 | /// ```no_run 50 | /// use inkwell::context::Context; 51 | /// 52 | /// let context = Context::create(); 53 | /// let md_type = context.metadata_type(); 54 | /// 55 | /// assert_eq!(md_type.get_context(), context); 56 | /// ``` 57 | pub fn get_context(self) -> ContextRef<'ctx> { 58 | self.metadata_type.get_context() 59 | } 60 | 61 | /// Print the definition of a `MetadataType` to `LLVMString`. 62 | pub fn print_to_string(self) -> LLVMString { 63 | self.metadata_type.print_to_string() 64 | } 65 | } 66 | 67 | unsafe impl AsTypeRef for MetadataType<'_> { 68 | fn as_type_ref(&self) -> LLVMTypeRef { 69 | self.metadata_type.ty 70 | } 71 | } 72 | 73 | impl Display for MetadataType<'_> { 74 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 75 | write!(f, "{}", self.print_to_string()) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/types/mod.rs: -------------------------------------------------------------------------------- 1 | //! A type is a classification which determines how data is used. 2 | 3 | #[deny(missing_docs)] 4 | mod array_type; 5 | mod enums; 6 | #[deny(missing_docs)] 7 | mod float_type; 8 | #[deny(missing_docs)] 9 | mod fn_type; 10 | #[deny(missing_docs)] 11 | mod int_type; 12 | #[deny(missing_docs)] 13 | mod metadata_type; 14 | #[deny(missing_docs)] 15 | mod ptr_type; 16 | #[deny(missing_docs)] 17 | mod scalable_vec_type; 18 | #[deny(missing_docs)] 19 | mod struct_type; 20 | #[deny(missing_docs)] 21 | mod traits; 22 | #[deny(missing_docs)] 23 | mod vec_type; 24 | #[deny(missing_docs)] 25 | mod void_type; 26 | 27 | pub use crate::types::array_type::ArrayType; 28 | pub use crate::types::enums::{AnyTypeEnum, BasicMetadataTypeEnum, BasicTypeEnum}; 29 | pub use crate::types::float_type::FloatType; 30 | pub use crate::types::fn_type::FunctionType; 31 | pub use crate::types::int_type::{IntType, StringRadix}; 32 | pub use crate::types::metadata_type::MetadataType; 33 | pub use crate::types::ptr_type::PointerType; 34 | pub use crate::types::scalable_vec_type::ScalableVectorType; 35 | pub use crate::types::struct_type::FieldTypesIter; 36 | pub use crate::types::struct_type::StructType; 37 | pub use crate::types::traits::{AnyType, AsTypeRef, BasicType, FloatMathType, IntMathType, PointerMathType}; 38 | pub use crate::types::vec_type::VectorType; 39 | pub use crate::types::void_type::VoidType; 40 | 41 | #[llvm_versions(12..)] 42 | use llvm_sys::core::LLVMScalableVectorType; 43 | 44 | #[llvm_versions(12..)] 45 | use llvm_sys::core::LLVMGetPoison; 46 | 47 | #[allow(deprecated)] 48 | use llvm_sys::core::LLVMArrayType; 49 | use llvm_sys::core::{ 50 | LLVMAlignOf, LLVMConstNull, LLVMConstPointerNull, LLVMFunctionType, LLVMGetElementType, LLVMGetTypeContext, 51 | LLVMGetTypeKind, LLVMGetUndef, LLVMPointerType, LLVMPrintTypeToString, LLVMSizeOf, LLVMTypeIsSized, LLVMVectorType, 52 | }; 53 | use llvm_sys::prelude::{LLVMTypeRef, LLVMValueRef}; 54 | use llvm_sys::LLVMTypeKind; 55 | #[cfg(feature = "experimental")] 56 | use static_alloc::Bump; 57 | 58 | use std::fmt; 59 | use std::marker::PhantomData; 60 | 61 | use crate::context::ContextRef; 62 | use crate::support::LLVMString; 63 | use crate::values::IntValue; 64 | use crate::AddressSpace; 65 | 66 | // Worth noting that types seem to be singletons. At the very least, primitives are. 67 | // Though this is likely only true per thread since LLVM claims to not be very thread-safe. 68 | #[derive(PartialEq, Eq, Clone, Copy)] 69 | struct Type<'ctx> { 70 | ty: LLVMTypeRef, 71 | _marker: PhantomData<&'ctx ()>, 72 | } 73 | 74 | impl<'ctx> Type<'ctx> { 75 | unsafe fn new(ty: LLVMTypeRef) -> Self { 76 | assert!(!ty.is_null()); 77 | 78 | Type { 79 | ty, 80 | _marker: PhantomData, 81 | } 82 | } 83 | 84 | fn const_zero(self) -> LLVMValueRef { 85 | unsafe { 86 | match LLVMGetTypeKind(self.ty) { 87 | LLVMTypeKind::LLVMMetadataTypeKind => LLVMConstPointerNull(self.ty), 88 | _ => LLVMConstNull(self.ty), 89 | } 90 | } 91 | } 92 | 93 | fn ptr_type(self, address_space: AddressSpace) -> PointerType<'ctx> { 94 | unsafe { PointerType::new(LLVMPointerType(self.ty, address_space.0)) } 95 | } 96 | 97 | fn vec_type(self, size: u32) -> VectorType<'ctx> { 98 | assert!(size != 0, "Vectors of size zero are not allowed."); 99 | // -- https://llvm.org/docs/LangRef.html#vector-type 100 | 101 | unsafe { VectorType::new(LLVMVectorType(self.ty, size)) } 102 | } 103 | 104 | #[llvm_versions(12..)] 105 | fn scalable_vec_type(self, size: u32) -> ScalableVectorType<'ctx> { 106 | assert!(size != 0, "Vectors of size zero are not allowed."); 107 | // -- https://llvm.org/docs/LangRef.html#vector-type 108 | 109 | unsafe { ScalableVectorType::new(LLVMScalableVectorType(self.ty, size)) } 110 | } 111 | 112 | #[cfg(not(feature = "experimental"))] 113 | fn fn_type(self, param_types: &[BasicMetadataTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { 114 | let mut param_types: Vec = param_types.iter().map(|val| val.as_type_ref()).collect(); 115 | unsafe { 116 | FunctionType::new(LLVMFunctionType( 117 | self.ty, 118 | param_types.as_mut_ptr(), 119 | param_types.len() as u32, 120 | is_var_args as i32, 121 | )) 122 | } 123 | } 124 | 125 | #[cfg(feature = "experimental")] 126 | fn fn_type(self, param_types: &[BasicMetadataTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { 127 | let pool: Bump<[usize; 16]> = Bump::uninit(); 128 | let mut pool_start = None; 129 | 130 | for (i, param_type) in param_types.iter().enumerate() { 131 | let addr = pool.leak(param_type.as_type_ref()).expect("Found more than 16 params"); 132 | 133 | if i == 0 { 134 | pool_start = Some(addr as *mut _); 135 | } 136 | } 137 | 138 | unsafe { 139 | FunctionType::new(LLVMFunctionType( 140 | self.ty, 141 | pool_start.unwrap_or(std::ptr::null_mut()), 142 | param_types.len() as u32, 143 | is_var_args as i32, 144 | )) 145 | } 146 | } 147 | 148 | #[allow(deprecated)] 149 | fn array_type(self, size: u32) -> ArrayType<'ctx> { 150 | unsafe { ArrayType::new(LLVMArrayType(self.ty, size)) } 151 | } 152 | 153 | fn get_undef(self) -> LLVMValueRef { 154 | unsafe { LLVMGetUndef(self.ty) } 155 | } 156 | 157 | #[llvm_versions(12..)] 158 | fn get_poison(&self) -> LLVMValueRef { 159 | unsafe { LLVMGetPoison(self.ty) } 160 | } 161 | 162 | fn get_alignment(self) -> IntValue<'ctx> { 163 | unsafe { IntValue::new(LLVMAlignOf(self.ty)) } 164 | } 165 | 166 | fn get_context(self) -> ContextRef<'ctx> { 167 | unsafe { ContextRef::new(LLVMGetTypeContext(self.ty)) } 168 | } 169 | 170 | // REVIEW: This should be known at compile time, maybe as a const fn? 171 | // On an enum or trait, this would not be known at compile time (unless 172 | // enum has only sized types for example) 173 | fn is_sized(self) -> bool { 174 | unsafe { LLVMTypeIsSized(self.ty) == 1 } 175 | } 176 | 177 | fn size_of(self) -> Option> { 178 | if !self.is_sized() { 179 | return None; 180 | } 181 | 182 | unsafe { Some(IntValue::new(LLVMSizeOf(self.ty))) } 183 | } 184 | 185 | fn print_to_string(self) -> LLVMString { 186 | unsafe { LLVMString::new(LLVMPrintTypeToString(self.ty)) } 187 | } 188 | 189 | pub fn get_element_type(self) -> AnyTypeEnum<'ctx> { 190 | unsafe { AnyTypeEnum::new(LLVMGetElementType(self.ty)) } 191 | } 192 | } 193 | 194 | impl fmt::Debug for Type<'_> { 195 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 196 | let llvm_type = self.print_to_string(); 197 | 198 | f.debug_struct("Type") 199 | .field("address", &self.ty) 200 | .field("llvm_type", &llvm_type) 201 | .finish() 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /src/types/traits.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::prelude::LLVMTypeRef; 2 | 3 | use std::fmt::Debug; 4 | 5 | use crate::support::LLVMString; 6 | use crate::types::enums::{AnyTypeEnum, BasicMetadataTypeEnum, BasicTypeEnum}; 7 | use crate::types::{ 8 | ArrayType, FloatType, FunctionType, IntType, PointerType, ScalableVectorType, StructType, Type, VectorType, 9 | VoidType, 10 | }; 11 | use crate::values::{ 12 | FloatMathValue, FloatValue, IntMathValue, IntValue, PointerMathValue, PointerValue, ScalableVectorValue, 13 | VectorValue, 14 | }; 15 | use crate::AddressSpace; 16 | 17 | /// Accessor to the inner LLVM type reference 18 | pub unsafe trait AsTypeRef { 19 | /// Returns the internal LLVM reference behind the type 20 | fn as_type_ref(&self) -> LLVMTypeRef; 21 | } 22 | 23 | macro_rules! trait_type_set { 24 | ($trait_name:ident: $($args:ident),*) => ( 25 | $( 26 | unsafe impl<'ctx> $trait_name<'ctx> for $args<'ctx> {} 27 | )* 28 | ); 29 | } 30 | 31 | /// Represents any LLVM type. 32 | pub unsafe trait AnyType<'ctx>: AsTypeRef + Debug { 33 | /// Returns an `AnyTypeEnum` that represents the current type. 34 | fn as_any_type_enum(&self) -> AnyTypeEnum<'ctx> { 35 | unsafe { AnyTypeEnum::new(self.as_type_ref()) } 36 | } 37 | 38 | /// Prints the definition of a Type to a `LLVMString`. 39 | fn print_to_string(&self) -> LLVMString { 40 | unsafe { Type::new(self.as_type_ref()).print_to_string() } 41 | } 42 | } 43 | 44 | /// Represents a basic LLVM type, that may be used in functions and struct definitions. 45 | pub unsafe trait BasicType<'ctx>: AnyType<'ctx> { 46 | /// Returns a `BasicTypeEnum` that represents the current type. 47 | fn as_basic_type_enum(&self) -> BasicTypeEnum<'ctx> { 48 | unsafe { BasicTypeEnum::new(self.as_type_ref()) } 49 | } 50 | 51 | /// Create a `FunctionType` with this `BasicType` as its return type. 52 | /// 53 | /// # Example: 54 | /// 55 | /// ```no_run 56 | /// use inkwell::context::Context; 57 | /// use inkwell::types::BasicType; 58 | /// 59 | /// let context = Context::create(); 60 | /// let int = context.i32_type(); 61 | /// let int_basic_type = int.as_basic_type_enum(); 62 | /// assert_eq!(int_basic_type.fn_type(&[], false), int.fn_type(&[], false)); 63 | /// ``` 64 | fn fn_type(&self, param_types: &[BasicMetadataTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { 65 | unsafe { Type::new(self.as_type_ref()).fn_type(param_types, is_var_args) } 66 | } 67 | 68 | /// Determines whether or not this `BasicType` is sized or not. 69 | /// For example, opaque structs are unsized. 70 | /// 71 | /// # Example 72 | /// 73 | /// ```no_run 74 | /// use inkwell::context::Context; 75 | /// use inkwell::types::BasicType; 76 | /// 77 | /// let context = Context::create(); 78 | /// let f32_type = context.f32_type(); 79 | /// let f32_vec_type = f32_type.vec_type(40); 80 | /// 81 | /// assert!(f32_vec_type.is_sized()); 82 | /// ``` 83 | fn is_sized(&self) -> bool { 84 | unsafe { Type::new(self.as_type_ref()).is_sized() } 85 | } 86 | 87 | /// Gets the size of this `BasicType`. Value may vary depending on the target architecture. 88 | /// 89 | /// # Example 90 | /// 91 | /// ```no_run 92 | /// use inkwell::context::Context; 93 | /// use inkwell::types::BasicType; 94 | /// 95 | /// let context = Context::create(); 96 | /// let f32_type = context.f32_type(); 97 | /// let f32_basic_type = f32_type.as_basic_type_enum(); 98 | /// let f32_type_size = f32_basic_type.size_of(); 99 | /// ``` 100 | fn size_of(&self) -> Option> { 101 | unsafe { Type::new(self.as_type_ref()).size_of() } 102 | } 103 | 104 | /// Create an `ArrayType` with this `BasicType` as its elements. 105 | /// 106 | /// Example: 107 | /// ```no_run 108 | /// use inkwell::context::Context; 109 | /// use inkwell::types::BasicType; 110 | /// 111 | /// let context = Context::create(); 112 | /// let int = context.i32_type(); 113 | /// let int_basic_type = int.as_basic_type_enum(); 114 | /// assert_eq!(int_basic_type.array_type(32), int.array_type(32)); 115 | /// ``` 116 | // FIXME: This likely doesn't belong on the trait, since not all basic types can be turned into arrays? 117 | fn array_type(&self, size: u32) -> ArrayType<'ctx> { 118 | unsafe { Type::new(self.as_type_ref()).array_type(size) } 119 | } 120 | 121 | /// Create a `PointerType` that points to this `BasicType`. 122 | /// 123 | /// Example: 124 | /// ```no_run 125 | /// use inkwell::context::Context; 126 | /// use inkwell::types::BasicType; 127 | /// use inkwell::AddressSpace; 128 | /// 129 | /// let context = Context::create(); 130 | /// let int = context.i32_type(); 131 | /// let int_basic_type = int.as_basic_type_enum(); 132 | /// let addr_space = AddressSpace::default(); 133 | /// assert_eq!(int_basic_type.ptr_type(addr_space), int.ptr_type(addr_space)); 134 | /// ``` 135 | #[cfg_attr( 136 | any( 137 | all(feature = "llvm15-0", not(feature = "typed-pointers")), 138 | all(feature = "llvm16-0", not(feature = "typed-pointers")), 139 | feature = "llvm17-0", 140 | feature = "llvm18-1" 141 | ), 142 | deprecated( 143 | note = "Starting from version 15.0, LLVM doesn't differentiate between pointer types. Use Context::ptr_type instead." 144 | ) 145 | )] 146 | fn ptr_type(&self, address_space: AddressSpace) -> PointerType<'ctx> { 147 | unsafe { Type::new(self.as_type_ref()).ptr_type(address_space) } 148 | } 149 | } 150 | 151 | /// Represents an LLVM type that can have integer math operations applied to it. 152 | pub unsafe trait IntMathType<'ctx>: BasicType<'ctx> { 153 | /// The value instance of an int or int vector type. 154 | type ValueType: IntMathValue<'ctx>; 155 | /// The type for int to float or int vector to float vector conversions. 156 | type MathConvType: FloatMathType<'ctx>; 157 | /// The type for int to pointer or int vector to pointer vector conversions. 158 | type PtrConvType: PointerMathType<'ctx>; 159 | } 160 | 161 | /// Represents an LLVM type that can have floating point math operations applied to it. 162 | pub unsafe trait FloatMathType<'ctx>: BasicType<'ctx> { 163 | /// The value instance of a float or float vector type. 164 | type ValueType: FloatMathValue<'ctx>; 165 | /// The type for float to int or float vector to int vector conversions. 166 | type MathConvType: IntMathType<'ctx>; 167 | } 168 | 169 | /// Represents an LLVM type that can have pointer operations applied to it. 170 | pub unsafe trait PointerMathType<'ctx>: BasicType<'ctx> { 171 | /// The value instance of a pointer type. 172 | type ValueType: PointerMathValue<'ctx>; 173 | /// The type for pointer to int or pointer vector to int conversions. 174 | type PtrConvType: IntMathType<'ctx>; 175 | } 176 | 177 | trait_type_set! {AnyType: AnyTypeEnum, BasicTypeEnum, IntType, FunctionType, FloatType, PointerType, StructType, ArrayType, VoidType, VectorType, ScalableVectorType} 178 | trait_type_set! {BasicType: BasicTypeEnum, IntType, FloatType, PointerType, StructType, ArrayType, VectorType, ScalableVectorType} 179 | 180 | unsafe impl<'ctx> IntMathType<'ctx> for IntType<'ctx> { 181 | type ValueType = IntValue<'ctx>; 182 | type MathConvType = FloatType<'ctx>; 183 | type PtrConvType = PointerType<'ctx>; 184 | } 185 | 186 | unsafe impl<'ctx> IntMathType<'ctx> for VectorType<'ctx> { 187 | type ValueType = VectorValue<'ctx>; 188 | type MathConvType = VectorType<'ctx>; 189 | type PtrConvType = VectorType<'ctx>; 190 | } 191 | 192 | unsafe impl<'ctx> IntMathType<'ctx> for ScalableVectorType<'ctx> { 193 | type ValueType = ScalableVectorValue<'ctx>; 194 | type MathConvType = ScalableVectorType<'ctx>; 195 | type PtrConvType = ScalableVectorType<'ctx>; 196 | } 197 | 198 | unsafe impl<'ctx> FloatMathType<'ctx> for FloatType<'ctx> { 199 | type ValueType = FloatValue<'ctx>; 200 | type MathConvType = IntType<'ctx>; 201 | } 202 | 203 | unsafe impl<'ctx> FloatMathType<'ctx> for VectorType<'ctx> { 204 | type ValueType = VectorValue<'ctx>; 205 | type MathConvType = VectorType<'ctx>; 206 | } 207 | 208 | unsafe impl<'ctx> FloatMathType<'ctx> for ScalableVectorType<'ctx> { 209 | type ValueType = ScalableVectorValue<'ctx>; 210 | type MathConvType = ScalableVectorType<'ctx>; 211 | } 212 | 213 | unsafe impl<'ctx> PointerMathType<'ctx> for PointerType<'ctx> { 214 | type ValueType = PointerValue<'ctx>; 215 | type PtrConvType = IntType<'ctx>; 216 | } 217 | 218 | unsafe impl<'ctx> PointerMathType<'ctx> for VectorType<'ctx> { 219 | type ValueType = VectorValue<'ctx>; 220 | type PtrConvType = VectorType<'ctx>; 221 | } 222 | 223 | unsafe impl<'ctx> PointerMathType<'ctx> for ScalableVectorType<'ctx> { 224 | type ValueType = ScalableVectorValue<'ctx>; 225 | type PtrConvType = ScalableVectorType<'ctx>; 226 | } 227 | -------------------------------------------------------------------------------- /src/types/void_type.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::prelude::LLVMTypeRef; 2 | 3 | use crate::context::ContextRef; 4 | use crate::support::LLVMString; 5 | use crate::types::enums::BasicMetadataTypeEnum; 6 | use crate::types::traits::AsTypeRef; 7 | use crate::types::{FunctionType, Type}; 8 | 9 | use std::fmt::{self, Display}; 10 | 11 | /// A `VoidType` is a special type with no possible direct instances. It's only 12 | /// useful as a function return type. 13 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] 14 | pub struct VoidType<'ctx> { 15 | void_type: Type<'ctx>, 16 | } 17 | 18 | impl<'ctx> VoidType<'ctx> { 19 | /// Create `VoidType` from [`LLVMTypeRef`] 20 | /// 21 | /// # Safety 22 | /// Undefined behavior, if referenced type isn't void type 23 | pub unsafe fn new(void_type: LLVMTypeRef) -> Self { 24 | assert!(!void_type.is_null()); 25 | 26 | VoidType { 27 | void_type: Type::new(void_type), 28 | } 29 | } 30 | 31 | // REVIEW: Always false -> const fn? 32 | /// Gets whether or not this `VoidType` is sized or not. This may always 33 | /// be false and as such this function may be removed in the future. 34 | /// 35 | /// # Example 36 | /// 37 | /// ```no_run 38 | /// use inkwell::context::Context; 39 | /// 40 | /// let context = Context::create(); 41 | /// let void_type = context.void_type(); 42 | /// 43 | /// assert!(void_type.is_sized()); 44 | /// ``` 45 | pub fn is_sized(self) -> bool { 46 | self.void_type.is_sized() 47 | } 48 | 49 | /// Gets a reference to the `Context` this `VoidType` was created in. 50 | /// 51 | /// # Example 52 | /// 53 | /// ```no_run 54 | /// use inkwell::context::Context; 55 | /// 56 | /// let context = Context::create(); 57 | /// let void_type = context.void_type(); 58 | /// 59 | /// assert_eq!(void_type.get_context(), context); 60 | /// ``` 61 | pub fn get_context(self) -> ContextRef<'ctx> { 62 | self.void_type.get_context() 63 | } 64 | 65 | /// Creates a `FunctionType` with this `VoidType` for its return type. 66 | /// This means the function does not return. 67 | /// 68 | /// # Example 69 | /// 70 | /// ```no_run 71 | /// use inkwell::context::Context; 72 | /// 73 | /// let context = Context::create(); 74 | /// let void_type = context.void_type(); 75 | /// let fn_type = void_type.fn_type(&[], false); 76 | /// ``` 77 | pub fn fn_type(self, param_types: &[BasicMetadataTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { 78 | self.void_type.fn_type(param_types, is_var_args) 79 | } 80 | 81 | /// Print the definition of a `VoidType` to `LLVMString`. 82 | pub fn print_to_string(self) -> LLVMString { 83 | self.void_type.print_to_string() 84 | } 85 | } 86 | 87 | unsafe impl AsTypeRef for VoidType<'_> { 88 | fn as_type_ref(&self) -> LLVMTypeRef { 89 | self.void_type.ty 90 | } 91 | } 92 | 93 | impl Display for VoidType<'_> { 94 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 95 | write!(f, "{}", self.print_to_string()) 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/values/array_value.rs: -------------------------------------------------------------------------------- 1 | #[llvm_versions(..17)] 2 | use llvm_sys::core::LLVMConstArray; 3 | #[llvm_versions(17..)] 4 | use llvm_sys::core::LLVMConstArray2 as LLVMConstArray; 5 | use llvm_sys::core::{LLVMGetAsString, LLVMIsAConstantArray, LLVMIsAConstantDataArray, LLVMIsConstantString}; 6 | use llvm_sys::prelude::LLVMTypeRef; 7 | use llvm_sys::prelude::LLVMValueRef; 8 | 9 | use std::ffi::CStr; 10 | use std::fmt::{self, Display}; 11 | 12 | use crate::types::{ArrayType, AsTypeRef}; 13 | use crate::values::traits::{AnyValue, AsValueRef}; 14 | use crate::values::{InstructionValue, Value}; 15 | 16 | /// An `ArrayValue` is a block of contiguous constants or variables. 17 | #[derive(PartialEq, Eq, Clone, Copy, Hash)] 18 | pub struct ArrayValue<'ctx> { 19 | array_value: Value<'ctx>, 20 | } 21 | 22 | impl<'ctx> ArrayValue<'ctx> { 23 | /// Get a value from an [LLVMValueRef]. 24 | /// 25 | /// # Safety 26 | /// 27 | /// The ref must be valid and of type array. 28 | pub unsafe fn new(value: LLVMValueRef) -> Self { 29 | assert!(!value.is_null()); 30 | 31 | ArrayValue { 32 | array_value: Value::new(value), 33 | } 34 | } 35 | 36 | /// Creates a new constant `ArrayValue` with the given type and values. 37 | /// 38 | /// # Safety 39 | /// 40 | /// `values` must be of the same type as `ty`. 41 | pub unsafe fn new_const_array(ty: &T, values: &[V]) -> Self { 42 | let values = values.iter().map(V::as_value_ref).collect::>(); 43 | Self::new_raw_const_array(ty.as_type_ref(), &values) 44 | } 45 | 46 | /// Creates a new constant `ArrayValue` with the given type and values. 47 | /// 48 | /// # Safety 49 | /// 50 | /// `values` must be of the same type as `ty`. 51 | pub unsafe fn new_raw_const_array(ty: LLVMTypeRef, values: &[LLVMValueRef]) -> Self { 52 | unsafe { Self::new(LLVMConstArray(ty, values.as_ptr().cast_mut(), values.len() as _)) } 53 | } 54 | 55 | /// Get name of the `ArrayValue`. If the value is a constant, this will 56 | /// return an empty string. 57 | pub fn get_name(&self) -> &CStr { 58 | self.array_value.get_name() 59 | } 60 | 61 | /// Set name of the `ArrayValue`. 62 | pub fn set_name(&self, name: &str) { 63 | self.array_value.set_name(name) 64 | } 65 | 66 | /// Gets the type of this `ArrayValue`. 67 | pub fn get_type(self) -> ArrayType<'ctx> { 68 | unsafe { ArrayType::new(self.array_value.get_type()) } 69 | } 70 | 71 | /// Determines whether or not this value is null. 72 | pub fn is_null(self) -> bool { 73 | self.array_value.is_null() 74 | } 75 | 76 | /// Determines whether or not this value is undefined. 77 | pub fn is_undef(self) -> bool { 78 | self.array_value.is_undef() 79 | } 80 | 81 | /// Prints this `ArrayValue` to standard error. 82 | pub fn print_to_stderr(self) { 83 | self.array_value.print_to_stderr() 84 | } 85 | 86 | /// Attempt to convert this `ArrayValue` to an `InstructionValue`, if possible. 87 | pub fn as_instruction(self) -> Option> { 88 | self.array_value.as_instruction() 89 | } 90 | 91 | /// Replaces all uses of this value with another value of the same type. 92 | /// If used incorrectly this may result in invalid IR. 93 | pub fn replace_all_uses_with(self, other: ArrayValue<'ctx>) { 94 | self.array_value.replace_all_uses_with(other.as_value_ref()) 95 | } 96 | 97 | /// Determines whether or not an `ArrayValue` is a constant. 98 | /// 99 | /// # Example 100 | /// 101 | /// ```no_run 102 | /// use inkwell::context::Context; 103 | /// 104 | /// let context = Context::create(); 105 | /// let i64_type = context.i64_type(); 106 | /// let i64_val = i64_type.const_int(23, false); 107 | /// let array_val = i64_type.const_array(&[i64_val]); 108 | /// 109 | /// assert!(array_val.is_const()); 110 | /// ``` 111 | pub fn is_const(self) -> bool { 112 | self.array_value.is_const() 113 | } 114 | 115 | /// Determines whether or not an `ArrayValue` represents a constant array of `i8`s. 116 | /// 117 | /// # Example 118 | /// 119 | /// ```no_run 120 | /// use inkwell::context::Context; 121 | /// 122 | /// let context = Context::create(); 123 | /// let string = context.const_string(b"my_string", false); 124 | /// 125 | /// assert!(string.is_const_string()); 126 | /// ``` 127 | // SubTypes: Impl only for ArrayValue> 128 | pub fn is_const_string(self) -> bool { 129 | unsafe { LLVMIsConstantString(self.as_value_ref()) == 1 } 130 | } 131 | 132 | /// Obtain the string from the ArrayValue 133 | /// if the value points to a constant string. 134 | /// 135 | /// # Example 136 | /// 137 | /// ```no_run 138 | /// use inkwell::context::Context; 139 | /// use std::ffi::CStr; 140 | /// 141 | /// let context = Context::create(); 142 | /// let string = context.const_string(b"hello!", false); 143 | /// 144 | /// let result = b"hello!".as_slice(); 145 | /// assert_eq!(string.as_const_string(), Some(result)); 146 | /// ``` 147 | // SubTypes: Impl only for ArrayValue> 148 | pub fn as_const_string(&self) -> Option<&[u8]> { 149 | let mut len = 0; 150 | let ptr = unsafe { LLVMGetAsString(self.as_value_ref(), &mut len) }; 151 | 152 | if ptr.is_null() { 153 | None 154 | } else { 155 | unsafe { Some(std::slice::from_raw_parts(ptr.cast(), len)) } 156 | } 157 | } 158 | 159 | /// Obtain the string from the ArrayValue 160 | /// if the value points to a constant string. 161 | /// 162 | /// # Example 163 | /// 164 | /// ```no_run 165 | /// use inkwell::context::Context; 166 | /// use std::ffi::CStr; 167 | /// 168 | /// let context = Context::create(); 169 | /// let string = context.const_string(b"hello!", true); 170 | /// 171 | /// let result = CStr::from_bytes_with_nul(b"hello!\0").unwrap(); 172 | /// assert_eq!(string.get_string_constant(), Some(result)); 173 | /// ``` 174 | // SubTypes: Impl only for ArrayValue> 175 | #[deprecated = "llvm strings can contain internal NULs, and this function truncates such values, use as_const_string instead"] 176 | pub fn get_string_constant(&self) -> Option<&CStr> { 177 | let mut len = 0; 178 | let ptr = unsafe { LLVMGetAsString(self.as_value_ref(), &mut len) }; 179 | 180 | if ptr.is_null() { 181 | None 182 | } else { 183 | unsafe { Some(CStr::from_ptr(ptr)) } 184 | } 185 | } 186 | } 187 | 188 | unsafe impl AsValueRef for ArrayValue<'_> { 189 | fn as_value_ref(&self) -> LLVMValueRef { 190 | self.array_value.value 191 | } 192 | } 193 | 194 | impl Display for ArrayValue<'_> { 195 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 196 | write!(f, "{}", self.print_to_string()) 197 | } 198 | } 199 | 200 | impl fmt::Debug for ArrayValue<'_> { 201 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 202 | let llvm_value = self.print_to_string(); 203 | let llvm_type = self.get_type(); 204 | let name = self.get_name(); 205 | let is_const = self.is_const(); 206 | let is_null = self.is_null(); 207 | let is_const_array = unsafe { !LLVMIsAConstantArray(self.as_value_ref()).is_null() }; 208 | let is_const_data_array = unsafe { !LLVMIsAConstantDataArray(self.as_value_ref()).is_null() }; 209 | 210 | f.debug_struct("ArrayValue") 211 | .field("name", &name) 212 | .field("address", &self.as_value_ref()) 213 | .field("is_const", &is_const) 214 | .field("is_const_array", &is_const_array) 215 | .field("is_const_data_array", &is_const_data_array) 216 | .field("is_null", &is_null) 217 | .field("llvm_value", &llvm_value) 218 | .field("llvm_type", &llvm_type) 219 | .finish() 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /src/values/basic_value_use.rs: -------------------------------------------------------------------------------- 1 | use either::{ 2 | Either, 3 | Either::{Left, Right}, 4 | }; 5 | use llvm_sys::core::{LLVMGetNextUse, LLVMGetUsedValue, LLVMGetUser, LLVMIsABasicBlock, LLVMValueAsBasicBlock}; 6 | use llvm_sys::prelude::LLVMUseRef; 7 | 8 | use std::marker::PhantomData; 9 | 10 | use crate::basic_block::BasicBlock; 11 | use crate::values::{AnyValueEnum, BasicValueEnum}; 12 | 13 | /// A usage of a `BasicValue` in another value. 14 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] 15 | pub struct BasicValueUse<'ctx>(LLVMUseRef, PhantomData<&'ctx ()>); 16 | 17 | impl<'ctx> BasicValueUse<'ctx> { 18 | /// Get a value from an [LLVMUseRef]. 19 | /// 20 | /// # Safety 21 | /// 22 | /// The ref must be valid and of type basic value. 23 | pub unsafe fn new(use_: LLVMUseRef) -> Self { 24 | debug_assert!(!use_.is_null()); 25 | 26 | BasicValueUse(use_, PhantomData) 27 | } 28 | 29 | /// Gets the next use of a `BasicBlock`, `InstructionValue` or `BasicValue` if any. 30 | /// 31 | /// The following example, 32 | /// 33 | /// ```no_run 34 | /// use inkwell::AddressSpace; 35 | /// use inkwell::context::Context; 36 | /// use inkwell::values::BasicValue; 37 | /// 38 | /// let context = Context::create(); 39 | /// let module = context.create_module("ivs"); 40 | /// let builder = context.create_builder(); 41 | /// let void_type = context.void_type(); 42 | /// let f32_type = context.f32_type(); 43 | /// #[cfg(feature = "typed-pointers")] 44 | /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default()); 45 | /// #[cfg(not(feature = "typed-pointers"))] 46 | /// let f32_ptr_type = context.ptr_type(AddressSpace::default()); 47 | /// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false); 48 | /// 49 | /// let function = module.add_function("take_f32_ptr", fn_type, None); 50 | /// let basic_block = context.append_basic_block(function, "entry"); 51 | /// 52 | /// builder.position_at_end(basic_block); 53 | /// 54 | /// let arg1 = function.get_first_param().unwrap().into_pointer_value(); 55 | /// let f32_val = f32_type.const_float(std::f64::consts::PI); 56 | /// let store_instruction = builder.build_store(arg1, f32_val).unwrap(); 57 | /// let free_instruction = builder.build_free(arg1).unwrap(); 58 | /// let return_instruction = builder.build_return(None).unwrap(); 59 | /// 60 | /// let arg1_first_use = arg1.get_first_use().unwrap(); 61 | /// 62 | /// assert!(arg1_first_use.get_next_use().is_some()); 63 | /// ``` 64 | /// 65 | /// will generate LLVM IR roughly like (varying slightly across LLVM versions): 66 | /// 67 | /// ```ir 68 | /// ; ModuleID = 'ivs' 69 | /// source_filename = "ivs" 70 | /// 71 | /// define void @take_f32_ptr(float* %0) { 72 | /// entry: 73 | /// store float 0x400921FB60000000, float* %0 74 | /// %1 = bitcast float* %0 to i8* 75 | /// tail call void @free(i8* %1) 76 | /// ret void 77 | /// } 78 | /// 79 | /// declare void @free(i8*) 80 | /// ``` 81 | /// 82 | /// which makes the arg1 (%0) uses clear: 83 | /// 1) In the store instruction 84 | /// 2) In the pointer bitcast 85 | pub fn get_next_use(self) -> Option { 86 | let use_ = unsafe { LLVMGetNextUse(self.0) }; 87 | 88 | if use_.is_null() { 89 | return None; 90 | } 91 | 92 | unsafe { Some(Self::new(use_)) } 93 | } 94 | 95 | /// Gets the user (an `AnyValueEnum`) of this use. 96 | /// 97 | /// ```no_run 98 | /// use inkwell::AddressSpace; 99 | /// use inkwell::context::Context; 100 | /// use inkwell::values::BasicValue; 101 | /// 102 | /// let context = Context::create(); 103 | /// let module = context.create_module("ivs"); 104 | /// let builder = context.create_builder(); 105 | /// let void_type = context.void_type(); 106 | /// let f32_type = context.f32_type(); 107 | /// #[cfg(feature = "typed-pointers")] 108 | /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default()); 109 | /// #[cfg(not(feature = "typed-pointers"))] 110 | /// let f32_ptr_type = context.ptr_type(AddressSpace::default()); 111 | /// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false); 112 | /// 113 | /// let function = module.add_function("take_f32_ptr", fn_type, None); 114 | /// let basic_block = context.append_basic_block(function, "entry"); 115 | /// 116 | /// builder.position_at_end(basic_block); 117 | /// 118 | /// let arg1 = function.get_first_param().unwrap().into_pointer_value(); 119 | /// let f32_val = f32_type.const_float(std::f64::consts::PI); 120 | /// let store_instruction = builder.build_store(arg1, f32_val).unwrap(); 121 | /// let free_instruction = builder.build_free(arg1).unwrap(); 122 | /// let return_instruction = builder.build_return(None).unwrap(); 123 | /// 124 | /// let store_operand_use0 = store_instruction.get_operand_use(0).unwrap(); 125 | /// let store_operand_use1 = store_instruction.get_operand_use(1).unwrap(); 126 | /// 127 | /// assert_eq!(store_operand_use0.get_user(), store_instruction); 128 | /// assert_eq!(store_operand_use1.get_user(), store_instruction); 129 | /// ``` 130 | pub fn get_user(self) -> AnyValueEnum<'ctx> { 131 | unsafe { AnyValueEnum::new(LLVMGetUser(self.0)) } 132 | } 133 | 134 | /// Gets the used value (a `BasicValueEnum` or `BasicBlock`) of this use. 135 | /// 136 | /// ```no_run 137 | /// use inkwell::AddressSpace; 138 | /// use inkwell::context::Context; 139 | /// use inkwell::values::BasicValue; 140 | /// 141 | /// let context = Context::create(); 142 | /// let module = context.create_module("ivs"); 143 | /// let builder = context.create_builder(); 144 | /// let void_type = context.void_type(); 145 | /// let f32_type = context.f32_type(); 146 | /// #[cfg(feature = "typed-pointers")] 147 | /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default()); 148 | /// #[cfg(not(feature = "typed-pointers"))] 149 | /// let f32_ptr_type = context.ptr_type(AddressSpace::default()); 150 | /// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false); 151 | /// 152 | /// let function = module.add_function("take_f32_ptr", fn_type, None); 153 | /// let basic_block = context.append_basic_block(function, "entry"); 154 | /// 155 | /// builder.position_at_end(basic_block); 156 | /// 157 | /// let arg1 = function.get_first_param().unwrap().into_pointer_value(); 158 | /// let f32_val = f32_type.const_float(std::f64::consts::PI); 159 | /// let store_instruction = builder.build_store(arg1, f32_val).unwrap(); 160 | /// let free_instruction = builder.build_free(arg1).unwrap(); 161 | /// let return_instruction = builder.build_return(None).unwrap(); 162 | /// 163 | /// let free_operand0 = free_instruction.get_operand(0).unwrap().left().unwrap(); 164 | /// let free_operand0_instruction = free_operand0.as_instruction_value().unwrap(); 165 | /// let bitcast_use_value = free_operand0_instruction 166 | /// .get_first_use() 167 | /// .unwrap() 168 | /// .get_used_value() 169 | /// .left() 170 | /// .unwrap(); 171 | /// 172 | /// assert_eq!(bitcast_use_value, free_operand0); 173 | /// ``` 174 | pub fn get_used_value(self) -> Either, BasicBlock<'ctx>> { 175 | let used_value = unsafe { LLVMGetUsedValue(self.0) }; 176 | 177 | let is_basic_block = unsafe { !LLVMIsABasicBlock(used_value).is_null() }; 178 | 179 | if is_basic_block { 180 | let bb = unsafe { BasicBlock::new(LLVMValueAsBasicBlock(used_value)) }; 181 | 182 | Right(bb.expect("BasicBlock should always be valid")) 183 | } else { 184 | unsafe { Left(BasicValueEnum::new(used_value)) } 185 | } 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/values/callable_value.rs: -------------------------------------------------------------------------------- 1 | use either::Either; 2 | use std::convert::TryFrom; 3 | use std::fmt::{self, Display}; 4 | 5 | use crate::types::AsTypeRef; 6 | use crate::values::AsValueRef; 7 | use crate::values::{AnyValue, FunctionValue, PointerValue}; 8 | 9 | use llvm_sys::core::{LLVMGetElementType, LLVMGetTypeKind, LLVMTypeOf}; 10 | use llvm_sys::prelude::LLVMTypeRef; 11 | use llvm_sys::prelude::LLVMValueRef; 12 | use llvm_sys::LLVMTypeKind; 13 | 14 | /// A value that can be called with the [`build_call`] instruction. 15 | /// 16 | /// In practice, the `F : Into>` bound of [`build_call`] means it is 17 | /// possible to pass a [`FunctionValue`] to [`build_call`] directly. It will be implicitly converted 18 | /// into a `CallableValue`. 19 | /// 20 | /// [`build_call`]: crate::builder::Builder::build_call 21 | /// 22 | /// ```no_run 23 | /// use inkwell::context::Context; 24 | /// 25 | /// // A simple function which calls itself: 26 | /// let context = Context::create(); 27 | /// let module = context.create_module("ret"); 28 | /// let builder = context.create_builder(); 29 | /// let i32_type = context.i32_type(); 30 | /// let fn_type = i32_type.fn_type(&[i32_type.into()], false); 31 | /// let fn_value = module.add_function("ret", fn_type, None); 32 | /// let entry = context.append_basic_block(fn_value, "entry"); 33 | /// let i32_arg = fn_value.get_first_param().unwrap(); 34 | /// 35 | /// builder.position_at_end(entry); 36 | /// 37 | /// let ret_val = builder.build_call(fn_value, &[i32_arg.into()], "call").unwrap() 38 | /// .try_as_basic_value() 39 | /// .left() 40 | /// .unwrap(); 41 | /// 42 | /// builder.build_return(Some(&ret_val)).unwrap(); 43 | /// ``` 44 | /// 45 | /// A [`PointerValue`] cannot be implicitly converted to a `CallableValue` because the pointer may 46 | /// point to a non-function value. Instead we can use [`TryFrom`] to handle this failure case explicitly. 47 | /// 48 | /// ```no_run 49 | /// use std::convert::TryFrom; 50 | /// use inkwell::context::Context; 51 | /// use inkwell::values::CallableValue; 52 | /// 53 | /// // A simple function which calls itself: 54 | /// let context = Context::create(); 55 | /// let module = context.create_module("ret"); 56 | /// let builder = context.create_builder(); 57 | /// let i32_type = context.i32_type(); 58 | /// let fn_type = i32_type.fn_type(&[i32_type.into()], false); 59 | /// let fn_value = module.add_function("ret", fn_type, None); 60 | /// let entry = context.append_basic_block(fn_value, "entry"); 61 | /// let i32_arg = fn_value.get_first_param().unwrap(); 62 | /// 63 | /// builder.position_at_end(entry); 64 | /// 65 | /// // take a pointer to the function value 66 | /// let fn_pointer_value = fn_value.as_global_value().as_pointer_value(); 67 | /// 68 | /// // convert that pointer value into a callable value 69 | /// // explicitly handling the failure case (here with `unwrap`) 70 | /// let callable_value = CallableValue::try_from(fn_pointer_value).unwrap(); 71 | /// 72 | /// let ret_val = builder.build_call(callable_value, &[i32_arg.into()], "call").unwrap() 73 | /// .try_as_basic_value() 74 | /// .left() 75 | /// .unwrap(); 76 | /// 77 | /// builder.build_return(Some(&ret_val)).unwrap(); 78 | /// ``` 79 | #[derive(Debug)] 80 | pub struct CallableValue<'ctx>(Either, PointerValue<'ctx>>); 81 | 82 | unsafe impl AsValueRef for CallableValue<'_> { 83 | fn as_value_ref(&self) -> LLVMValueRef { 84 | use either::Either::*; 85 | 86 | match self.0 { 87 | Left(function) => function.as_value_ref(), 88 | Right(pointer) => pointer.as_value_ref(), 89 | } 90 | } 91 | } 92 | 93 | unsafe impl<'ctx> AnyValue<'ctx> for CallableValue<'ctx> {} 94 | 95 | unsafe impl AsTypeRef for CallableValue<'_> { 96 | fn as_type_ref(&self) -> LLVMTypeRef { 97 | use either::Either::*; 98 | 99 | match self.0 { 100 | Left(function) => function.get_type().as_type_ref(), 101 | Right(pointer) => pointer.get_type().get_element_type().as_type_ref(), 102 | } 103 | } 104 | } 105 | 106 | impl CallableValue<'_> { 107 | #[llvm_versions(..=14)] 108 | pub(crate) fn returns_void(&self) -> bool { 109 | use llvm_sys::core::LLVMGetReturnType; 110 | 111 | let return_type = 112 | unsafe { LLVMGetTypeKind(LLVMGetReturnType(LLVMGetElementType(LLVMTypeOf(self.as_value_ref())))) }; 113 | 114 | matches!(return_type, LLVMTypeKind::LLVMVoidTypeKind) 115 | } 116 | } 117 | 118 | impl<'ctx> From> for CallableValue<'ctx> { 119 | fn from(value: FunctionValue<'ctx>) -> Self { 120 | Self(Either::Left(value)) 121 | } 122 | } 123 | 124 | impl<'ctx> TryFrom> for CallableValue<'ctx> { 125 | type Error = (); 126 | 127 | fn try_from(value: PointerValue<'ctx>) -> Result { 128 | // If using a pointer value, we must validate it's a valid function ptr 129 | let value_ref = value.as_value_ref(); 130 | let ty_kind = unsafe { LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(value_ref))) }; 131 | let is_a_fn_ptr = matches!(ty_kind, LLVMTypeKind::LLVMFunctionTypeKind); 132 | 133 | if is_a_fn_ptr { 134 | Ok(Self(Either::Right(value))) 135 | } else { 136 | Err(()) 137 | } 138 | } 139 | } 140 | 141 | impl Display for CallableValue<'_> { 142 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 143 | write!(f, "{}", self.print_to_string()) 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/values/float_value.rs: -------------------------------------------------------------------------------- 1 | #[llvm_versions(..=17)] 2 | use crate::types::IntType; 3 | #[llvm_versions(..=15)] 4 | use llvm_sys::core::LLVMConstFNeg; 5 | use llvm_sys::core::{LLVMConstFCmp, LLVMConstRealGetDouble}; 6 | #[llvm_versions(..=17)] 7 | use llvm_sys::core::{LLVMConstFPCast, LLVMConstFPExt, LLVMConstFPToSI, LLVMConstFPToUI, LLVMConstFPTrunc}; 8 | use llvm_sys::prelude::LLVMValueRef; 9 | 10 | use std::convert::TryFrom; 11 | use std::ffi::CStr; 12 | use std::fmt::{self, Display}; 13 | 14 | #[llvm_versions(..=17)] 15 | use crate::types::AsTypeRef; 16 | use crate::types::FloatType; 17 | use crate::values::traits::AsValueRef; 18 | use crate::values::{InstructionValue, IntValue, Value}; 19 | use crate::FloatPredicate; 20 | 21 | use super::AnyValue; 22 | 23 | #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] 24 | pub struct FloatValue<'ctx> { 25 | float_value: Value<'ctx>, 26 | } 27 | 28 | impl<'ctx> FloatValue<'ctx> { 29 | /// Get a value from an [LLVMValueRef]. 30 | /// 31 | /// # Safety 32 | /// 33 | /// The ref must be valid and of type float. 34 | pub unsafe fn new(value: LLVMValueRef) -> Self { 35 | assert!(!value.is_null()); 36 | 37 | FloatValue { 38 | float_value: Value::new(value), 39 | } 40 | } 41 | 42 | /// Gets name of the `FloatValue`. If the value is a constant, this will 43 | /// return an empty string. 44 | pub fn get_name(&self) -> &CStr { 45 | self.float_value.get_name() 46 | } 47 | 48 | /// Set name of the `FloatValue`. 49 | pub fn set_name(&self, name: &str) { 50 | self.float_value.set_name(name) 51 | } 52 | 53 | pub fn get_type(self) -> FloatType<'ctx> { 54 | unsafe { FloatType::new(self.float_value.get_type()) } 55 | } 56 | 57 | pub fn is_null(self) -> bool { 58 | self.float_value.is_null() 59 | } 60 | 61 | pub fn is_undef(self) -> bool { 62 | self.float_value.is_undef() 63 | } 64 | 65 | pub fn print_to_stderr(self) { 66 | self.float_value.print_to_stderr() 67 | } 68 | 69 | pub fn as_instruction(self) -> Option> { 70 | self.float_value.as_instruction() 71 | } 72 | 73 | #[llvm_versions(..=15)] 74 | pub fn const_neg(self) -> Self { 75 | unsafe { FloatValue::new(LLVMConstFNeg(self.as_value_ref())) } 76 | } 77 | 78 | #[llvm_versions(..=14)] 79 | pub fn const_add(self, rhs: FloatValue<'ctx>) -> Self { 80 | use llvm_sys::core::LLVMConstFAdd; 81 | 82 | unsafe { FloatValue::new(LLVMConstFAdd(self.as_value_ref(), rhs.as_value_ref())) } 83 | } 84 | 85 | #[llvm_versions(..=14)] 86 | pub fn const_sub(self, rhs: FloatValue<'ctx>) -> Self { 87 | use llvm_sys::core::LLVMConstFSub; 88 | 89 | unsafe { FloatValue::new(LLVMConstFSub(self.as_value_ref(), rhs.as_value_ref())) } 90 | } 91 | 92 | #[llvm_versions(..=14)] 93 | pub fn const_mul(self, rhs: FloatValue<'ctx>) -> Self { 94 | use llvm_sys::core::LLVMConstFMul; 95 | 96 | unsafe { FloatValue::new(LLVMConstFMul(self.as_value_ref(), rhs.as_value_ref())) } 97 | } 98 | 99 | #[llvm_versions(..=14)] 100 | pub fn const_div(self, rhs: FloatValue<'ctx>) -> Self { 101 | use llvm_sys::core::LLVMConstFDiv; 102 | 103 | unsafe { FloatValue::new(LLVMConstFDiv(self.as_value_ref(), rhs.as_value_ref())) } 104 | } 105 | 106 | #[llvm_versions(..=14)] 107 | pub fn const_remainder(self, rhs: FloatValue<'ctx>) -> Self { 108 | use llvm_sys::core::LLVMConstFRem; 109 | 110 | unsafe { FloatValue::new(LLVMConstFRem(self.as_value_ref(), rhs.as_value_ref())) } 111 | } 112 | 113 | #[llvm_versions(..=17)] 114 | pub fn const_cast(self, float_type: FloatType<'ctx>) -> Self { 115 | unsafe { FloatValue::new(LLVMConstFPCast(self.as_value_ref(), float_type.as_type_ref())) } 116 | } 117 | 118 | #[llvm_versions(..=17)] 119 | pub fn const_to_unsigned_int(self, int_type: IntType<'ctx>) -> IntValue<'ctx> { 120 | unsafe { IntValue::new(LLVMConstFPToUI(self.as_value_ref(), int_type.as_type_ref())) } 121 | } 122 | 123 | #[llvm_versions(..=17)] 124 | pub fn const_to_signed_int(self, int_type: IntType<'ctx>) -> IntValue<'ctx> { 125 | unsafe { IntValue::new(LLVMConstFPToSI(self.as_value_ref(), int_type.as_type_ref())) } 126 | } 127 | 128 | #[llvm_versions(..=17)] 129 | pub fn const_truncate(self, float_type: FloatType<'ctx>) -> FloatValue<'ctx> { 130 | unsafe { FloatValue::new(LLVMConstFPTrunc(self.as_value_ref(), float_type.as_type_ref())) } 131 | } 132 | 133 | #[llvm_versions(..=17)] 134 | pub fn const_extend(self, float_type: FloatType<'ctx>) -> FloatValue<'ctx> { 135 | unsafe { FloatValue::new(LLVMConstFPExt(self.as_value_ref(), float_type.as_type_ref())) } 136 | } 137 | 138 | // SubType: rhs same as lhs; return IntValue 139 | pub fn const_compare(self, op: FloatPredicate, rhs: FloatValue<'ctx>) -> IntValue<'ctx> { 140 | unsafe { IntValue::new(LLVMConstFCmp(op.into(), self.as_value_ref(), rhs.as_value_ref())) } 141 | } 142 | 143 | /// Determines whether or not a `FloatValue` is a constant. 144 | /// 145 | /// # Example 146 | /// 147 | /// ```no_run 148 | /// use inkwell::context::Context; 149 | /// 150 | /// let context = Context::create(); 151 | /// let f64_type = context.f64_type(); 152 | /// let f64_val = f64_type.const_float(1.2); 153 | /// 154 | /// assert!(f64_val.is_const()); 155 | /// ``` 156 | pub fn is_const(self) -> bool { 157 | self.float_value.is_const() 158 | } 159 | 160 | /// Obtains a constant `FloatValue`'s value and whether or not it lost info. 161 | /// 162 | /// # Example 163 | /// 164 | /// ```no_run 165 | /// use inkwell::context::Context; 166 | /// 167 | /// let context = Context::create(); 168 | /// let f64_type = context.f64_type(); 169 | /// let f64_1_2 = f64_type.const_float(1.2); 170 | /// 171 | /// assert_eq!(f64_1_2.get_constant(), Some((1.2, false))); 172 | /// ``` 173 | pub fn get_constant(self) -> Option<(f64, bool)> { 174 | // Nothing bad happens as far as I can tell if we don't check if const 175 | // unlike the int versions, but just doing this just in case and for consistency 176 | if !self.is_const() { 177 | return None; 178 | } 179 | 180 | let mut lossy = 0; 181 | let constant = unsafe { LLVMConstRealGetDouble(self.as_value_ref(), &mut lossy) }; 182 | 183 | Some((constant, lossy == 1)) 184 | } 185 | 186 | pub fn replace_all_uses_with(self, other: FloatValue<'ctx>) { 187 | self.float_value.replace_all_uses_with(other.as_value_ref()) 188 | } 189 | } 190 | 191 | unsafe impl AsValueRef for FloatValue<'_> { 192 | fn as_value_ref(&self) -> LLVMValueRef { 193 | self.float_value.value 194 | } 195 | } 196 | 197 | impl Display for FloatValue<'_> { 198 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 199 | write!(f, "{}", self.print_to_string()) 200 | } 201 | } 202 | 203 | impl<'ctx> TryFrom> for FloatValue<'ctx> { 204 | type Error = (); 205 | 206 | fn try_from(value: InstructionValue) -> Result { 207 | if value.get_type().is_float_type() { 208 | unsafe { Ok(FloatValue::new(value.as_value_ref())) } 209 | } else { 210 | Err(()) 211 | } 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /src/values/generic_value.rs: -------------------------------------------------------------------------------- 1 | use libc::c_void; 2 | use llvm_sys::execution_engine::{ 3 | LLVMCreateGenericValueOfPointer, LLVMDisposeGenericValue, LLVMGenericValueIntWidth, LLVMGenericValueRef, 4 | LLVMGenericValueToFloat, LLVMGenericValueToInt, LLVMGenericValueToPointer, 5 | }; 6 | 7 | use crate::types::{AsTypeRef, FloatType}; 8 | 9 | use std::marker::PhantomData; 10 | 11 | // SubTypes: GenericValue 12 | #[derive(Debug)] 13 | pub struct GenericValue<'ctx> { 14 | pub(crate) generic_value: LLVMGenericValueRef, 15 | _phantom: PhantomData<&'ctx ()>, 16 | } 17 | 18 | impl<'ctx> GenericValue<'ctx> { 19 | pub(crate) unsafe fn new(generic_value: LLVMGenericValueRef) -> Self { 20 | assert!(!generic_value.is_null()); 21 | 22 | GenericValue { 23 | generic_value, 24 | _phantom: PhantomData, 25 | } 26 | } 27 | 28 | // SubType: GenericValue only 29 | pub fn int_width(self) -> u32 { 30 | unsafe { LLVMGenericValueIntWidth(self.generic_value) } 31 | } 32 | 33 | // SubType: create_generic_value() -> GenericValue 34 | // REVIEW: How safe is this really? 35 | pub unsafe fn create_generic_value_of_pointer(value: &mut T) -> Self { 36 | let value = LLVMCreateGenericValueOfPointer(value as *mut _ as *mut c_void); 37 | 38 | GenericValue::new(value) 39 | } 40 | 41 | // SubType: impl only for GenericValue 42 | pub fn as_int(self, is_signed: bool) -> u64 { 43 | unsafe { LLVMGenericValueToInt(self.generic_value, is_signed as i32) } 44 | } 45 | 46 | // SubType: impl only for GenericValue 47 | pub fn as_float(self, float_type: &FloatType<'ctx>) -> f64 { 48 | unsafe { LLVMGenericValueToFloat(float_type.as_type_ref(), self.generic_value) } 49 | } 50 | 51 | // SubType: impl only for GenericValue 52 | // REVIEW: How safe is this really? 53 | pub unsafe fn into_pointer(self) -> *mut T { 54 | LLVMGenericValueToPointer(self.generic_value) as *mut T 55 | } 56 | } 57 | 58 | impl Drop for GenericValue<'_> { 59 | fn drop(&mut self) { 60 | unsafe { LLVMDisposeGenericValue(self.generic_value) } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/values/metadata_value.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{ 2 | LLVMGetMDNodeNumOperands, LLVMGetMDNodeOperands, LLVMGetMDString, LLVMIsAMDNode, LLVMIsAMDString, 3 | }; 4 | use llvm_sys::prelude::LLVMValueRef; 5 | 6 | use llvm_sys::core::LLVMValueAsMetadata; 7 | use llvm_sys::prelude::LLVMMetadataRef; 8 | 9 | use crate::values::traits::AsValueRef; 10 | use crate::values::{BasicMetadataValueEnum, Value}; 11 | 12 | use super::AnyValue; 13 | 14 | use std::ffi::CStr; 15 | use std::fmt::{self, Display}; 16 | 17 | /// Value returned by [`Context::get_kind_id()`](crate::context::Context::get_kind_id) 18 | /// for the first input string that isn't known. 19 | /// 20 | /// Each LLVM version has a different set of pre-defined metadata kinds. 21 | pub const FIRST_CUSTOM_METADATA_KIND_ID: u32 = if cfg!(feature = "llvm8-0") { 22 | 26 23 | } else if cfg!(feature = "llvm9-0") { 24 | 28 25 | } else if cfg!(any(feature = "llvm10-0", feature = "llvm11-0")) { 26 | 30 27 | } else if cfg!(any(feature = "llvm12-0", feature = "llvm13-0", feature = "llvm14-0",)) { 28 | 31 29 | } else if cfg!(feature = "llvm15-0") { 30 | 36 31 | } else if cfg!(any(feature = "llvm16-0", feature = "llvm17-0")) { 32 | 39 33 | } else if cfg!(feature = "llvm18-1") { 34 | 40 35 | } else { 36 | panic!("Unhandled LLVM version") 37 | }; 38 | 39 | #[derive(PartialEq, Eq, Clone, Copy, Hash)] 40 | pub struct MetadataValue<'ctx> { 41 | metadata_value: Value<'ctx>, 42 | } 43 | 44 | impl<'ctx> MetadataValue<'ctx> { 45 | /// Get a value from an [LLVMValueRef]. 46 | /// 47 | /// # Safety 48 | /// 49 | /// The ref must be valid and of type metadata. 50 | pub unsafe fn new(value: LLVMValueRef) -> Self { 51 | assert!(!value.is_null()); 52 | assert!(!LLVMIsAMDNode(value).is_null() || !LLVMIsAMDString(value).is_null()); 53 | 54 | MetadataValue { 55 | metadata_value: Value::new(value), 56 | } 57 | } 58 | 59 | pub(crate) fn as_metadata_ref(self) -> LLVMMetadataRef { 60 | unsafe { LLVMValueAsMetadata(self.as_value_ref()) } 61 | } 62 | 63 | /// Get name of the `MetadataValue`. 64 | pub fn get_name(&self) -> &CStr { 65 | self.metadata_value.get_name() 66 | } 67 | 68 | // SubTypes: This can probably go away with subtypes 69 | pub fn is_node(self) -> bool { 70 | unsafe { LLVMIsAMDNode(self.as_value_ref()) == self.as_value_ref() } 71 | } 72 | 73 | // SubTypes: This can probably go away with subtypes 74 | pub fn is_string(self) -> bool { 75 | unsafe { LLVMIsAMDString(self.as_value_ref()) == self.as_value_ref() } 76 | } 77 | 78 | pub fn get_string_value(&self) -> Option<&CStr> { 79 | if self.is_node() { 80 | return None; 81 | } 82 | 83 | let mut len = 0; 84 | let c_str = unsafe { CStr::from_ptr(LLVMGetMDString(self.as_value_ref(), &mut len)) }; 85 | 86 | Some(c_str) 87 | } 88 | 89 | // SubTypes: Node only one day 90 | pub fn get_node_size(self) -> u32 { 91 | if self.is_string() { 92 | return 0; 93 | } 94 | 95 | unsafe { LLVMGetMDNodeNumOperands(self.as_value_ref()) } 96 | } 97 | 98 | // SubTypes: Node only one day 99 | // REVIEW: BasicMetadataValueEnum only if you can put metadata in metadata... 100 | pub fn get_node_values(self) -> Vec> { 101 | if self.is_string() { 102 | return Vec::new(); 103 | } 104 | 105 | let count = self.get_node_size() as usize; 106 | let mut vec: Vec = Vec::with_capacity(count); 107 | let ptr = vec.as_mut_ptr(); 108 | 109 | unsafe { 110 | LLVMGetMDNodeOperands(self.as_value_ref(), ptr); 111 | 112 | vec.set_len(count) 113 | }; 114 | 115 | vec.iter() 116 | .map(|val| unsafe { BasicMetadataValueEnum::new(*val) }) 117 | .collect() 118 | } 119 | 120 | pub fn print_to_stderr(self) { 121 | self.metadata_value.print_to_stderr() 122 | } 123 | 124 | pub fn replace_all_uses_with(self, other: &MetadataValue<'ctx>) { 125 | self.metadata_value.replace_all_uses_with(other.as_value_ref()) 126 | } 127 | } 128 | 129 | unsafe impl AsValueRef for MetadataValue<'_> { 130 | fn as_value_ref(&self) -> LLVMValueRef { 131 | self.metadata_value.value 132 | } 133 | } 134 | 135 | impl Display for MetadataValue<'_> { 136 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 137 | write!(f, "{}", self.print_to_string()) 138 | } 139 | } 140 | 141 | impl fmt::Debug for MetadataValue<'_> { 142 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 143 | let mut d = f.debug_struct("MetadataValue"); 144 | d.field("address", &self.as_value_ref()); 145 | 146 | if self.is_string() { 147 | d.field("value", &self.get_string_value().unwrap()); 148 | } else { 149 | d.field("values", &self.get_node_values()); 150 | } 151 | 152 | d.field("repr", &self.print_to_string()); 153 | 154 | d.finish() 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/values/mod.rs: -------------------------------------------------------------------------------- 1 | //! A value is an instance of a type. 2 | 3 | #[deny(missing_docs)] 4 | mod array_value; 5 | #[deny(missing_docs)] 6 | mod basic_value_use; 7 | #[deny(missing_docs)] 8 | mod call_site_value; 9 | mod enums; 10 | mod float_value; 11 | mod fn_value; 12 | mod generic_value; 13 | mod global_value; 14 | mod instruction_value; 15 | mod int_value; 16 | mod metadata_value; 17 | mod phi_value; 18 | mod ptr_value; 19 | mod scalable_vec_value; 20 | mod struct_value; 21 | mod traits; 22 | mod vec_value; 23 | 24 | #[cfg(feature = "llvm18-1")] 25 | pub(crate) mod operand_bundle; 26 | 27 | #[cfg(not(any( 28 | feature = "llvm15-0", 29 | feature = "llvm16-0", 30 | feature = "llvm17-0", 31 | feature = "llvm18-1" 32 | )))] 33 | mod callable_value; 34 | 35 | #[cfg(not(any( 36 | feature = "llvm15-0", 37 | feature = "llvm16-0", 38 | feature = "llvm17-0", 39 | feature = "llvm18-1" 40 | )))] 41 | pub use crate::values::callable_value::CallableValue; 42 | 43 | #[llvm_versions(18..)] 44 | pub use crate::values::operand_bundle::OperandBundle; 45 | 46 | use crate::support::{to_c_str, LLVMString}; 47 | pub use crate::values::array_value::ArrayValue; 48 | pub use crate::values::basic_value_use::BasicValueUse; 49 | pub use crate::values::call_site_value::CallSiteValue; 50 | pub use crate::values::enums::{AggregateValueEnum, AnyValueEnum, BasicMetadataValueEnum, BasicValueEnum}; 51 | pub use crate::values::float_value::FloatValue; 52 | pub use crate::values::fn_value::FunctionValue; 53 | pub use crate::values::generic_value::GenericValue; 54 | pub use crate::values::global_value::GlobalValue; 55 | 56 | pub use crate::values::global_value::UnnamedAddress; 57 | pub use crate::values::instruction_value::{InstructionOpcode, InstructionValue, OperandIter, OperandUseIter}; 58 | pub use crate::values::int_value::IntValue; 59 | pub use crate::values::metadata_value::{MetadataValue, FIRST_CUSTOM_METADATA_KIND_ID}; 60 | pub use crate::values::phi_value::IncomingIter; 61 | pub use crate::values::phi_value::PhiValue; 62 | pub use crate::values::ptr_value::PointerValue; 63 | pub use crate::values::scalable_vec_value::ScalableVectorValue; 64 | pub use crate::values::struct_value::FieldValueIter; 65 | pub use crate::values::struct_value::StructValue; 66 | pub use crate::values::traits::AsValueRef; 67 | pub use crate::values::traits::{ 68 | AggregateValue, AnyValue, BasicValue, FloatMathValue, IntMathValue, PointerMathValue, VectorBaseValue, 69 | }; 70 | pub use crate::values::vec_value::VectorValue; 71 | 72 | #[llvm_versions(18..)] 73 | pub use llvm_sys::LLVMTailCallKind; 74 | 75 | use llvm_sys::core::{ 76 | LLVMDumpValue, LLVMGetFirstUse, LLVMGetSection, LLVMGetValueName2, LLVMIsAInstruction, LLVMIsConstant, LLVMIsNull, 77 | LLVMIsUndef, LLVMPrintTypeToString, LLVMPrintValueToString, LLVMReplaceAllUsesWith, LLVMSetSection, 78 | LLVMSetValueName2, LLVMTypeOf, 79 | }; 80 | use llvm_sys::prelude::{LLVMTypeRef, LLVMValueRef}; 81 | 82 | use std::ffi::CStr; 83 | use std::fmt; 84 | use std::marker::PhantomData; 85 | 86 | #[derive(PartialEq, Eq, Clone, Copy, Hash)] 87 | struct Value<'ctx> { 88 | value: LLVMValueRef, 89 | _marker: PhantomData<&'ctx ()>, 90 | } 91 | 92 | impl<'ctx> Value<'ctx> { 93 | pub(crate) unsafe fn new(value: LLVMValueRef) -> Self { 94 | debug_assert!( 95 | !value.is_null(), 96 | "This should never happen since containing struct should check null ptrs" 97 | ); 98 | 99 | Value { 100 | value, 101 | _marker: PhantomData, 102 | } 103 | } 104 | 105 | fn is_instruction(self) -> bool { 106 | unsafe { !LLVMIsAInstruction(self.value).is_null() } 107 | } 108 | 109 | fn as_instruction(self) -> Option> { 110 | if !self.is_instruction() { 111 | return None; 112 | } 113 | 114 | unsafe { Some(InstructionValue::new(self.value)) } 115 | } 116 | 117 | fn is_null(self) -> bool { 118 | unsafe { LLVMIsNull(self.value) == 1 } 119 | } 120 | 121 | fn is_const(self) -> bool { 122 | unsafe { LLVMIsConstant(self.value) == 1 } 123 | } 124 | 125 | // TODOC: According to https://stackoverflow.com/questions/21593752/llvm-how-to-pass-a-name-to-constantint 126 | // you can't use set_name name on a constant(by can't, I mean it wont do anything), unless it's also a global. 127 | // So, you can set names on variables (ie a function parameter) 128 | // REVIEW: It'd be great if we could encode this into the type system somehow. For example, 129 | // add a ParamValue wrapper type that always have it but conditional types (IntValue) 130 | // that also have it. This isn't a huge deal though, since it hasn't proven to be UB so far 131 | fn set_name(self, name: &str) { 132 | let c_string = to_c_str(name); 133 | 134 | unsafe { LLVMSetValueName2(self.value, c_string.as_ptr(), c_string.to_bytes().len()) } 135 | } 136 | 137 | // get_name should *not* return a LLVMString, because it is not an owned value AFAICT 138 | // TODO: Should make this take ownership of self. But what is the lifetime of the string? 'ctx? 139 | fn get_name(&self) -> &CStr { 140 | let ptr = unsafe { 141 | let mut len = 0; 142 | 143 | LLVMGetValueName2(self.value, &mut len) 144 | }; 145 | 146 | unsafe { CStr::from_ptr(ptr) } 147 | } 148 | 149 | fn is_undef(self) -> bool { 150 | unsafe { LLVMIsUndef(self.value) == 1 } 151 | } 152 | 153 | fn get_type(self) -> LLVMTypeRef { 154 | unsafe { LLVMTypeOf(self.value) } 155 | } 156 | 157 | fn print_to_string(self) -> LLVMString { 158 | unsafe { LLVMString::new(LLVMPrintValueToString(self.value)) } 159 | } 160 | 161 | fn print_to_stderr(self) { 162 | unsafe { LLVMDumpValue(self.value) } 163 | } 164 | 165 | // REVIEW: I think this is memory safe, though it may result in an IR error 166 | // if used incorrectly, which is OK. 167 | fn replace_all_uses_with(self, other: LLVMValueRef) { 168 | // LLVM may infinite-loop when they aren't distinct, which is UB in C++. 169 | if self.value != other { 170 | unsafe { LLVMReplaceAllUsesWith(self.value, other) } 171 | } 172 | } 173 | 174 | pub fn get_first_use(self) -> Option> { 175 | let use_ = unsafe { LLVMGetFirstUse(self.value) }; 176 | 177 | if use_.is_null() { 178 | return None; 179 | } 180 | 181 | unsafe { Some(BasicValueUse::new(use_)) } 182 | } 183 | 184 | /// Gets the section of the global value 185 | pub fn get_section(&self) -> Option<&CStr> { 186 | let ptr = unsafe { LLVMGetSection(self.value) }; 187 | 188 | if ptr.is_null() { 189 | return None; 190 | } 191 | 192 | // On MacOS we need to remove ',' before section name 193 | if cfg!(target_os = "macos") { 194 | let name = unsafe { CStr::from_ptr(ptr) }; 195 | let name_string = name.to_string_lossy(); 196 | let mut chars = name_string.chars(); 197 | if Some(',') == chars.next() { 198 | Some(unsafe { CStr::from_ptr(ptr.add(1)) }) 199 | } else { 200 | Some(name) 201 | } 202 | } else { 203 | Some(unsafe { CStr::from_ptr(ptr) }) 204 | } 205 | } 206 | 207 | /// Sets the section of the global value 208 | fn set_section(self, section: Option<&str>) { 209 | #[cfg(target_os = "macos")] 210 | let mapped_section = section.map(|s| { 211 | if s.contains(",") { 212 | format!("{}", s) 213 | } else { 214 | format!(",{}", s) 215 | } 216 | }); 217 | #[cfg(target_os = "macos")] 218 | let section = mapped_section.as_deref(); 219 | 220 | let c_string = section.map(to_c_str); 221 | 222 | unsafe { 223 | LLVMSetSection( 224 | self.value, 225 | // The as_ref call is important here so that we don't drop the cstr mid use 226 | c_string.as_ref().map(|s| s.as_ptr()).unwrap_or(std::ptr::null()), 227 | ) 228 | } 229 | } 230 | } 231 | 232 | impl fmt::Debug for Value<'_> { 233 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 234 | let llvm_value = self.print_to_string(); 235 | let llvm_type = unsafe { CStr::from_ptr(LLVMPrintTypeToString(LLVMTypeOf(self.value))) }; 236 | let name = self.get_name(); 237 | let is_const = self.is_const(); 238 | let is_null = self.is_null(); 239 | let is_undef = self.is_undef(); 240 | 241 | f.debug_struct("Value") 242 | .field("name", &name) 243 | .field("address", &self.value) 244 | .field("is_const", &is_const) 245 | .field("is_null", &is_null) 246 | .field("is_undef", &is_undef) 247 | .field("llvm_value", &llvm_value) 248 | .field("llvm_type", &llvm_type) 249 | .finish() 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /src/values/operand_bundle.rs: -------------------------------------------------------------------------------- 1 | use crate::context::Context; 2 | use crate::support::to_c_str; 3 | use crate::values::{AnyValueEnum, AsValueRef, BasicValueEnum, CallSiteValue}; 4 | use llvm_sys::core::{ 5 | LLVMCreateOperandBundle, LLVMDisposeOperandBundle, LLVMGetNumOperandBundleArgs, LLVMGetNumOperandBundles, 6 | LLVMGetOperandBundleArgAtIndex, LLVMGetOperandBundleAtIndex, LLVMGetOperandBundleTag, 7 | }; 8 | use llvm_sys::prelude::{LLVMOperandBundleRef, LLVMValueRef}; 9 | use std::cell::Cell; 10 | use std::ffi::CStr; 11 | use std::marker::PhantomData; 12 | 13 | /// One of an instruction's operand bundles. 14 | #[derive(Debug)] 15 | pub struct OperandBundle<'ctx> { 16 | bundle: Cell, 17 | _marker: PhantomData<&'ctx Context>, 18 | } 19 | 20 | /// Iterator over an instruction's operand bundles. 21 | #[derive(Debug)] 22 | pub struct OperandBundleIter<'a, 'ctx> { 23 | instruction: &'a CallSiteValue<'ctx>, 24 | current: u32, 25 | size: u32, 26 | } 27 | 28 | /// Iterator over an operand bundle's arguments. 29 | #[derive(Debug)] 30 | pub struct OperandBundleArgsIter<'a, 'ctx> { 31 | bundle: &'a OperandBundle<'ctx>, 32 | current: u32, 33 | size: u32, 34 | } 35 | 36 | impl<'ctx> OperandBundle<'ctx> { 37 | /// Get an operand bundle from a [LLVMOperandBundleRef]. 38 | /// 39 | /// # Safety 40 | /// 41 | /// The ref must be valid and represent an operand bundle. 42 | pub unsafe fn new(bundle: LLVMOperandBundleRef) -> Self { 43 | Self { 44 | bundle: Cell::new(bundle), 45 | _marker: PhantomData, 46 | } 47 | } 48 | 49 | /// Create a new operand bundle. 50 | /// 51 | /// # Example 52 | /// 53 | /// ``` 54 | /// use inkwell::context::Context; 55 | /// use inkwell::values::OperandBundle; 56 | /// 57 | /// let context = Context::create(); 58 | /// let i32_type = context.i32_type(); 59 | /// 60 | /// let op_bundle = OperandBundle::create("tag", &[i32_type.const_zero().into()]); 61 | /// 62 | /// assert_eq!(op_bundle.get_tag().unwrap(), "tag"); 63 | /// let arg = op_bundle.get_args().nth(0).unwrap().into_int_value(); 64 | /// assert!(arg.is_const()); 65 | /// assert_eq!(arg.get_zero_extended_constant().unwrap(), 0); 66 | /// ``` 67 | pub fn create(tag: &str, args: &[AnyValueEnum<'ctx>]) -> Self { 68 | let c_tag = to_c_str(tag); 69 | let mut args: Vec = args.iter().map(|value| value.as_value_ref()).collect(); 70 | 71 | unsafe { 72 | let bundle = LLVMCreateOperandBundle(c_tag.as_ptr(), tag.len(), args.as_mut_ptr(), args.len() as u32); 73 | Self::new(bundle) 74 | } 75 | } 76 | 77 | /// Acquire the underlying raw pointer belonging to this `OperandBundle` type. 78 | pub fn as_mut_ptr(&self) -> LLVMOperandBundleRef { 79 | self.bundle.get() 80 | } 81 | 82 | /// Get this operand bundle's tag. 83 | /// 84 | /// # Example 85 | /// 86 | /// ``` 87 | /// use inkwell::values::OperandBundle; 88 | /// 89 | /// let op_bundle = OperandBundle::create("tag", &[]); 90 | /// assert_eq!(op_bundle.get_tag().unwrap(), "tag"); 91 | /// ``` 92 | pub fn get_tag(&self) -> Result<&str, std::str::Utf8Error> { 93 | unsafe { 94 | let mut size = 0usize; 95 | let tag = LLVMGetOperandBundleTag(self.bundle.get(), &mut size as *mut usize); 96 | CStr::from_ptr(tag).to_str() 97 | } 98 | } 99 | 100 | /// Iterate over this operand bundle's arguments. 101 | /// 102 | /// # Example 103 | /// 104 | /// ``` 105 | /// use inkwell::context::Context; 106 | /// use inkwell::values::OperandBundle; 107 | /// 108 | /// let context = Context::create(); 109 | /// let i32_type = context.i32_type(); 110 | /// let f32_type = context.f32_type(); 111 | /// 112 | /// let op_bundle = OperandBundle::create("tag", &[i32_type.const_zero().into(), f32_type.const_float(1.23).into()]); 113 | /// assert_eq!(op_bundle.get_args().count(), 2); 114 | /// assert_eq!(op_bundle.get_args().len(), 2); 115 | /// ``` 116 | pub fn get_args(&self) -> OperandBundleArgsIter<'_, 'ctx> { 117 | OperandBundleArgsIter::new(self) 118 | } 119 | } 120 | 121 | impl Drop for OperandBundle<'_> { 122 | fn drop(&mut self) { 123 | unsafe { LLVMDisposeOperandBundle(self.as_mut_ptr()) } 124 | } 125 | } 126 | 127 | impl<'a, 'ctx> OperandBundleIter<'a, 'ctx> { 128 | pub(crate) fn new(instruction: &'a CallSiteValue<'ctx>) -> Self { 129 | let size = unsafe { LLVMGetNumOperandBundles(instruction.as_value_ref()) }; 130 | 131 | Self { 132 | instruction, 133 | current: 0, 134 | size, 135 | } 136 | } 137 | } 138 | 139 | impl<'ctx> Iterator for OperandBundleIter<'_, 'ctx> { 140 | type Item = OperandBundle<'ctx>; 141 | 142 | fn next(&mut self) -> Option { 143 | if self.current < self.size { 144 | let bundle = unsafe { 145 | OperandBundle::new(LLVMGetOperandBundleAtIndex( 146 | self.instruction.as_value_ref(), 147 | self.current, 148 | )) 149 | }; 150 | self.current += 1; 151 | Some(bundle) 152 | } else { 153 | None 154 | } 155 | } 156 | 157 | fn size_hint(&self) -> (usize, Option) { 158 | let remaining = (self.size - self.current) as usize; 159 | (remaining, Some(remaining)) 160 | } 161 | } 162 | 163 | impl ExactSizeIterator for OperandBundleIter<'_, '_> {} 164 | 165 | impl<'a, 'ctx> OperandBundleArgsIter<'a, 'ctx> { 166 | fn new(bundle: &'a OperandBundle<'ctx>) -> Self { 167 | let size = unsafe { LLVMGetNumOperandBundleArgs(bundle.as_mut_ptr()) }; 168 | Self { 169 | bundle, 170 | current: 0, 171 | size, 172 | } 173 | } 174 | } 175 | 176 | impl<'ctx> Iterator for OperandBundleArgsIter<'_, 'ctx> { 177 | type Item = BasicValueEnum<'ctx>; 178 | 179 | fn next(&mut self) -> Option { 180 | if self.current < self.size { 181 | unsafe { 182 | let arg = LLVMGetOperandBundleArgAtIndex(self.bundle.as_mut_ptr(), self.current); 183 | self.current += 1; 184 | Some(BasicValueEnum::new(arg)) 185 | } 186 | } else { 187 | None 188 | } 189 | } 190 | 191 | fn size_hint(&self) -> (usize, Option) { 192 | let remaining = (self.size - self.current) as usize; 193 | (remaining, Some(remaining)) 194 | } 195 | } 196 | 197 | impl ExactSizeIterator for OperandBundleArgsIter<'_, '_> {} 198 | -------------------------------------------------------------------------------- /src/values/phi_value.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMAddIncoming, LLVMCountIncoming, LLVMGetIncomingBlock, LLVMGetIncomingValue}; 2 | use llvm_sys::prelude::{LLVMBasicBlockRef, LLVMValueRef}; 3 | use std::convert::TryFrom; 4 | 5 | use std::ffi::CStr; 6 | use std::fmt::{self, Display}; 7 | 8 | use crate::basic_block::BasicBlock; 9 | use crate::values::traits::AsValueRef; 10 | use crate::values::{BasicValue, BasicValueEnum, InstructionOpcode, InstructionValue, Value}; 11 | 12 | use super::AnyValue; 13 | 14 | // REVIEW: Metadata for phi values? 15 | /// A Phi Instruction returns a value based on which basic block branched into 16 | /// the Phi's containing basic block. 17 | #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] 18 | pub struct PhiValue<'ctx> { 19 | phi_value: Value<'ctx>, 20 | } 21 | 22 | impl<'ctx> PhiValue<'ctx> { 23 | /// Get a value from an [LLVMValueRef]. 24 | /// 25 | /// # Safety 26 | /// 27 | /// The ref must be valid and of type phi. 28 | pub unsafe fn new(value: LLVMValueRef) -> Self { 29 | assert!(!value.is_null()); 30 | 31 | PhiValue { 32 | phi_value: Value::new(value), 33 | } 34 | } 35 | 36 | pub fn add_incoming(self, incoming: &[(&dyn BasicValue<'ctx>, BasicBlock<'ctx>)]) { 37 | let (mut values, mut basic_blocks): (Vec, Vec) = { 38 | incoming 39 | .iter() 40 | .map(|&(v, bb)| (v.as_value_ref(), bb.basic_block)) 41 | .unzip() 42 | }; 43 | 44 | unsafe { 45 | LLVMAddIncoming( 46 | self.as_value_ref(), 47 | values.as_mut_ptr(), 48 | basic_blocks.as_mut_ptr(), 49 | incoming.len() as u32, 50 | ); 51 | } 52 | } 53 | 54 | pub fn count_incoming(self) -> u32 { 55 | unsafe { LLVMCountIncoming(self.as_value_ref()) } 56 | } 57 | 58 | pub fn get_incoming(self, index: u32) -> Option<(BasicValueEnum<'ctx>, BasicBlock<'ctx>)> { 59 | if index >= self.count_incoming() { 60 | return None; 61 | } 62 | 63 | let basic_block = 64 | unsafe { BasicBlock::new(LLVMGetIncomingBlock(self.as_value_ref(), index)).expect("Invalid BasicBlock") }; 65 | let value = unsafe { BasicValueEnum::new(LLVMGetIncomingValue(self.as_value_ref(), index)) }; 66 | 67 | Some((value, basic_block)) 68 | } 69 | 70 | /// # Safety 71 | /// 72 | /// The index must be smaller [PhiValue::count_incoming]. 73 | pub unsafe fn get_incoming_unchecked(self, index: u32) -> (BasicValueEnum<'ctx>, BasicBlock<'ctx>) { 74 | let basic_block = 75 | unsafe { BasicBlock::new(LLVMGetIncomingBlock(self.as_value_ref(), index)).expect("Invalid BasicBlock") }; 76 | let value = unsafe { BasicValueEnum::new(LLVMGetIncomingValue(self.as_value_ref(), index)) }; 77 | 78 | (value, basic_block) 79 | } 80 | 81 | /// Get an incoming edge iterator. 82 | pub fn get_incomings(self) -> IncomingIter<'ctx> { 83 | IncomingIter { 84 | pv: self, 85 | i: 0, 86 | count: self.count_incoming(), 87 | } 88 | } 89 | 90 | /// Gets the name of a `ArrayValue`. If the value is a constant, this will 91 | /// return an empty string. 92 | pub fn get_name(&self) -> &CStr { 93 | self.phi_value.get_name() 94 | } 95 | 96 | // I believe PhiValue is never a constant, so this should always work 97 | pub fn set_name(self, name: &str) { 98 | self.phi_value.set_name(name); 99 | } 100 | 101 | pub fn is_null(self) -> bool { 102 | self.phi_value.is_null() 103 | } 104 | 105 | pub fn is_undef(self) -> bool { 106 | self.phi_value.is_undef() 107 | } 108 | 109 | // SubType: -> InstructionValue 110 | pub fn as_instruction(self) -> InstructionValue<'ctx> { 111 | self.phi_value 112 | .as_instruction() 113 | .expect("PhiValue should always be a Phi InstructionValue") 114 | } 115 | 116 | pub fn replace_all_uses_with(self, other: &PhiValue<'ctx>) { 117 | self.phi_value.replace_all_uses_with(other.as_value_ref()) 118 | } 119 | 120 | pub fn as_basic_value(self) -> BasicValueEnum<'ctx> { 121 | unsafe { BasicValueEnum::new(self.as_value_ref()) } 122 | } 123 | } 124 | 125 | unsafe impl AsValueRef for PhiValue<'_> { 126 | fn as_value_ref(&self) -> LLVMValueRef { 127 | self.phi_value.value 128 | } 129 | } 130 | 131 | impl Display for PhiValue<'_> { 132 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 133 | write!(f, "{}", self.print_to_string()) 134 | } 135 | } 136 | 137 | impl<'ctx> TryFrom> for PhiValue<'ctx> { 138 | type Error = (); 139 | 140 | fn try_from(value: InstructionValue) -> Result { 141 | if value.get_opcode() == InstructionOpcode::Phi { 142 | unsafe { Ok(PhiValue::new(value.as_value_ref())) } 143 | } else { 144 | Err(()) 145 | } 146 | } 147 | } 148 | 149 | /// Iterate over all the incoming edges of a phi value. 150 | #[derive(Debug)] 151 | pub struct IncomingIter<'ctx> { 152 | pv: PhiValue<'ctx>, 153 | i: u32, 154 | count: u32, 155 | } 156 | 157 | impl<'ctx> Iterator for IncomingIter<'ctx> { 158 | type Item = (BasicValueEnum<'ctx>, BasicBlock<'ctx>); 159 | 160 | fn next(&mut self) -> Option { 161 | if self.i < self.count { 162 | let result = unsafe { self.pv.get_incoming_unchecked(self.i) }; 163 | self.i += 1; 164 | Some(result) 165 | } else { 166 | None 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/values/ptr_value.rs: -------------------------------------------------------------------------------- 1 | #[cfg(all(feature = "typed-pointers", not(feature = "llvm16-0")))] 2 | #[allow(deprecated)] 3 | use llvm_sys::core::{LLVMConstGEP, LLVMConstInBoundsGEP}; 4 | #[cfg(any(not(feature = "typed-pointers"), feature = "llvm16-0"))] 5 | use llvm_sys::core::{LLVMConstGEP2, LLVMConstInBoundsGEP2}; 6 | 7 | use llvm_sys::core::{LLVMConstAddrSpaceCast, LLVMConstPointerCast, LLVMConstPtrToInt}; 8 | use llvm_sys::prelude::LLVMValueRef; 9 | 10 | use std::convert::TryFrom; 11 | use std::ffi::CStr; 12 | use std::fmt::{self, Display}; 13 | 14 | #[cfg(not(feature = "typed-pointers"))] 15 | use crate::types::BasicType; 16 | use crate::types::{AsTypeRef, IntType, PointerType}; 17 | use crate::values::{AsValueRef, InstructionValue, IntValue, Value}; 18 | 19 | use super::AnyValue; 20 | 21 | #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] 22 | pub struct PointerValue<'ctx> { 23 | ptr_value: Value<'ctx>, 24 | } 25 | 26 | impl<'ctx> PointerValue<'ctx> { 27 | /// Get a value from an [LLVMValueRef]. 28 | /// 29 | /// # Safety 30 | /// 31 | /// The ref must be valid and of type pointer. 32 | pub unsafe fn new(value: LLVMValueRef) -> Self { 33 | assert!(!value.is_null()); 34 | 35 | PointerValue { 36 | ptr_value: Value::new(value), 37 | } 38 | } 39 | 40 | /// Get name of the `PointerValue`. If the value is a constant, this 41 | /// will return an empty string. 42 | pub fn get_name(&self) -> &CStr { 43 | self.ptr_value.get_name() 44 | } 45 | 46 | /// Set name of the `PointerValue`. 47 | pub fn set_name(&self, name: &str) { 48 | self.ptr_value.set_name(name) 49 | } 50 | 51 | pub fn get_type(self) -> PointerType<'ctx> { 52 | unsafe { PointerType::new(self.ptr_value.get_type()) } 53 | } 54 | 55 | pub fn is_null(self) -> bool { 56 | self.ptr_value.is_null() 57 | } 58 | 59 | pub fn is_undef(self) -> bool { 60 | self.ptr_value.is_undef() 61 | } 62 | 63 | /// Determines whether or not a `PointerValue` is a constant. 64 | /// 65 | /// # Example 66 | /// 67 | /// ```no_run 68 | /// use inkwell::AddressSpace; 69 | /// use inkwell::context::Context; 70 | /// 71 | /// let context = Context::create(); 72 | /// let void_type = context.void_type(); 73 | /// ``` 74 | pub fn is_const(self) -> bool { 75 | self.ptr_value.is_const() 76 | } 77 | 78 | pub fn print_to_stderr(self) { 79 | self.ptr_value.print_to_stderr() 80 | } 81 | 82 | pub fn as_instruction(self) -> Option> { 83 | self.ptr_value.as_instruction() 84 | } 85 | 86 | // REVIEW: Should this be on array value too? 87 | /// GEP is very likely to segfault if indexes are used incorrectly, and is therefore an unsafe function. Maybe we can change this in the future. 88 | #[cfg(feature = "typed-pointers")] 89 | pub unsafe fn const_gep(self, ordered_indexes: &[IntValue<'ctx>]) -> PointerValue<'ctx> { 90 | let mut index_values: Vec = ordered_indexes.iter().map(|val| val.as_value_ref()).collect(); 91 | 92 | #[cfg(not(feature = "llvm16-0"))] 93 | #[allow(deprecated)] 94 | let value = { 95 | LLVMConstGEP( 96 | self.as_value_ref(), 97 | index_values.as_mut_ptr(), 98 | index_values.len() as u32, 99 | ) 100 | }; 101 | #[cfg(feature = "llvm16-0")] 102 | let value = { 103 | LLVMConstGEP2( 104 | self.get_type().get_element_type().as_type_ref(), 105 | self.as_value_ref(), 106 | index_values.as_mut_ptr(), 107 | index_values.len() as u32, 108 | ) 109 | }; 110 | 111 | PointerValue::new(value) 112 | } 113 | 114 | // REVIEW: Should this be on array value too? 115 | /// GEP is very likely to segfault if indexes are used incorrectly, and is therefore an unsafe function. Maybe we can change this in the future. 116 | #[cfg(not(feature = "typed-pointers"))] 117 | pub unsafe fn const_gep>(self, ty: T, ordered_indexes: &[IntValue<'ctx>]) -> PointerValue<'ctx> { 118 | let mut index_values: Vec = ordered_indexes.iter().map(|val| val.as_value_ref()).collect(); 119 | 120 | let value = { 121 | LLVMConstGEP2( 122 | ty.as_type_ref(), 123 | self.as_value_ref(), 124 | index_values.as_mut_ptr(), 125 | index_values.len() as u32, 126 | ) 127 | }; 128 | 129 | PointerValue::new(value) 130 | } 131 | 132 | /// GEP is very likely to segfault if indexes are used incorrectly, and is therefore an unsafe function. Maybe we can change this in the future. 133 | #[cfg(feature = "typed-pointers")] 134 | pub unsafe fn const_in_bounds_gep(self, ordered_indexes: &[IntValue<'ctx>]) -> PointerValue<'ctx> { 135 | let mut index_values: Vec = ordered_indexes.iter().map(|val| val.as_value_ref()).collect(); 136 | 137 | #[cfg(not(feature = "llvm16-0"))] 138 | #[allow(deprecated)] 139 | let value = { 140 | LLVMConstInBoundsGEP( 141 | self.as_value_ref(), 142 | index_values.as_mut_ptr(), 143 | index_values.len() as u32, 144 | ) 145 | }; 146 | #[cfg(feature = "llvm16-0")] 147 | let value = { 148 | LLVMConstInBoundsGEP2( 149 | self.get_type().get_element_type().as_type_ref(), 150 | self.as_value_ref(), 151 | index_values.as_mut_ptr(), 152 | index_values.len() as u32, 153 | ) 154 | }; 155 | 156 | PointerValue::new(value) 157 | } 158 | 159 | /// GEP is very likely to segfault if indexes are used incorrectly, and is therefore an unsafe function. Maybe we can change this in the future. 160 | #[cfg(not(feature = "typed-pointers"))] 161 | pub unsafe fn const_in_bounds_gep>( 162 | self, 163 | ty: T, 164 | ordered_indexes: &[IntValue<'ctx>], 165 | ) -> PointerValue<'ctx> { 166 | let mut index_values: Vec = ordered_indexes.iter().map(|val| val.as_value_ref()).collect(); 167 | 168 | let value = { 169 | LLVMConstInBoundsGEP2( 170 | ty.as_type_ref(), 171 | self.as_value_ref(), 172 | index_values.as_mut_ptr(), 173 | index_values.len() as u32, 174 | ) 175 | }; 176 | 177 | PointerValue::new(value) 178 | } 179 | } 180 | 181 | impl<'ctx> PointerValue<'ctx> { 182 | pub fn const_to_int(self, int_type: IntType<'ctx>) -> IntValue<'ctx> { 183 | unsafe { IntValue::new(LLVMConstPtrToInt(self.as_value_ref(), int_type.as_type_ref())) } 184 | } 185 | 186 | pub fn const_cast(self, ptr_type: PointerType<'ctx>) -> PointerValue<'ctx> { 187 | unsafe { PointerValue::new(LLVMConstPointerCast(self.as_value_ref(), ptr_type.as_type_ref())) } 188 | } 189 | 190 | pub fn const_address_space_cast(self, ptr_type: PointerType<'ctx>) -> PointerValue<'ctx> { 191 | unsafe { PointerValue::new(LLVMConstAddrSpaceCast(self.as_value_ref(), ptr_type.as_type_ref())) } 192 | } 193 | 194 | pub fn replace_all_uses_with(self, other: PointerValue<'ctx>) { 195 | self.ptr_value.replace_all_uses_with(other.as_value_ref()) 196 | } 197 | } 198 | 199 | unsafe impl AsValueRef for PointerValue<'_> { 200 | fn as_value_ref(&self) -> LLVMValueRef { 201 | self.ptr_value.value 202 | } 203 | } 204 | 205 | impl Display for PointerValue<'_> { 206 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 207 | write!(f, "{}", self.print_to_string()) 208 | } 209 | } 210 | 211 | impl<'ctx> TryFrom> for PointerValue<'ctx> { 212 | type Error = (); 213 | 214 | fn try_from(value: InstructionValue) -> Result { 215 | if value.get_type().is_pointer_type() { 216 | unsafe { Ok(PointerValue::new(value.as_value_ref())) } 217 | } else { 218 | Err(()) 219 | } 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /src/values/scalable_vec_value.rs: -------------------------------------------------------------------------------- 1 | #[llvm_versions(..=16)] 2 | use llvm_sys::core::LLVMConstSelect; 3 | #[allow(deprecated)] 4 | use llvm_sys::core::LLVMGetElementAsConstant; 5 | use llvm_sys::core::{LLVMConstExtractElement, LLVMConstInsertElement, LLVMConstShuffleVector}; 6 | use llvm_sys::prelude::LLVMValueRef; 7 | 8 | use std::ffi::CStr; 9 | use std::fmt::{self, Display}; 10 | 11 | use crate::types::ScalableVectorType; 12 | use crate::values::traits::AsValueRef; 13 | use crate::values::{BasicValue, BasicValueEnum, InstructionValue, IntValue, Value}; 14 | 15 | use super::AnyValue; 16 | 17 | #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] 18 | pub struct ScalableVectorValue<'ctx> { 19 | scalable_vec_value: Value<'ctx>, 20 | } 21 | 22 | impl<'ctx> ScalableVectorValue<'ctx> { 23 | /// Get a value from an [LLVMValueRef]. 24 | /// 25 | /// # Safety 26 | /// 27 | /// The ref must be valid and of type scalable vector. 28 | pub unsafe fn new(scalable_vector_value: LLVMValueRef) -> Self { 29 | assert!(!scalable_vector_value.is_null()); 30 | 31 | ScalableVectorValue { 32 | scalable_vec_value: Value::new(scalable_vector_value), 33 | } 34 | } 35 | 36 | /// Determines whether or not a `ScalableVectorValue` is a constant. 37 | /// 38 | /// # Example 39 | /// 40 | /// ```ignore 41 | /// use inkwell::context::Context; 42 | /// 43 | /// let context = Context::create(); 44 | /// let i8_type = context.i8_type(); 45 | /// let i8_scalable_vec_type = i8_type.scalable_vec_type(3); 46 | /// let i8_scalable_vec_zero = i8_scalable_vec_type.const_zero(); 47 | /// 48 | /// assert!(i8_scalable_vec_zero.is_const()); 49 | /// ``` 50 | pub fn is_const(self) -> bool { 51 | self.scalable_vec_value.is_const() 52 | } 53 | 54 | pub fn print_to_stderr(self) { 55 | self.scalable_vec_value.print_to_stderr() 56 | } 57 | 58 | /// Gets the name of a `ScalableVectorValue`. If the value is a constant, this will 59 | /// return an empty string. 60 | pub fn get_name(&self) -> &CStr { 61 | self.scalable_vec_value.get_name() 62 | } 63 | 64 | /// Set name of the `ScalableVectorValue`. 65 | pub fn set_name(&self, name: &str) { 66 | self.scalable_vec_value.set_name(name) 67 | } 68 | 69 | pub fn get_type(self) -> ScalableVectorType<'ctx> { 70 | unsafe { ScalableVectorType::new(self.scalable_vec_value.get_type()) } 71 | } 72 | 73 | pub fn is_null(self) -> bool { 74 | self.scalable_vec_value.is_null() 75 | } 76 | 77 | pub fn is_undef(self) -> bool { 78 | self.scalable_vec_value.is_undef() 79 | } 80 | 81 | pub fn as_instruction(self) -> Option> { 82 | self.scalable_vec_value.as_instruction() 83 | } 84 | 85 | pub fn const_extract_element(self, index: IntValue<'ctx>) -> BasicValueEnum<'ctx> { 86 | unsafe { BasicValueEnum::new(LLVMConstExtractElement(self.as_value_ref(), index.as_value_ref())) } 87 | } 88 | 89 | // SubTypes: value should really be T in self: ScalableVectorValue I think 90 | pub fn const_insert_element>(self, index: IntValue<'ctx>, value: BV) -> BasicValueEnum<'ctx> { 91 | unsafe { 92 | BasicValueEnum::new(LLVMConstInsertElement( 93 | self.as_value_ref(), 94 | value.as_value_ref(), 95 | index.as_value_ref(), 96 | )) 97 | } 98 | } 99 | 100 | pub fn replace_all_uses_with(self, other: ScalableVectorValue<'ctx>) { 101 | self.scalable_vec_value.replace_all_uses_with(other.as_value_ref()) 102 | } 103 | 104 | // TODOC: Value seems to be zero initialized if index out of bounds 105 | // SubType: ScalableVectorValue -> BV 106 | #[allow(deprecated)] 107 | pub fn get_element_as_constant(self, index: u32) -> BasicValueEnum<'ctx> { 108 | unsafe { BasicValueEnum::new(LLVMGetElementAsConstant(self.as_value_ref(), index)) } 109 | } 110 | 111 | // SubTypes: self can only be ScalableVectoValue> 112 | #[llvm_versions(..=16)] 113 | pub fn const_select>(self, then: BV, else_: BV) -> BasicValueEnum<'ctx> { 114 | unsafe { 115 | BasicValueEnum::new(LLVMConstSelect( 116 | self.as_value_ref(), 117 | then.as_value_ref(), 118 | else_.as_value_ref(), 119 | )) 120 | } 121 | } 122 | 123 | // SubTypes: > self: V, right: V, mask: V -> V 124 | pub fn const_shuffle_vector( 125 | self, 126 | right: ScalableVectorValue<'ctx>, 127 | mask: ScalableVectorValue<'ctx>, 128 | ) -> ScalableVectorValue<'ctx> { 129 | unsafe { 130 | ScalableVectorValue::new(LLVMConstShuffleVector( 131 | self.as_value_ref(), 132 | right.as_value_ref(), 133 | mask.as_value_ref(), 134 | )) 135 | } 136 | } 137 | } 138 | 139 | unsafe impl AsValueRef for ScalableVectorValue<'_> { 140 | fn as_value_ref(&self) -> LLVMValueRef { 141 | self.scalable_vec_value.value 142 | } 143 | } 144 | 145 | impl Display for ScalableVectorValue<'_> { 146 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 147 | write!(f, "{}", self.print_to_string()) 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/values/struct_value.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMGetNumOperands, LLVMGetOperand, LLVMSetOperand}; 2 | 3 | use llvm_sys::prelude::LLVMValueRef; 4 | 5 | use std::ffi::CStr; 6 | use std::fmt::{self, Display}; 7 | 8 | use crate::types::StructType; 9 | use crate::values::traits::AsValueRef; 10 | use crate::values::{BasicValue, InstructionValue, Value}; 11 | 12 | use super::{AnyValue, BasicValueEnum}; 13 | 14 | #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] 15 | pub struct StructValue<'ctx> { 16 | struct_value: Value<'ctx>, 17 | } 18 | 19 | impl<'ctx> StructValue<'ctx> { 20 | /// Get a value from an [LLVMValueRef]. 21 | /// 22 | /// # Safety 23 | /// 24 | /// The ref must be valid and of type struct. 25 | pub unsafe fn new(value: LLVMValueRef) -> Self { 26 | assert!(!value.is_null()); 27 | 28 | StructValue { 29 | struct_value: Value::new(value), 30 | } 31 | } 32 | 33 | /// Gets the value of a field belonging to this `StructValue`. 34 | /// 35 | /// ```no_run 36 | /// use inkwell::context::Context; 37 | /// 38 | /// let context = Context::create(); 39 | /// let i32_type = context.i32_type(); 40 | /// let i8_type = context.i8_type(); 41 | /// let i8_val = i8_type.const_all_ones(); 42 | /// let i32_val = i32_type.const_all_ones(); 43 | /// let struct_type = context.struct_type(&[i8_type.into(), i32_type.into()], false); 44 | /// let struct_val = struct_type.const_named_struct(&[i8_val.into(), i32_val.into()]); 45 | /// 46 | /// assert!(struct_val.get_field_at_index(0).is_some()); 47 | /// assert!(struct_val.get_field_at_index(1).is_some()); 48 | /// assert!(struct_val.get_field_at_index(3).is_none()); 49 | /// assert!(struct_val.get_field_at_index(0).unwrap().is_int_value()); 50 | /// ``` 51 | pub fn get_field_at_index(self, index: u32) -> Option> { 52 | // OoB indexing seems to be unchecked and therefore is UB 53 | if index >= self.count_fields() { 54 | return None; 55 | } 56 | 57 | Some(unsafe { self.get_field_at_index_unchecked(index) }) 58 | } 59 | 60 | /// Gets the value of a field belonging to this `StructValue`. 61 | /// 62 | /// # Safety 63 | /// 64 | /// The index must be smaller than [StructValue::count_fields]. 65 | pub unsafe fn get_field_at_index_unchecked(self, index: u32) -> BasicValueEnum<'ctx> { 66 | unsafe { BasicValueEnum::new(LLVMGetOperand(self.as_value_ref(), index)) } 67 | } 68 | 69 | /// Get a field value iterator. 70 | pub fn get_fields(self) -> FieldValueIter<'ctx> { 71 | FieldValueIter { 72 | sv: self, 73 | i: 0, 74 | count: self.count_fields(), 75 | } 76 | } 77 | 78 | /// Sets the value of a field belonging to this `StructValue`. 79 | pub fn set_field_at_index>(self, index: u32, val: BV) -> bool { 80 | if self 81 | .get_type() 82 | .get_field_type_at_index(index) 83 | .map(|t| t == val.as_basic_value_enum().get_type()) 84 | != Some(true) 85 | { 86 | return false; 87 | } 88 | 89 | unsafe { LLVMSetOperand(self.as_value_ref(), index, val.as_value_ref()) } 90 | 91 | true 92 | } 93 | 94 | /// Counts the number of fields. 95 | /// 96 | /// ```no_run 97 | /// use inkwell::context::Context; 98 | /// 99 | /// let context = Context::create(); 100 | /// let i32_type = context.i32_type(); 101 | /// let i8_type = context.i8_type(); 102 | /// let i8_val = i8_type.const_all_ones(); 103 | /// let i32_val = i32_type.const_all_ones(); 104 | /// let struct_type = context.struct_type(&[i8_type.into(), i32_type.into()], false); 105 | /// let struct_val = struct_type.const_named_struct(&[i8_val.into(), i32_val.into()]); 106 | /// 107 | /// assert_eq!(struct_val.count_fields(), 2); 108 | /// assert_eq!(struct_val.count_fields(), struct_type.count_fields()); 109 | /// ``` 110 | pub fn count_fields(self) -> u32 { 111 | unsafe { LLVMGetNumOperands(self.as_value_ref()) as u32 } 112 | } 113 | 114 | /// Gets the name of a `StructValue`. If the value is a constant, this will 115 | /// return an empty string. 116 | pub fn get_name(&self) -> &CStr { 117 | self.struct_value.get_name() 118 | } 119 | 120 | /// Get name of the `StructValue`. 121 | pub fn set_name(&self, name: &str) { 122 | self.struct_value.set_name(name) 123 | } 124 | 125 | pub fn get_type(self) -> StructType<'ctx> { 126 | unsafe { StructType::new(self.struct_value.get_type()) } 127 | } 128 | 129 | pub fn is_null(self) -> bool { 130 | self.struct_value.is_null() 131 | } 132 | 133 | pub fn is_undef(self) -> bool { 134 | self.struct_value.is_undef() 135 | } 136 | 137 | pub fn print_to_stderr(self) { 138 | self.struct_value.print_to_stderr() 139 | } 140 | 141 | pub fn as_instruction(self) -> Option> { 142 | self.struct_value.as_instruction() 143 | } 144 | 145 | pub fn replace_all_uses_with(self, other: StructValue<'ctx>) { 146 | self.struct_value.replace_all_uses_with(other.as_value_ref()) 147 | } 148 | 149 | /// Determines whether or not a `StructValue` is a constant. 150 | /// 151 | /// # Example 152 | /// 153 | /// ```no_run 154 | /// use inkwell::{context::Context, values::BasicValue}; 155 | /// 156 | /// let context = Context::create(); 157 | /// let i64_type = context.i64_type(); 158 | /// let i64_val = i64_type.const_int(23, false).as_basic_value_enum(); 159 | /// let struct_val = context.const_struct(&[i64_val, i64_val], false); 160 | /// 161 | /// assert!(struct_val.is_const()); 162 | /// ``` 163 | pub fn is_const(self) -> bool { 164 | self.struct_value.is_const() 165 | } 166 | } 167 | 168 | unsafe impl AsValueRef for StructValue<'_> { 169 | fn as_value_ref(&self) -> LLVMValueRef { 170 | self.struct_value.value 171 | } 172 | } 173 | 174 | impl Display for StructValue<'_> { 175 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 176 | write!(f, "{}", self.print_to_string()) 177 | } 178 | } 179 | 180 | /// Iterate over all the field values of this struct. 181 | #[derive(Debug)] 182 | pub struct FieldValueIter<'ctx> { 183 | sv: StructValue<'ctx>, 184 | i: u32, 185 | count: u32, 186 | } 187 | 188 | impl<'ctx> Iterator for FieldValueIter<'ctx> { 189 | type Item = BasicValueEnum<'ctx>; 190 | 191 | fn next(&mut self) -> Option { 192 | if self.i < self.count { 193 | let result = unsafe { self.sv.get_field_at_index_unchecked(self.i) }; 194 | self.i += 1; 195 | Some(result) 196 | } else { 197 | None 198 | } 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /src/values/traits.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::prelude::LLVMValueRef; 2 | 3 | #[llvm_versions(12..)] 4 | use llvm_sys::core::LLVMIsPoison; 5 | 6 | use std::fmt::Debug; 7 | 8 | use crate::support::LLVMString; 9 | use crate::types::{ 10 | FloatMathType, FloatType, IntMathType, IntType, PointerMathType, PointerType, ScalableVectorType, VectorType, 11 | }; 12 | use crate::values::{ 13 | AggregateValueEnum, AnyValueEnum, ArrayValue, BasicValueEnum, BasicValueUse, CallSiteValue, FloatValue, 14 | FunctionValue, GlobalValue, InstructionValue, IntValue, PhiValue, PointerValue, ScalableVectorValue, StructValue, 15 | Value, VectorValue, 16 | }; 17 | 18 | use super::{BasicMetadataValueEnum, MetadataValue}; 19 | 20 | // This is an ugly privacy hack so that Type can stay private to this module 21 | // and so that super traits using this trait will be not be implementable 22 | // outside this library 23 | pub unsafe trait AsValueRef { 24 | fn as_value_ref(&self) -> LLVMValueRef; 25 | } 26 | 27 | macro_rules! trait_value_set { 28 | ($trait_name:ident: $($args:ident),*) => ( 29 | $( 30 | unsafe impl<'ctx> $trait_name<'ctx> for $args<'ctx> {} 31 | )* 32 | 33 | // REVIEW: Possible encompassing methods to implement: 34 | // as_instruction, is_sized, ge/set metadata methods 35 | ); 36 | } 37 | 38 | macro_rules! math_trait_value_set { 39 | ($trait_name:ident: $(($value_type:ident => $base_type:ident)),*) => ( 40 | $( 41 | unsafe impl<'ctx> $trait_name<'ctx> for $value_type<'ctx> { 42 | type BaseType = $base_type<'ctx>; 43 | unsafe fn new(value: LLVMValueRef) -> $value_type<'ctx> { 44 | unsafe { 45 | $value_type::new(value) 46 | } 47 | } 48 | } 49 | )* 50 | ) 51 | } 52 | 53 | macro_rules! base_trait_value_set { 54 | ($trait_name:ident: $($value_type:ident),*) => ( 55 | $( 56 | unsafe impl<'ctx> $trait_name<'ctx> for $value_type<'ctx> { 57 | unsafe fn new(value: LLVMValueRef) -> $value_type<'ctx> { 58 | unsafe { 59 | $value_type::new(value) 60 | } 61 | } 62 | } 63 | )* 64 | ) 65 | } 66 | 67 | /// Represents an aggregate value, built on top of other values. 68 | pub unsafe trait AggregateValue<'ctx>: BasicValue<'ctx> { 69 | /// Returns an enum containing a typed version of the `AggregateValue`. 70 | fn as_aggregate_value_enum(&self) -> AggregateValueEnum<'ctx> { 71 | unsafe { AggregateValueEnum::new(self.as_value_ref()) } 72 | } 73 | 74 | // REVIEW: How does LLVM treat out of bound index? Maybe we should return an Option? 75 | // or is that only in bounds GEP 76 | // REVIEW: Should this be AggregatePointerValue? 77 | #[llvm_versions(..=14)] 78 | fn const_extract_value(&self, indexes: &mut [u32]) -> BasicValueEnum<'ctx> { 79 | use llvm_sys::core::LLVMConstExtractValue; 80 | 81 | unsafe { 82 | BasicValueEnum::new(LLVMConstExtractValue( 83 | self.as_value_ref(), 84 | indexes.as_mut_ptr(), 85 | indexes.len() as u32, 86 | )) 87 | } 88 | } 89 | 90 | // SubTypes: value should really be T in self: VectorValue I think 91 | #[llvm_versions(..=14)] 92 | fn const_insert_value>(&self, value: BV, indexes: &mut [u32]) -> BasicValueEnum<'ctx> { 93 | use llvm_sys::core::LLVMConstInsertValue; 94 | 95 | unsafe { 96 | BasicValueEnum::new(LLVMConstInsertValue( 97 | self.as_value_ref(), 98 | value.as_value_ref(), 99 | indexes.as_mut_ptr(), 100 | indexes.len() as u32, 101 | )) 102 | } 103 | } 104 | } 105 | 106 | /// Represents a basic value, which can be used both by itself, or in an `AggregateValue`. 107 | pub unsafe trait BasicValue<'ctx>: AnyValue<'ctx> { 108 | /// Returns an enum containing a typed version of the `BasicValue`. 109 | fn as_basic_value_enum(&self) -> BasicValueEnum<'ctx> { 110 | unsafe { BasicValueEnum::new(self.as_value_ref()) } 111 | } 112 | 113 | /// Most `BasicValue`s are the byproduct of an instruction 114 | /// and so are convertible into an `InstructionValue` 115 | fn as_instruction_value(&self) -> Option> { 116 | let value = unsafe { Value::new(self.as_value_ref()) }; 117 | 118 | if !value.is_instruction() { 119 | return None; 120 | } 121 | 122 | unsafe { Some(InstructionValue::new(self.as_value_ref())) } 123 | } 124 | 125 | fn get_first_use(&self) -> Option { 126 | unsafe { Value::new(self.as_value_ref()).get_first_use() } 127 | } 128 | 129 | /// Sets the name of a `BasicValue`. If the value is a constant, this is a noop. 130 | fn set_name(&self, name: &str) { 131 | unsafe { Value::new(self.as_value_ref()).set_name(name) } 132 | } 133 | 134 | // REVIEW: Possible encompassing methods to implement: 135 | // get/set metadata 136 | } 137 | 138 | /// Represents a value which is permitted in integer math operations 139 | pub unsafe trait IntMathValue<'ctx>: BasicValue<'ctx> { 140 | type BaseType: IntMathType<'ctx>; 141 | unsafe fn new(value: LLVMValueRef) -> Self; 142 | } 143 | 144 | /// Represents a value which is permitted in floating point math operations 145 | pub unsafe trait FloatMathValue<'ctx>: BasicValue<'ctx> { 146 | type BaseType: FloatMathType<'ctx>; 147 | unsafe fn new(value: LLVMValueRef) -> Self; 148 | } 149 | 150 | pub unsafe trait PointerMathValue<'ctx>: BasicValue<'ctx> { 151 | type BaseType: PointerMathType<'ctx>; 152 | unsafe fn new(value: LLVMValueRef) -> Self; 153 | } 154 | 155 | /// Represents a value which is permitted in vector operations, either fixed or scalable 156 | pub unsafe trait VectorBaseValue<'ctx>: BasicValue<'ctx> { 157 | unsafe fn new(value: LLVMValueRef) -> Self; 158 | } 159 | 160 | // REVIEW: print_to_string might be a good candidate to live here? 161 | /// Defines any struct wrapping an LLVM value. 162 | pub unsafe trait AnyValue<'ctx>: AsValueRef + Debug { 163 | /// Returns an enum containing a typed version of `AnyValue`. 164 | fn as_any_value_enum(&self) -> AnyValueEnum<'ctx> { 165 | unsafe { AnyValueEnum::new(self.as_value_ref()) } 166 | } 167 | 168 | /// Prints a value to a `LLVMString` 169 | fn print_to_string(&self) -> LLVMString { 170 | unsafe { Value::new(self.as_value_ref()).print_to_string() } 171 | } 172 | 173 | /// Returns whether the value is `poison` 174 | #[llvm_versions(12..)] 175 | fn is_poison(&self) -> bool { 176 | unsafe { LLVMIsPoison(self.as_value_ref()) == 1 } 177 | } 178 | } 179 | 180 | trait_value_set! {AggregateValue: ArrayValue, AggregateValueEnum, StructValue} 181 | trait_value_set! {AnyValue: AnyValueEnum, BasicValueEnum, BasicMetadataValueEnum, AggregateValueEnum, ArrayValue, IntValue, FloatValue, GlobalValue, PhiValue, PointerValue, FunctionValue, StructValue, VectorValue, ScalableVectorValue, InstructionValue, CallSiteValue, MetadataValue} 182 | trait_value_set! {BasicValue: ArrayValue, BasicValueEnum, AggregateValueEnum, IntValue, FloatValue, GlobalValue, StructValue, PointerValue, VectorValue, ScalableVectorValue} 183 | math_trait_value_set! {IntMathValue: (IntValue => IntType), (VectorValue => VectorType), (ScalableVectorValue => ScalableVectorType), (PointerValue => IntType)} 184 | math_trait_value_set! {FloatMathValue: (FloatValue => FloatType), (VectorValue => VectorType), (ScalableVectorValue => ScalableVectorType)} 185 | math_trait_value_set! {PointerMathValue: (PointerValue => PointerType), (VectorValue => VectorType), (ScalableVectorValue => ScalableVectorType)} 186 | base_trait_value_set! {VectorBaseValue: VectorValue, ScalableVectorValue} 187 | -------------------------------------------------------------------------------- /src/values/vec_value.rs: -------------------------------------------------------------------------------- 1 | #[llvm_versions(..=16)] 2 | use llvm_sys::core::LLVMConstSelect; 3 | #[allow(deprecated)] 4 | use llvm_sys::core::LLVMGetElementAsConstant; 5 | use llvm_sys::core::{ 6 | LLVMConstExtractElement, LLVMConstInsertElement, LLVMConstShuffleVector, LLVMIsAConstantDataVector, 7 | LLVMIsAConstantVector, 8 | }; 9 | use llvm_sys::prelude::LLVMValueRef; 10 | 11 | use std::ffi::CStr; 12 | use std::fmt::{self, Display}; 13 | 14 | use crate::types::VectorType; 15 | use crate::values::traits::AsValueRef; 16 | use crate::values::{BasicValue, BasicValueEnum, InstructionValue, IntValue, Value}; 17 | 18 | use super::AnyValue; 19 | 20 | #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] 21 | pub struct VectorValue<'ctx> { 22 | vec_value: Value<'ctx>, 23 | } 24 | 25 | impl<'ctx> VectorValue<'ctx> { 26 | /// Get a value from an [LLVMValueRef]. 27 | /// 28 | /// # Safety 29 | /// 30 | /// The ref must be valid and of type vector. 31 | pub unsafe fn new(vector_value: LLVMValueRef) -> Self { 32 | assert!(!vector_value.is_null()); 33 | 34 | VectorValue { 35 | vec_value: Value::new(vector_value), 36 | } 37 | } 38 | 39 | /// Determines whether or not a `VectorValue` is a constant. 40 | /// 41 | /// # Example 42 | /// 43 | /// ```no_run 44 | /// use inkwell::context::Context; 45 | /// 46 | /// let context = Context::create(); 47 | /// let i8_type = context.i8_type(); 48 | /// let i8_vec_type = i8_type.vec_type(3); 49 | /// let i8_vec_zero = i8_vec_type.const_zero(); 50 | /// 51 | /// assert!(i8_vec_zero.is_const()); 52 | /// ``` 53 | pub fn is_const(self) -> bool { 54 | self.vec_value.is_const() 55 | } 56 | 57 | pub fn is_constant_vector(self) -> bool { 58 | unsafe { !LLVMIsAConstantVector(self.as_value_ref()).is_null() } 59 | } 60 | 61 | pub fn is_constant_data_vector(self) -> bool { 62 | unsafe { !LLVMIsAConstantDataVector(self.as_value_ref()).is_null() } 63 | } 64 | 65 | pub fn print_to_stderr(self) { 66 | self.vec_value.print_to_stderr() 67 | } 68 | 69 | /// Gets the name of a `VectorValue`. If the value is a constant, this will 70 | /// return an empty string. 71 | pub fn get_name(&self) -> &CStr { 72 | self.vec_value.get_name() 73 | } 74 | 75 | /// Set name of the `VectorValue`. 76 | pub fn set_name(&self, name: &str) { 77 | self.vec_value.set_name(name) 78 | } 79 | 80 | pub fn get_type(self) -> VectorType<'ctx> { 81 | unsafe { VectorType::new(self.vec_value.get_type()) } 82 | } 83 | 84 | pub fn is_null(self) -> bool { 85 | self.vec_value.is_null() 86 | } 87 | 88 | pub fn is_undef(self) -> bool { 89 | self.vec_value.is_undef() 90 | } 91 | 92 | pub fn as_instruction(self) -> Option> { 93 | self.vec_value.as_instruction() 94 | } 95 | 96 | pub fn const_extract_element(self, index: IntValue<'ctx>) -> BasicValueEnum<'ctx> { 97 | unsafe { BasicValueEnum::new(LLVMConstExtractElement(self.as_value_ref(), index.as_value_ref())) } 98 | } 99 | 100 | // SubTypes: value should really be T in self: VectorValue I think 101 | pub fn const_insert_element>(self, index: IntValue<'ctx>, value: BV) -> BasicValueEnum<'ctx> { 102 | unsafe { 103 | BasicValueEnum::new(LLVMConstInsertElement( 104 | self.as_value_ref(), 105 | value.as_value_ref(), 106 | index.as_value_ref(), 107 | )) 108 | } 109 | } 110 | 111 | pub fn replace_all_uses_with(self, other: VectorValue<'ctx>) { 112 | self.vec_value.replace_all_uses_with(other.as_value_ref()) 113 | } 114 | 115 | // TODOC: Value seems to be zero initialized if index out of bounds 116 | // SubType: VectorValue -> BV 117 | #[allow(deprecated)] 118 | pub fn get_element_as_constant(self, index: u32) -> BasicValueEnum<'ctx> { 119 | unsafe { BasicValueEnum::new(LLVMGetElementAsConstant(self.as_value_ref(), index)) } 120 | } 121 | 122 | // SubTypes: self can only be VectoValue> 123 | #[llvm_versions(..=16)] 124 | pub fn const_select>(self, then: BV, else_: BV) -> BasicValueEnum<'ctx> { 125 | unsafe { 126 | BasicValueEnum::new(LLVMConstSelect( 127 | self.as_value_ref(), 128 | then.as_value_ref(), 129 | else_.as_value_ref(), 130 | )) 131 | } 132 | } 133 | 134 | // SubTypes: > self: V, right: V, mask: V -> V 135 | pub fn const_shuffle_vector(self, right: VectorValue<'ctx>, mask: VectorValue<'ctx>) -> VectorValue<'ctx> { 136 | unsafe { 137 | VectorValue::new(LLVMConstShuffleVector( 138 | self.as_value_ref(), 139 | right.as_value_ref(), 140 | mask.as_value_ref(), 141 | )) 142 | } 143 | } 144 | } 145 | 146 | unsafe impl AsValueRef for VectorValue<'_> { 147 | fn as_value_ref(&self) -> LLVMValueRef { 148 | self.vec_value.value 149 | } 150 | } 151 | 152 | impl Display for VectorValue<'_> { 153 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 154 | write!(f, "{}", self.print_to_string()) 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /tests/all/main.rs: -------------------------------------------------------------------------------- 1 | //! Having a main.rs in a directory w/ mods will force tests to be built in a single binary 2 | 3 | #[macro_use] 4 | extern crate inkwell_internals; 5 | 6 | mod test_attributes; 7 | mod test_basic_block; 8 | mod test_builder; 9 | mod test_context; 10 | mod test_debug_info; 11 | mod test_execution_engine; 12 | mod test_instruction_conversion; 13 | mod test_instruction_values; 14 | #[cfg(not(feature = "llvm8-0"))] 15 | mod test_intrinsics; 16 | mod test_module; 17 | mod test_object_file; 18 | #[cfg(not(any(feature = "llvm17-0", feature = "llvm18-1")))] 19 | mod test_passes; 20 | mod test_targets; 21 | mod test_tari_example; 22 | mod test_types; 23 | mod test_values; 24 | -------------------------------------------------------------------------------- /tests/all/test_basic_block.rs: -------------------------------------------------------------------------------- 1 | use inkwell::context::Context; 2 | use inkwell::values::InstructionOpcode; 3 | 4 | #[test] 5 | fn test_basic_block_ordering() { 6 | let context = Context::create(); 7 | let module = context.create_module("test"); 8 | let builder = context.create_builder(); 9 | 10 | assert!(builder.get_insert_block().is_none()); 11 | 12 | let i128_type = context.i128_type(); 13 | let fn_type = i128_type.fn_type(&[], false); 14 | 15 | let function = module.add_function("testing", fn_type, None); 16 | 17 | assert!(function.get_first_basic_block().is_none()); 18 | 19 | let basic_block = context.append_basic_block(function, "entry"); 20 | let basic_block4 = context.insert_basic_block_after(basic_block, "block4"); 21 | let basic_block2 = context.insert_basic_block_after(basic_block, "block2"); 22 | let basic_block3 = context.prepend_basic_block(basic_block4, "block3"); 23 | 24 | for basic_blocks in [function.get_basic_blocks(), function.get_basic_block_iter().collect()] { 25 | assert_eq!(basic_blocks.len(), 4); 26 | assert_eq!(basic_blocks[0], basic_block); 27 | assert_eq!(basic_blocks[1], basic_block2); 28 | assert_eq!(basic_blocks[2], basic_block3); 29 | assert_eq!(basic_blocks[3], basic_block4); 30 | } 31 | 32 | assert!(basic_block3.move_before(basic_block2).is_ok()); 33 | assert!(basic_block.move_after(basic_block4).is_ok()); 34 | 35 | let basic_block5 = context.prepend_basic_block(basic_block, "block5"); 36 | 37 | for basic_blocks in [function.get_basic_blocks(), function.get_basic_block_iter().collect()] { 38 | assert_eq!(basic_blocks.len(), 5); 39 | assert_eq!(basic_blocks[0], basic_block3); 40 | assert_eq!(basic_blocks[1], basic_block2); 41 | assert_eq!(basic_blocks[2], basic_block4); 42 | assert_eq!(basic_blocks[3], basic_block5); 43 | assert_eq!(basic_blocks[4], basic_block); 44 | 45 | assert_ne!(basic_blocks[0], basic_block); 46 | assert_ne!(basic_blocks[1], basic_block3); 47 | assert_ne!(basic_blocks[2], basic_block2); 48 | assert_ne!(basic_blocks[3], basic_block4); 49 | assert_ne!(basic_blocks[4], basic_block5); 50 | } 51 | 52 | context.append_basic_block(function, "block6"); 53 | 54 | let bb1 = function.get_first_basic_block().unwrap(); 55 | let bb4 = basic_block5.get_previous_basic_block().unwrap(); 56 | 57 | assert_eq!(bb1, basic_block3); 58 | assert_eq!(bb4, basic_block4); 59 | assert!(basic_block3.get_previous_basic_block().is_none()); 60 | 61 | unsafe { 62 | assert!(bb4.delete().is_ok()); 63 | } 64 | 65 | let bb2 = basic_block5.get_previous_basic_block().unwrap(); 66 | 67 | assert_eq!(bb2, basic_block2); 68 | 69 | let bb3 = function.get_first_basic_block().unwrap(); 70 | 71 | assert_eq!(bb3, basic_block3); 72 | assert_eq!(basic_block.get_name().to_str(), Ok("entry")); 73 | assert_eq!(basic_block2.get_name().to_str(), Ok("block2")); 74 | assert_eq!(basic_block3.get_name().to_str(), Ok("block3")); 75 | assert_eq!(basic_block5.get_name().to_str(), Ok("block5")); 76 | } 77 | 78 | #[test] 79 | fn test_get_basic_blocks() { 80 | let context = Context::create(); 81 | let module = context.create_module("test"); 82 | 83 | let bool_type = context.bool_type(); 84 | let fn_type = bool_type.fn_type(&[], false); 85 | 86 | let function = module.add_function("testing", fn_type, None); 87 | 88 | assert_eq!(function.get_name().to_str(), Ok("testing")); 89 | assert_eq!(fn_type.get_return_type().unwrap().into_int_type().get_bit_width(), 1); 90 | 91 | assert!(function.get_last_basic_block().is_none()); 92 | assert_eq!(function.get_basic_blocks().len(), 0); 93 | assert_eq!(function.get_basic_block_iter().count(), 0); 94 | 95 | let basic_block = context.append_basic_block(function, "entry"); 96 | 97 | let last_basic_block = function 98 | .get_last_basic_block() 99 | .expect("Did not find expected basic block"); 100 | 101 | assert_eq!(last_basic_block, basic_block); 102 | 103 | for basic_blocks in [function.get_basic_blocks(), function.get_basic_block_iter().collect()] { 104 | assert_eq!(basic_blocks.len(), 1); 105 | assert_eq!(basic_blocks[0], basic_block); 106 | } 107 | } 108 | 109 | #[test] 110 | fn test_get_terminator() { 111 | let context = Context::create(); 112 | let module = context.create_module("test"); 113 | let builder = context.create_builder(); 114 | 115 | let void_type = context.void_type(); 116 | let fn_type = void_type.fn_type(&[], false); 117 | 118 | let function = module.add_function("testing", fn_type, None); 119 | let basic_block = context.append_basic_block(function, "entry"); 120 | 121 | builder.position_at_end(basic_block); 122 | 123 | // REVIEW: What's the difference between a terminator and last instruction? 124 | assert!(basic_block.get_terminator().is_none()); 125 | assert!(basic_block.get_first_instruction().is_none()); 126 | assert!(basic_block.get_last_instruction().is_none()); 127 | 128 | builder.build_return(None).unwrap(); 129 | 130 | assert_eq!( 131 | basic_block.get_terminator().unwrap().get_opcode(), 132 | InstructionOpcode::Return 133 | ); 134 | assert_eq!( 135 | basic_block.get_first_instruction().unwrap().get_opcode(), 136 | InstructionOpcode::Return 137 | ); 138 | assert_eq!( 139 | basic_block.get_last_instruction().unwrap().get_opcode(), 140 | InstructionOpcode::Return 141 | ); 142 | assert_eq!(basic_block.get_last_instruction(), basic_block.get_terminator()); 143 | } 144 | 145 | #[test] 146 | fn test_no_parent() { 147 | let context = Context::create(); 148 | let module = context.create_module("test"); 149 | 150 | let void_type = context.void_type(); 151 | let fn_type = void_type.fn_type(&[], false); 152 | 153 | let function = module.add_function("testing", fn_type, None); 154 | let basic_block = context.append_basic_block(function, "entry"); 155 | let basic_block2 = context.append_basic_block(function, "next"); 156 | 157 | assert_eq!(basic_block.get_parent().unwrap(), function); 158 | assert_eq!(basic_block.get_next_basic_block().unwrap(), basic_block2); 159 | 160 | assert!(basic_block.remove_from_function().is_ok()); 161 | 162 | assert!(basic_block.get_next_basic_block().is_none()); 163 | assert!(basic_block2.get_previous_basic_block().is_none()); 164 | 165 | assert!(basic_block.remove_from_function().is_err()); 166 | assert!(basic_block.remove_from_function().is_err()); 167 | 168 | assert!(basic_block.get_parent().is_none()); 169 | } 170 | 171 | #[test] 172 | fn test_rauw() { 173 | let context = Context::create(); 174 | let builder = context.create_builder(); 175 | let module = context.create_module("my_mod"); 176 | let void_type = context.void_type(); 177 | let fn_type = void_type.fn_type(&[], false); 178 | let fn_val = module.add_function("my_fn", fn_type, None); 179 | let entry = context.append_basic_block(fn_val, "entry"); 180 | let bb1 = context.append_basic_block(fn_val, "bb1"); 181 | let bb2 = context.append_basic_block(fn_val, "bb2"); 182 | builder.position_at_end(entry); 183 | let branch_inst = builder.build_unconditional_branch(bb1).unwrap(); 184 | 185 | bb1.replace_all_uses_with(&bb1); // no-op 186 | bb1.replace_all_uses_with(&bb2); 187 | 188 | assert_eq!(branch_inst.get_operand(0).unwrap().right().unwrap(), bb2); 189 | } 190 | 191 | #[test] 192 | fn test_get_first_use() { 193 | let context = Context::create(); 194 | let module = context.create_module("ivs"); 195 | let builder = context.create_builder(); 196 | let void_type = context.void_type(); 197 | let fn_type = void_type.fn_type(&[], false); 198 | let fn_val = module.add_function("my_fn", fn_type, None); 199 | let entry = context.append_basic_block(fn_val, "entry"); 200 | let bb1 = context.append_basic_block(fn_val, "bb1"); 201 | let bb2 = context.append_basic_block(fn_val, "bb2"); 202 | builder.position_at_end(entry); 203 | let branch_inst = builder.build_unconditional_branch(bb1).unwrap(); 204 | 205 | assert!(bb2.get_first_use().is_none()); 206 | assert!(bb1.get_first_use().is_some()); 207 | assert_eq!(bb1.get_first_use().unwrap().get_user(), branch_inst); 208 | assert!(bb1.get_first_use().unwrap().get_next_use().is_none()); 209 | } 210 | 211 | #[test] 212 | fn test_get_address() { 213 | let context = Context::create(); 214 | let module = context.create_module("my_mod"); 215 | let void_type = context.void_type(); 216 | let fn_type = void_type.fn_type(&[], false); 217 | let fn_val = module.add_function("my_fn", fn_type, None); 218 | let entry_bb = context.append_basic_block(fn_val, "entry"); 219 | let next_bb = context.append_basic_block(fn_val, "next"); 220 | 221 | assert!(unsafe { entry_bb.get_address() }.is_none()); 222 | assert!(unsafe { next_bb.get_address() }.is_some()); 223 | } 224 | -------------------------------------------------------------------------------- /tests/all/test_context.rs: -------------------------------------------------------------------------------- 1 | use inkwell::context::Context; 2 | use inkwell::AddressSpace; 3 | 4 | #[test] 5 | fn test_no_context_double_free() { 6 | let context = Context::create(); 7 | let int = context.i8_type(); 8 | 9 | { 10 | int.get_context(); 11 | } 12 | } 13 | 14 | #[test] 15 | fn test_no_context_double_free3() { 16 | unsafe { 17 | Context::get_global(|_ctx| ()); 18 | Context::get_global(|_ctx| ()); 19 | } 20 | } 21 | 22 | #[test] 23 | fn test_get_context_from_contextless_value() { 24 | let context = Context::create(); 25 | 26 | unsafe { 27 | Context::get_global(|global_context| { 28 | let int = global_context.i8_type(); 29 | 30 | assert_ne!(int.get_context(), context); 31 | assert_eq!(int.get_context(), *global_context); 32 | assert_ne!(*global_context, context); 33 | }) 34 | }; 35 | } 36 | 37 | #[test] 38 | fn test_basic_block_context() { 39 | let context = Context::create(); 40 | let module = context.create_module("my_mod"); 41 | let void_type = context.void_type(); 42 | let fn_type = void_type.fn_type(&[], false); 43 | let fn_value = module.add_function("my_fn", fn_type, None); 44 | let basic_block = context.append_basic_block(fn_value, "entry"); 45 | 46 | assert_eq!(basic_block.get_context(), context); 47 | } 48 | 49 | #[test] 50 | fn test_values_get_context() { 51 | let context = Context::create(); 52 | let void_type = context.void_type(); 53 | let i8_type = context.i8_type(); 54 | let f32_type = context.f32_type(); 55 | let f32_vec_type = f32_type.vec_type(3); 56 | #[cfg(feature = "typed-pointers")] 57 | let f32_ptr_type = f32_type.ptr_type(AddressSpace::default()); 58 | #[cfg(not(feature = "typed-pointers"))] 59 | let f32_ptr_type = context.ptr_type(AddressSpace::default()); 60 | let f32_array_type = f32_type.array_type(2); 61 | let fn_type = f32_type.fn_type(&[], false); 62 | let struct_type = context.struct_type(&[i8_type.into(), f32_type.into()], false); 63 | 64 | assert_eq!(f32_type.get_context(), context); 65 | assert_eq!(void_type.get_context(), context); 66 | assert_eq!(f32_vec_type.get_context(), context); 67 | assert_eq!(f32_ptr_type.get_context(), context); 68 | assert_eq!(f32_array_type.get_context(), context); 69 | assert_eq!(fn_type.get_context(), context); 70 | assert_eq!(i8_type.get_context(), context); 71 | assert_eq!(struct_type.get_context(), context); 72 | } 73 | 74 | #[llvm_versions(12..)] 75 | #[test] 76 | fn test_get_struct_type() { 77 | let context = Context::create(); 78 | 79 | let name = "opaque"; 80 | let opaque = context.opaque_struct_type(name); 81 | 82 | let got = context.get_struct_type(name); 83 | assert_eq!(got, Some(opaque)); 84 | 85 | assert_eq!(context.get_struct_type("non-existent"), None); 86 | } 87 | -------------------------------------------------------------------------------- /tests/all/test_instruction_conversion.rs: -------------------------------------------------------------------------------- 1 | use std::convert::TryInto; 2 | 3 | use inkwell::context::Context; 4 | use inkwell::values::{FloatValue, IntValue, PhiValue, PointerValue}; 5 | use inkwell::AddressSpace; 6 | 7 | #[test] 8 | fn test_phi_conversion() { 9 | let context = Context::create(); 10 | let module = context.create_module("phi"); 11 | let builder = context.create_builder(); 12 | 13 | let fn_type = context.void_type().fn_type(&[], false); 14 | let function = module.add_function("do_stuff", fn_type, None); 15 | let basic_block = context.append_basic_block(function, "entry"); 16 | builder.position_at_end(basic_block); 17 | 18 | // test that conversion succeeds 19 | let bool_type = context.bool_type(); 20 | let expect_phi_name = "phi_node"; 21 | let phi = builder.build_phi(bool_type, expect_phi_name).unwrap(); 22 | let instruction = phi.as_instruction(); 23 | 24 | let phi_from_instruction: PhiValue = instruction.try_into().unwrap(); 25 | let name = phi_from_instruction.get_name().to_str().unwrap(); 26 | assert_eq!(name, expect_phi_name); 27 | 28 | // test that conversion fails 29 | let ret_instruction = builder.build_return(None).unwrap(); 30 | let phi_from_instruction: Result = ret_instruction.try_into(); 31 | assert!(phi_from_instruction.is_err()); 32 | } 33 | 34 | #[test] 35 | fn test_conversion_to_int_value() { 36 | let context = Context::create(); 37 | let module = context.create_module("testing"); 38 | let builder = context.create_builder(); 39 | 40 | // Create a function whose the first parameter is of IntType 41 | let i64_type = context.i64_type(); 42 | let fn_type = context.void_type().fn_type(&[i64_type.into()], false); 43 | let function = module.add_function("testing", fn_type, None); 44 | let basic_block = context.append_basic_block(function, "entry"); 45 | builder.position_at_end(basic_block); 46 | 47 | // Create an IntType instruction 48 | let int_arg = function.get_nth_param(0).unwrap().into_int_value(); 49 | let int_const = i64_type.const_int(1, false); 50 | let int_instr = builder 51 | .build_int_add(int_arg, int_const, "add") 52 | .unwrap() 53 | .as_instruction() 54 | .unwrap(); 55 | 56 | // Test the instruction conversion to an IntValue 57 | let int_conversion: Result = int_instr.try_into(); 58 | assert!(int_conversion.is_ok()); 59 | 60 | // Test the instruction conversion to other LLVM Values 61 | let float_conversion: Result = int_instr.try_into(); 62 | assert!(float_conversion.is_err()); 63 | let ptr_conversion: Result = int_instr.try_into(); 64 | assert!(ptr_conversion.is_err()); 65 | } 66 | 67 | #[test] 68 | fn test_conversion_to_float_value() { 69 | let context = Context::create(); 70 | let module = context.create_module("testing"); 71 | let builder = context.create_builder(); 72 | 73 | // Create a function whose the first parameter is of IntType 74 | let f16_type = context.f16_type(); 75 | let fn_type = context.void_type().fn_type(&[f16_type.into()], false); 76 | let function = module.add_function("testing", fn_type, None); 77 | let basic_block = context.append_basic_block(function, "entry"); 78 | builder.position_at_end(basic_block); 79 | 80 | // Create a FloatType instruction 81 | let float_arg = function.get_nth_param(0).unwrap().into_float_value(); 82 | let float_const = f16_type.const_float(1.2); 83 | let float_instr = builder 84 | .build_float_add(float_arg, float_const, "add") 85 | .unwrap() 86 | .as_instruction() 87 | .unwrap(); 88 | 89 | // Test the instruction conversion to a FloatValue 90 | let float_conversion: Result = float_instr.try_into(); 91 | assert!(float_conversion.is_ok()); 92 | 93 | // Test the instruction conversion to other LLVM Values 94 | let int_conversion: Result = float_instr.try_into(); 95 | assert!(int_conversion.is_err()); 96 | let phi_conversion: Result = float_instr.try_into(); 97 | assert!(phi_conversion.is_err()); 98 | } 99 | 100 | #[test] 101 | fn test_conversion_to_pointer_value() { 102 | let context = Context::create(); 103 | let module = context.create_module("testing"); 104 | let builder = context.create_builder(); 105 | 106 | // Create a function whose the first parameter is of IntType 107 | let fn_type = context.void_type().fn_type(&[], false); 108 | let function = module.add_function("testing", fn_type, None); 109 | let basic_block = context.append_basic_block(function, "entry"); 110 | builder.position_at_end(basic_block); 111 | 112 | // Create a PointerType instruction 113 | #[cfg(feature = "typed-pointers")] 114 | let i64_ptr_type = context.i64_type().ptr_type(AddressSpace::default()); 115 | #[cfg(not(feature = "typed-pointers"))] 116 | let i64_ptr_type = context.ptr_type(AddressSpace::default()); 117 | let alloca_instr = builder 118 | .build_alloca(i64_ptr_type, "alloca") 119 | .unwrap() 120 | .as_instruction() 121 | .unwrap(); 122 | 123 | // Test the instruction conversion to a FloatValue 124 | let ptr_conversion: Result = alloca_instr.try_into(); 125 | assert!(ptr_conversion.is_ok()); 126 | 127 | // Test the instruction conversion to other LLVM Values 128 | let int_conversion: Result = alloca_instr.try_into(); 129 | assert!(int_conversion.is_err()); 130 | let float_conversion: Result = alloca_instr.try_into(); 131 | assert!(float_conversion.is_err()); 132 | } 133 | -------------------------------------------------------------------------------- /tests/all/test_intrinsics.rs: -------------------------------------------------------------------------------- 1 | use inkwell::context::Context; 2 | use inkwell::intrinsics::Intrinsic; 3 | 4 | #[test] 5 | fn test_get_cos() { 6 | Intrinsic::find("llvm.cos").unwrap(); 7 | } 8 | 9 | #[test] 10 | fn test_get_nonexistent() { 11 | assert!(Intrinsic::find("nonsense").is_none()) 12 | } 13 | 14 | #[test] 15 | fn test_get_decl_cos() { 16 | let cos = Intrinsic::find("llvm.cos").unwrap(); 17 | 18 | assert!(cos.is_overloaded()); 19 | 20 | let context = Context::create(); 21 | let module = context.create_module("my_module"); 22 | 23 | // overloaded, so we can't get it w/o specifying types 24 | assert!(cos.get_declaration(&module, &[]).is_none()); 25 | 26 | let decl = cos.get_declaration(&module, &[context.f32_type().into()]).unwrap(); 27 | 28 | assert_eq!(decl.get_name().to_str().unwrap(), "llvm.cos.f32"); 29 | } 30 | 31 | #[test] 32 | fn test_get_decl_va_copy() { 33 | let va_copy = Intrinsic::find("llvm.va_copy").unwrap(); 34 | 35 | assert!(!va_copy.is_overloaded()); 36 | 37 | let context = Context::create(); 38 | let module = context.create_module("my_module"); 39 | 40 | assert!(va_copy.get_declaration(&module, &[]).is_some()); 41 | 42 | // even though this is nonsensial and ¿might? lead to errors later, we can still get an overloaded version for nonoverloaded intrinsic 43 | // this does not assert, which is.. Ok, I guess? 44 | let decl = va_copy.get_declaration(&module, &[context.f32_type().into()]).unwrap(); 45 | 46 | assert_eq!(decl.get_name().to_str().unwrap(), "llvm.va_copy.f32"); 47 | } 48 | -------------------------------------------------------------------------------- /tests/all/test_tari_example.rs: -------------------------------------------------------------------------------- 1 | use inkwell::context::Context; 2 | use inkwell::execution_engine::JitFunction; 3 | use inkwell::targets::{InitializationConfig, Target}; 4 | use inkwell::OptimizationLevel; 5 | 6 | #[test] 7 | fn test_tari_example() { 8 | Target::initialize_native(&InitializationConfig::default()).expect("Failed to initialize native target"); 9 | 10 | let context = Context::create(); 11 | let module = context.create_module("sum"); 12 | let builder = context.create_builder(); 13 | let execution_engine = module.create_jit_execution_engine(OptimizationLevel::None).unwrap(); 14 | 15 | let i64_type = context.i64_type(); 16 | let fn_type = i64_type.fn_type(&[i64_type.into(), i64_type.into(), i64_type.into()], false); 17 | 18 | let function = module.add_function("sum", fn_type, None); 19 | let basic_block = context.append_basic_block(function, "entry"); 20 | 21 | builder.position_at_end(basic_block); 22 | 23 | let x = function.get_nth_param(0).unwrap().into_int_value(); 24 | let y = function.get_nth_param(1).unwrap().into_int_value(); 25 | let z = function.get_nth_param(2).unwrap().into_int_value(); 26 | 27 | let sum = builder.build_int_add(x, y, "sum").unwrap(); 28 | let sum = builder.build_int_add(sum, z, "sum").unwrap(); 29 | 30 | builder.build_return(Some(&sum)).unwrap(); 31 | 32 | unsafe { 33 | type Sum = unsafe extern "C" fn(u64, u64, u64) -> u64; 34 | let sum: JitFunction = execution_engine.get_function("sum").unwrap(); 35 | 36 | let x = 1u64; 37 | let y = 2u64; 38 | let z = 3u64; 39 | 40 | assert_eq!(sum.call(x, y, z), x + y + z); 41 | } 42 | } 43 | --------------------------------------------------------------------------------