├── .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 | [](https://crates.io/crates/inkwell)
4 | [](https://github.com/TheDan64/inkwell/actions/workflows/test.yml?query=branch%3Amaster)
5 | [](https://codecov.io/gh/TheDan64/inkwell)
6 | [](https://github.com/Aaronepower/tokei)
7 | [](https://gitter.im/inkwell-rs/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
8 | 
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 |
--------------------------------------------------------------------------------